【问题标题】:Show PyQt5 elements from inside Dash callback从 Dash 回调中显示 PyQt5 元素
【发布时间】:2020-03-11 16:28:25
【问题描述】:

在我的 Python Dash 应用程序中,我想显示一些 PyQt5 窗口弹出窗口。 这些是在回调中从内部激活的。

不幸的是,当显示弹出窗口时,我在控制台中收到以下警告:

警告:未在 main() 线程中创建 QApplication。

我的问题:如果从 Python Dash 回调内部调用,我如何在 main() 线程中创建 QApplication?

您可以在下面找到代表 mwe 的代码。如果你运行这个 sn-p,你会看到警告。显然,当 QApplication 从回调中激活时,它不会在主线程上运行(我的猜测是 app.run_server() 已经在主线程上运行)。如何修改它,使 QApplication 在主线程中?

示例类似于 Use Dash (plot.ly) in PyQt5 GUI 但不一样(我想要 Dash 中的 pyqt5,而不是 pyqt5 中的 Dash)。


import os, dash
from PyQt5.QtWidgets import QApplication,QMainWindow
from PyQt5.QtCore import QCoreApplication
import dash_html_components as html
from dash.dependencies import Input, Output

class MainWindow(QMainWindow):
    #some Qpop up
    pass

app = dash.Dash()

app.layout = html.Div(children=[
    html.H1(children='Hello Dash'),
    #button which, if pressed, created a QApplication in a non-main thread
    html.Button("show pop up", id="button"),
    html.H2(children='', id='result')
    ])

#The callback which creates the pop up I want to show.
#This is activated when the button "show pop up" is pressed, and causes the warning to appear
@app.callback(
Output(component_id='result', component_property='children'),
[Input(component_id='button', component_property='n_clicks')]
)   
def popUp(n_clicks):
    if not n_clicks:
        raise dash.exceptions.PreventUpdate
    app = QCoreApplication.instance()
    if app is None:
        app = QApplication([os.getcwd()])
    mainWin = MainWindow()
    mainWin.show()
    app.exec_()
    return "You saw a pop-up"

if __name__ == '__main__':
    app.run_server(debug=False)

【问题讨论】:

  • 你的问题必须准确,你也不能在没有详细解释你想要什么的情况下显示代码
  • 好的,我编辑了它。希望现在更好。

标签: python python-3.x pyqt pyqt5 plotly-dash


【解决方案1】:

逻辑是在辅助线程中运行 Dash 并通过信号向 GUI 发送通知,如下所示(此答案基于 my other answer):

import functools
import os
import threading

from PyQt5 import QtCore, QtWidgets

import dash
import dash_html_components as html
from dash.dependencies import Input, Output


class MainWindow(QtWidgets.QMainWindow):
    closed = QtCore.pyqtSignal()

    def closeEvent(self, event):
        self.closed.emit()
        super().closeEvent(event)


class Manager(QtCore.QObject):
    def __init__(self, parent=None):
        super().__init__(parent)
        self._view = None

    @property
    def view(self):
        return self._view

    def init_gui(self):
        self._view = MainWindow()

    @QtCore.pyqtSlot()
    def show_popup(self):
        if self.view is not None:
            self.view.show()


qt_manager = Manager()

app = dash.Dash()

app.layout = html.Div(
    children=[
        html.H1(children="Hello Dash"),
        html.Button("show pop up", id="button"),
        html.H2(children="", id="result"),
    ]
)


@app.callback(
    Output(component_id="result", component_property="children"),
    [Input(component_id="button", component_property="n_clicks")],
)
def popUp(n_clicks):
    if not n_clicks:
        raise dash.exceptions.PreventUpdate

    loop = QtCore.QEventLoop()
    qt_manager.view.closed.connect(loop.quit)
    QtCore.QMetaObject.invokeMethod(
        qt_manager, "show_popup", QtCore.Qt.QueuedConnection
    )
    loop.exec_()

    return "You saw a pop-up"


def main():
    qt_app = QtWidgets.QApplication.instance()
    if qt_app is None:
        qt_app = QtWidgets.QApplication([os.getcwd()])
    qt_app.setQuitOnLastWindowClosed(False)
    qt_manager.init_gui()
    threading.Thread(
        target=app.run_server, kwargs=dict(debug=False), daemon=True,
    ).start()

    return qt_app.exec_()


if __name__ == "__main__":
    main()

【讨论】:

  • 好的,这解决了我的问题。但是,它卡在了这个 qt_app.exec_() 中,它对我的​​ ctr+c 没有响应。有没有办法安全退出我的程序?
猜你喜欢
  • 2021-11-14
  • 1970-01-01
  • 1970-01-01
  • 2020-10-17
  • 1970-01-01
  • 1970-01-01
  • 2021-03-31
  • 2020-03-07
  • 1970-01-01
相关资源
最近更新 更多