在 PyQt 主窗口中处理关闭按钮的正确方法,(红色“X”)

Posted

技术标签:

【中文标题】在 PyQt 主窗口中处理关闭按钮的正确方法,(红色“X”)【英文标题】:Proper way to handle the close button in a main window PyQt, (Red "X") 【发布时间】:2014-08-23 07:10:27 【问题描述】:

首先,我是 PyQt 的新手。

我一直在尝试将一个函数链接到主窗口的关闭按钮(窗口角落的红色 x),但没有成功。现在,我的代码看起来像这样:

class Ui_MainWindow(QtGui.QMainWindow):
    def __init__(self):
        QtGui.QMainWindow.__init__(self)
        self.setupUi(self)
    def setupUi(self, MainWindow):
        #setup code goes here
    def retranslateUi(self, MainWindow):
        #re translation of the GUI code 
    def closeEvent(self, event):
        print "User has clicked the red x on the main window"

在一个单独的“主”文件中,我有以下内容:

class GUIForm(QtGui.QMainWindow):
    def __init__(self, parent=None):
        QtGui.QMainWindow.__init__(self,parent)
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)
        #self.ui.ECUStatus_txt = MyWidget.__init__.text_list
        self.threadData()


    if __name__ == "__main__":

        app = QtGui.QApplication(sys.argv)
        myapp = GUIForm()
        myapp.show()
        ret = app.exec_()
        sys.exit(ret)

但是,当我通过命令提示符运行时,当我点击红色 x 时,我无法看到打印语句。我知道我是 Qt 新手,但是我看到很多人问这个问题,而且似乎没有一个答案超出上面已经写的内容。

以下答案之一: Answer #1 Answer #2

这两个解决方案都与我的相似,但仍然不起作用

尽管答案可能适用于该用户的特定代码,但我和我的 PyQt 同事对于我们的推理不起作用仍然很模糊。 PyQt 中内置的“红色 X 框”是否有定义的按钮名称?我可以像其他按钮一样将它连接到其他功能吗?

【问题讨论】:

也许aboutToQuit 信号是您正在寻找的? qt-project.org/doc/qt-5/qcoreapplication.html#aboutToQuit 可能在您的代码中您缺少到插槽的连接信号。这是 Qt 库的“主干”。 @user3419537 ,我试试看! @NickLesnykh ,如果是这种情况,我将如何解决它? @sudobangbang,在您的情况下,您可以将 aboutToQuit 信号(从 QApplication 实例发出)连接到处理程序,或 Qt 术语中的插槽。您可以在app 实例化之后添加:app.aboutToQuit.connect(on_exit) 【参考方案1】:

您永远不应该修改从您的 ui 文件生成的类。相反,您应该子类化并修改子类。

从您的代码的外观来看,您实际上是在创建两个QMainWindows,并且 closeEvent 被错误的捕获(大概是隐藏了一个?)。那就是self.ui 是一个QMainWindow,它没有显示出来,也没有添加到GUIForm 的UI 中。相反,您自己明确地使用Ui_MainWindow.setupUi() 方法,将小部件添加到您自己的QMainWindow, 'GUIForm`。

相反,您应该将 Ui_MainWindow 类保留为从 ui 文件生成时的状态,然后将您的主 python 文件修改为:

class GUIForm(Ui_MainWindow):
    def __init__(self, parent=None):
        Ui_MainWindow.__init__(self, parent)
        self.threadData()

    def closeEvent(self, event):
        print "User has clicked the red x on the main window"
        event.accept()


if __name__ == "__main__":

    app = QtGui.QApplication(sys.argv)
    myapp = GUIForm()
    myapp.show()
    ret = app.exec_()
    sys.exit(ret)

通过这种方式,您可以扩展自动生成的 UI 文件的行为。这样可以轻松地从 .ui 文件重新生成 python 文件,而无需重新添加代码(这正是您永远不应该修改自动生成的 Python 文件的原因)

