PyQt4 Mdi sub window not resizing properly - python-3.x

In the following example, when you click the button, the entire form is rebuilt adding a new label each time. At the end is a resize call that doesn't appear to work. While debugging, I validated the sizeHint() is returning the correct dimensions, and internally the widget thinks it is the correct size, but what is drawn is not correct. What can I do to force the MDI window to resize correctly? Also of note, when not sized correctly, if you manually start resizing, it suddenly snaps to the appropriate size.
import sys
import os
from PyQt4.QtCore import *
from PyQt4.QtGui import *
import PyQt4.Qt
class MdiWindow(QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)
self.count = 0
self.buildWindow()
def buildWindow(self):
main = QVBoxLayout()
button = QPushButton('Change Count')
button.clicked.connect(self.changeCount)
main.addWidget(button)
for i in range(self.count):
main.addWidget(QLabel(str(i)))
widget = QWidget()
widget.setLayout(main)
self.setCentralWidget(widget)
self.resize(main.sizeHint())
def changeCount(self, event):
self.count += 1
self.buildWindow()
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle('Resize Test')
self.mdiArea = QMdiArea()
self.setCentralWidget(self.mdiArea)
child = MdiWindow()
self.mdiArea.addSubWindow(child)
if __name__ == '__main__':
app = QApplication(sys.argv)
mainWin = MainWindow()
mainWin.show()
sys.exit(app.exec_())

Related

PyQt5: count seconds mouse is over QPushButton in tooltip

The following running code gives a window with a button on it . The tooltip displays when the mouse enters the button.
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtTest import QTest
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.layout = QVBoxLayout()
self.button = QPushButton("MyButton")
global i
i = 0
self.button.setToolTip(str(i) + " seconds has passed since you move your mouse onto MyButton")
self.button.leaveEvent = self.clear()
self.layout.addWidget(self.button)
timer = QTimer(self)
timer.timeout.connect(self.start_counting)
timer.start(1000)
self.widget = QWidget()
self.widget.setLayout(self.layout)
self.setCentralWidget(self.widget)
def clear(self):
global i
i = 0
def start_counting(self):
if self.button.underMouse() == True:
global i
i = i + 1
self.button.setToolTip(str(i) + " seconds has passed since you move your mouse onto MyButton")
if __name__ == "__main__":
app = QApplication(sys.argv)
mainWin = MainWindow()
mainWin.show()
sys.exit( app.exec_() )
My goal is to count the number of seconds the mouse is inside the button and live display it using the tooltip. More precisely, I need to make sure all of the following is happening:
Every time the mouse enters the button, the count starts at 0 seconds and the tooltip shows up.
While the mouse stays inside the button (stationary or moving), the tooltip stays shown with the number of seconds (the text displayed inside the tooltip) updated over time.
When the mouse leaves the button, the count is cleared to zero.
As seen in the code, I have attempted to use underMouse to achieve my goals. My attempt is a partial success as the tooltip does update itself when the mouse moves inside the button. However, the tooltip does not update itself when the mouse stays stationary inside the button. Also, the count does not seem to be cleared when the mouse moves outside of the button .
What am I missing ?
One solution is to use an event-filter to monitor the enter and leave events, and also use an elapsed-timer to get an accurate measure of how long the mouse has been over the target widget. Below is a basic demo based on your example that implements the above. It also tries to match the normal behaviour of tooltips, but if necessary you can easily adjust the code to suit your own needs:
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.layout = QVBoxLayout()
self.button = QPushButton("MyButton")
self.layout.addWidget(self.button)
self.widget = QWidget()
self.widget.setLayout(self.layout)
self.setCentralWidget(self.widget)
self.position = QPoint()
self.counter = QElapsedTimer()
self.timer = QTimer()
self.timer.timeout.connect(self.start_counting)
self.button.installEventFilter(self)
def eventFilter(self, source, event):
if event.type() == QEvent.Enter and source is self.button:
self.counter.start()
self.timer.start(1000)
QTimer.singleShot(500, self.start_counting)
elif event.type() == QEvent.Leave and source is self.button:
self.timer.stop()
QToolTip.hideText()
return super().eventFilter(source, event)
def start_counting(self):
if self.button.underMouse():
if not QToolTip.isVisible():
self.position = QCursor.pos()
count = int(self.counter.elapsed() / 1000)
QToolTip.showText(self.position, (
f'{count} seconds have passed since '
'you moved your mouse onto MyButton'
))
if __name__ == "__main__":
app = QApplication(sys.argv)
mainWin = MainWindow()
mainWin.show()
sys.exit( app.exec_() )

