在Python中完成线程时启动QMessageBox

时间:2018-04-20 14:19:56

标签: python-3.x pyqt5 python-multithreading

我在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>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p align=&quot;center&quot;&gt;&lt;span style=&quot; font-size:24pt;&quot;&gt;Not running&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</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。如果没有,还有另一种方法可以达到同样的目的吗?

1 个答案:

答案 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()