我在PyQt 5.5.1中使用Python 3.5.2。当按下一个按钮时,一个函数作为一个线程启动,这个函数包含一个while循环,它可以从线程内的特定事件终止,也可以再次按下按钮。如果循环从内部终止,我想启动一个QMessageBox来解释原因。
MWE:
from PyQt5 import QtCore, QtGui, QtWidgets, uic
import sys, threading, random
qtCreatorMain = "CloseThread.ui"
Ui_MainWindow, QtBaseClass = uic.loadUiType(qtCreatorMain)
myKillReason = 20
class OperatorGUI(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self, parent=None):
super(OperatorGUI, self).__init__(parent)
self.setupUi(self)
self.running = False
self.kill_reason = None
self.lock = threading.Lock()
self.runBtn.clicked.connect(self.run_pushed)
def run_pushed(self):
self.running = not self.running
if self.running:
self.thread_1 = threading.Thread(target=self.myThread).start()
else:
self.label.setText("Not Running")
def myThread(self):
self.kill_reason = None
self.label.setText("Running")
while self.running:
self.lock.acquire()
num = random.random()
if num > 0.99999999:
self.kill_reason = myKillReason
self.running = False
self.lock.release()
if self.kill_reason == myKillReason:
self.label.setText("Not Running")
QtWidgets.QMessageBox.information(None, "Error", "Random value above limit",
QtWidgets.QMessageBox.Ok)
if __name__ == "__main__":
sys.settrace
app = QtWidgets.QApplication(sys.argv)
window = OperatorGUI()
window.show()
sys.exit(app.exec_())
.ui文件
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Form</class>
<widget class="QWidget" name="Form">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>154</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<widget class="QPushButton" name="runBtn">
<property name="geometry">
<rect>
<x>150</x>
<y>110</y>
<width>85</width>
<height>27</height>
</rect>
</property>
<property name="text">
<string>Run</string>
</property>
</widget>
<widget class="QLabel" name="label">
<property name="geometry">
<rect>
<x>10</x>
<y>20</y>
<width>381</width>
<height>81</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>24</pointsize>
</font>
</property>
<property name="text">
<string><html><head/><body><p align="center"><span style=" font-size:24pt;">Not running</span></p></body></html></string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</widget>
<resources/>
<connections/>
</ui>
执行此操作我收到错误消息:QApplication: Object event filter cannot be in a different thread.
有没有办法让线程在关闭时发送SIGNAL
?如果是这样,我知道如何使用它来启动QMessageBox。如果没有,还有另一种方法可以达到同样的目的吗?
答案 0 :(得分:2)
在Qt中,您只能从主线程更新GUI,如果您想要在另一个线程中发生的事件之前更新GUI的任何元素,则必须使用信号进行更新。
class OperatorGUI(QtWidgets.QMainWindow, Ui_MainWindow):
finished = QtCore.pyqtSignal()
def __init__(self, parent=None):
super(OperatorGUI, self).__init__(parent)
self.setupUi(self)
self.running = False
self.kill_reason = None
self.lock = threading.Lock()
self.runBtn.clicked.connect(self.run_pushed)
self.finished.connect(self.on_finished, QtCore.Qt.QueuedConnection)
def run_pushed(self):
self.running = not self.running
if self.running:
self.thread_1 = threading.Thread(target=self.myThread).start()
self.label.setText("Running")
else:
self.label.setText("Not Running")
def on_finished(self):
self.label.setText("Not Running")
QtWidgets.QMessageBox.information(None, "Error", "Random value above limit",
QtWidgets.QMessageBox.Ok)
def myThread(self):
self.kill_reason = None
while self.running:
self.lock.acquire()
num = random.random()
if num > 0.99:
self.kill_reason = myKillReason
self.running = False
self.lock.release()
if self.kill_reason == myKillReason:
self.finished.emit()