Python 显示来自不同线程的对话框和其他gui对象

Python 显示来自不同线程的对话框和其他gui对象,python,python-3.x,pyqt,pyqt5,python-multithreading,Python,Python 3.x,Pyqt,Pyqt5,Python Multithreading,我有一个用python运行的websocket服务器,对于每个新连接,都将创建一个新线程,并提供请求 在主线程[Gui线程]中,我正在初始化QApplication([])。用例是,当我处理我想要等待的请求时,通过QInputDialog从用户那里获得文本响应。 当我运行它时,有一个事件循环正在运行,但没有显示gui。因为所有gui元素都可以从gui线程本身显示 我尝试过使用QSignals/slots和Pypubsub的各种方法,但无法实现所需的功能。请确实提出一些想法来完成用例。伪代码很受欢

我有一个用python运行的websocket服务器,对于每个新连接,都将创建一个新线程,并提供请求

在主线程[Gui线程]中,我正在初始化QApplication([])。用例是,当我处理我想要等待的请求时,通过QInputDialog从用户那里获得文本响应。 当我运行它时,有一个事件循环正在运行,但没有显示gui。因为所有gui元素都可以从gui线程本身显示

我尝试过使用QSignals/slots和Pypubsub的各种方法,但无法实现所需的功能。请确实提出一些想法来完成用例。伪代码很受欢迎

下面提到的代码是我尝试过的一些示例。我在下面的示例中使用线程,因为正如我所提到的,来自连接的每个请求都是使用分配给连接的线程执行的。线程需要对话框中的文本

提前谢谢

下面是websockets服务器代码,它提供了请求调用服务器扩展功能,每次收到请求时,我都必须显示QInputDialog

import websockets
import asyncio
from PyQt5.QtWidgets import QInputDialog, QApplication

app = QApplication([])

async def server_extentions(websocket, path):
    try:
        while(True):
            request = await websocket.recv()

            # this is where i need to show input dialog.
            text, ok = QInputDialog.getText(None, "Incoming message", request)
            if ok:
                response = text
            else:
                response = "NO REPLY"

            await websocket.send(response)
    except websockets.ConnectionClosed as exp:
        print("connection closed.")


start_server = websockets.serve(server_extentions, '127.0.0.1', 5588)
loop = asyncio.get_event_loop()

try:
    loop.run_until_complete(start_server)
    loop.run_forever()
finally:
    loop.run_until_complete(loop.shutdown_asyncgens())
    loop.close()


----编辑-----

下面是一些一般的想法,我尝试使用pypubsub

import threading
import pubsub.pub
from PyQt5.QtWidgets import QInputDialog, QApplication


class MainThread:

    def __init__(self):
        self.app = QApplication([])
        pubsub.pub.subscribe(self.pub_callback, "lala")

    def pub_callback(self):
        print("this is Main thread's pub callback.")
        QInputDialog.getText(None, "main-thread", "lala call back : ")

    def start_thread(self):
        self.th = threading.Thread(target=self.thread_proc)
        self.th.start()

    def thread_proc(self):
        pubsub.pub.sendMessage("lala")


m = MainThread()
m.start_thread()

-----编辑2-------

下面是我用QSignal试过的东西。[检查代码中的注释,如何使用Mainthread调用函数]

import threading
from PyQt5.QtWidgets import QInputDialog, QApplication
from PyQt5.QtCore import pyqtSignal, QObject, QThread


class TextDialog(QObject):
    sig = pyqtSignal(str)

    def __init__(self):
        QObject.__init__(self)

    def get_text(self):
        print("class Thread2, showing QInputDialog.")
        text, ok = QInputDialog.getText(None, "Lala", "give me some text : ")
        if ok:
            self.sig.emit(text)
            return 
        self.sig.emit("NO TEXT")
        return 


class Thread1:

    def thread_proc(self):
        td = TextDialog()
        td.sig.connect(self.get_text_callback)
        td.moveToThread(m.main_thread)
        # here i dont understand how to invoke MainThread's show_dialog with main thread. [GUI Thread]
        #m.show_dialog(td)


    def get_text_callback(self, txt):
        print("this is get_text_callback, input : " + str(txt))

