Datepickerctrlgeneric

There is a bug in datepickerctrlgeneric.

When the event wx.EVT_DATE_CHANGED is triggered, it breaks the tabbing order. So it skips over widgets when tabbing. I even used SetTabIndex ().

I know it’s a bug because when I switch to datepickerctrl and trigger the event, the tabbing goes in order of the widgets.

Anybody know why?

Hi,

Which platform and which version of wxPython are you using?

I tested the code below using Python 3.10.6 + wxPython 4.2.0 gtk3 (phoenix) wxWidgets 3.2.0 on Linux Mint 21.1

The tab order was the same, before and after a wx.EVT_DATE_CHANGED event was triggered.

import wx
import wx.adv

class MyFrame(wx.Frame):
    def __init__(self, *args, **kwds):
        kwds["style"] = kwds.get("style", 0) | wx.DEFAULT_FRAME_STYLE
        wx.Frame.__init__(self, *args, **kwds)
        self.SetSize((400, 200))
        self.SetTitle("DatePickerCtrlGeneric")
        self.main_panel = wx.Panel(self, wx.ID_ANY)
        main_sizer = wx.BoxSizer(wx.VERTICAL)
        self.datepicker_ctrl = wx.adv.DatePickerCtrlGeneric(self.main_panel, wx.ID_ANY)
        main_sizer.Add(self.datepicker_ctrl, 0, wx.ALIGN_CENTER_HORIZONTAL | wx.TOP, 16)
        self.text_ctrl = wx.TextCtrl(self.main_panel, wx.ID_ANY, "")
        main_sizer.Add(self.text_ctrl, 0, wx.ALIGN_CENTER_HORIZONTAL | wx.TOP, 16)
        bottom_sizer = wx.BoxSizer(wx.HORIZONTAL)
        main_sizer.Add(bottom_sizer, 0, wx.ALIGN_CENTER_HORIZONTAL | wx.BOTTOM | wx.TOP, 16)
        self.button_1 = wx.Button(self.main_panel, wx.ID_ANY, "button_1")
        bottom_sizer.Add(self.button_1, 0, wx.RIGHT, 32)
        self.button_2 = wx.Button(self.main_panel, wx.ID_ANY, "button_2")
        bottom_sizer.Add(self.button_2, 0, 0, 0)
        self.main_panel.SetSizer(main_sizer)
        self.Layout()
        self.Bind(wx.adv.EVT_DATE_CHANGED, self.OnDateChanged, self.datepicker_ctrl)

    def OnDateChanged(self, event):
        print(event.GetDate())


class MyApp(wx.App):
    def OnInit(self):
        self.frame = MyFrame(None, wx.ID_ANY, "")
        self.SetTopWindow(self.frame)
        self.frame.Show()
        return True


if __name__ == "__main__":
    app = MyApp(0)
    app.MainLoop()

Using windows,python 3.7.4, wx 4.2 phoenix

Could it be due to python 3.7 ?

It’s possible, but I would have thought that UI differences would be more likely due to Windows vs Linux/GTK. Unfortunately, I don’t have any Windows PCs on which to test.

Does explicitly setting the tab order, as shown in the code below, make any difference?

import wx
import wx.adv

class MyFrame(wx.Frame):
    def __init__(self, *args, **kwds):
        kwds["style"] = kwds.get("style", 0) | wx.DEFAULT_FRAME_STYLE
        wx.Frame.__init__(self, *args, **kwds)
        self.SetSize((400, 200))
        self.SetTitle("DatePickerCtrlGeneric")
        self.main_panel = wx.Panel(self, wx.ID_ANY)
        main_sizer = wx.BoxSizer(wx.VERTICAL)
        self.datepicker_ctrl = wx.adv.DatePickerCtrlGeneric(self.main_panel, wx.ID_ANY)
        main_sizer.Add(self.datepicker_ctrl, 0, wx.ALIGN_CENTER_HORIZONTAL | wx.TOP, 16)
        self.text_ctrl = wx.TextCtrl(self.main_panel, wx.ID_ANY, "")
        main_sizer.Add(self.text_ctrl, 0, wx.ALIGN_CENTER_HORIZONTAL | wx.TOP, 16)
        bottom_sizer = wx.BoxSizer(wx.HORIZONTAL)
        main_sizer.Add(bottom_sizer, 0, wx.ALIGN_CENTER_HORIZONTAL | wx.BOTTOM | wx.TOP, 16)
        self.button_1 = wx.Button(self.main_panel, wx.ID_ANY, "button_1")
        bottom_sizer.Add(self.button_1, 0, wx.RIGHT, 32)
        self.button_2 = wx.Button(self.main_panel, wx.ID_ANY, "button_2")
        bottom_sizer.Add(self.button_2, 0, 0, 0)
        self.main_panel.SetSizer(main_sizer)
        self.Layout()
        self.Bind(wx.adv.EVT_DATE_CHANGED, self.OnDateChanged, self.datepicker_ctrl)
        self._setTabOrder()

    def _setTabOrder(self):
        order = (self.datepicker_ctrl,
                 self.text_ctrl,
                 self.button_1,
                 self.button_2)

        for i in range(len(order) - 1):
            order[i+1].MoveAfterInTabOrder(order[i])

    def OnDateChanged(self, event):
        print(event.GetDate())


