【问题标题】:pyqt5 - closing/terminating applicationpyqt5 - 关闭/终止应用程序
【发布时间】:2016-08-01 23:54:48
【问题描述】:

我正在阅读此处的 pyqt5 教程Zetcode, PyQt5

作为我自己的练习,我正在尝试扩展一个示例,以便无论用于关闭应用程序的方法如何,我都会看到相同的对话框消息框:

  • 单击标题栏中的“X”按钮(按预期工作)
  • 单击“关闭”按钮(产生属性错误)
  • 按“退出”键(有效,但不确定如何/为什么)

对话框消息框在closeEvent方法中实现,最后提供完整脚本。

我有两个问题:

1.单击“关闭”按钮时,我想调用 closeEvent 方法,包括消息框对话框,而不是仅仅退出。

我已经为“关闭”按钮替换了一行示例代码:

btn.clicked.connect(QCoreApplication.instance().quit)

而是尝试调用已经实现了我想要的对话框的closeEvent 方法:

btn.clicked.connect(self.closeEvent)

但是,当我运行脚本并单击“关闭”按钮并在对话框中选择生成的“关闭”选项时,我得到以下信息:

Traceback (most recent call last):
File "5-terminator.py", line 41, in closeEvent
    event.accept()
AttributeError: 'bool' object has no attribute 'accept'
Aborted

谁能告诉我我做错了什么以及需要在这里做什么?

2。当以某种方式按下转义键时,会显示消息框对话框并且工作正常。

好的,它很好用,但我想知道CloseEvent 方法中定义的消息框功能是如何以及为什么在keyPressEvent 方法中调用的。

完整的脚本如下:

import sys
from PyQt5.QtWidgets import (
    QApplication, QWidget, QToolTip, QPushButton, QMessageBox)
from PyQt5.QtCore import QCoreApplication, Qt


class Window(QWidget):

    def __init__(self):
        super().__init__()

        self.initUI()

    def initUI(self):

        btn = QPushButton("Close", self)
        btn.setToolTip("Close Application")
        # btn.clicked.connect(QCoreApplication.instance().quit)
        # instead of above button signal, try to call closeEvent method below
        btn.clicked.connect(self.closeEvent)

        btn.resize(btn.sizeHint())
        btn.move(410, 118)
        self.setGeometry(30, 450, 500, 150)
        self.setWindowTitle("Terminator")
        self.show()

    def closeEvent(self, event):
        """Generate 'question' dialog on clicking 'X' button in title bar.

        Reimplement the closeEvent() event handler to include a 'Question'
        dialog with options on how to proceed - Save, Close, Cancel buttons
        """
        reply = QMessageBox.question(
            self, "Message",
            "Are you sure you want to quit? Any unsaved work will be lost.",
            QMessageBox.Save | QMessageBox.Close | QMessageBox.Cancel,
            QMessageBox.Save)

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

    def keyPressEvent(self, event):
        """Close application from escape key.

        results in QMessageBox dialog from closeEvent, good but how/why?
        """
        if event.key() == Qt.Key_Escape:
            self.close()

if __name__ == '__main__':

    app = QApplication(sys.argv)
    w = Window()
    sys.exit(app.exec_())

希望有人能花时间启发我。

【问题讨论】:

    标签: python exit messagebox pyqt5 terminate


    【解决方案1】:

    你的第二个问题回答了第一个问题。

    重新实现的keyPressEvent 方法调用close(),它将QCloseEvent 发送到小部件。随后,小部件的 closeEvent 将被调用,该事件作为其参数。

    所以您只需将按钮连接到小部件的close() 插槽,一切都会按预期工作:

        btn.clicked.connect(self.close)
    

    【讨论】:

    • 现在工作,谢谢。顺便说一句,无论我如何在这一行中对它们进行排序,我似乎都无法在对话框中设置按钮顺序:QMessageBox.Save | QMessageBox.Close | QMessageBox.Cancel。我假设它会自动按字母升序设置它们?
    • @user3548783。它必须使用QDialogButtonBox,它以适合当前平台和/或小部件样式的任何方式对按钮进行排序。如果您想要不同的行为,您可以随时创建自己的消息框类。
    【解决方案2】:

    X 按钮不同,您的自定义按钮似乎不会传递close event,而只是传递bool。这就是为什么这个练习应该适用于X 按钮而不是普通按钮的原因。无论如何,对于您的第一个问题,您可以使用 destroy()pass 代替(acceptignore),就像这样:

    import sys
    from PyQt5.QtWidgets import (
        QApplication, QWidget, QToolTip, QPushButton, QMessageBox)
    from PyQt5.QtCore import QCoreApplication, Qt
    
    
    class Window(QWidget):
    
        def __init__(self):
            super().__init__()
    
            self.initUI()
    
        def initUI(self):
    
            btn = QPushButton("Close", self)
            btn.setToolTip("Close Application")
            # btn.clicked.connect(QCoreApplication.instance().quit)
            # instead of above button signal, try to call closeEvent method below
            btn.clicked.connect(self.closeEvent)
    
            btn.resize(btn.sizeHint())
            btn.move(410, 118)
            self.setGeometry(30, 450, 500, 150)
            self.setWindowTitle("Terminator")
            self.show()
    
        def closeEvent(self, event):
            """Generate 'question' dialog on clicking 'X' button in title bar.
    
            Reimplement the closeEvent() event handler to include a 'Question'
            dialog with options on how to proceed - Save, Close, Cancel buttons
            """
            reply = QMessageBox.question(
                self, "Message",
                "Are you sure you want to quit? Any unsaved work will be lost.",
                QMessageBox.Save | QMessageBox.Close | QMessageBox.Cancel,
                QMessageBox.Save)
    
            if reply == QMessageBox.Close:
                app.quit()
            else:
                pass
    
        def keyPressEvent(self, event):
            """Close application from escape key.
    
            results in QMessageBox dialog from closeEvent, good but how/why?
            """
            if event.key() == Qt.Key_Escape:
                self.close()
    
    if __name__ == '__main__':
    
        app = QApplication(sys.argv)
        w = Window()
        sys.exit(app.exec_())
    

    对于您的第二个问题,Qt 具有取决于 Widget 的默认行为(对话框可能有其他行为,请尝试在消息对话框打开时按下 Esc 键以查看)。当您确实需要覆盖 Esc 行为时,您可以尝试以下操作:

    def keyPressEvent(self, event):
        if event.key() == QtCore.Qt.Key_Escape:
            print("esc")
    

    正如您最终将在 ZetCode 中看到的那样。

    【讨论】:

    • 你真的测试过这些吗?调用destroy() 将删除小部件并让应用程序运行而无法停止它,这当然不是正确的做法。此外,正如 OP 已经说过的那样,keyPressEvent 有效,因此无需更改它。
    • @ekhumoro 不,我没有。已更正。我只是想创建在这种情况下不起作用的 event.accept() 的替代方案。谢谢你的提醒。至于esc,我没有说别的。我只是解释了发生了什么,并提供了覆盖默认行为的代码,以防用户需要。这是一个让我的回答更完整的问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-27
    • 1970-01-01
    • 2021-07-07
    相关资源
    最近更新 更多