pyqt5 - 关闭/终止应用程序

新手上路,请多包涵

我正在通过在这里找到的 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. 当以某种方式按下转义键时,会出现消息框对话框并且工作正常。

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

完整脚本如下:

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

希望有人能抽空赐教。

原文由 user3548783 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1.6k
2 个回答

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

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

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

     btn.clicked.connect(self.close)

原文由 ekhumoro 发布,翻译遵循 CC BY-SA 3.0 许可协议

X 按钮不同,您的自定义按钮似乎没有传递 close event 只是一个 bool 。这就是为什么这个练习应该适用于 X 按钮而不是普通按钮。 In any case, for your first question you might use destroy() and pass instead (of accept and ignore ) just like this:

 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 有默认行为取决于小部件(对话框可能有另一个,尝试按下 Esc 键当你的消息对话框打开时只是为了看)。当您确实需要覆盖 Esc 行为时,您可以尝试这样做:

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

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

原文由 armatita 发布,翻译遵循 CC BY-SA 3.0 许可协议

推荐问题