I have a wx.DatePickerCtrl with the dropdown popup window that allows the user to pick a date from the calendar. What I would l like to have my program do is process an event when the user has clicked on a day in the dropdown calendar. Unfortunately the only native event for this control is EVT_DATE_CHANGED and that event gets fired every time the user scrolls the month/year while looking for the date of their choice (firing the event many more times than I would like). I can't seem to access the popup window that is created below the datepickerctrl to see if the window is shown or to bind events directly to it. It isn't created as a child of the datepickerctrl. Basically I'm trying to have the user 1.Click the dropdown button, 2.navigate through the popupwindow calendar, 3. Click on a date, have the popupwindow disappear, 4. Process the event

Something like this?

import wx

class MyFrame(wx.Frame):
    def __init__(self, parent, mytitle, mysize):
        wx.Frame.__init__(self, parent, wx.ID_ANY, mytitle, size=mysize)

        #--Panel so it look good on all platforms
        self.panel = wx.Panel(self)
        self.datepick = wx.DatePickerCtrl(self.panel,-1, pos=(20,15),
                              style=wx.DP_DROPDOWN|wx.DP_SHOWCENTURY)
        self.datepick.Bind(wx.EVT_DATE_CHANGED, self.onAction)
        self.label = wx.StaticText(self.panel,-1,"", pos=(20,50))

    def onAction(self, event):
        '''Process data from picked date'''
        selected = self.datepick.GetValue()
        month = selected.Month + 1
        day = selected.Day
        year = selected.Year
        date_str = "%02d/%02d/%4d" % (month, day, year)
        self.label.SetLabel("Date selected = {}".format(date_str))

app = wx.App()
MyFrame(None, 'DatePickerCtrl', (350, 240)).Show()
app.MainLoop()

Edited 4 Years Ago by snippsat

no, that's similar to what I have. When you are choosing what month/year you want, before clicking on the date you choose I event fires. If you want to move the month forward one, the event fires, if you want to move the year forward one, the event fires again. I'm trying to catch when the user actually clicks on a day and the popup closes.

The wx.calendar.CalendarCtrl() control gives you more flexibility:

# explore the wx.calendar.CalendarCtrl() control
# allows for point and click date input

import wx
import wx.calendar as cal

class MyCalendar(wx.Dialog):
    """create a simple dialog window with a calendar display"""
    def __init__(self, parent, mytitle):
        wx.Dialog.__init__(self, parent, wx.ID_ANY, mytitle)
        # use a box sizer to position controls vertically
        vbox = wx.BoxSizer(wx.VERTICAL)

        # wx.DateTime_Now() sets calendar to current date
        self.calendar = cal.CalendarCtrl(self, wx.ID_ANY, wx.DateTime_Now())
        vbox.Add(self.calendar, 0, wx.EXPAND|wx.ALL, border=20)
        # click on day
        self.calendar.Bind(cal.EVT_CALENDAR_DAY, self.onCalSelected)
        # change month
        #self.calendar.Bind(cal.EVT_CALENDAR_MONTH, self.onCalSelected)
        # change year
        #self.calendar.Bind(cal.EVT_CALENDAR_YEAR, self.onCalSelected)

        self.label = wx.StaticText(self, wx.ID_ANY, 'click on a day')
        vbox.Add(self.label, 0, wx.EXPAND|wx.ALL, border=20)

        button = wx.Button(self, wx.ID_ANY, 'Exit')
        vbox.Add(button, 0, wx.ALL|wx.ALIGN_CENTER, border=20)
        self.Bind(wx.EVT_BUTTON, self.onQuit, button)

        self.SetSizerAndFit(vbox)
        self.Show(True)
        self.Centre()

    def onCalSelected(self, event):
        #date = event.GetDate()
        date = self.calendar.GetDate()
        day = date.GetDay()
        # for some strange reason month starts with zero
        month = date.GetMonth() + 1
        # year is yyyy format
        year = date.GetYear()
        # format the date string to your needs
        ds = "%02d/%02d/%d \n" % (month, day, year)
        self.label.SetLabel(ds)

    def onQuit(self, event):
        self.Destroy()


app = wx.App(0)
MyCalendar(None, 'wx.calendar.CalendarCtrl()')
app.MainLoop()

The DatePickerCtrl works really well with what I'm developing. I guess I could recreate a DatePickerCtrl using a CalendarCtrl on a PopupWindow, it just seems unecessary.

It might be time for you to abandon wxPython and use the PySide/PyQT GUI toolkit.
QCalendarWidget behaves the way you want to, here is a test code:

'''ps_test_QCalendarWidget1.py
simple test code for any PySide widget
select a day from a calendar image

PySide is the official LGPL-licensed version of PyQT
You can downloaded the Windows self-extracting installer
for Python27:
PySide-1.1.0qt474.win32-py2.7.exe
or for Python32:
PySide-1.1.0qt474.win32-py3.2.exe
from:
http://developer.qt.nokia.com/wiki/PySide_Binaries_Windows

code tested with pyside474 and Python27/Python32
'''

from PySide.QtCore import *
from PySide.QtGui import *

app = QApplication([])  # no need to import sys

# ----- start your widget test code ----

def show_date():
    date = cal.selectedDate()
    # to get month/day/year like '8/13/2009' use ...
    sd = "%s/%s/%s" % (date.month(), date.day(), date.year())
    window.setWindowTitle(sd)

window = QWidget()
# setGeometry(x, y, width, height)
window.setGeometry(320, 320, 300, 200)
window.setWindowTitle("Select a Day")
window.show()

# create a calendar
cal = QCalendarWidget(window)
cal.move(25, 20)
cal.show()
# signal only on a day change
cal.selectionChanged.connect(show_date)

# ---- end of widget test code -----

app.exec_()

Note that wxPython was an amateur project and always will be. PyQT is much more professional.

Edited 4 Years Ago by HiHe

I'm taking a look at this now, but have you tried using the widget inspection tool to see what events are generated by the DatePickerCtrl?