class MainThread:

    def __init__(self):
        self.app = QApplication([])
        self.main_thread = QThread.currentThread()

    def main_proc(self):
        th1 = Thread1()
        th = threading.Thread(target=th1.thread_proc)
        th.start()

    def show_dialog(self, text_dialog: TextDialog):
        print("got a call to MainThread's show_dialog.")
        text_dialog.get_text()

m = MainThread()
m.main_proc()

exit()


对于这种类型的应用程序,最好实现辅助线程方法。这种方法的主要思想是实现QoObject,将它们移动到新线程并异步调用插槽(通过QEvents、pyqtSignals、
QTimer.singleShot(…)
QMetaObject::invokeMethod(…)
,等等),以便在QoObject所在的线程中执行任务

导入线程
从functools导入部分
从PyQt5导入QtCore、QtWidgets
类文本对话框(QtCore.QObject):
sig=QtCore.pyqtSignal(str)
@QtCore.pyqtSlot()
def get_文本(自身):
打印(“类Thread2,显示对话框”)
text,ok=qtwidts.QInputDialog.getText(
无,“拉拉”,“给我一些文字:”
)
如果确定:
self.sig.emit(文本)
返回
self.sig.emit(“无文本”)
返回
类Worker1(QtCore.QObject):
@QtCore.pyqtSlot(QtCore.QObject)
def thread_proc(自我,管理器):
印刷品(
“当前:{}-main:{}”。格式(
threading.current_thread(),threading.main_thread()
)
)
manager.td.sig.connect(self.get\u text\u回调)
QtCore.QTimer.singleShot(0,manager.show_对话框)
@QtCore.pyqtSlot(str)
def get_text_回调(self,txt):
印刷品(
“当前:{}-main:{}”。格式(
threading.current_thread(),threading.main_thread()
)
)
打印(“这是get_text_回调,输入:%s”%(txt,))
类管理器(QtCore.QObject):
def uuu init uuu(self,parent=None):
super()。\uuuu init\uuuu(父级)
self.td=TextDialog()
@QtCore.pyqtSlot()
def显示_对话框(自身):
print(“调用了MainThread的show_对话框”)
self.td.get_text()
班级申请:
定义初始化(自):
印刷品(
“当前:{}-main:{}”。格式(
threading.current_thread(),threading.main_thread()
)
)
self.app=QtWidgets.QApplication([])
#默认情况下,如果打开窗口后所有窗口都关闭
#在这种情况下,申请将在打开后终止
#关闭对话框,应用程序将被关闭
#会注意到调用了get_text_callback,
#为避免上述情况,它是停用的行为。
self.app.setQuitOnLastWindowClosed(False)
self.manager=manager()
def主程序(自身):
#
self.thread=QtCore.QThread()
self.thread.start()
self.worker=Worker1()
#移动辅助线程,使其位于处理QThread的线程中
self.worker.moveToThread(self.thread)
#异步调用函数
#将导致函数在辅助线程上运行
QtCore.QTimer.singleShot(
0,部分(self.worker.thread\u proc,self.manager)
)
def运行(自):
返回self.app.exec()
如果名称=“\uuuuu main\uuuuuuuu”:
导入系统
m=应用程序()
m、 主程序
ret=m.run()
系统退出(ret)

1)
QInputDialog.getText(…)
用于获取文本,您在哪里使用该文本?我问,因为它可能会更改代码的结构。另外,为什么需要使用线程?1)输入文本要传递给线程。2) 我在代码中实现了一个websockets服务器。它为唯一连接创建一个线程。请求是从该线程发出的。因为我不能在这里发布所有的代码。为了达到这个用例,我使用了另一个线程。这是一个很好的线程。但这里的问题是我无法控制websockets服务器创建的线程。因此,我无法将工作线程移动到请求线程。因为我在初始化服务器时不会有线程实例。我想要一个解决方案,以便可以从请求线程本身显示gui。@在您提供的代码中,ManthriAnvesh出现了什么错误?QInputDialog未显示。因为它位于由WebSocket创建的线程中server@ManthriAnvesh真奇怪,我在没有修改的情况下执行了您的代码,如果它在Linux5中的PyQt5 5.12.2和Python3.7.3中显示正确的话,感谢您这么长时间以来对我的批评。我在代码中发现了这个问题。问题是,在我的原始代码中,我在一个单独的线程中启动服务器。但在我发布的示例中,它是直的。现在,由于线程处于控制状态,我可以使用您的解决方案查看对话框。:)非常感谢您的帮助。:)