【讨论】:

我认为这个例子的问题在于它不包括任何方法来区分 X 关闭和由于操作完成而关闭的窗口 - 例如,单击 OK 按钮或其他东西。由于 closeEvent 在窗口关闭时运行并且不是唯一的。 @NL23codes 大多数人不需要区分,Qt 没有明确的方式来区分“x”按钮,因为该按钮由操作系统窗口管理器处理。但是,基于this,您可以通过查看closeEvent 方法中event.spontaneous() 的值来有效区分它。【参考方案2】:

有时,在处理来自主窗口的事件信号时会出现问题。

您可以使用代码:

app.aboutToQuit.connect(self.closeEvent)

您可以在 closeEvent 函数中编写自己的代码。

注意:

appQtGui.QApplication 实例的名称

这是完整代码的演示:

from PyQt4 import QtCore, QtGui

class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(800, 600)
        self.centralwidget = QtGui.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        MainWindow.setCentralWidget(self.centralwidget)
        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

        #================================

        app.aboutToQuit.connect(self.closeEvent)

        #================================

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

    #================================

    def closeEvent(self):
        #Your desired functionality here
        print('Close button pressed')
        import sys
        sys.exit(0)

    #================================


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

希望对你有帮助。

【讨论】:

aboutToQuit 信号对我来说太迟了。我想让一个弹出窗口询问用户是否要退出,但是一旦启动此信号,应用程序就已经退出,我只是得到一个问题弹出窗口,现在它对应用程序是否关闭没有影响。有什么想法吗? 'aboutToQuit' 事件调用另一个函数 closeEvent。您可以在此处放置 if-else 逻辑以检查确认。最终 'sys.exit(0)' 关闭应用程序。 我就是这样尝试的,但是 gui 在确认弹出窗口打开之前就关闭了,所以即使你选择 No 程序已经关闭了。 有没有办法绕过@Kajsa 提出的问题? 这个例子对我有用,但 closeEvent 需要两个参数,就像这样给出 (self,g)。【参考方案3】:

我遇到了同样的问题,我有一个对话框窗口提示,在继续操作之前要求用户输入。用户可以在处理操作之前添加输入,跳过添加输入并继续处理,或者使用取消按钮或单击对话框窗口的 X 取消操作。

我所做的是创建一个保存布尔值的变量,该变量将在关闭窗口之前进行检查,以便在窗口被强制关闭的情况下,很明显进程已中止。

class Ui_MainWindow(QtGui.QMainWindow):
    def __init__(self):
        QtGui.QMainWindow.__init__(self)
        self.setupUi(self)
        #This variable will be your way of determining how the window was closed
        self.force_close = True
        self.buttonOk.clicked.connect(self.someOtherFunction)

    def setupUi(self, MainWindow):
        #setup code goes here

    def retranslateUi(self, MainWindow):
        #re translation of the GUI code 

    def someOtherFunction(self):
        # Do some things here if needed
        print('All done')
        # Assuming some operation is performed and a value or result is generated            
        # Since this function completed, there is no need to force close the window
        # So it can be set to False
        self.force_close = False
        # the below close() is a built-in function and will automatically trigger the
        # closeEvent
        self.close()

    def closeEvent(self, event):            
        if self.force_close is True:
            # Here is where you could add you code to perform some operation
            # due to the user clicking the X

【讨论】:

以上是关于在 PyQt 主窗口中处理关闭按钮的正确方法,(红色“X”)的主要内容,如果未能解决你的问题,请参考以下文章

如何关闭登录对话框并显示主窗口(PyQt4)[重复]

PyQT对象无意中出现在单独的窗口中[关闭]

按下保存按钮pyqt5后关闭第二个小部件

PyQt:为啥新窗口在打开后立即关闭[重复]

如何在 PyQt5 中同时读取和写入文件时正确执行多线程?

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