wxProgressDialog problems

Larry Bates larry.bates at websafe.com
Sun Feb 24 12:49:03 PST 2008


Robin Dunn wrote:
> Larry Bates wrote:
>> Robin Dunn wrote:
>>> Larry Bates wrote:
> 
>>>> Thoughts?
>>>
>>> Do the other code in a thread, and make the callback use wx.CallAfter 
>>> or post an event so the update of the progress dialog can be done in 
>>> the gui thread.  If the cancel button was pressed then set a flag 
>>> that the download thread will check periodically so it knows to stop 
>>> (or send the message in some other thread-safe way).
>>>
>>>
>> Real newbie here.  It sounds like this would be the best way:
>>
>>  > or post an event so the update of the progress dialog can be done in
>>  > the gui thread.
>>
>> I "really" tried on this one, but it exhibits the same behavior.  
>> Can't ever click on the Cancel button.  See sample code below.
>>
>> Thanks for all your help.
> 
> You still are not calling the app's MainLoop method.  And you seem to 
> have missed the "Do the other code in a thread" part of my comment.
> 
> 

 >>> Do the other code in a thread, and make the callback use wx.CallAfter
 >>> or post an event so the update of the progress dialog can be done in
 >>> the gui thread.

Sorry, I read your instructions as "Do in a thread and make callback or post
an event..." Note the OR.

I tried running my other code in a separate thread, but Python DAVLIB refuses 
run in a separate thread and I'm not up to a complete rewrite of that code at 
the present.

I tried running the MainLoop in another thread, but it makes no difference.

import wx
import time
myEVT_UPDATE_PROGRESS = wx.NewEventType()
EVT_UPDATE_PROGRESS = wx.PyEventBinder(myEVT_UPDATE_PROGRESS, 1)

class MyProgressEvent(wx.PyCommandEvent):
     def __init(self, evtType, id):
         wxPYcommendEvent.__init(self, evType, id)
         self.myVal=None

     def SetVal(self, val):
         self.myVal=val

     def GetVal(self):
         return self.myVal

class GUIprogressCallback(object):
     def __init__(self, parent):
         self.uploadTotal=0
         self.uploadPosition=0

         #
         # Bind my custom event that gets posted by caller to update the progress
         #
         parent.Bind(EVT_UPDATE_PROGRESS, self.update)

     def setUploadTotal(self, uploadTotal):
         '''
         setUploadTotal - if user is doing a mult-file upload and would like to
                          set the total upload size for all files, use this
                          method.  Otherwise we will assume a single-file upload
                          and the total will be the size of the file being
                          uploaded.
         '''
         self.uploadTotal=uploadTotal

     def start(self, fileName, fileSize):
         '''
         start - This method is called to start the upload of a file
         '''
         #
         # Truncate the fileName if it is too long to display
         #
         if len(fileName) > 90:
             fileName=".."+fileName[-90:]
         #
         # Create the dialog unless I've already created it (e.g. previous file
         # in a multi-file upload).
         #
         if not hasattr(self, 'dlg'):
             self._createDialog(msg=fileName, maximum=self.uploadTotal)

         #
         # Handle the possibility that files changed sizes between the time that
         # I calculated uploadTotal and when I actually get to uploading them by
         # backing down from uploadTotal, but can't be less than 0.
         #
         if self.uploadPosition+fileSize > self.uploadTotal:
             self.uploadPosition=max(self.uploadTotal-fileSize, 0)
         #
         # Update the dialog with the info
         #
         self.dlg.Update(self.uploadPosition, newmsg=fileName)
         return True

     def update(self, event):
         '''
         update - Events are posted as file upload is progressing.  This method
                  is bound so it picks up those events (every block).  We
                  calculate the percentage complete and update the progessDialog
                  with this information and update the progress gauge.
         '''
         filePosition=event.GetVal()
         #
         # Handle both single- and mult-file upload percentage complete.
         #
         uploadPosition=self.uploadPosition+filePosition
         #
         # Calculate and display the percent complete and update the position
         # of the progress dialog gauge.
         #
         percentstr=int(100.0*float(uploadPosition)/float(self.uploadTotal))
         msg="WebSafe Upload-%s%%" % percentstr
         self.dlg.SetLabel(msg)
         wx.Yield()
         keepgoing, skip=self.dlg.Update(uploadPosition)
         #
         # See if user clicked the cancel button
         #
         if not keepgoing:
             self.close()

         return True

     def _createDialog(self, msg='', maximum=100):
         #
         # Create progress dialog and display it, but it must run in a different
         # thread or user won't be able to click cancel button.
         #
         self.dlg=wx.ProgressDialog(title="WebSafe Upload",
                                    message="",
                                    maximum=maximum,
                                    style=wx.PD_APP_MODAL |
                                          #wx.PD_AUTO_HIDE | \
                                          wx.PD_CAN_ABORT | \
                                          wx.PD_REMAINING_TIME)

         self.dlg.SetDimensions(-1, -1, width=500, height=-1,
                                sizeFlags=wx.SIZE_AUTO_HEIGHT)

         self.dlg.Show(True)

     def complete(self, fileSize):
         self.uploadPosition=self.uploadPosition+fileSize
         return True

     def close(self):
         self.isRunning=False
         self.dlg.Destroy()
         return False


class MyApp(wx.PySimpleApp):
     def OnInit(self):
         wx.InitAllImageHandlers(0)
         return True




if __name__ == "__main__":
     import time
     import thread
     app=wx.PySimpleApp(0)
     wx.InitAllImageHandlers()
     thread.start_new_thread(app.MainLoop, ())
     evt=MyProgressEvent(myEVT_UPDATE_PROGRESS, -1)
     blockSize=1<<16
     #
     # Test multi-file upload
     #
     fileNames=['filename1.txt', 'filename2.txt', 'filename3.txt']
     fileSizes=[(1<<20), 2*(1<<20), 3*(1<<20)]
     CB=GUIprogressCallback(app)
     CB.setUploadTotal(sum(fileSizes))
     for fileName, fileSize in zip(fileNames, fileSizes):
         CB.start(fileName, fileSize)
         for i in xrange(blockSize, fileSize, blockSize):
             evt.SetVal(i)
             app.ProcessEvent(evt)
             time.sleep(0.5)

         CB.complete(fileSize)
     CB.close()







More information about the wxpython-users mailing list