Niek de Klein
Niek de Klein

Reputation: 8824

How to update progress bar while performing a task

I want to use wx.ProgressDialog to show the progress of my program. I have a button that when pressed runs this function:

def runmiP(self, event):
    predictor.runPrediction(self.uploadProtInterestField.GetValue(), self.uploadAllProteinsField.GetValue(), self.uploadPfamTextField.GetValue(), \
                   self.edit_eval_all.Value, self.edit_eval_small.Value, self.saveOutputField)

predictor is a python package I wrote. How can I get progress from predictor and show it in a progress bar? I can only return one value. Should I call it multiple times (like every minute), remember where it left, return how far it is and call it again? Something like

while 1: 
    time.sleep(60)
    predictor.runPrediction(self.uploadProtInterestField.GetValue(), self.uploadAllProteinsField.GetValue(), self.uploadPfamTextField.GetValue(), \
                   self.edit_eval_all.Value, self.edit_eval_small.Value, self.saveOutputField)

Or is there a better way to do this?

Upvotes: 1

Views: 828

Answers (1)

abarnert
abarnert

Reputation: 365667

This is a general problem. (And unless you're already running this on another thread, you're blocking your entire UI, not just failing to update the progress bar, right?) And there are two general ways to solve it.

  • Pass a callback to runPrediction, and make it call progressCallback(sofar, total) every X times through the loop, every Y%, or every Z seconds. (You could use some other communication mechanism—post to a queue and fire a condition, send a message over a pipe or socket, etc.—but the idea is the same.)

  • Break runPrediction up into separate, smaller jobs that you can run in sequence, and update the progress each time you start the next job.

Your solution is basically a slightly clumsier, but often perfectly reasonable, version of the second idea. If there's no clear way to break the job up, but there is a reasonable way to abort the job, stashing where it is, and resume later, that's effectively the same thing as breaking the job up, right?

Python provides a often simpler and cleaner way to do the second idea: Turn runPrediction into a generator, that yields results as they come in, instead of returning all of the results at the end. Then you just update the progress as each value comes back.

Upvotes: 3

Related Questions