refresh/repaint of ObjectListView control when doing dlg.ShowModal

I have a really strange problem I can't figure out, i.e. when dlg.ShowModal is called on a "child" dialog then all visible listctrls refresh.

Simplified structure of the app is:

sizedFrame
- aui
--- aui.nb
---- sizedpanel
------ listctrl 1
----- sizedpanel
------- listctrl 2
------- button to load dialog

Both listctrl's will repaint all the items (top down) when the dlg.ShowModal is called by the button handler and they do it again when the dialog is closed.

I put logging.debug all over the place to narrow it down, tried using freeze/thaw to hide the refresh but no success. If I freeze listctrl 1 just before dlg.ShowModal then the listctrl disappears when dlg.ShowModal is called and shows up when the thaw is called after ShowModal returns.

The listctrl's may get updated via pubsub calls from the dlg but in my tests I just cancel the dialog which means listctrl does not need to be updated and the relevant methods do NOT show in the logging debug output.

Also suspected my use of InfoBar, but running a test without it didn't not change anything, then my other suspect is the use of EVT_UPDATE_UI to enable/disable buttons, toolbar tools and sub-panels. Commenting the Bind for it didn't make any difference either.

Anyone has some tips for what else I could possibly have messed up to cause this?

Werner

Python 2.7, wxPython 2.9.3.2 on Win7

werner wrote:

I have a really strange problem I can't figure out, i.e. when
dlg.ShowModal is called on a "child" dialog then all visible listctrls
refresh.

Why is that a problem? A control is expected to be able to repaint
itself at any point in time. Any time a portion of your window is
obscured and then revealed, you get a paint event.

···

--
Tim Roberts, timr@probo.com
Providenza & Boekelheide, Inc.

Hi Tim,

werner wrote:

I have a really strange problem I can't figure out, i.e. when
dlg.ShowModal is called on a "child" dialog then all visible listctrls
refresh.

Why is that a problem? A control is expected to be able to repaint
itself at any point in time. Any time a portion of your window is
obscured and then revealed, you get a paint event.

I don't think it is a paint event which does it. I use the OLV for a long time and in my old code when I do the same I don't see this same refresh/reloading of the list.

I am pretty sure I am doing something stupid in my new code or there is something in 2.9.3 different to 2.8 (which I use for my old stuff) which causes this.

Let me try to describe it differently.

I open the application, then I select an item in the first list which causes items to be displayed in the second list. Clicking on the button to open the dialog to edit/add an item to the second list causes the both lists to refresh/reload even so they are mostly behind the dialog and non of my methods which add items to a list are showing in my debug output (when when I walk it through the debugger). Now I move that dialog to my second monitor, I don't see a visible reload of the list which was behind the dialog, but when I close it on the second monitor both lists on the first monitor look/behave as if the items get reloaded.

Werner

···

On 23/03/2012 18:20, Tim Roberts wrote:

I am getting closer, the dialog closes and the list is still fine, but it gets into wx.lib.agw.aui.framemanager and at some point the list is getting cleared, and then later on the OLV rebuilds it.

It seems to be in framemanager.OnEraseBackground (line 8693), but this shouldn't do anything except on Mac and I am on Windows, it is definitely during the framemanager.OnSize (line 8707) but this gets hit a lot.

Will have to try to narrow it further down, but that will be tomorrow.

Werner

Hi Werner,

···

On 23 March 2012 19:34, werner wrote:

I am getting closer, the dialog closes and the list is still fine, but it
gets into wx.lib.agw.aui.framemanager and at some point the list is getting
cleared, and then later on the OLV rebuilds it.

It seems to be in framemanager.OnEraseBackground (line 8693), but this
shouldn't do anything except on Mac and I am on Windows, it is definitely
during the framemanager.OnSize (line 8707) but this gets hit a lot.

Will have to try to narrow it further down, but that will be tomorrow.

Be sure you're not using wx.SafeYield/wx.Yield/wx.YieldIfNeeded or any
of their friends while showing/destroying the dialog, as these methods
will (needlessly) force a repaint of stuff in framemanager.AuiManager.

Andrea.

"Imagination Is The Only Weapon In The War Against Reality."
http://xoomer.alice.it/infinity77/

Hi Andrea,

Hi Werner,

I am getting closer, the dialog closes and the list is still fine, but it
gets into wx.lib.agw.aui.framemanager and at some point the list is getting
cleared, and then later on the OLV rebuilds it.

It seems to be in framemanager.OnEraseBackground (line 8693), but this
shouldn't do anything except on Mac and I am on Windows, it is definitely
during the framemanager.OnSize (line 8707) but this gets hit a lot.

Will have to try to narrow it further down, but that will be tomorrow.

Be sure you're not using wx.SafeYield/wx.Yield/wx.YieldIfNeeded or any
of their friends while showing/destroying the dialog, as these methods
will (needlessly) force a repaint of stuff in framemanager.AuiManager.

