Seems to work just fine for me on MSW with recentish master (binding the event to the control's parent though)
Code: Select all
#include <wx/wx.h>
#include <wx/calctrl.h>
#include <wx/generic/calctrlg.h>
#include <wx/timectrl.h>
#include <wx/combo.h>
#include <wx/settings.h>
// wxCustomDateTimePicker declaration
class wxCustomDateTimePicker : public wxComboCtrl
{
public:
wxCustomDateTimePicker(wxWindow* parent, const wxDateTime& dateTime, bool instantUpdate = false);
wxDateTime GetDateTime() const { return m_dateTime; }
void SetDateTime(const wxDateTime& dateTime, bool fromUser = false);
private:
wxDateTime m_dateTime;
};
// wxCustomDateTimePickerPopup declaration
class wxCustomDateTimePickerPopup : public wxPanel, public wxComboPopup
{
public:
wxCustomDateTimePickerPopup(bool instantUpdate = false);
bool Create(wxWindow* parent) wxOVERRIDE;
wxWindow* GetControl() wxOVERRIDE { return this; }
wxString GetStringValue() const wxOVERRIDE;
wxSize GetAdjustedSize(int minWidth, int prefHeight, int maxHeight) wxOVERRIDE;
void OnPopup() wxOVERRIDE;
bool GetInstantUpdate() const { return m_instantUpdate; }
void SetInstantUpdate(bool instantUpdate);
static wxString GetDisplayDateTimeString(const wxDateTime& dateTime);
private:
bool m_instantUpdate;
wxDateTime m_originalDateTime;
wxGenericCalendarCtrl* m_calendar;
wxTimePickerCtrl* m_timePicker;
wxButton* m_button;
wxCustomDateTimePicker* GetCustomDateTimePicker() const;
wxDateTime GetDateTime() const;
void SetDateTime(const wxDateTime& dateTime);
void SetComboCtrlDateTime(const wxDateTime& dateTime, bool fromUser = false);
void Close(bool cancelled);
void OnChar(wxKeyEvent& evt);
void OnButtonClicked(wxCommandEvent&);
void OnDateChanged(wxCalendarEvent&);
void OnTimeChanged(wxDateEvent&);
};
// wxCustomDateTimePickerPopup definition
wxCustomDateTimePickerPopup::wxCustomDateTimePickerPopup(bool instantUpdate)
: m_instantUpdate(instantUpdate)
{}
bool wxCustomDateTimePickerPopup::Create(wxWindow* parent)
{
if ( !wxPanel::Create(parent, wxID_ANY, wxDefaultPosition,
wxDefaultSize, wxBORDER_RAISED | wxTAB_TRAVERSAL) )
{
return false;
}
SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_FRAMEBK));
wxBoxSizer* mainSizer = new wxBoxSizer(wxVERTICAL);
wxBoxSizer* timerAndButtonSizer = new wxBoxSizer(wxHORIZONTAL);
const int borderAround = FromDIP(3);
m_calendar = new wxGenericCalendarCtrl(this, wxID_ANY, wxDefaultDateTime,
wxDefaultPosition, wxDefaultSize, wxNO_BORDER | wxWANTS_CHARS | wxCAL_SHOW_HOLIDAYS);
m_calendar->SetHighlightColours(*wxGREEN, *wxRED);
mainSizer->Add(m_calendar, wxSizerFlags().Expand().Border(wxALL, borderAround));
m_timePicker = new wxTimePickerCtrl(this, wxID_ANY, wxDefaultDateTime,
wxDefaultPosition, wxDefaultSize, wxWANTS_CHARS);
timerAndButtonSizer->Add(m_timePicker, wxSizerFlags().Proportion(1).Expand().Border(wxALL, borderAround));
m_button = new wxButton(this, wxID_ANY, wxEmptyString);
m_button->Bind(wxEVT_COMMAND_BUTTON_CLICKED, &wxCustomDateTimePickerPopup::OnButtonClicked, this);
timerAndButtonSizer->Add(m_button, wxSizerFlags().Border(wxALL, borderAround));
if ( m_instantUpdate )
{
m_button->SetLabel(_("Cancel"));
m_calendar->Bind(wxEVT_CALENDAR_SEL_CHANGED, &wxCustomDateTimePickerPopup::OnDateChanged, this);
m_timePicker->Bind(wxEVT_TIME_CHANGED, &wxCustomDateTimePickerPopup::OnTimeChanged, this);
}
else
{
m_button->SetLabel(_("OK"));
m_button->SetDefault();
}
m_calendar->Bind(wxEVT_CHAR, &wxCustomDateTimePickerPopup::OnChar, this);
m_timePicker->Bind(wxEVT_CHAR, &wxCustomDateTimePickerPopup::OnChar, this);
mainSizer->Add(timerAndButtonSizer, wxSizerFlags().Expand());
SetSizerAndFit(mainSizer);
return true;
}
wxString wxCustomDateTimePickerPopup::GetStringValue() const
{
return GetDisplayDateTimeString(GetDateTime());
}
wxSize wxCustomDateTimePickerPopup::GetAdjustedSize(int, int, int)
{
return GetSize();
}
void wxCustomDateTimePickerPopup::SetInstantUpdate(bool instantUpdate)
{
wxCHECK_RET(IsCreated() == false, "SetInstantUpdate() cannot be called after calling Create()");
m_instantUpdate = instantUpdate;
}
void wxCustomDateTimePickerPopup::OnPopup()
{
m_originalDateTime = GetCustomDateTimePicker()->GetDateTime();
SetDateTime(GetCustomDateTimePicker()->GetDateTime());
if ( m_instantUpdate )
m_button->SetToolTip(wxString::Format(_("Reverts to %s"), GetDisplayDateTimeString(m_originalDateTime)));
}
wxDateTime wxCustomDateTimePickerPopup::GetDateTime() const
{
wxCHECK(IsCreated(), wxInvalidDateTime);
wxDateTime dateOnly, timeOnly;
dateOnly = m_calendar->GetDate();
wxCHECK(dateOnly.IsValid(), wxInvalidDateTime);
timeOnly = m_timePicker->GetValue();
wxCHECK(timeOnly.IsValid(), wxInvalidDateTime);
return wxDateTime(dateOnly.GetDay(), dateOnly.GetMonth(), dateOnly.GetYear(),
timeOnly.GetHour(), timeOnly.GetMinute(), timeOnly.GetSecond());
}
void wxCustomDateTimePickerPopup::SetDateTime(const wxDateTime& dateTime)
{
wxCHECK_RET(IsCreated(), "Call Create() before calling SetDateTime()");
m_calendar->SetDate(dateTime);
m_timePicker->SetValue(dateTime);
}
wxString wxCustomDateTimePickerPopup::GetDisplayDateTimeString(const wxDateTime& dateTime)
{
wxCHECK(dateTime.IsValid(), wxString(_("Invalid date and/or time")));
// @fixme: change the format string as needed
return dateTime.Format();
}
wxCustomDateTimePicker* wxCustomDateTimePickerPopup::GetCustomDateTimePicker() const
{
wxCHECK(IsCreated(), NULL);
wxCustomDateTimePicker* picker = dynamic_cast<wxCustomDateTimePicker*>(GetComboCtrl());
wxCHECK_MSG(picker, NULL, "Invalid ComboCtrl type");
return picker;
}
void wxCustomDateTimePickerPopup::SetComboCtrlDateTime(const wxDateTime& dateTime, bool fromUser)
{
GetCustomDateTimePicker()->SetDateTime(dateTime, fromUser);
}
void wxCustomDateTimePickerPopup::Close(bool cancelled)
{
if ( cancelled )
{
SetDateTime(m_originalDateTime);
SetComboCtrlDateTime(m_originalDateTime, true);
}
else
{
const wxDateTime dateTime = GetDateTime();
SetDateTime(dateTime);
SetComboCtrlDateTime(dateTime, true);
}
Dismiss();
}
void wxCustomDateTimePickerPopup::OnChar(wxKeyEvent& evt)
{
if ( (evt.GetKeyCode() == WXK_RETURN || evt.GetKeyCode() == WXK_ESCAPE)
&& !evt.HasAnyModifiers() )
{
if ( m_instantUpdate )
Close(false); // in the instant update mode <Esc> does not revert the value, only Cancel does
else
Close(evt.GetKeyCode() == WXK_ESCAPE);
}
else
{
evt.Skip();
}
}
void wxCustomDateTimePickerPopup::OnButtonClicked(wxCommandEvent&)
{
if ( m_instantUpdate ) // button is Cancel
{
Close(true);
}
else // button is OK
{
Close(false);
}
}
void wxCustomDateTimePickerPopup::OnDateChanged(wxCalendarEvent&)
{
SetComboCtrlDateTime(GetDateTime());
}
void wxCustomDateTimePickerPopup::OnTimeChanged(wxDateEvent&)
{
SetComboCtrlDateTime(GetDateTime());
}
// wxCustomDateTimePicker definition
wxCustomDateTimePicker::wxCustomDateTimePicker(wxWindow* parent, const wxDateTime& dateTime, bool instantUpdate)
: wxComboCtrl(parent, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0),
m_dateTime(dateTime)
{
UseAltPopupWindow();
wxCustomDateTimePickerPopup* popup = new wxCustomDateTimePickerPopup(instantUpdate);
SetPopupControl(popup);
SetDateTime(m_dateTime);
// make the combo control fit the date and time string
const wxDateTime dt(28, wxDateTime::Jan, 2222, 22, 58, 58);
const wxString dateTimeStr = wxCustomDateTimePickerPopup::GetDisplayDateTimeString(dt);
wxSize size = GetMinClientSize();
size.SetWidth(GetSizeFromTextSize(GetTextExtent(wxString::Format(" %s ", dateTimeStr))).GetWidth());
SetMinClientSize(size);
}
void wxCustomDateTimePicker::SetDateTime(const wxDateTime& dateTime, bool fromUser)
{
const wxString dateTimeStr = wxCustomDateTimePickerPopup::GetDisplayDateTimeString(dateTime);
m_dateTime = dateTime;
if ( fromUser )
SetValueByUser(dateTimeStr);
else
SetValue(dateTimeStr);
}
class MyFrame : public wxFrame
{
public:
MyFrame() : wxFrame(NULL, wxID_ANY, "Test", wxDefaultPosition, wxSize(800, 600))
{
wxPanel* mainPanel = new wxPanel(this);
wxBoxSizer* mainSizer = new wxBoxSizer(wxVERTICAL);
wxDateTime dateTime = wxDateTime::Now();
wxCustomDateTimePicker* picker = new wxCustomDateTimePicker(mainPanel, dateTime, true);
picker->Bind(wxEVT_TEXT, &MyFrame::OnText, this);
mainSizer->Add(picker, wxSizerFlags().DoubleBorder());
wxTextCtrl* textCtrl = new wxTextCtrl(mainPanel, wxID_ANY, wxEmptyString,
wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE | wxTE_READONLY | wxTE_RICH2);
mainSizer->Add(textCtrl, wxSizerFlags().Proportion(1).Expand().DoubleBorder());
wxLog::SetActiveTarget(new wxLogTextCtrl(textCtrl));
wxLog::SetTimestamp("");
mainPanel->SetSizer(mainSizer);
}
void OnText(wxCommandEvent& evt)
{
wxCustomDateTimePicker* picker = dynamic_cast<wxCustomDateTimePicker*>(evt.GetEventObject());
wxCHECK_RET(picker, "Invalid Control");
wxLogMessage("OnText: %s", picker->GetValue());
}
};
class MyApp : public wxApp
{
public:
bool OnInit()
{
(new MyFrame)->Show();
return true;
}
}; wxIMPLEMENT_APP(MyApp);
The only difference in wxCustomDateTimePicker code from the one linked above is the removal of wxCB_READONLY.