'PyQt5: how to reimplement close-event in event-filter
I have this Qt Designer made main-window: main.py
:
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(364, 480)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.verticalLayout = QtWidgets.QVBoxLayout(self.centralwidget)
self.verticalLayout.setObjectName("verticalLayout")
self.label = QtWidgets.QLabel(self.centralwidget)
self.label.setMinimumSize(QtCore.QSize(341, 71))
font = QtGui.QFont()
font.setPointSize(14)
font.setBold(True)
font.setItalic(False)
font.setWeight(75)
self.label.setFont(font)
self.label.setLayoutDirection(QtCore.Qt.LeftToRight)
self.label.setAlignment(QtCore.Qt.AlignCenter)
self.label.setObjectName("label")
self.verticalLayout.addWidget(self.label)
self.models = QtWidgets.QGroupBox(self.centralwidget)
self.models.setObjectName("models")
self.gridLayout_2 = QtWidgets.QGridLayout(self.models)
self.gridLayout_2.setObjectName("gridLayout_2")
self.scrollArea = QtWidgets.QScrollArea(self.models)
self.scrollArea.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn)
self.scrollArea.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn)
self.scrollArea.setWidgetResizable(True)
self.scrollArea.setObjectName("scrollArea")
self.scrollAreaWidgetContents = QtWidgets.QWidget()
self.scrollAreaWidgetContents.setGeometry(QtCore.QRect(0, 0, 311, 196))
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.scrollAreaWidgetContents.sizePolicy().hasHeightForWidth())
self.scrollAreaWidgetContents.setSizePolicy(sizePolicy)
self.scrollAreaWidgetContents.setObjectName("scrollAreaWidgetContents")
self.gridLayout = QtWidgets.QGridLayout(self.scrollAreaWidgetContents)
self.gridLayout.setObjectName("gridLayout")
spacerItem = QtWidgets.QSpacerItem(296, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
self.gridLayout.addItem(spacerItem, 0, 0, 1, 1)
self.scrollArea.setWidget(self.scrollAreaWidgetContents)
self.gridLayout_2.addWidget(self.scrollArea, 0, 0, 1, 1)
self.pushButton_parent_none = QtWidgets.QPushButton(self.models)
self.pushButton_parent_none.setObjectName("pushButton_parent_none")
self.gridLayout_2.addWidget(self.pushButton_parent_none, 1, 0, 1, 1)
self.pushButton_parent_main = QtWidgets.QPushButton(self.models)
self.pushButton_parent_main.setObjectName("pushButton_parent_main")
self.gridLayout_2.addWidget(self.pushButton_parent_main, 2, 0, 1, 1)
self.verticalLayout.addWidget(self.models)
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 364, 29))
self.menubar.setObjectName("menubar")
MainWindow.setMenuBar(self.menubar)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.label.setText(_translate("MainWindow", "Main"))
self.models.setTitle(_translate("MainWindow", "GroupBox"))
self.pushButton_parent_none.setText(_translate("MainWindow", "Test-set-parent_None"))
self.pushButton_parent_main.setText(_translate("MainWindow", "Test-set-parent_Main"))
and this code : myapp.py
:
import sys
from PyQt5.QtWidgets import QApplication, QMainWindow, QDesktopWidget
from main import Ui_MainWindow
class MyApp(QMainWindow, Ui_MainWindow):
def __init__(self, parent=None):
super(MyApp, self).__init__(parent)
self.setupUi(self)
self.qtRectangle = self.frameGeometry()
self.centerPoint = QDesktopWidget().availableGeometry().center()
self.qtRectangle.moveCenter(self.centerPoint)
self.move(self.qtRectangle.topLeft())
self.pushButton_parent_none.clicked.connect(
lambda checked, x=self.models: self.set_parent_none(x))
self.pushButton_parent_main.clicked.connect(
lambda checked, x=self.models: self.set_parent_main(x))
self.cnt = 0
self.models.installEventFilter(self)
self.show
def eventFilter(self, source, event):
if source == self.models:
self.cnt += 1
# print('filteredddddddddddddd : ', self.cnt, event, type(event), source)
# print('filteredddddddddddddd', event.type(), event)
if event.type() == 19:
print(source.windowTitle())
print(source)
print('filteredddddddddddddd : ',
self.cnt, event.type(), event, type(event), source)
print('source.parent() :', source.parent())
self.set_parent_main(source)
print('source.parent() :', source.parent())
return True
else:
return False
else:
return False
def closeEvent(self, evnt):
print('clooossssing main !!')
evnt.accept()
def set_parent_main(self, sender):
print('main before !!!!!! :', sender.parent())
sender.setParent(self)
print('main after !!!!!! :', sender.parent())
sender.hide()
sender.show()
def set_parent_none(self, sender):
print('none before !!!!! :', sender.parent())
sender.setParent(None)
print('none after !!!!! :', sender.parent())
sender.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
myapp = MyApp()
myapp.show()
try:
sys.exit(app.exec_())
except SystemExit:
print('Closing Window...')
When I click the Test-set-parent_None
button the QGroupBox
Widget gets detached from MainWindow; and it gets re-attached if I click the Test-set-parent_Main
button.
What is puzzling me it's why my eventFilter
it's not working. If I close the QGroupBox
with the X closing button (top right corner), I get the :
main before !!!!!! : None
main after !!!!!! : <__main__.MyApp object at 0x7ff7f35be550>
source.parent() : <__main__.MyApp object at 0x7ff7f35be550>
print that tells me that my QGroupBox
is again the child of my MainWindow - but it doesn't show up. What am I missing in my 'eventFilter' implementation?
Solution 1:[1]
Returning True
in the event-filter isn't always sufficient to prevent propagation of the event. For close-events, you must also explicitly ignore the event:
class MyApp(QMainWindow, Ui_MainWindow):
...
def eventFilter(self, source, event):
if event.type() == QtCore.QEvent.Close and source is self.models:
self.set_parent_main(source)
event.ignore()
return True
return super().eventFilter(source, event)
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | ekhumoro |