PyQt:单击 X 不会触发 closeEvent

Posted

技术标签:

【中文标题】PyQt:单击 X 不会触发 closeEvent【英文标题】:PyQt: clicking X doesn't trigger closeEvent 【发布时间】:2013-02-12 14:11:38 【问题描述】:

我是一个尝试开发简单应用程序的 PyQt 新手。我用 Qt-designer 设计了简单的 ui。如果用户真的想在单击 X 或 ,,Exit'' 按钮或从菜单中选择 Exit 时退出应用程序,我需要额外确认。

代码如下:

import sys
from PyQt4 import QtGui, QtCore, uic

class MainWindow(QtGui.QMainWindow):
    def __init__(self):
        QtGui.QMainWindow.__init__(self)

        self.ui = uic.loadUi('main_window.ui')
        self.ui.show()

        self.ui.btnExit.clicked.connect(self.close)
        self.ui.actionExit.triggered.connect(self.close)

    def closeEvent(self, event):
        print("event")
        reply = QtGui.QMessageBox.question(self, 'Message',
            "Are you sure to quit?", QtGui.QMessageBox.Yes, QtGui.QMessageBox.No)

        if reply == QtGui.QMessageBox.Yes:
            event.accept()
        else:
            event.ignore()


def main():
    app = QtGui.QApplication(sys.argv)
    win = MainWindow()
    sys.exit(app.exec_())


if __name__ == "__main__":
    main()

问题是:

当我在主窗口单击 X 时,closeEvent 函数不会触发 当我单击退出按钮或从菜单中选择 ,,Exit'' 时,该功能 已调用,但单击“是”不会关闭应用程序。

我发现了一些关于 SO 的问题并搜索了教程,但没有任何内容涵盖此类问题。我做错了什么?

【问题讨论】:

【参考方案1】:

注意你正在做的事情:

self.ui = uic.loadUi('main_window.ui')
self.ui.show()

您的 实际 窗口是一个实例属性 (ui) inside win。不是win 本身。而且它没有实现closeEvent

loadUi 可以在实例中加载.ui 文件。

PyQt4.uic.loadUi(uifile[, baseinstance=None[, package='']])

你应该使用它。这样,您的代码将是:

import sys
from PyQt4 import QtGui, QtCore, uic

class MainWindow(QtGui.QMainWindow):
    def __init__(self):
        QtGui.QMainWindow.__init__(self)

        uic.loadUi('main_window.ui', self)

        self.btnExit.clicked.connect(self.close)
        self.actionExit.triggered.connect(self.close)

    def closeEvent(self, event):
        print("event")
        reply = QtGui.QMessageBox.question(self, 'Message',
            "Are you sure to quit?", QtGui.QMessageBox.Yes, QtGui.QMessageBox.No)

        if reply == QtGui.QMessageBox.Yes:
            event.accept()
        else:
            event.ignore()


def main():
    app = QtGui.QApplication(sys.argv)
    win = MainWindow()
    win.show()
    sys.exit(app.exec_())


if __name__ == "__main__":
    main()

注意:我不喜欢show__init__ 中的窗口。明确的更好。所以,我把它移到了main。随意修改。

【讨论】:

非常感谢,这解决了我的两个问题。我知道我遗漏了一些非常简单的东西,但是我发现的教程并未涵盖该主题。显式显示也是一个很好的解决方案,感谢您指出这一点。顺便说一句:你能推荐任何学习 PyQt4 的好资源吗? @Wookie88:我知道的教程不多。 This one 看起来不错。此外,官方 Qt 文档到处都有使用示例。 PyQt 附带了很多示例。【参考方案2】:

它对我有用,只需添加这一行

self.ui.closeEvent = self.closeEvent

所以你的代码是:

import sys
from PyQt4 import QtGui, QtCore, uic

class MainWindow(QtGui.QMainWindow):
    def __init__(self):
        QtGui.QMainWindow.__init__(self)

        self.ui = uic.loadUi('main_window.ui')
        self.ui.closeEvent = self.closeEvent
        self.ui.show()

        self.ui.btnExit.clicked.connect(self.close)
        self.ui.actionExit.triggered.connect(self.close)

    def closeEvent(self, event):
        print("event")
        reply = QtGui.QMessageBox.question(self, 'Message',
            "Are you sure to quit?", QtGui.QMessageBox.Yes, QtGui.QMessageBox.No)

        if reply == QtGui.QMessageBox.Yes:
            event.accept()
        else:
            event.ignore()


def main():
    app = QtGui.QApplication(sys.argv)
    win = MainWindow()
    sys.exit(app.exec_())


if __name__ == "__main__":
    main()

【讨论】:

self.ui.closeEvent = self.closeEvent 解决了我的问题。 我知道这基本上是在移动一些函数地址,但除此之外,我完全不知道为什么会这样。但这行得通。 这对我不起作用。实际上这段代码是直接关闭 QMainWindow 而不是加载的 ui【参考方案3】:

另一个简单的解决方案是在用户单击关闭按钮时使用 app.aboutToQuit.connect(self.close_event) 运行 closeEvent 函数中的代码。

此处为示例代码

class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

#--------------------------------------------------------------------------------

        app.aboutToQuit.connect(self.closeEvent) #this line is what ur looking for !!!!!!

#--------------------------------------------------------------------------------

    def retranslateUi(self, MainWindow):
        MainWindow.setWindowTitle('Demo')

    #______________________________________

    def closeEvent(self):
        #Your code here
        print('User has pressed the close button')
        import sys
        sys.exit(0)

    #______________________________________


if __name__ == "__main__":
    import sys
    app = QtGui.QApplication(sys.argv)
    MainWindow = QtGui.QMainWindow()
    ui = Ui_MainWindow()
    ui.setupUi(MainWindow)

【讨论】:

【参考方案4】:

在设计器中你可以将事件连接到主窗口,并在设计器中添加新的插槽,然后只需在python中实现方法,事件->插槽连接将自动完成。

【讨论】:

以上是关于PyQt:单击 X 不会触发 closeEvent的主要内容,如果未能解决你的问题,请参考以下文章

PyQt 的 QMainWindow closeEvent 永远不会被调用

如何从 closeEvent 处理使用 PyQt4 检测注销/关闭?

self.close() 将关闭程序,即使 closeEvent() 内部有 self.ignore()

Qt Designer PyQt5 覆盖 CloseEvent 子窗口不起作用

在pyqt5中单击按钮之前触发浏览按钮方法[重复]

如何覆盖 closeEvent 函数以使其正常工作