从各种线程显示QInputDialog和其他gui对象

时间:2019-06-10 09:57:39

标签: python python-3.x pyqt pyqt5 python-multithreading

我有一个运行在python中的websocket服务器,对于每个新连接,将创建一个新线程并处理请求。

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

我尝试了使用QSignals / slots和Pypubsub的各种方法,但是无法实现所需的功能。请提出一些想法以完成用例。伪代码是很好的理解。

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

提前谢谢。

下面是Websockets服务器代码,用于服务调用server_extensions函数的请求,每次收到传入请求时,我都必须显示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()

1 个答案:

答案 0 :(得分:2)

对于这种类型的应用程序,最好实现工作线程方法。这种方法的主要思想是实现QObject,将它们移动到新线程并异步调用插槽(通过QEvents,pyqtSignals,QMetaObject::invokeMethod(...)import threading from functools import partial from PyQt5 import QtCore, QtWidgets class TextDialog(QtCore.QObject): sig = QtCore.pyqtSignal(str) @QtCore.pyqtSlot() def get_text(self): print("class Thread2, showing QInputDialog.") text, ok = QtWidgets.QInputDialog.getText( None, "Lala", "give me some text : " ) if ok: self.sig.emit(text) return self.sig.emit("NO TEXT") return class Worker1(QtCore.QObject): @QtCore.pyqtSlot(QtCore.QObject) def thread_proc(self, manager): print( "current: {}- main: {}".format( threading.current_thread(), threading.main_thread() ) ) manager.td.sig.connect(self.get_text_callback) QtCore.QTimer.singleShot(0, manager.show_dialog) @QtCore.pyqtSlot(str) def get_text_callback(self, txt): print( "current: {}- main: {}".format( threading.current_thread(), threading.main_thread() ) ) print("this is get_text_callback, input : %s" % (txt,)) class Manager(QtCore.QObject): def __init__(self, parent=None): super().__init__(parent) self.td = TextDialog() @QtCore.pyqtSlot() def show_dialog(self): print("got a call to MainThread's show_dialog.") self.td.get_text() class Application: def __init__(self): print( "current: {}- main: {}".format( threading.current_thread(), threading.main_thread() ) ) self.app = QtWidgets.QApplication([]) # By default if after opening a window all the windows are closed # the application will be terminated, in this case after opening # and closing the QInputDialog the application will be closed avoiding # that it will be noticed that get_text_callback is called, # to avoid the above it is deactivated behavior. self.app.setQuitOnLastWindowClosed(False) self.manager = Manager() def main_proc(self): # self.thread = QtCore.QThread() self.thread.start() self.worker = Worker1() # move the worker so that it lives in the thread that handles the QThread self.worker.moveToThread(self.thread) # calling function asynchronously # will cause the function to run on the worker's thread QtCore.QTimer.singleShot( 0, partial(self.worker.thread_proc, self.manager) ) def run(self): return self.app.exec_() if __name__ == "__main__": import sys m = Application() m.main_proc() ret = m.run() sys.exit(ret) 等),以便任务在线程中执行住了QObject。

public function __construct() {        
    if (Auth::user()->hasRole('administrator')) {
        $route = 'admin';
    } else if (Auth::user()->hasRole('company')) {
        $route = 'company';
    } else if (Auth::user()->hasRole('schoolowner')) {
        $route = 'school';
    }
}

public function index()
{
    return view($route.'.person.index', compact('user'))->with('status', 'No school');
}