我正在Spyder3.8上使用PyQT5.10编写GUI。用户输入多个参数,包括字符串、整数和浮点,然后按下“发送参数/启动线程”按钮。这将启动一个存储参数的新线程,并由一个函数进行计算。线程应该立即从GUI中获取这些参数,但除此之外,GUI还有一些按钮,可以编辑参数或向线程发送新参数,希望能够实时更新这些参数。
我的问题:是否可以在不同的时间使用信号/插槽将所有这些int/str/float参数发送到同一个线程?是否有一个特别的策略是最好的?我还没有在网上找到类似的例子,但我相信这可能会在许多领域对Python用户有广泛的应用。
我在下面提供了一个脚本的缩小版本,它可以生成GUI,并且可以启动一个新线程,但不能将初始变量列表传递给正在运行的线程。我尝试过不同的策略,到目前为止没有任何效果。当前脚本没有设置用于实时编辑线程变量的函数按钮,因为这会生成错误。我想讨论将变量传递到运行线程的细节,但是我的主要问题仍然是“这可能吗?”
import sys
from PyQt5.QtCore import QThreadPool, QThread, QObject, pyqtSignal, pyqtSlot
from PyQt5.QtCore import *
import time
from PyQt5.QtWidgets import (QApplication, QComboBox, QDialog,
QGridLayout, QGroupBox, QHBoxLayout, QLabel, QLineEdit, QPushButton,
QSpinBox, QStyleFactory, QTextEdit, QVBoxLayout)
from PyQt5.QtWidgets import *
import logging
import logging.handlers
# threadpool = QThreadPool()
# print("Multithreading with maximum %d threads" % threadpool.maxThreadCount())
thread_id = int(QThread.currentThreadId())
print('Intro thread ID: ',thread_id)
def trap_exc_during_debug(*args):
print('debug arg:',args)
sys.excepthook = trap_exc_during_debug
# This class sets up the thread
class Worker(QObject):
print('begin ThreadClass')
sig_msg = pyqtSignal(str)
@pyqtSlot(float,float,int,str)
def __init__(self,param1,param2,param3,param4,parent = None):
#print('params in Worker init: ',param1,param2,param3,param4)
self.p1=param1; self.p2=param2; self.p3=param3; self.p4=param4
print('params in Worker init: ',self.p1,self.p2,self.p3,self.p4)
QThread.__init__(self, parent)
thread_id = int(QThread.currentThreadId())
print('Worker __Init__ thread ID: ',thread_id)
self.__id = 1
self.__abort = False
self.__reset = False
print('end Worker init')
@pyqtSlot()
def work(self): # This function is what will happen in the thread when it starts
thread_id = int(QThread.currentThreadId())
print('work thread ID: ',thread_id)
print('params in work fcn: ',self.p1,self.p2,self.p3,self.p4)
p1=self.p1
p2=self.p2
p3=self.p3
p4=self.p4
print('params in work fcn: ',p1,p2,p3,p4)
thread_id = int(QThread.currentThreadId())
print('work thread ID: ',thread_id)
# app.processEvents() # This approach generated a TypeError:
# if fn==1: #("work() missing 1 required positional argument: 'fn'
# p1-=1
# print('New param1 value in thread: ',p1)
# thread_id = int(QThread.currentThreadId())
# print('fcn1b thread ID: ',thread_id)
# elif fn==2:
# p2+=1
# print('New param2 value in thread: ',p2)
# thread_id = int(QThread.currentThreadId())
# print('fcn2b thread ID: ',thread_id)
# elif fn==3:
# p3+=1
# print('New param3 value in thread: ',p3)
# thread_id = int(QThread.currentThreadId())
# print('fcn1b thread ID: ',thread_id)
# elif fn==4:
# p4=param4
# print('New param4 value in thread: ',p4)
# thread_id = int(QThread.currentThreadId())
# print('fcn1b thread ID: ',thread_id)
@pyqtSlot(float)
def fcn1b(self,prm1):
print('New fcn1 value in thread: ',prm1)
thread_id = int(QThread.currentThreadId())
print('fcn1b thread ID: ',thread_id)
@pyqtSlot(float)
def fcn2b(self,prm2):
print('New fcn2 value in thread: ',prm2)
thread_id = int(QThread.currentThreadId())
print('fcn2b thread ID: ',thread_id)
@pyqtSlot(int)
def fcn3b(self,prm3):
print('New fcn3 value in thread: ',prm3)
thread_id = int(QThread.currentThreadId())
print('fcn3b thread ID: ',thread_id)
@pyqtSlot(str)
def fcn4b(self,prm4):
print('New fcn4 value in thread: ',prm4)
thread_id = int(QThread.currentThreadId())
print('fcn4b thread ID: ',thread_id)
#This class creates the GUI, sets up the buttons, starts new thread, allows parameter edits after thread start.
#Parameter edits are seen in GUI and are supposed to be sent to thread also.
class WidgetGallery(QDialog):
sendinitialparams = pyqtSignal(float,float,int,str)
sendparameter1 = pyqtSignal(float)
sendparameter2 = pyqtSignal(float)
sendparameter3 = pyqtSignal(int)
sendparameter4 = pyqtSignal(str)
NUM_THREADS = 1
def __init__(self):
super(WidgetGallery, self).__init__()
self.originalPalette = QApplication.palette()
styleComboBox = QComboBox()
styleComboBox.addItems(QStyleFactory.keys())
self.createTopLeftGroupBox()
self.createTopRightGroupBox()
self.createbottomRightGroupBox()
topLayout = QHBoxLayout()
mainLayout = QGridLayout()
mainLayout.addLayout(topLayout, 0, 0, 1, 2)
mainLayout.addWidget(self.topLeftGroupBox, 2, 0)
mainLayout.addWidget(self.topRightGroupBox, 2, 1)
mainLayout.addWidget(self.bottomRightGroupBox, 3, 1)
mainLayout.setRowStretch(1, 1)
mainLayout.setRowStretch(2, 1)
mainLayout.setColumnStretch(0, 1)
mainLayout.setColumnStretch(1, 1)
self.setLayout(mainLayout)
self.setWindowTitle("GUI")
def createTopLeftGroupBox(self):
self.topLeftGroupBox = QGroupBox("Settings")
l1= QLabel("Param1 Value:")
self.DoubleSpinBox1 = QDoubleSpinBox()
self.DoubleSpinBox1.setMinimum(0)
self.DoubleSpinBox1.setMaximum(99)
self.DoubleSpinBox1.setValue(20.5)
l2 = QLabel("Param2 Value:")
self.DoubleSpinBox2 = QDoubleSpinBox()
self.DoubleSpinBox2.setMinimum(0)
self.DoubleSpinBox2.setMaximum(99)
self.DoubleSpinBox2.setValue(10.5)
l3= QLabel("Param3 Value:")
self.SpinBox1 = QSpinBox()
self.SpinBox1.setMinimum(0)
self.SpinBox1.setMaximum(99)
self.SpinBox1.setValue(5)
l4 = QLabel("Param4 Value:")
self.textEdit1 = QLineEdit('string1')
layout = QGridLayout()
layout.addWidget(l1, 1,0,1,2)
layout.addWidget(self.DoubleSpinBox1, 1, 2, 1, 2)
layout.addWidget(l2, 2,0,1,2)
layout.addWidget(self.DoubleSpinBox2, 2, 2, 1, 2)
layout.addWidget(l3, 3,0,1,2)
layout.addWidget(self.SpinBox1, 3, 2, 1, 2)
layout.addWidget(l4, 4,0,1,2)
layout.addWidget(self.textEdit1, 4, 2, 1, 2)
layout.setRowStretch(5, 1)
self.topLeftGroupBox.setLayout(layout)
def createTopRightGroupBox(self):
self.topRightGroupBox = QGroupBox("Adjust")
self.defaultPushButton0 = QPushButton("Send params/start thread")
self.defaultPushButton0.setDefault(False)
self.defaultPushButton0.pressed.connect(self.start_threads)
self.defaultPushButton1 = QPushButton("Decrease Param1 in GUI/thread", self) # self? # log
self.defaultPushButton1.setDefault(False)
self.defaultPushButton1.pressed.connect(self.func1)
self.defaultPushButton2 = QPushButton("Increase Param2 in GUI/thread")
self.defaultPushButton2.setDefault(False)
self.defaultPushButton2.pressed.connect(self.func2)
self.defaultPushButton3 = QPushButton("Increase Param3 in GUI/thread")
self.defaultPushButton3.setDefault(False)
self.defaultPushButton3.pressed.connect(self.func3)
self.defaultPushButton4 = QPushButton("Send new Param4 to GUI/thread")
self.defaultPushButton4.setDefault(False)
self.defaultPushButton4.pressed.connect(self.func4)
self.defaultPushButton5 = QPushButton("Abort Worker")
self.defaultPushButton5.setDefault(False)
self.defaultPushButton5.pressed.connect(self.abort_workers)
layout = QVBoxLayout()
layout.addWidget(self.defaultPushButton0)
layout.addWidget(self.defaultPushButton1)
layout.addWidget(self.defaultPushButton2)
layout.addWidget(self.defaultPushButton3)
layout.addWidget(self.defaultPushButton4)
layout.addWidget(self.defaultPushButton5)
layout.addStretch(1)
self.topRightGroupBox.setLayout(layout)
def createbottomRightGroupBox(self):
self.bottomRightGroupBox = QGroupBox("Log")
self.log = QTextEdit()
layout = QGridLayout()
layout.addWidget(self.log)
self.bottomRightGroupBox.setLayout(layout)
def func1(self):
param1=float(self.DoubleSpinBox1.value())
param1-=1
self.DoubleSpinBox1.setValue(param1)
self.sendparameter1.emit(param1)
def func2(self):
param2 = float(self.DoubleSpinBox2.value())
param2+=1
self.DoubleSpinBox2.setValue(param2)
self.sendparameter2.emit(param2)
def func3(self):
param3 = int(self.SpinBox1.value())
param3+=1
self.SpinBox1.setValue(param3)
self.sendparameter3.emit(param3)
def func4(self):
param4=str(self.textEdit1.text())
self.sendparameter4.emit(param4)
def start_threads(self):
self.log.append('starting {} thread'.format(self.NUM_THREADS))
self.__workers_done = 0
self.__threads = []
worker = Worker(float,float,int,str)
print('a')
thread = QThread()
thread.setObjectName('thread_1')
print('b')
self.__threads.append((thread, worker))
worker.moveToThread(thread)
# get progress messages from worker:
worker.sig_msg.connect(self.log.append)
# get ready to start worker:
receiving_class = Worker(float,float,int,str)
print('c')
thread.started.connect(worker.work)
#thread.start()
print('d')
param1=float(self.DoubleSpinBox1.value())
param2 = float(self.DoubleSpinBox2.value())
param3 = int(self.SpinBox1.value())
param4 = str(self.textEdit1.text())
#time.sleep(.0001) # .01 # .005 # .001
print('Transfer data to Worker init')
self.sendinitialparams.emit(param1,param2,param3,param4)
thread.start()
print('End of start_threads')
@pyqtSlot()
def abort_workers(self):
for thread, worker in self.__threads:
print(thread)
thread.quit()
thread.wait()
self.log.append('Thread exited')
print('Thread quit')
# This class coordinates many of the above classes and functions.
if __name__ == "__main__":
print('1')
app = QApplication([])
WG = WidgetGallery()
WG.show()
print('2')
receiving_class = Worker(float,float,int,str)
print('3')
WG.sendinitialparams.connect(receiving_class.__init__) # work # __init__
WG.sendparameter1.connect(receiving_class.fcn1b)
WG.sendparameter2.connect(receiving_class.fcn2b)
WG.sendparameter3.connect(receiving_class.fcn3b)
WG.sendparameter4.connect(receiving_class.fcn4b)
print('4')
sys.exit(app.exec_())
以下代码成功创建了GUI和线程,但变量未传递给线程。请点击开始线程,然后点击GUI/Thread中的DELEASE Param1
我认为可以在任何时候通过线程发送信号。你犯了什么样的错误? 这里有一个例子
但我不认为这是一个好主意,因为pythongil的存在,这项工作需要大量的计算。为什么不使用纯python呢?只需生成一个python进程来进行计算
编辑您的示例:
相关问题 更多 >
编程相关推荐