Zwierzak
Zwierzak

Reputation: 686

Updating PyQt4 GUI while in loop

I would like to show progress of calculation if in my GUI. To do so I would like to update my PyQt4 label each time a calculation is made. I know that I am supposed to use thread to do it, but it doesn't work. Nothing changes, and after while loop is complete, the label is updated to "100%".Even though the thread is working the value still won't update smoothly. There are comments in my code explaining what is what. Please help me :)

from PyQt4 import QtGui, QtCore
import time

class MyThread(QtCore.QThread):
    trigger = QtCore.pyqtSignal(int)
    def __init__(self, progress, parent=None):
        super(MyThread, self).__init__(parent)
        self.progress = progress #progress is a PyQt4 label object

    def update_progress(self, value):
        self.progress.setText(QtGui.QApplication.translate("Dialog", "Progress: %s " % value, None))
        print "I was called", value
        print self.progress #prints <PyQt4.QtGui.QLabel object at 0x0000000008151708>
        #as you can see the object is passed all right
    def run(self, value):
        self.trigger.emit(value)

class Calculus:
    def __init__(self):
        print "object created"

    @staticmethod
    def euler(b,h,progress):    
        #progress is a PyQt4 label object, b and h are some integers
        actions_done = 0
        actions_number = b / h

        thread = MyThread(progress)#create a thread
        thread.trigger.connect(thread.update_progress)#connect it with a update function
        thread.start()#start the thread


        while t <= b:
            actions_done+=1
            progress_value = (actions_done/actions_number)*100

            thread.run(progress_value)#emit signal?
            t += h

        thread.terminate()

@EDIT, here is my solution but with memory leaking problem

from PyQt4 import QtGui

class Calculus:
    def __init__(self):
        print "object created"

    @staticmethod
    def update_progress(self,value,ui_object): 
        ui_object.setText(QtGui.QApplication.translate("Dialog", "Progress: %s %%" % value, None))

        #MEMORY LEAK WHEN UPDATING TOO MUCH (H=0.0001 AND B=1000)
        QtGui.QApplication.processEvents() #update gui for pyqt



    @staticmethod
    def euler(b,h,progress):
        actions_done = 0
        actions_number = b * (1./h) #t = t+h. When h = 0.01 we need to perform t=t+h 100(1/h) times to get 1. 
                                    #when t varies from 0 to b, then we need to multiply this 1 * b(end time)
                                    #so we get b * (1/h) as a number of actions to perform

        scale = actions_number * 0.01

        while t <= b:
            actions_done+=1
            progress_value = (actions_done/actions_number)*100

            if (actions_done % scale == 0):
                Calculus.update_progress(None,progress_value, progress)         

            t += h

Upvotes: 2

Views: 1482

Answers (1)

three_pineapples
three_pineapples

Reputation: 11849

Calling thread.run() in the way that you are does not do what you think it does. Currently it is simply executing the thread.run() method in the main thread.

It is the call to thread.start() which starts the thread, and automatically calls the thread.run() method. As such, you need the while loop inside the thread.run() method.

This is because you want to pass complete control over to the thread, and finish the euler method so that control can be returned to the GUI event loop (so it can process redraws, and the method to update the progress bar) as soon as possible. You should not be trying to manage the threads execution from the main thread.

Upvotes: 1

Related Questions