在python运行时从GUI向线程传递数据
我正在尝试构建一个小型python应用程序,其中一个简单的Web服务器在后台运行,您可以使用GUI发送不同的消息 我使用的是PyQt5和Python3.6,我已经成功地将数据从工作线程传递到GUI,但我不知道如何以另一种方式实现 以下是我的代码框架:在python运行时从GUI向线程传递数据,python,multithreading,pyqt,pyqt5,python-3.6,Python,Multithreading,Pyqt,Pyqt5,Python 3.6,我正在尝试构建一个小型python应用程序,其中一个简单的Web服务器在后台运行,您可以使用GUI发送不同的消息 我使用的是PyQt5和Python3.6,我已经成功地将数据从工作线程传递到GUI,但我不知道如何以另一种方式实现 以下是我的代码框架: 主窗口: class Ui_MainWindow(object): def __init__(self): super().__init__() self.input = True # 1
主窗口:
class Ui_MainWindow(object):
def __init__(self):
super().__init__()
self.input = True
# 1 - create Worker and Thread inside the Form
self.obj = WebServer.WebServer(self.input) # no parent!
self.thread = QtCore.QThread() # no parent!
# 2 - Connect Worker`s Signals to Form method slots to post data.
self.obj.dataReady.connect(self.onDataReady)
# 3 - Move the Worker object to the Thread object
self.obj.moveToThread(self.thread)
# 4 - Connect Worker Signals to the Thread slots
self.obj.finished.connect(self.thread.quit)
# 5 - Connect Thread started signal to Worker operational slot method
self.thread.started.connect(self.obj.startServer)
# 6 - Start the thread
self.thread.start()
# 7 - Start the form
self.setupUi()
def setupUi(self):
# Set up the GUI
#...
self.MainWindow.show()
def onDataReady(self, data):
# Data received from working thread
# Do stuff...
def on_click_set2(self):
self.input = not self.input
print(self.input)
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
ui = Ui_MainWindow()
sys.exit(app.exec_())
class WebServer(QObject):
finished = pyqtSignal()
dataReady = pyqtSignal(dict)
def __init__(self, input):
super().__init__()
self.input = input
@pyqtSlot()
def startServer(self): # A slot takes no params
# self.loop = asyncio.get_event_loop()
self.loop = asyncio.new_event_loop()
asyncio.set_event_loop(self.loop)
coro = asyncio.start_server(self.handle_update, '192.168.2.1', 8888, loop=self.loop)
self.server = self.loop.run_until_complete(coro)
# Serve requests until Ctrl+C is pressed
print('Serving on {}'.format(self.server.sockets[0].getsockname()))
try:
self.loop.run_forever()
except KeyboardInterrupt:
pass
self.finished.emit()
async def handle_update(self, reader, writer):
data = await reader.read(100)
message = data.decode()
addr = writer.get_extra_info('peername')
print(f'Received: {message} from {addr}')
if self.input:
print("Input is True")
else:
print("Input is False")
reply = self.input
print(f'Send: {reply}')
writer.write(str(reply).encode())
await writer.drain()
print("Close the client socket")
writer.close()
self.dataReady.emit(reply)
WebServer:
class Ui_MainWindow(object):
def __init__(self):
super().__init__()
self.input = True
# 1 - create Worker and Thread inside the Form
self.obj = WebServer.WebServer(self.input) # no parent!
self.thread = QtCore.QThread() # no parent!
# 2 - Connect Worker`s Signals to Form method slots to post data.
self.obj.dataReady.connect(self.onDataReady)
# 3 - Move the Worker object to the Thread object
self.obj.moveToThread(self.thread)
# 4 - Connect Worker Signals to the Thread slots
self.obj.finished.connect(self.thread.quit)
# 5 - Connect Thread started signal to Worker operational slot method
self.thread.started.connect(self.obj.startServer)
# 6 - Start the thread
self.thread.start()
# 7 - Start the form
self.setupUi()
def setupUi(self):
# Set up the GUI
#...
self.MainWindow.show()
def onDataReady(self, data):
# Data received from working thread
# Do stuff...
def on_click_set2(self):
self.input = not self.input
print(self.input)
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
ui = Ui_MainWindow()
sys.exit(app.exec_())
class WebServer(QObject):
finished = pyqtSignal()
dataReady = pyqtSignal(dict)
def __init__(self, input):
super().__init__()
self.input = input
@pyqtSlot()
def startServer(self): # A slot takes no params
# self.loop = asyncio.get_event_loop()
self.loop = asyncio.new_event_loop()
asyncio.set_event_loop(self.loop)
coro = asyncio.start_server(self.handle_update, '192.168.2.1', 8888, loop=self.loop)
self.server = self.loop.run_until_complete(coro)
# Serve requests until Ctrl+C is pressed
print('Serving on {}'.format(self.server.sockets[0].getsockname()))
try:
self.loop.run_forever()
except KeyboardInterrupt:
pass
self.finished.emit()
async def handle_update(self, reader, writer):
data = await reader.read(100)
message = data.decode()
addr = writer.get_extra_info('peername')
print(f'Received: {message} from {addr}')
if self.input:
print("Input is True")
else:
print("Input is False")
reply = self.input
print(f'Send: {reply}')
writer.write(str(reply).encode())
await writer.drain()
print("Close the client socket")
writer.close()
self.dataReady.emit(reply)
例如,我想把输入传递给线程,如果我喜欢上面的(显然)输入总是保持初始值,当我点击GUI上的按钮时,线程中的输入不会改变
我该怎么做呢?只要我按下按钮,输入的值就会更新(所以在运行时从GUI向线程传递一个值)?我假设这类似于从线程传递到GUI,因此从GUI发出一个信号,并在踏板上连接到它,但我不知道如何从工作线程找到对GUI的引用
有什么建议吗?当然,欢迎您提供有关应用程序/后台服务器解决方案的代码或方法的任何其他输入!提前谢谢你的帮助
更新:
也许我不清楚我的问题是什么,所以这里是:
当GUI线程和辅助线程并行运行时,如何将值从GUI线程发送到辅助线程?(如果上面的代码对您来说有任何意义,请将其用作示例,否则请使用一般示例)Web服务器不必位于另一个线程中,只需要在另一个线程中执行eventloop。在这种情况下,Web服务器通过队列与服务器线程交换数据。虽然QObject不是线程安全的,但信号是线程安全的,从QObject所在线程以外的线程发出信号没有问题
导入异步IO
导入线程
导入队列
从functools导入部分
从PyQt5导入QtCore、QtGui、QtWidgets
类Web服务器(QtCore.QObject):
dataReady=QtCore.pyqtSignal(对象)
def startServer(自):
self.m_loop=asyncio.new_event_loop()
self.m_queue=queue.queue()
asyncio.set\u事件\u循环(self.m\u循环)
coro=asyncio.start\u服务器(
self.handle\u更新,“127.0.0.1”,10000,循环=self.m\u循环
)
self.server=self.m_循环。运行_直到_完成(coro)
打印(“服务于{}”。格式(self.server.sockets[0].getsockname())
threading.Thread(target=self.m_loop.run_forever,daemon=True).start()
@QtCore.pyqtSlot(对象)
def setData(自身,数据):
如果hasattr(self,“m_队列”):
self.m_queue.put(数据)
def停止(自):
如果hasattr(self,“m_循环”):
self.m_loop.stop()
异步def句柄_更新(self、reader、writer):
reply=“”
数据=等待读卡器读取(100)
message=data.decode()
addr=writer.get\u额外信息(“peername”)
打印(f“从{addr}收到:{message}”)
如果不是self.m_queue.empty():
data=self.m_queue.get(block=False)
答复=数据
打印(f“发送:{reply}”)
writer.write(str(reply.encode())
等待writer.drain()
打印(“关闭客户端套接字”)
writer.close()
self.dataReady.emit(回复)
类小部件(qtwidts.QWidget):
dataChanged=QtCore.pyqtSignal(对象)
def uuu init uuu(self,parent=None):
super()。\uuuu init\uuuu(父级)
self.m_lineedit=qtwidts.QLineEdit()
button=QtWidgets.QPushButton(“发送”,单击=self.onClicked)
lay=qtwidts.QVBoxLayout(self)
lay.addWidget(self.m_lineedit)
lay.addWidget(按钮)
self.m_web=WebServer()
self.m_web.startServer()
self.dataChanged.connect(self.m_web.setData)
@QtCore.pyqtSlot()
def onClicked(自):
text=self.m_lineedit.text()
self.dataChanged.emit(文本)
@QtCore.pyqtSlot(对象)
def onDataReady(自身,数据):
打印(数据)
def关闭事件(自身、事件):
self.m_web.stop()
super().closeEvent(事件)
如果名称=“\uuuuu main\uuuuuuuu”:
导入系统
app=qtwidts.QApplication(sys.argv)
w=Widget()
w、 show()
sys.exit(app.exec_())
它显示所有GUI代码,但无法分析问题出在何处代码的问题是input
变量的值在创建时传递给线程,但在运行时不会更新。但我更新了我的帖子,强调了我的问题。