当线程在 Python 中完成时启动 QMessageBox
Launch a QMessageBox when a thread is finished in Python
我正在使用 Python 3.5.2 和 PyQt 5.5.1。当按下按钮时,函数作为线程启动,该函数包含一个 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。如果没有,是否有其他方法可以达到同样的效果?
在 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()
我正在使用 Python 3.5.2 和 PyQt 5.5.1。当按下按钮时,函数作为线程启动,该函数包含一个 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。如果没有,是否有其他方法可以达到同样的效果?
在 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()