wxProgressDialog problems
Larry Bates
larry.bates at websafe.com
Sat Feb 23 12:46:16 PST 2008
Robin Dunn wrote:
> Larry Bates wrote:
>> Robin Dunn wrote:
>>> Larry Bates wrote:
>>>> I am trying to implement a file upload dialog (see code below). It
>>>> almost works, except that I can't get the cancel button to respond
>>>> as expect. I'm certain it is something really small.
>>>
>>> Events (like the cancel button event) won't be delivered if program
>>> flow is not in the main loop. In real life that probably won't be a
>>> problem for most apps, as long as you don't block some event handler
>>> in a long running task. In your sample it can be taken care of by
>>> using a timer to update the progress dialog. See
>>> http://wiki.wxpython.org/LongRunningTasks for ideas on how to
>>> approach other situations.
>>>
>>> class MyApp(wx.App):
>>> def OnInit(self):
>>> self.callback = Callback("test file upload")
>>> self.callback.start(100)
>>> self.timer = wx.Timer(self)
>>> self.Bind(wx.EVT_TIMER, self.OnTimer, self.timer)
>>> self.timer.Start(200)
>>> self.count = 0
>>> return True
>>>
>>> def OnTimer(self, evt):
>>> if self.count < 100:
>>> self.callback(100, self.count)
>>> self.count += 1
>>> else:
>>> self.callback.complete()
>>>
>>> app = MyApp(0)
>>> app.MainLoop()
>>>
>>>
>>
>> Robin,
>>
>> My problem is that the thing that calls this Callback is WAY down deep in
>> other code. I want to register the Callback instance with that and it
>> gets called as the file is streamed (once per (65K block) over a
>> WEBDAV connection. I don't see how to adapt what you wrote or the
>> examples on
>> the wiki like you sent. When the cancel button is pushed it needs to
>> return False so I can cancel the streaming upload and work my way back
>> through all the layers back to my main program.
>>
>> 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.
-Larry
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
if __name__ == "__main__":
import time
app=wx.PySimpleApp(0)
wx.InitAllImageHandlers()
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