class MyApp(wx.App):
    def OnInit(self):
        self.frame = MyFrame(None, wx.ID_ANY, "")
        self.SetTopWindow(self.frame)
        self.frame.Show()
        return True


if __name__ == "__main__":
    app = MyApp(0)
    app.MainLoop()

@Chris_Keo
I’ll probably be accused of blowing my own trumpet here, but you could give my minidatepicker a whirl, with the caveat, that I don’t think it has been tested on Windows.
You can find the latest version using this link:

Here I stole the code from @RichardT (sorry Richard) and replaced the date widget.
On Linux it behaves itself. :slight_smile:

import wx
#import wx.adv
import minidatepicker as MDP

class MyFrame(wx.Frame):
    def __init__(self, *args, **kwds):
        kwds["style"] = kwds.get("style", 0) | wx.DEFAULT_FRAME_STYLE
        wx.Frame.__init__(self, *args, **kwds)
        self.SetSize((400, 200))
        self.SetTitle("MiniDatePicker")
        self.main_panel = wx.Panel(self, wx.ID_ANY)
        main_sizer = wx.BoxSizer(wx.VERTICAL)
        format = (lambda dt: (f'{dt.Format("%A %d-%m-%Y")}'))
        #self.datepicker_ctrl = wx.adv.DatePickerCtrlGeneric(self.main_panel, wx.ID_ANY)
        self.datepicker_ctrl = MDP.MiniDatePicker(self.main_panel, -1, formatter=format)

        main_sizer.Add(self.datepicker_ctrl, 0, wx.ALIGN_CENTER_HORIZONTAL | wx.TOP, 16)
        self.text_ctrl = wx.TextCtrl(self.main_panel, wx.ID_ANY, "")
        main_sizer.Add(self.text_ctrl, 0, wx.ALIGN_CENTER_HORIZONTAL | wx.TOP, 16)
        bottom_sizer = wx.BoxSizer(wx.HORIZONTAL)
        main_sizer.Add(bottom_sizer, 0, wx.ALIGN_CENTER_HORIZONTAL | wx.BOTTOM | wx.TOP, 16)
        self.button_1 = wx.Button(self.main_panel, wx.ID_ANY, "button_1")
        bottom_sizer.Add(self.button_1, 0, wx.RIGHT, 32)
        self.button_2 = wx.Button(self.main_panel, wx.ID_ANY, "button_2")
        bottom_sizer.Add(self.button_2, 0, 0, 0)
        self.main_panel.SetSizer(main_sizer)
        self.Layout()
        #self.Bind(wx.adv.EVT_DATE_CHANGED, self.OnDateChanged, self.datepicker_ctrl)
        self.Bind(MDP.EVT_DATE_CHANGED, self.OnDateChanged, self.datepicker_ctrl)

    def OnDateChanged(self, event):
        print(event.GetDate())


class MyApp(wx.App):
    def OnInit(self):
        self.frame = MyFrame(None, wx.ID_ANY, "")
        self.SetTopWindow(self.frame)
        self.frame.Show()
        return True


if __name__ == "__main__":
    app = MyApp(0)
    app.MainLoop()

1 Like

Wow, so much respect for people who can build these tools.

Looks awesome, going to test it this noon! Thanks for the response.

How can I turn off the blue rectangle and “today: 6/30/2023” in the drop down calendar