Python pyqt5 - 关闭/终止应用程序

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/36555153/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-19 18:01:52  来源:igfitidea点击:

pyqt5 - closing/terminating application

pythonexitmessageboxpyqt5terminate

提问by user3548783

I'm working though the pyqt5 tutorial found here Zetcode, PyQt5

我正在使用 pyqt5 教程在这里找到Zetcode, PyQt5

As an exercise for myself I'm trying to expand on an example so that I am presented with the same dialog message box regardless of method used to close the app:

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

  • clicking the 'X' button in the title bar (works as intended)
  • clicking the 'Close' button (produces attribute error)
  • pressing the 'escape' key (works but not sure how/why)
  • 单击标题栏中的“X”按钮(按预期工作)
  • 单击“关闭”按钮(产生属性错误)
  • 按“退出”键(有效但不确定如何/为什么)

The dialog message box is implemented in the closeEventmethod, full script provided at the end.

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

I'm having two issues:

我有两个问题:

1. When clicking 'Close' button, instead of just quitting, I want to call closeEventmethod including message box dialog.

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

I have replaced a line of the example code for the 'Close' push button:

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

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

And instead am trying to call the closeEventmethod which already implements the dialog I want:

相反,我试图调用closeEvent已经实现了我想要的对话框的方法:

btn.clicked.connect(self.closeEvent)

However when i run the script and click the 'Close' button and select the resulting 'Close' option in the dialog i get the following:

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

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

Can anyone advise what I'm doing wrong and what needs to be done here?

任何人都可以建议我做错了什么以及需要在这里做什么?

2. When hitting the escape key somehow the message box dialog is presented and works just fine.

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

Ok, it's great that it works, but I'd like to know how and why the message box functionality defined in CloseEventmethod is called within the keyPressEventmethod.

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

Full script follows:

完整脚本如下:

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

Hope someone can take the time to enlighten me.

希望有人能抽出时间来启发我。

采纳答案by ekhumoro

Your second question answers the first question.

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

The reimplemented keyPressEventmethod calls close(), which sends a QCloseEventto the widget. Subsequently, the widget's closeEventwill be called with that event as its argument.

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

So you just need to connect the button to the widget's close()slot, and everything will work as expected:

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

    btn.clicked.connect(self.close)

回答by armatita

Unlike the Xbutton your custom button does not seem to pass an close eventjust a bool. That's why this exercise should work for the Xbutton but not a normal button. In any case, for your first question you might use destroy()and passinstead (of acceptand ignore) just like this:

X按钮不同,您的自定义按钮似乎不只传递close event一个bool. 这就是为什么这个练习应该适用于X按钮而不是普通按钮。无论如何,对于您的第一个问题,您可能会使用destroy()andpass代替(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_())

For your second question Qt has default behaviors depending on the Widget (Dialogs might have another, try pressing the Esckey when your Message Dialog is open just to see). When you do need to override the Escbehavior you might try this:

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

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

As you'll eventually see in ZetCode.

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