什么是 PyQt 等价于 WinForms 激活事件?

Posted

技术标签:

【中文标题】什么是 PyQt 等价于 WinForms 激活事件?【英文标题】:What is the PyQt Equivalent to WinForms Activated Event? 【发布时间】:2019-12-30 17:43:39 【问题描述】:

我正在编写一个小型 PyQt 应用程序,它需要在应用程序启动之前运行一些检查,如果任何检查失败,应用程序需要通知用户它无法运行然后退出。

在 WinForms 中。我可以简单地做到这一点:

var form = new Form();
form.Activated += (s, e) =>

    var condition = true;
    if (condition)
    
        MessageBox.Show("oh dear, something's wrong.");
        Application.Exit();
    
;

当主应用程序窗口加载时,PyQt 似乎没有可以连接的信号,并且当条件失败时我当前的尝试甚至没有触发对话框。

这是我目前拥有的(MRE(。程序流程如下:

import sys
import winreg
from PyQt5.QtWidgets import QApplication, QWidget,  QMessageBox

class MainWindow(QWidget):
    def __init__(self):
        super(MainWindow, self).__init__()

    def loadData(self):
        try:
            key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, r'SOFTWARE\Path\To\Nonexistant\Key')
            x = winreg.QueryValueEx(key, 'some_key')[0]
            print(x)
        except FileNotFoundError:
            error = QMessageBox()
            error.setIcon(QMessageBox.Critical)
            error.setText('Cannot locate installation directory.')
            error.setWindowTitle('Cannot find registry key')
            error.setStandardButtons(QMessageBox.Ok)
            error.show()
            QApplication.quit()

def main():
    app = QApplication(sys.argv)
    main_window = MainWindow()
    main_window.show()
    main_window.loadData()
    sys.exit(app.exec_())


main()

我的最终目标是让loadData() 在应用程序完全加载并显示给用户时运行。

更新:程序现在按预期运行。我不得不:

error.show() 更改为error.exec_()QApplication.quit() 更改为sys.exit()main_window.show() 之后致电main_window.loadData()

【问题讨论】:

据我了解(我不知道 winforms),您希望应用程序在用户单击 QMessageBox 上的 OK 后结束,对吗? 没错。一旦应用程序加载,我需要它来执行检查,如果它失败,显示 QMessageBox 然后退出。我现在根本无法显示 QMessageBox。 【参考方案1】:

show 方法没有阻塞,所以一旦执行,QMessageBox 就会显示在QApplication.quit(),而你应该使用exec_(),它会等到用户通过按钮关闭QMessageBox。

# ...
error.setStandardButtons(QMessageBox.Ok)
# error.show()
error.exec_()
QApplication.quit()

更新:

另一方面,QApplication.quit() 在 eventloop 尚未启动时无法使用,因此这种情况下的解决方案是稍后使用 QTimer.singleShot() 删除应用程序:

class MainWindow(QWidget):

    # UI stuff omitted...

    def loadData(self):
        try:
            key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, r'SOFTWARE\Path\To\Key')
            path = winreg.QueryValueEx(key, 'install_path')[0]
            # I'll do stuff with path here...
        except FileNotFoundError:
            error = QMessageBox()
            error.setIcon(QMessageBox.Critical)
            error.setText('Cannot locate directory.')
            error.setWindowTitle('Cannot find registry key')
            error.setStandardButtons(QMessageBox.Ok)
            error.exec_()
            QTimer.singleShot(0, QApplication.quit)


def main():
    app = QApplication(sys.argv)
    main_window = MainWindow()
    main_window.show()
    main_window.loadData()
    sys.exit(app.exec_())


if __name__ == '__main__':
    main()

另外一个等价的代码如下

class MainWindow(QWidget):

    # UI stuff omitted...

    def loadData(self):
        try:
            key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, r'SOFTWARE\Path\To\Key')
            path = winreg.QueryValueEx(key, 'install_path')[0]
            # I'll do stuff with path here...
        except FileNotFoundError:
            error = QMessageBox()
            error.setIcon(QMessageBox.Critical)
            error.setText('Cannot locate directory.')
            error.setWindowTitle('Cannot find registry key')
            error.setStandardButtons(QMessageBox.Ok)
            error.exec_()
            QApplication.quit()


def main():
    app = QApplication(sys.argv)
    main_window = MainWindow()
    main_window.show()
    QTimer.singleShot(0, main_window.loadData)
    sys.exit(app.exec_())


if __name__ == '__main__':
    main()

【讨论】:

好的,问题解决了一半,但是点击确定后,应用程序仍在加载中。我该如何解决? @Jake 我建议你添加一个版本,并且不要覆盖代码,因为如果你这样做了,那么我的回答将毫无意义。另一方面,您必须提供minimal reproducible example,因为可能存在问题,但不幸的是我们不知道。 这很奏效,第二个例子对我来说更像是“winforms”。 @eyllanesc 因为即使应用程序未启动也可以执行 QMessageBox,如果loadData 成功并在这种情况下执行应用程序,是否应该返回 True 更好? @musicamante OP 希望首先显示窗口(而不是 QMessageBox),此外 OP 似乎有一个我不想更改的项目结构,但它也是一个有效的选项。

以上是关于什么是 PyQt 等价于 WinForms 激活事件?的主要内容,如果未能解决你的问题,请参考以下文章

pyQT slot decorator 啥是 C++ 等价物

PyQt_PyObject在使用新式信号/插槽时是等价的吗?

pyqt5 如何识别该函数中是哪个qpush_button激活了该函数? [关闭]

什么是'import * as ...'等价于require?

在c语言里,if (x)等价于if (x!=0)、if (!x)等价于if (x==0)吗?

pyqt - 在 QLineEdit 中达到一定数量的字母后激活 QCompleter