如何在 Python 函数中创建简单的 PyQt 弹出窗口并在其末尾关闭?

Posted

技术标签:

【中文标题】如何在 Python 函数中创建简单的 PyQt 弹出窗口并在其末尾关闭?【英文标题】:How to create simple PyQt popup in Python function and close at the end of it? 【发布时间】:2017-11-06 22:42:55 【问题描述】:

我正在运行一个函数,我想在其中打开一个 PyQt 弹出窗口,上面写着“Waiting...”之类的内容,只要函数完成,它就会持续。之后我想将文本更改为“完成”,休眠一两秒钟,然后关闭弹出窗口。我已经尝试了很多方法来做到这一点,但到目前为止都没有成功。看起来每当我调用app.exec_() 时,该函数都会暂停该函数,直到我关闭弹出窗口。我想在 PyQt 的主事件循环的上下文之外执行此操作(我尝试异步运行此事件循环但无济于事)。如果我不打电话给exec_(),我根本看不到弹出窗口。基本上我想要这样的东西:

# this is the function that is being run
def run():
    create_popup() # show popup
    wait_for_some_messages() # do some stuff
    close_popup() # close popup

def create_popup():
    app = QApplication([])
    popup = Popup()
    popup.show()

class Popup(QDialog):
    super().__init__()
    self.label = QLabel(self) 

非常感谢任何帮助。谢谢!

【问题讨论】:

【参考方案1】:

我认为您要执行的任务很繁重,因此您可以阻止GUI循环,因此建议实现QRunnable并使用QThreadPool启动它,在run方法中将调用繁重的函数,在最后这个任务会通过QMetaObject::invokeMethod更新数据,然后我们用QEventLoop等待2秒,调用close方法。

class Runnable(QRunnable):
    def __init__(self, popup, func):
        QRunnable.__init__(self)
        self.popUp = popup
        self.func = func

    def run(self):
        # execute hard function
        self.func()
        # Update the text shown in the popup
        QMetaObject.invokeMethod(self.popUp, "setText",
                                 Qt.QueuedConnection,
                                 Q_ARG(str, "Complete"))
        # wait 2 seconds
        loop = QEventLoop()
        QTimer.singleShot(2000, loop.quit)
        loop.exec_()
        # call the close method of the popup
        QMetaObject.invokeMethod(self.popUp, "close",
                                 Qt.QueuedConnection)


class PopUp(QDialog):
    def __init__(self, *args, **kwargs):
        QDialog.__init__(self, *args, **kwargs)
        self.setLayout(QVBoxLayout())
        self.label = QLabel(self)
        self.layout().addWidget(self.label)

    @pyqtSlot(str)
    def setText(self, text):
        self.label.setText(text)

# emulate the heavy task
def func():
    for i in range(10000):
        print(i)
        QThread.msleep(1)

if __name__ == '__main__':
    import sys

    app = QApplication(sys.argv)
    w = PopUp()
    w.show()
    w.setText("Waiting...")
    runnable = Runnable(w, func)
    QThreadPool.globalInstance().start(runnable)
    w.exec_()

加:

如果您想调用另一个函数,只需更改:

runnable = Runnable(w, func)

到:

runnable = Runnable(w, name_of_your_function)

【讨论】:

有没有办法在 PyQt 的范围之外调用fun()?在我的应用程序中,我有一个进程正在运行,我认为将所有逻辑移动到 PyQt 应用程序中,这样我才能得到一个弹出窗口,这有点难看。使用您的示例让我们假设 fun() 已经被调用,并且在其中我想在第一行创建/显示一个弹出窗口并在最后一行关闭它。你知道这是否可能。 @Stefan 检查我修改后的答案,您只需调用它传递函数的名称。 谢谢 eyllanesc,我终于用你的解决方案搞定了。

以上是关于如何在 Python 函数中创建简单的 PyQt 弹出窗口并在其末尾关闭?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 QML 中创建 PyQT 注册类型的动态实例

在PyQt中创建MapQuickItem并将其添加到Map中

在 GitLab 中创建 pyqt 构建

在 PyQt 中创建动态按钮

如何在 PyQt 中创建“色环”?

如何在 PyQT5 中创建导航栏