I don't have any yield calls, i.e. in the whole project I only have two of them and they are to do with the splashscreen, which has gone by the time I run into this problem.

When I step through in the debugger I can see that just about all controls at some point go empty and then redraw. But I still have not been able to get it down to the exact function which does it.

Will try to narrow it down.

Werner

···

On 23/03/2012 20:55, Andrea Gavana wrote:

On 23 March 2012 19:34, werner wrote:

Andrea.

"Imagination Is The Only Weapon In The War Against Reality."
http://xoomer.alice.it/infinity77/

I can not narrow it down (when I try to step through in the debugger I get into a loop of repaint etc etc) and for the moment I have put a hack into my OLV class.

         # TODO: hack to prevent list to be rebuilt from scratch due to
         # someone sending/causing an erase background
         self.myOlv.Bind(wx.EVT_CONTEXT_MENU, self.onListContextMenu)

     def onEraseBackground(self, event):
         pass

I am doing the bind after the initial creation of the list, but this is still not perfect, but a bit less annoying - at least for the moment.

Will have to try and create a small app showing the problem.

Werner

When and who should issue a EraseBackground event?

I am sure pretty everyone guessed/know that my hack would not last long.

When I step through things with the debugger I seem to get a lot of them, if I just put debug statements I get 1 to 2 which I still don't understand, i.e. why is the background erased instead of just calling something like Layout or Refresh?

Can anyone explain a bit on what background erase should be doing, and when it should be used and who should call/cause it.

Stack on first hit:

app_cb.py, line 576, in <module>
   app.MainLoop()
_core.py, line 8651, in MainLoop
   wx.PyApp.MainLoop(self)
_core.py, line 7943, in MainLoop
   return _core_.PyApp_MainLoop(*args, **kwargs)
base.py, line 1635, in onCreateItemButton
   dlg.view.ShowModal()
_windows.py, line 801, in ShowModal
   return _windows_.Dialog_ShowModal(*args, **kwargs)
base.py, line 1377, in onUndoItemButton
   self.view.Close()
_core.py, line 9169, in Close
   return _core_.Window_Close(*args, **kwargs)
cellarbook.py, line 191, in onEraseBG
   log.debug("erase bg: %s" % event.GetEventObject().Name)

In the above my onUndoItemButton is:
     def onUndoItemButton(self, event):
         self.doItemRollBack()
         self.view.Close()

and doItemRollBack is:
     def doItemRollBack(self):
         """Do the actual rollback"""
         self.ds.rollback()
         pub.sendMessage(pTopics.data.rollbackDone, dbparent=self.dbParent)
         pub.sendMessage(pTopics.statusText, msg="")
         self._invalidControls = []
         self._myDataIsDirty = False

So, it does a database rollback (SQLalchemy which doesn't know anything about wx) and the sendMessage calls are resetting a flag and clearing a statusText (statusbar and/or infobar)

Oops, sorry pressed the wrong button.

I am looking for:

- should these background erase events actually happen at this point
- if yes, what causes them and what could I do to at least freeze/thaw to hide the reload
- if yes, even better would be if I could suppress the erase event (in my view at this point not needed)

Werner

···

On 25/03/2012 17:51, werner wrote:

When and who should issue a EraseBackground event?

I am sure pretty everyone guessed/know that my hack would not last long.

When I step through things with the debugger I seem to get a lot of them, if I just put debug statements I get 1 to 2 which I still don't understand, i.e. why is the background erased instead of just calling something like Layout or Refresh?

Can anyone explain a bit on what background erase should be doing, and when it should be used and who should call/cause it.

Stack on first hit:

app_cb.py, line 576, in <module>
  app.MainLoop()
_core.py, line 8651, in MainLoop
  wx.PyApp.MainLoop(self)
_core.py, line 7943, in MainLoop
  return _core_.PyApp_MainLoop(*args, **kwargs)
base.py, line 1635, in onCreateItemButton
  dlg.view.ShowModal()
_windows.py, line 801, in ShowModal
  return _windows_.Dialog_ShowModal(*args, **kwargs)
base.py, line 1377, in onUndoItemButton
  self.view.Close()
_core.py, line 9169, in Close
  return _core_.Window_Close(*args, **kwargs)
cellarbook.py, line 191, in onEraseBG
  log.debug("erase bg: %s" % event.GetEventObject().Name)

In the above my onUndoItemButton is:
    def onUndoItemButton(self, event):
        self.doItemRollBack()
        self.view.Close()

and doItemRollBack is:
    def doItemRollBack(self):
        """Do the actual rollback"""
        self.ds.rollback()
        pub.sendMessage(pTopics.data.rollbackDone, dbparent=self.dbParent)
        pub.sendMessage(pTopics.statusText, msg="")
        self._invalidControls =
        self._myDataIsDirty = False

So, it does a database rollback (SQLalchemy which doesn't know anything about wx) and the sendMessage calls are resetting a flag and clearing a statusText (statusbar and/or infobar)