QMainWindow mouseDoubleClickEvent override not working

I'm using the below code to try and capture double clicks within the main window"
import sys
from PySide6 import QtCore
from PySide6.QtWidgets import (
QApplication,
QGridLayout,
QMainWindow,
QSplitter,
QTreeView,
QWidget,
)
from PySide6.QtWebEngineWidgets import QWebEngineView
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.windowLayout = QGridLayout()
self.splitter = QSplitter()
self.webView = QWebEngineView()
self.webView.setUrl(QtCore.QUrl("http://127.0.0.1:8080"))
self.tree = QTreeView()
self.splitter.addWidget(self.webView)
self.splitter.addWidget(self.tree)
self.windowLayout.addWidget(self.splitter)
self.mainWidget = QWidget()
self.mainWidget.setLayout(self.windowLayout)
self.setCentralWidget(self.mainWidget)
def mouseDoubleClickEvent(self, e):
print('test')
if __name__ == "__main__":
app = QApplication(sys.argv)
window = MainWindow()
window.resize(1500, 1000)
window.show()
app.exec()
And I get the following console output:
qt.pointer.dispatch: delivering touch release to same window QWindow(0x0) not QWidgetWindow(0x600003bb8e40, name="MainWindowClassWindow")
qt.pointer.dispatch: skipping QEventPoint(id=1 ts=0 pos=0,0 scn=749.346,451.159 gbl=749.346,451.159 Released ellipse=(1x1 ∡ 0) vel=0,0 press=-749.346,-451.159 last=-749.346,-451.159 Δ 749.346,451.159) : no target window
however, when I comment out self.setCentralWidget(self.mainWidget) I obviously don't see anything, but the double click triggers. Any suggestions?
EDIT: update to min repro, also note that clicking anywhere not inside the QWebEngineView correctly results in mouseDoubleClickEvent triggering. However, the above error results when I click in the QWebEngineView, and nothing happens when I click inside the QTreeView
As per musicamante's very useful comments (see original post), the solution I ended up using was
...
self.tree.doubleClicked.connect(self.treeDoubleClicked)
...
def treeDoubleClicked(self, index):
self.selectedFilepath = index.model().filePath(index)

slot to right click menu action does does not work

I have written the below code to which I finally managed to add menu but connecitn menu to a function doesnt seem to work:
import os
from PyQt5 import uic
from PyQt5 import QtWidgets
from PyQt5 import QtCore
FILE_LOCATION = os.path.dirname(os.path.realpath(__file__))
class MainDialogWindow(QtWidgets.QDialog):
def __init__(self):
super(MainDialogWindow,self).__init__()
ui_file = os.path.join(FILE_LOCATION, "example.ui")
self._ui = uic.loadUi(ui_file, self)
self.registerCallbacks()
self.initUI()
def initUI(self):
"""Initialize the UI.
"""
self.textBrowser.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
def registerCallbacks(self):
self.textBrowser.customContextMenuRequested.connect(self.context_menu)
# self.connect(self.textBrowser, QtCore.Signal('customContextMenuRequested(const QPoint &)'), self.context_menu)
def context_menu(self, pos):
menu = QtWidgets.QMenu(self)
action = menu.addAction("clear")
menu.exec_(self.mapToGlobal(pos))
action.trigered.connect(self.clear)
def clear(self):
"""Slot to claer text.
"""
print("clear")
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
window = MainDialogWindow()
window.show()
window.setGeometry(500, 300, 300, 300)
sys.exit(app.exec_())
please helpp,, I want call the clear function from the right click menu
I don't seem to understand how the menu.exec_() method works, that method blocks the execution of sequential tasks until the user selects a QAction from the QMenu. In your case, for example, until when you press "clear" and the triggered signal is emitted (note: you have a typo), but at that moment there is no connection, so the clear method will not be called. The solution is to make the connection before invoking the QMenu exec_():
def context_menu(self, pos):
menu = QtWidgets.QMenu(self)
action = menu.addAction("clear")
action.triggered.connect(self.clear)
menu.exec_(self.mapToGlobal(pos))

PyQt5 - Can QTabWidget content extend up to Main Window edges, even with no content?

