Tab traversal after window disable/enable

I have a collection of panels that create and immediately disable. I enable them after the user has done some interaction. However if I disable the panels before the app.MainLoop(), later when I enable them, TAB_TRAVERSAL doesn’t work.

I have a test case that shows the failure. A limitation is that I’m working on legacy code using linux python 2.7.8 and wx 3.0.2 (yes, I know) and can’t upgrade in the short term.

Am I missing some step that I should be doing after I re-enable the panel to get that panel back in the TAB_TRAVERSAL list?

In example code below, if the call to frame.on_button_toggle() is left where it is right before app.MainLoop(), then pushing the toggle state button will make tab traversal not include the originally disabled objects.

If it’s a feature, what event can I trigger on to disable the panels before the user has a chance to interact, but after app.MainLoop() ?

Thanks for any suggestions!

import wx


class TCPanel(wx.Panel):
    """A panel with 2 textctrl's"""

    counter = 0

    def __init__(self, parent, *args, **kwargs):
        super(TCPanel, self).__init__(parent, *args, **kwargs)
        gbs = wx.GridBagSizer(vgap=2, hgap=4)

        self.tcx = wx.TextCtrl(self, name="tcx", value=str(TCPanel.counter))
        TCPanel.counter += 1

        self.tcy = wx.TextCtrl(self, name="tcy", value=str(TCPanel.counter))
        TCPanel.counter += 1

        gbs.Add(self.tcx, (0, 0))
        gbs.Add(self.tcy, (0, 1))

        self.SetSizer(gbs)
        self.Layout()


class MainWindow(wx.Frame):
    """ Test window to hold a TCPanel """

    def __init__(self, parent, title, num_panels=5, slice_size=2):
        super(MainWindow, self).__init__(parent, title=title)

        self.slice = slice_size

        sizer = wx.BoxSizer(wx.VERTICAL)
        self.state = True
        self.plist = []
        for i in range(num_panels):
            p = TCPanel(self, style=wx.TAB_TRAVERSAL)
            sizer.Add(p, 0, 0, 0)
            self.plist += [p]

        btn = wx.Button(self, label="toggle state")
        sizer.Add(btn, 0, flag=wx.ALL, border=10)
        btn.Bind(wx.EVT_BUTTON, self.on_button_toggle)
        self.SetSizer(sizer)
        self.SetClientSize(self.GetBestSize())
        self.Show()
        # breaks if self.state is set to False and windows are disabled before app.MainLoop()
        # self.on_button_toggle(None)

    def on_button_toggle(self, event=None):
        """toggle some panels between enable and disable
        If panels are disabled before app.MainLoop(), can't get traversal to work again."""
        self.state = not self.state
        for p in self.plist[::self.slice]:
            p.Enable(self.state)


app = wx.App(False)
frame = MainWindow(None, 'Test', num_panels=6, slice_size=2)
frame.Show(True)
# uncomment on_button_toggle() to make traversal not work after pushing button to enable all
# comment and it will work
frame.on_button_toggle()
app.MainLoop()

you are not missing anything: I’ve tried all your versions and even if I put the toggle right after the plist creation it works; I’m on a Windows everything newest, so I would say it’s your setup

I was afraid of that. Thanks for testing!

Can you suggest an event I can trigger on once that happens after everything gets built? The search terms I’ve used haven’t taken me in the right direction.

straight from the docu of wx.lib.newevent (roll your own)

tab_evt.py (2.3 KB)

Thanks! Turns out QueueEvent also has problems in my setup but PostEvent works. But I’ve got things to try now. Appreciate it.