【发布时间】:2017-01-27 13:47:00
【问题描述】:
我的程序有一个主窗口,在这个窗口中它运行一个线程来读取光电探测器的功率,然后它发送一个信号,该信号由主窗口中的一个插槽捕获,该插槽更新主窗口的 gui。
然后我有另一个从主窗口弹出的小部件(我们称之为编程小部件),它基本上是一个纯文本,用户可以在其中插入命令,以便程序执行它们。现在问题来了:
当我用“显示”打开编程小部件时,主窗口会不断更新光电探测器。但是,当我开始从编程小部件执行序列时,主窗口会冻结,并且在执行命令时光电探测器读数会随之停止(我猜它会继续读取,因为它在另一个线程中,但它会停止更新主窗口的 gui)。
我的问题是:默认情况下,编程小部件已经在另一个线程中,因为主窗口在弹出时会继续工作。那么,为什么当编程小部件处于循环状态时它(主窗口)会冻结?
这里是线程代码:
class PDThread(QtCore.QThread):
valueupdate = QtCore.pyqtSignal(float)
state = 1
def __init__(self, state, port):
QtCore.QThread.__init__(self)
self.photodetector = PM100D()
self.port = port
def run(self):
while True:
try:
self.photodetector.connect(self.port)
break
except:
self.dialog = dialog_classes.DialogPort()
self.dialog.set_instrument('PM100D')
self.dialog.exec_()
ret = self.dialog.pm100d.itemText(self.dialog.pm100d.currentIndex())
if ret == QtGui.QDialog.Accepted:
self.port = str(ret)
else:
self.photodetector.__del__()
self.quit()
return
window.PDState = 1
window.startpd.setText('Stop PD')
while self.state == 1:
time.sleep(0.1)
value = self.photodetector.get_pow()
self.valueupdate.emit(value)
这是在主窗口中创建线程和槽的函数:
def ActionConnect_PM100D(self):
if self.PDState == 0:
self.PD = PDThread(self.PDState, self.PDport)
self.PD.valueupdate.connect(self.PDHandler)
self.threads = []
self.threads.append(self.PD)
self.PD.start()
else:
self.PDState = 0
self.PD.state = 0
self.startpd.setText('Start PD')
def PDHandler(self, value):
ref = float(self.refpd.value())
self.outputpd.setText(str(value-ref))
这里也是在主窗口中,创建小部件的函数:
def ActionSetup(self):
self.program = dialog_classes.Programming(self.newport, self.output, self.outputpd)
self.program.show()
最后是小部件代码:
class Programming(QtGui.QDialog, Ui_Programming_Dialog, gui.MyApp):
def __init__(self, ESP300, output, outputpd):
QtGui.QDialog.__init__(self)
self.setupUi(self)
self.setWindowTitle('Programming Setup')
self.openbuttom.clicked.connect(self.Open)
self.save.clicked.connect(self.Save)
self.execute.clicked.connect(self.Execute)
self.newport = ESP300
self.output = output
self.outputpd = outputpd
def Open(self):
self.fileName = QtGui.QFileDialog.getOpenFileName(self, 'OpenFile', '', '*.txt')
try:
text = open(self.fileName).read()
except:
None
else:
self.program.setPlainText(text)
def Save(self):
self.fileName = QtGui.QFileDialog.getSaveFileName(self, 'Save File', '', '*.txt')
try:
open(self.fileName, 'w').write(str(self.program.toPlainText()))
except:
None
def Execute(self):
text = str(self.program.toPlainText())
lines = text.split('\n')
for line in lines:
arg = []
List = line.split(',')
for word in List:
arg.append(word.strip())
if arg[0].lower() == 'move':
if arg[1].lower() == 'x':
self.newport.move_x(float(arg[2]))
elif arg[1].lower() == 'y':
self.newport.move_y(float(arg[2]))
elif arg[1].lower() == 'z':
self.newport.move_z(float(arg[2]))
elif arg[0].lower() == 'wait':
self.newport.wait()
elif arg[0].lower() == 'home':
self.newport.home()
while True:
try:
self.GetPosition()
except:
time.sleep(0.5)
else:
if self.newport.x == 0 and self.newport.y == 0 and self.newport.z == 0:
break
elif arg[0].lower() == 'power on':
self.newport.power_on(arg[1])
elif arg[0].lower() == 'power off':
self.newport.power_off(arg[1])
elif arg[0].lower() == 'pos':
self.newport.pos_x(arg[1])
self.newport.pos_y(arg[2])
self.newport.pos_z(arg[3])
while True:
try:
self.GetPosition()
except:
time.sleep(0.5)
else:
time.sleep(1)
break
elif arg[0].lower() == 'get pos':
self.GetPosition()
elif arg[0].lower() == 'get error':
self.GetError()
elif arg[0].lower() == 'get pow':
print(self.outputpd.toPlainText())
time.sleep(2)
def closeIt(self):
self.close()
感谢您的支持。
【问题讨论】:
-
没有
QWidget-derived 对象可以在除主线程之外的任何线程中。您的代码不是多线程的,它只是在您处于循环中时阻塞 UI。 UI 代码通过执行分发事件的事件循环来工作,当您卡在任何插槽或事件处理程序中时,事件循环不会运行。反转控制流程:不要在循环中等待,而是使用一个计时器,每隔一段时间调用你的代码来读取内容,或者在新数据可用时做出反应,如果你正在使用例如QSerialPort. -
你不妨也看看 Stack Overflow PyQt documentation page on threads。
标签: python multithreading qt dialog pyqt