I am new to PyQt5... Simple question here.
I am using PyQt5 to build a simple application. This application has a Main Window containing a QTabWidget with 3 tabs. Once the application starts, all tab pages are empty and get filled later on. When tab pages are empty, I would still like them to appear as blank pages and extend up to the Main Window edges.
I've been trying to achieve this in two ways: using a layout and using the setGeometry function. Yet the tab pages never extend vertically very far, and horizontally they never go beyond the last tab. See code below.
import sys
from PyQt5.QtWidgets import *
class MainWindow(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("Window With Tabs")
self.setGeometry(50,50,400,400)
oTabWidget = QTabWidget(self)
oPage1 = QWidget()
oLabel1 = QLabel("Hello",self)
oVBox1 = QVBoxLayout()
oVBox1.addWidget(oLabel1)
oPage1.setLayout(oVBox1)
oPage2 = QWidget()
oPage2.setGeometry(0,0,400,400)
oPage3 = QWidget()
oPage3.setGeometry(0,0,400,400)
oTabWidget.addTab(oPage1,"Page1")
oTabWidget.addTab(oPage2,"Page2")
oTabWidget.addTab(oPage3,"Page3")
self.show()
if __name__ == "__main__":
app = QApplication(sys.argv)
oMainwindow = MainWindow()
sys.exit(app.exec_())
Any idea how to modify the code so the empty pages will extend up to the edges of Main Window ?
Set a layout on the main widget:
class MainWindow(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("Window With Tabs")
self.setGeometry(50,50,400,400)
layout = QVBoxLayout(self)
oTabWidget = QTabWidget(self)
layout.addWidget(oTabWidget)
The setGeometry calls on the other widgets are redundant.
import sys
from PyQt5.QtWidgets import *
class MainWindow(QWidget):
# window object
def __init__(self):
super().__init__()
self.initGUI() # call custom code
def initGUI(self):
self.setWindowTitle("Window With Tabs") # window...
self.setGeometry(50,50,400,400) #...properties
TabW=self.createTabs() # a custom-tab object
layout = QVBoxLayout(self) # main window layout
layout.addWidget(TabW) #populate layout with Tab object
self.show() # display window
def createTabs(self): # create and return Tab object
oPage1 = QWidget() # tabs...
oPage2 = QWidget()
oPage3 = QWidget()
oTabWidget = QTabWidget() # Tabobject
oTabWidget.addTab(oPage1,"Page1") # populate tab object...
oTabWidget.addTab(oPage2,"Page2")
oTabWidget.addTab(oPage3,"Page3")
return oTabWidget # return tab object
if __name__ == "__main__": # Rest is History!
app = QApplication(sys.argv)
oMainwindow = MainWindow()
sys.exit(app.exec_())

PyQt keyPressEvent not triggered from QDialog

I have a simple example of of a dialog window that has the keyPressEvent method. However, no matter what is typed when the sub window has focus, the event is not triggered.
import sys
from PyQt4.QtCore import *
from PyQt4.QtGui import *
import PyQt4.Qt
class KpeWindow(QDialog):
def __init__(self, parent=None):
super().__init__(parent)
main = QVBoxLayout(self)
label = QLabel(self)
label.setText('Test the keyPressEvent')
self.adjustSize()
self.setLayout(main)
def keyPressEvent(self, event):
QMessageBox.warning(self, 'MDI', 'keyPressEvent')
super().keyPressEvent(event)
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle('KeyPressEvent Test')
child = KpeWindow()
self.setCentralWidget(child)
if __name__ == '__main__':
app = QApplication(sys.argv)
mainWin = MainWindow()
mainWin.show()
sys.exit(app.exec_())
The following code works:
class KpeWindow(QWidget):
def __init__(self, parent=None):
QWidget.__init__(self,parent)
main = QVBoxLayout(self)
label = QLabel(self)
label.setText('Test the keyPressEvent')
main.addWidget(label)
self.adjustSize()
self.setLayout(main)
def keyPressEvent(self, event):
QMessageBox.warning(self, 'MDI', 'keyPressEvent')
self.parent().keyPressEvent(event)
class MainWindow(QMainWindow):
def __init__(self):
QMainWindow.__init__(self)
self.setWindowTitle('KeyPressEvent Test')
main = QVBoxLayout(self)
child = KpeWindow(self)
child.setFocusPolicy(Qt.StrongFocus)
self.setFocusProxy(child)
main.addWidget(child)
child.setFocus(True)
self.adjustSize()
self.setLayout(main)
I am not sure which of my changes work, I suspect setFocusProxy. In general I would recommend using QWidget as the child, and putting things into layouts even when there are no siblings.
The keyPressEvent is sensitive to the focus policy. In your example, the event is going to the QMainWindow (if you move the keyPressEvent to there, it does receive key events).
Is there any reason to have a dialog within a window? If you launch the dialog in the usual way, using child.show(), child.exec_() instead of setCentralWidget, it shows in a separate window and captures the key event.

Resources