要么我不完全理解 Qt 的事件传播是如何工作的,要么是其他什么,但我无法理解为什么 QPushButton 派生类和 QWidget 派生类本身都没有调用 closeEvent。
wid.closeEvent() 不应该触发所有子部件的 closeEvents 吗?
#!/bin/env python
# -*- coding: utf-8 -*-
import sys, os
from Qt.QtCore import *
from Qt.QtWidgets import *
from Qt.QtGui import *
class butt(QPushButton):
def __init__(self, parent, name='Button'):
super(self.__class__, self).__init__(parent)
self.name = name
def closeEvent(self, e):
print('butt closeevent')
e.accept()
class wid(QWidget):
def __init__(self, parent=None):
super(self.__class__, self).__init__(parent)
self.initUI()
def initUI(self):
#self.setAttribute(Qt.WA_DeleteOnClose)
self.vl = QVBoxLayout(self)
self.button = butt(self)
self.button.setText('test1')
self.vl.addWidget(self.button)
self.button.clicked.connect(QCoreApplication.quit)
def closeEvent(self, e):
print('wid closeevent')
e.accept()
def show():
app = QApplication(sys.argv)
win = QMainWindow()
widget = wid(win)
win.setCentralWidget(widget)
win.show()
app.exec_()
if __name__ == "__main__":
show()
Run Code Online (Sandbox Code Playgroud)
我期望看到 2 行 wid closeevent butt closeevent 作为输出,但我什么也没看到。为什么 closeEvent 没有被调用?
在下面的示例中,当您直观地按下按钮时,您将观察到相同的行为:窗口将关闭,但我们看到了区别,在第一个窗口中它被称为 closeEvent(),而在第二个窗口中则不是。
示例1:
#!/bin/env python
# -*- coding: utf-8 -*-
from Qt import QtCore, QtGui, QtWidgets
class Button(QtWidgets.QPushButton):
def closeEvent(self, event):
print("button closeEvent")
event.accept()
def main():
import sys
app = QtWidgets.QApplication(sys.argv)
button = Button(text="Press me")
button.clicked.connect(button.close)
button.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()
Run Code Online (Sandbox Code Playgroud)
示例2:
#!/bin/env python
# -*- coding: utf-8 -*-
from Qt import QtCore, QtGui, QtWidgets
class Button(QtWidgets.QPushButton):
def closeEvent(self, event):
print("button closeEvent")
event.accept()
def main():
import sys
app = QtWidgets.QApplication(sys.argv)
button = Button(text="Press me")
button.clicked.connect(QtCore.QCoreApplication.quit)
button.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()
Run Code Online (Sandbox Code Playgroud)
为什么在调用 QCoreApplication::quit 时不调用 closeEvent? 因为该方法用于退出Qt的事件循环,如果没有事件循环,则events(QCloseEvent)不起作用。
当一个widget关闭时,子widget并没有关闭,也就是说,只有当一个widget关闭时,才会调用它自己的closeEvent。因此,如果您希望调用小部件的 closeevent,请调用您的方法 close。
#!/bin/env python
# -*- coding: utf-8 -*-
from Qt import QtCore, QtGui, QtWidgets
class Button(QtWidgets.QPushButton):
def __init__(self, name="Button", parent=None):
super(Button, self).__init__(parent)
self.m_name = name
def closeEvent(self, event):
print("button closeEvent")
event.accept()
class Widget(QtWidgets.QWidget):
def __init__(self, parent=None):
super(Widget, self).__init__(parent)
self.initUI()
def initUI(self):
vl = QtWidgets.QVBoxLayout(self)
button = Button()
button.setText("test1")
vl.addWidget(button)
button.clicked.connect(self.close)
def closeEvent(self, event):
print("Widget closeevent")
event.accept()
def main():
import sys
app = QtWidgets.QApplication(sys.argv)
w = QtWidgets.QMainWindow()
widget = Widget()
w.setCentralWidget(widget)
w.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()
Run Code Online (Sandbox Code Playgroud)
在前面的示例中,根据您与小部件交互的方式,您将获得以下行为:
如果您按下按钮,小部件将关闭,因此它将被称为 closeEvent,并且不会调用按钮的 closeEvent,因为即使您的孩子也没有关闭它。
如果你按下窗口中的“X”按钮,它不会被称为窗口部件的closeEvent,而是被称为QMainWindow,解释与上一相同。
结论:
每种类型的事件都有自己的工作流程,某些事件仅由小部件接收,而不会由子部件接收,而其他事件则将信息发送给子部件。
close 方法使用事件循环来通知小部件要关闭,但 QCoreApplication::quit() 终止事件循环。
更新:
为什么当用户在 Qt 窗口上按“X”按钮时不调用 wid.closeEvent?主窗口不应该在其所有子窗口小部件上调用 closeEvent 然后正确销毁它们吗?
不,一件事是关闭小部件,另一件事是小部件的销毁,它可以在不关闭的情况下被销毁,并且关闭窗口不涉及销毁对象。
正如已经指出的那样,关闭窗口并不意味着删除它,可能还有其他窗口打开,但是如果默认情况下关闭最后一个 QApplication 窗口,则意味着小部件销毁的事件循环将被终止,这并不一定意味着调用 close方法。
为了便于理解,我们使用以下代码:
from Qt import QtCore, QtGui, QtWidgets
class Button(QtWidgets.QPushButton):
def closeEvent(self, event):
print("closeEvent Button")
super(Button, self).closeEvent(event)
class Widget(QtWidgets.QWidget):
def __init__(self, parent=None):
super(Widget, self).__init__(parent)
button_quit = Button(
text="quit",
clicked=QtCore.QCoreApplication.quit
)
button_close = Button(
text="close",
clicked=self.close
)
lay = QtWidgets.QVBoxLayout(self)
lay.addWidget(button_quit)
lay.addWidget(button_close)
def closeEvent(self, event):
print("closeEvent Widget")
super(Widget, self).closeEvent(event)
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
w = Widget()
w.show()
sys.exit(app.exec_())
Run Code Online (Sandbox Code Playgroud)
有 2 个按钮,在第一个按钮调用 QCoreApplication::quit() 的情况下,它将结束事件循环,因此所有小部件将被销毁,在这种情况下,不会调用 closeEvent,在第二个按钮的情况下它将在窗口附近调用,因此它将调用其 closeEvent,但不会调用其子级的 closeEvent。
我的实际问题是我在 closeEvent 中有 saveUI() 函数,并且在窗口关闭时小部件层次结构破坏时没有调用它
如果您希望分层调用 closeEvent 方法,那么您必须手动调用 close 方法,因为 Qt 没有这样设计。下一部分有一个例子:
from PyQt5 import QtCore, QtGui, QtWidgets
class PushButton(QtWidgets.QPushButton):
def closeEvent(self, event):
for children in self.findChildren(
QtWidgets.QWidget, options=QtCore.Qt.FindDirectChildrenOnly
):
children.close()
print("closeEvent PushButton")
super(PushButton, self).closeEvent(event)
class LineEdit(QtWidgets.QLineEdit):
def closeEvent(self, event):
for children in self.findChildren(
QtWidgets.QWidget, options=QtCore.Qt.FindDirectChildrenOnly
):
children.close()
print("closeEvent LineEdit")
super(LineEdit, self).closeEvent(event)
class ComboBox(QtWidgets.QComboBox):
def closeEvent(self, event):
for children in self.findChildren(
QtWidgets.QWidget, options=QtCore.Qt.FindDirectChildrenOnly
):
children.close()
print("closeEvent ComboBox")
super(ComboBox, self).closeEvent(event)
class Widget(QtWidgets.QWidget):
def __init__(self, parent=None):
super(Widget, self).__init__(parent)
button_close = PushButton(text="close", clicked=self.close)
lay = QtWidgets.QVBoxLayout(self)
lay.addWidget(button_close)
lay.addWidget(LineEdit())
lay.addWidget(ComboBox())
def closeEvent(self, event):
for children in self.findChildren(
QtWidgets.QWidget, options=QtCore.Qt.FindDirectChildrenOnly
):
children.close()
print("closeEvent Widget")
super(Widget, self).closeEvent(event)
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
w = Widget()
w.show()
sys.exit(app.exec_())
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
3347 次 |
| 最近记录: |