paul marguerite
paul marguerite

Reputation: 143

PyQt: send information from GUI to a thread

My HMI is composed of 2 butons: Start and stop, and also a field QStatusBar to print information from a thread to GUI. When I do "start", I launch a thread that I can interrupt with Stop button. What I want to do is to open a popup window at a certain point in the thread to give a choice to the users while the thread is paused.

from PyQt4 import QtCore, QtGui
import sys
import os
import time
from PyQt4.QtGui import QApplication, QDialog, QListWidgetItem, QListWidget, QIcon
from test_bench_tool2 import Ui_MainWindow
from popup import Ui_popup

"""Class poppup window(continue/quit)"""
class MyPopup(QtGui.QDialog):
    def __init__(self,type):
        super(MyPopup, self).__init__()
        self.res = 0
        self.type=type
        self.ui = Ui_popup()
        self.ui.setupUi(self)
        QtCore.QObject.connect(self.ui.Quit,QtCore.SIGNAL("clicked()"),self.showDialogstop)
       QtCore.QObject.connect(self.ui.Continue,QtCore.SIGNAL("clicked()"),self.showDialogcontinue)

    def showDialogcontinue(self):
        self.res=1
        self.close()
    def showDialogstop(self):
        self.res=0
        self.close()


class MyThread(QtCore.QThread):
    Statuschanged = QtCore.pyqtSignal(str)
    popupmodechanged = QtCore.pyqtSignal(str)
    def __init__(self, parent=None):
        super(MyThread, self).__init__(parent=parent)
        self.Status_auto = ''
        self.dialog = MyPopup('toto')
        self.Status_auto +=''
        self.popup=''
        self.answer=''

    def run(self):
        result = self.get_result()

    def get_result(self, ):
        empty_result = []
        self.popup='Vn'
        self.popupmodechanged.emit((self.popup))
        self.Status_auto +='\n\nMeasures finished!!'
        self.Statuschanged.emit((self.Status_auto))
        results=[]
        #do things to calculate results
        return(results)


class Main(QtGui.QDialog):
    def __init__(self):
        QtGui.QMainWindow.__init__(self)
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)
        # Connect the Buttons
        QtCore.QObject.connect(self.ui.Start,QtCore.SIGNAL("clicked()"),self.Start)
        QtCore.QObject.connect(self.ui.Stop,QtCore.SIGNAL("clicked()"),self.Stop)
        self.__thread = MyThread(self)
        self.__thread.Statuschanged.connect(self.ui.report_auto.setText)
        self.__thread.popupmodechanged.connect(self.open_popup)

    def open_popup(self):
        self.__thread.dialog.__init__(self.__thread.dialog.type)
        self.__thread.dialog.exec_()

    def Start(self):
        global tableRx, tableTx
        self.ui.report_auto.setText('test in process...')
        self.__thread.start()

    def  Stop(self):
        self.ui.report_auto.setText('test canceled')
        if self.__thread.isRunning():
            self.__thread.terminate()

def main():

    app = QtGui.QApplication(sys.argv)
    window = Main()

    window.show()
    sys.exit(app.exec_())

if __name__ == "__main__":
    main()

How could I get the result of the choice from the popup to continue the thread? I have tried to put in get_result() function a test like this

if self.dialog.res == 1:
            print "continue"
            self.dialog.close()
            #do things
        else:
            self.dialog.close()

but I can't get the result from GUI to the thread. How can I get information from GUI to my thread?? Do I have tu use a Queue??

Upvotes: 3

Views: 7281

Answers (1)

Mátyás Kuti
Mátyás Kuti

Reputation: 820

In my experience a queue is the best solution. It's a thread safe way to share information between threads. You should instantiate the queue in your Main class and pass it as an init argument to the thread:

#MyThread init
def __init__(self, queue, parent=None):
    #the input queue
    self.in_queue = queue 
    #flag indicating if the thread's run function should actually run
    self.running = True 
    super(MyThread, self).__init__(parent=parent)
    self.Status_auto = ''
    self.dialog = MyPopup('toto')
    self.Status_auto +=''
    self.popup=''
    self.answer=''

With a queue your thread worker function should look something like this:

def run(self)
    while self.running: #to keep the thread running
        if not self.in_queue.empty():
            msg = self.in_queue.get()
            #do something according to the message
        else:
            #do regular operation

This also allows you to put (using self.queue.put(value)) a 'STOP' message or something in the message queue. Note that in this case the queue's get method would block the thread until it can actually get something from the queue (hence the if). You can change this behaviour:

msg = self.in_queue.get(block = False)

This way if the queue is empy an Empty exception will be raised.

To access the Queue class:

from queue import Queue
queue = Queue()

Instead of the above solution you could possibly connect signals from the dialog to event handlers in the thread but I haven't tried this way and not sure wether it would work properly.

I hope this solves your problem.

Cheers, Mátyás

Upvotes: 7

Related Questions