В следующих примерах, когда вы визуально нажимаете кнопку, вы наблюдаете то же поведение: окно закроется, но мы увидим разницу, в первом оно называется closeEvent (), а во втором - нет. .
Example1:
#!/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()
Пример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()
Почему вы не вызываете closeEvent при вызове QCoreApplication :: quit?
Поскольку этот метод используется для выхода из цикла событий Qt, и если цикл событий отсутствует, события (QCloseEvent) не работают.
Когда виджет закрыт, дочерний виджет не закрыт, то есть, только если виджет закрыт, будет вызываться только его собственный 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()
В предыдущем примере, в зависимости от того, как вы взаимодействуете с виджетом, вы получите следующее поведение:
Если вы нажмете кнопку, виджет закроется, поэтому он будет называться closeEvent и не будет вызывать closeEvent кнопки, потому что даже ваш ребенок не закрывает его.
Если вы нажмете кнопку «X» в окне, она будет называться не closeEvent виджета, а QMainWindow, объяснение будет таким же, как и в предыдущем.
Выводы:
Каждый тип события имеет собственный рабочий процесс, некоторые события принимаются только виджетом, а не дочерними элементами, а другие отправляют информацию дочерним элементам.
Метод close использует цикл событий для уведомления о том, что виджет должен быть закрыт, но QCoreApplication :: quit () завершает цикл событий.
Обновление:
почему wid.closeEvent не вызывается, когда пользователь нажимает кнопку "X" в окне Qt? Разве главное окно не должно вызывать closeEvent для всех дочерних виджетов, а затем правильно их уничтожать?
Нет, одно - это закрытие виджета, а другое - уничтожение виджета, его можно уничтожить, не закрывая, а закрытие окна не требует уничтожения объекта.
Как уже указывалось, закрытие окна не подразумевает его удаления, могут быть открыты другие окна, но если последнее окно QApplication закрыто по умолчанию, Eventloop, который подразумевает уничтожение виджета, будет завершен, что не обязательно подразумевает вызов метода 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_())
Есть две кнопки, в случае первой кнопки, которая вызывает QCoreApplication :: quit (), которая завершит цикл события, так что все виджеты будут уничтожены, и в этом случае не будет вызываться closeEvent, в случае вторая кнопка будет вызываться рядом с окном, поэтому она будет вызывать свое closeEvent, но не closeEvents своих дочерних элементов.
Моя настоящая проблема в том, что у меня есть функция saveUI () в closeEvent, и она не вызывается при иерархическом разрушении виджетов при закрытии окна
Если вы хотите, чтобы метод 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_())