PyQt: 点击X不触发closeEvent

14 投票
4 回答
47803 浏览
提问于 2025-04-17 15:37

我刚开始学习PyQt,想开发一个简单的应用程序。我用Qt-designer设计了一个简单的界面。我希望在用户点击窗口右上角的X按钮、点击“退出”按钮,或者从菜单中选择“退出”时,能有额外的确认,确保用户真的想退出应用程序。

这是我的代码:

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这个函数没有被触发。
  • 当我点击“退出”按钮或者从菜单中选择“退出”时,这个函数会被调用,但点击“是”后应用程序并没有关闭。

我在StackOverflow上找了一些相关的问题,也搜索了一些教程,但没有找到解决这个问题的内容。我到底哪里做错了呢?

4 个回答

2

另一个简单的解决办法是使用 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)
16

对我来说,这个方法有效,只需要加上这一行

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()
19

注意,你正在做的是:

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

你的实际窗口是一个实例属性(ui),它在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()

注意:我不太喜欢在__init__里直接show窗口。明确一点会更好。所以,我把这个移动到了main里。你可以随意修改。

撰写回答