Hi Robin, Andrea,
Note how the panel at 0x8455758 now receives the event 12 times, twice
as much as before!
If one additional layer (one panel) doubles the number of events sent
I'm not surprised that my dialog with 10 layers or so becomes very
sluggish
Indeed. Please create a bug ticket about this. Personally I'm a bit
surprised to see the events coming from the panel(s) when the child
which is actually receiving focus is not the panel, but there may be a
good reason for that which I'm not seeing at the moment. But the
doubling of the number of events is clearly a bug.
I've been bitten by this issue again I think. This time on Windows.
When opening a dialog with a wx.lib.agw.customtreectrl.CustomTreeCtrl
in it the customtreectrl calls self.SetFocus() at the end of its
__init__ method. This call takes 0,5 second. Since this dialog has two
customtreectrls in it, opening the dialog takes a whole second; quite
noticeable for users.
The call to self.SetFocus in CustomTreeCtrl.__init__ causes 74
wx.EVT_CHILD_FOCUS events. I guess this is understandable since the
dialog is quite complicated (a notebook with 8 pages, each with
several widgets). However, the main window of the application uses
wx.lib.agw.aui to manage its panes. The framemanager binds to
wx.EVT_CHILD_FOCUS events. For each wx.EVT_CHILD_FOCUS event received
it activates the active pane. Here's the framemanager.OnChildFocus
handler:
def OnChildFocus(self, event):
"""
Handles the wx.EVT_CHILD_FOCUS event for L{AuiManager}.
:param `event`: a L{wx.ChildFocusEvent} to be processed.
"""
# when a child pane has it's focus set, we should change the
# pane's active state to reflect this. (this is only true if
# active panes are allowed by the owner)
window = event.GetWindow()
if isinstance(window.GetParent(), AuiFloatingFrame):
rootManager = GetManager(window)
else:
rootManager = self
if rootManager:
rootManager.ActivatePane(window)
event.Skip()
This calls ActivatePane:
def ActivatePane(self, window):
"""
Activates the pane to which `window` is associated.
:param `window`: a L{wx.Window} derived window.
"""
if self.GetFlags() & AUI_MGR_ALLOW_ACTIVE_PANE:
while window:
ret, self._panes = SetActivePane(self._panes, window)
if ret:
break
window = window.GetParent()
self.RefreshCaptions()
I think that is the culprit: ret is True when the active pane is
changed, but in my case it is never True, since the dialog is not
managed by AUI. Consequence is that ActivatePane calls SetActivePane
for each widget that sends wx.EVT_CHILD_FOCUS (which is already 74
times) and each of its ancestors. ActivatePane takes 0.015 seconds per
call, long enough to matter.
Adapting OnChildFocus to ignore wx.EVT_CHILD_FOCUS events coming from
dialogs fixes the issue for me, see attached patch. I'm not sure
that's the best solution though. What do you think, Andrea, Robin?
Thanks, Frank
patch.txt (812 Bytes)
···
2009/10/9 Robin Dunn <robin@alldunn.com>:
On 10/9/09 12:42 PM, Frank Niessink wrote: