I had a Progress class that was working fine in 2.8.12.1 unicode:
class Progress(bolt.Progress):
"""Progress as progress dialog."""
def __init__(self,title=_(u'Progress'),message=u' '*60,parent=None,
style=wx.PD_APP_MODAL|wx.PD_ELAPSED_TIME|wx.PD_AUTO_HIDE|wx.PD_SMOOTH,
abort=False, onAbort=None):
if abort:
style |= wx.PD_CAN_ABORT
self.fnAbort = onAbort
self.dialog = wx.ProgressDialog(title,message,100,parent,style)
self.dialog.SetFocus() #### line 1295 in the traceback is here ####
bolt.Progress.__init__(self)
self.message = message
self.isDestroyed = False
self.prevMessage = u''
self.prevState = -1
self.prevTime = 0
(bolt.Progress has no wx in it)
In 3.02 however blows with:
Traceback (most recent call last):
...
File "bash\basher\__init__.py", line 2670, in _refresh_installers_if_needed
with balt.Progress(_(u'Refreshing Installers...'),u'\n'+u' '*60, abort=canCancel) as progress:
File "bash\balt.py", line 1295, in __init__
self.dialog.SetFocus()
File "C:\_\Python27\lib\site-packages\wx-3.0-msw\wx\_core.py", line 10129, in SetFocus
return _core_.Window_SetFocus(*args, **kwargs)
wx._core.PyAssertionError: C++ assertion "hWnd" failed at ..\..\src\msw\window.cpp(562) in wxWindow::SetFocus(): can't set focus to invalid window
Now can anyone spot what is invalid about this window ? As seen the Progress is instantiated in:
with balt.Progress(_(u'Refreshing Installers...'),u'\n'+u' '*60, abort=canCancel) as progress:
so parent is None - is it because of that ? However why the change in behavior in 3.0.2 ? EDIT: well no - passing a non None parent in makes no difference
Incidentally if I remove the SetFocus call it goes on to blow in another setFocus call later on:
def doProgress(self,state,message):
if not self.dialog:
raise StateError(u'Dialog already destroyed.')
elif (state == 0 or state == 1 or (message != self.prevMessage) or
(state - self.prevState) > 0.05 or (time.time() - self.prevTime) > 0.5):
self.dialog.SetFocus() #### blows here, this self.dialog is really, really invalid ####
if message != self.prevMessage:
ret = self.dialog.Update(int(state*100),message)
if not ret[0]:
if self.onAbort():
raise CancelError
else:
ret = self.dialog.Update(int(state*100))
if not ret[0]:
if self.onAbort():
raise CancelError
self.prevMessage = message
self.prevState = state
self.prevTime = time.time()
Not sure if all this hocus pocus is needed or if it could be simplified, but my immediate concern is why the window is invalid.
On Windows the ProgressDialog
is now a stock common control (like MessageDialog
, FileDialog
, etc.) instead of a generic dialog implemented in wx like it used to be. So it is not a real native window any longer but just a wrapper around a platform API. So this means that it has no native window handle, and most non-ProgressDialog
-specific APIs like SetFocus
will not work.