The Bearded Templar
The Bearded Templar

Reputation: 701

QProgressDialog cancel button sometimes not responsive

I am running a processor heavy operation and using a QProgressDialog to report back to the user. However, the cancel button works erratically - sometimes it is ignored for the entire run and sometimes it responds, but only after a certain point in the progress (this point is not consistent either). It seems to me as if the event loop is not being called, so I've put in a call to QApplication.instance().processEvents() but the erratic behaviour remains.

Here is the function doing the work.

def import(self):

    imp = worker()
    imp.progressChanged.connect(self.setImportProgress)
    self.progress.canceled.connect(imp.cancel)

    imp.run()

    self.progress.setValue(100) #Ensures we reach the end, in case of rounding errors

@Slot(int)
def setImportProgress(self,p):
    self.progress.setValue(p)
    QApplication.instance().processEvents()

Here is the worker's run class and cancel slot.

def run(self):
    frameCount = 0
    hundredth = self.numFrames/100 #Used to output percentages
    while True:
        ret, frame = self.cam.read()
        if not ret: #Breaks when the last frame is reached
            break
        if frameCount >= self.start:
            self.doWorkOnFrame()

            #Output the percentage completed
            if frameCount % hundredth == 0:
                self.progressChanged.emit(frameCount/hundredth)

@QtCore.Slot()
def cancel(self):
    print "Cancel Pressed"

I realize that the cancel slot does not do anything at the moment, I'm just trying to get it to activate consistently before I implement the actual functionality. I do get the "Cancel Pressed" output so I know the signal-slot connection is set up properly, it just isn't consistent when I press the button.

I realize there are similar questions to this, but I can't find the exact same problem nor do the solutions to similar problems seem to work. Sorry if this is a duplicate.

Edit - Upon reading about a similar problem elsewhere, I wrote QApplication.instance().processEvents() 10 times in a row, and this solves the problem. Not exactly a pleasant solution - is there a limit on how many events are processed in one go?

Upvotes: 2

Views: 1282

Answers (1)

ekhumoro
ekhumoro

Reputation: 120638

You're probably not updating the GUI often enough for the cancel button to work properly.

Calling QApplication.instance().processEvents() is the right thing to do, but definitely not from within the worker thread. It needs to be called from within the GUI thread (i.e. in the setImportProgress signal handler).

The question is: how long does it take to process 1 percent of the frames? Because the progress dialog is going to be unresponsive during this period of time. You need to find a more appropriate step value for emitting the progressChanged signal - one that is short enough to keep the cancel button responsive, but not so short that it impacts overall performance.

Upvotes: 1

Related Questions