即使closeEvent()内部有self.ignore(),self.close()也会关闭程序

时间:2019-08-16 18:42:44

标签: python python-3.x pyqt5

当我在应用程序上单击“ X”并在MessageBox中按“否”时,程序将不会关闭。但是,当我隐藏该程序并从系统托盘上的菜单中单击“退出”,然后从消息框中单击“否”时,该程序仍将成功关闭。...

我的代码是这样的:

    exitAction = menu.addAction("Quit")
    exitAction.triggered.connect(self.close)

然后我的closeEvent()代码是:

    def closeEvent(self, event):
        reply = QMessageBox.question(self, 'Quit', 'Are You Sure to Quit?', QMessageBox.No | QMessageBox.Yes)
        if reply == QMessageBox.Yes:
            event.accept()
        else:
            event.ignore()

编辑: 我意识到只要菜单弹出一个QMessageBox,无论我选择哪个选项,整个程序仍然会关闭,我认为可能是这个问题?:

os._exit(app2.exec_())

我在消息框前添加了 self.show(),它可以正常工作吗,有没有办法让它在没有self.show()的情况下工作?因为我允许用户在程序隐藏时从系统托盘中退出程序

   def closeEvent(self, event):
        self.show() << I added this and it works
        reply = QMessageBox.question(self, 'Quit', 'Are You Sure to Quit?', QMessageBox.No | QMessageBox.Yes)
        if reply == QMessageBox.Yes:
            event.accept()
        else:
            event.ignore()

可复制的代码:

class Example(QWidget):
    def __init__(self):
        super().__init__()
        self.initUi()

    def initUi(self):
        self.resize(350, 150)
        self.setWindowTitle("Test")
        pb_min = QPushButton("Minimise the Program", self)
        pb_min.clicked.connect(self.pbMin)

        h_box = QHBoxLayout()
        h_box.addStretch()

        h_box.addWidget(pb_min)
        h_box.addStretch()

        self.setLayout(h_box)

    def pbMin(self):
        menu = QMenu()
        showAction = menu.addAction('Show')
        showAction.triggered.connect(self.showGUI)
        exitAction = menu.addAction("Quit")
        exitAction.triggered.connect(self.close)
        self.hide()
        self.mSysTrayIcon = QSystemTrayIcon(self)
        icon = QIcon("test.png")
        self.mSysTrayIcon.setIcon(icon)
        self.mSysTrayIcon.setContextMenu(menu)
        self.mSysTrayIcon.setToolTip("Show Test")
        self.mSysTrayIcon.activated.connect(self.onActivated)
        self.mSysTrayIcon.show()

    def showGUI(self):
        self.show()
        self.mSysTrayIcon.hide()

    def onActivated(self, reason):
        if reason == self.mSysTrayIcon.Trigger:
            self.show()
            self.mSysTrayIcon.hide()


    def closeEvent(self, event):
        reply = QMessageBox.question(self, 'Quit', 'Are You Sure to Quit?', QMessageBox.Yes | QMessageBox.No)
        if reply == QMessageBox.Yes:
            event.accept()
        else:
            event.ignore()

if __name__ == "__main__":
    app = QApplication(sys.argv)
    ex = Example()
    ex.show()
    os._exit(app.exec_())

2 个答案:

答案 0 :(得分:1)

您提供的代码存在一些问题。

首先,您不应在每次最小化窗口时创建新的系统任务栏图标。虽然可能使有意义,但这可能是一个问题,因为在某些平台(尤其是Windows)中,图标可能并不总是被“删除”(如“隐藏” )时,除非您明确将其删除(通常使用deleteLater())。

然后,尽管您说“该程序仍将成功关闭”,但可能不会。通常这取决于平台(不同的OS和OS版本),但这不是重点。

此外,由于您需要一种统一的方式来确保用户确实想要退出,因此您应该提供相应的方法来执行此操作,并因此对它的返回值做出反应,因为{{1 }}和触发的动作连接以不同的方式响应。

我已对您的代码进行了修改,统一了一种“ closeRequest”方法,该方法应能更好地响应用户交互。


一些注意事项。

  1. 无论何时使用“非标准” QWidget(例如QSystemTrayIcon),您都需要更好地控制程序实际退出的方式/时间,并且在设置QApplication.setQuitOnLastWindowClosed(bool)时需要特别注意。

  2. 使用closeEventos._exit 不相同:“ sys.exit通常只应在fork()之后的子进程中使用“,这是(很少)并发事件循环的情况,例如将PyQt事件循环与PyGame一起使用(请参阅official docs)。

os._exit()

答案 1 :(得分:0)

找到了自己的解决方案,每当隐藏主程序时,关闭系统托盘中显示的消息框,整个程序也会关闭, 因此,添加app.setQuitOnLastWindowClosed(False)以避免关闭MessageBox导致整个程序关闭。
最后,在closeEvent()中添加quit()