Combined date and time picker Topic is solved
-
- Earned some good credits
- Posts: 107
- Joined: Tue Aug 28, 2018 1:02 pm
- Location: Belarus
Combined date and time picker
Hi all,
I need DateTimePicker control, something like this one on the screenshot, but with one text field for time values and one combobox for choosing AM/PM value.
I haven't find this control in wxWidgets as well as some custom solutions. So the only way to meet my needs is to write this control by myself. I understand, that I need to combine wxCalendarCtrl, wxTextCtrl and wxComboBox in one class, but I've got some questions here:
1) What class should I use as a base class of my control?
2) How to draw all the controls in one frame?
3) How to make it possible to collapse/expand my control?
I've got only assumptions regrading the answers, so I'd like to get answers from others.
Thanks.
I need DateTimePicker control, something like this one on the screenshot, but with one text field for time values and one combobox for choosing AM/PM value.
I haven't find this control in wxWidgets as well as some custom solutions. So the only way to meet my needs is to write this control by myself. I understand, that I need to combine wxCalendarCtrl, wxTextCtrl and wxComboBox in one class, but I've got some questions here:
1) What class should I use as a base class of my control?
2) How to draw all the controls in one frame?
3) How to make it possible to collapse/expand my control?
I've got only assumptions regrading the answers, so I'd like to get answers from others.
Thanks.
Re: Combined date and time picker
1. I would suggest wxPanel.
2. What drawing? You will use standard controls which draw themselves.
3. I guess you need to switch between the control sets and hide/display the appropriate controls as needed while taking care of changing the best size for the panel.
I assume that you are aware that there are many countries that do not subscribe to am/pm notation and use 24 hrs format.
2. What drawing? You will use standard controls which draw themselves.
3. I guess you need to switch between the control sets and hide/display the appropriate controls as needed while taking care of changing the best size for the panel.
I assume that you are aware that there are many countries that do not subscribe to am/pm notation and use 24 hrs format.
-
- Earned some good credits
- Posts: 107
- Joined: Tue Aug 28, 2018 1:02 pm
- Location: Belarus
Re: Combined date and time picker
I started to implement in based on wxPanel. It wasn't difficult to place needed controls on it.
How can I now make this panel collapse and expand? I need the panel starts in collapsed state so only string with chosen date and time is shown (see calendar.png in attachments). And when I click on calendar icon (on the right of text control) it should expand. Currently I've got only pane with needed controls and for some reason background is transparent: So at the moment I've got two questions:
1) How can I collapse/expand my control to make it look on collapsed state as it shown on "calendar.png" attachment and on expanded state as it looks now?
2) How can I make specific background color?
And cpp file:
How can I now make this panel collapse and expand? I need the panel starts in collapsed state so only string with chosen date and time is shown (see calendar.png in attachments). And when I click on calendar icon (on the right of text control) it should expand. Currently I've got only pane with needed controls and for some reason background is transparent: So at the moment I've got two questions:
1) How can I collapse/expand my control to make it look on collapsed state as it shown on "calendar.png" attachment and on expanded state as it looks now?
2) How can I make specific background color?
Code: Select all
#pragma once
#include <wx/wxprec.h>
#include <wx/calctrl.h>
#include <wx/textctrl.h>
class wxCustomDateTimePicker : public wxPanel
{
public:
wxCustomDateTimePicker();
explicit wxCustomDateTimePicker(wxWindow* parent);
virtual ~wxCustomDateTimePicker();
bool Create(wxWindow *parent,
wxWindowID winid = wxID_ANY,
const wxPoint& pos = wxDefaultPosition,
const wxSize& size = wxDefaultSize,
long style = wxTAB_TRAVERSAL | wxNO_BORDER,
const wxString& name = wxPanelNameStr);
private:
wxCalendarCtrl* m_calendar;
wxTextCtrl* m_timeText;
};
Code: Select all
#include "stdafx.h"
#include "wxCustomDateTimePicker.h"
#include <wx/statline.h>
wxCustomDateTimePicker::wxCustomDateTimePicker(wxWindow* parent)
{
Create(parent);
}
wxCustomDateTimePicker::wxCustomDateTimePicker(){}
bool wxCustomDateTimePicker::Create(wxWindow *parent, wxWindowID winid /*= wxID_ANY*/, const wxPoint& pos /*= wxDefaultPosition*/, const wxSize& size /*= wxDefaultSize*/, long style /*= wxTAB_TRAVERSAL | wxNO_BORDER*/, const wxString& name /*= wxPanelNameStr*/)
{
bool res = wxPanel::Create(parent, winid, pos, size, style, name);
SetBackgroundColour(parent->GetBackgroundColour());
SetBackgroundStyle(wxBG_STYLE_PAINT);
SetForegroundColour(parent->GetForegroundColour());
m_calendar = new wxCalendarCtrl(this, wxID_ANY, wxDefaultDateTime, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL | wxNO_BORDER);
wxPoint pt(m_calendar->GetPosition());
pt.y += m_calendar->GetSize().GetHeight() + 5;
wxStaticLine* line = new wxStaticLine(this, wxID_ANY, pt, wxSize(m_calendar->GetSize().GetWidth(), 2));
pt.y += 6;
m_timeText = new wxTextCtrl(this, wxID_ANY, wxT("12:34:56"), pt);
return res;
}
wxCustomDateTimePicker::~wxCustomDateTimePicker(){}
Re: Combined date and time picker
That's because you have a bug in your code. You callrudolfninja wrote:Currently I've got only pane with needed controls and for some reason background is transparent:
Code: Select all
SetBackgroundStyle(wxBG_STYLE_PAINT);
Unless you for some odd reason need custom-drawn panel background, do not call the above. This will most likely fix the issue you asked about in question #2. BTW, I do not think calling SetForegroundColour() on wxPanel does anything, as the panel has only background.
Edited
Regarding question #1, it depends on how the control should behave. I.e., should it really expand or just display a pop-up. If the latter and you do not wish to use a wxDialog, you may take a look at the popup sample or perhaps using wxComboPopup? If it is the former, it would be a bit more complex but should not be difficult, it is basically the same thing wxCollapsiblePane does.
-
- Earned some good credits
- Posts: 107
- Joined: Tue Aug 28, 2018 1:02 pm
- Location: Belarus
Re: Combined date and time picker
I guess, it should display pop-up on click.PB wrote: Regarding question #1, it depends on how the control should behave. I.e., should it really expand or just display a pop-up. If the latter and you do not wish to use a wxDialog, you may take a look at the popup sample or perhaps using wxComboPopup? If it is the former, it would be a bit more complex but should not be difficult, it is basically the same thing wxCollapsiblePane does.
Do you mean this sample? If it so, then I need to inherit my class from wxPopupTransientWindow and place all the control on wxScrolledWindow, don't I?
Second question is solved, thanks.
Re: Combined date and time picker
Yes, that's the sample. I meant to run it to see how it behaves and whether this fits your requirements. Perhaps wxComboBox-like control using custom wxComboCtrl with the panel displayed using wxComboPopup would be better or easier to implement...rudolfninja wrote:Do you mean this sample? If it so, then I need to inherit my class from wxPopupTransientWindow and place all the control on wxScrolledWindow, don't I?
I believe that you do not need to use wxScrolledWindow if you do not plan on the panel to be scrollable. OTOH, it should do no harm...
-
- Earned some good credits
- Posts: 107
- Joined: Tue Aug 28, 2018 1:02 pm
- Location: Belarus
Re: Combined date and time picker
Yes, I don't need to use wxScrolledWindow.
Thanks.
The way the sample behaves looks fine and I think that such behavior is suitable for me.PB wrote: Yes, that's the sample. I meant to run it to see how it behaves and whether this fits your requirements.
Where can I find an example of this approach or just the result? I don't understand completely final result of such approach.PB wrote: Perhaps wxComboBox-like control using custom wxComboCtrl with the panel displayed using wxComboPopup would be better or easier to implement...
Thanks.
Re: Combined date and time picker
Hi,
Just look at the sample itself and how wxComboCtrl class is defined.
Thank you.
Just look at the sample itself and how wxComboCtrl class is defined.
Thank you.
-
- Earned some good credits
- Posts: 107
- Joined: Tue Aug 28, 2018 1:02 pm
- Location: Belarus
Re: Combined date and time picker
Yes, I've already find how to use this variant and it seems easier to implement and it is more suitable for my needs. I'll try to implement this variant.
Thanks a lot!
Thanks a lot!
-
- Earned some good credits
- Posts: 107
- Joined: Tue Aug 28, 2018 1:02 pm
- Location: Belarus
Re: Combined date and time picker
I tried to implement variant with wxComboPopup and it looks very similar to what I want. Now I have the problem with the size of popup pane. I tried different variants to resize it, but all fails.
.h file:
.cpp file:
And the result:
As you can see, pop up pane is cut off on the left and on the right and has a lot of empty space on the bottom.
1) How can I resize calendar to fit in the size of popup part?
2) How can I resize only popup part?
Thanks.
.h file:
Code: Select all
#pragma once
#include <wx/combo.h>
#include "wx/panel.h"
#include <wx/calctrl.h>
class wxCustomDateTimePickerPopup : public wxPanel, public wxComboPopup
{
public:
virtual wxWindow *GetControl() { return this; }
virtual wxString GetStringValue() const { return wxEmptyString; }
virtual bool Create(wxWindow* parent);
private:
wxCalendarCtrl* m_calendar;
wxTextCtrl* m_timeText;
};
class wxCustomDateTimePicker : public wxComboCtrl
{
public:
wxCustomDateTimePicker(wxWindow* parent);
~wxCustomDateTimePicker();
private:
wxCustomDateTimePickerPopup* m_popup;
};
Code: Select all
#include "stdafx.h"
#include "wxCustomDateTimePicker.h"
#include <wx/statline.h>
#include <wx/textctrl.h>
#include <wx/sizer.h>
wxCustomDateTimePicker::wxCustomDateTimePicker(wxWindow* parent) :
wxComboCtrl(parent)
{
m_popup = new wxCustomDateTimePickerPopup();
SetPopupControl(m_popup);
}
wxCustomDateTimePicker::~wxCustomDateTimePicker()
{
}
bool wxCustomDateTimePickerPopup::Create(wxWindow* parent)
{
bool res = wxPanel::Create(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize);
SetBackgroundColour(parent->GetBackgroundColour());
SetForegroundColour(parent->GetForegroundColour());
auto sizer = new wxBoxSizer(wxVERTICAL);
m_calendar = new wxCalendarCtrl(this, wxID_ANY, wxDefaultDateTime, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL | wxNO_BORDER);
sizer->Add(m_calendar);
wxPoint pt(m_calendar->GetPosition());
pt.y += m_calendar->GetSize().GetHeight() + 5;
wxStaticLine* line = new wxStaticLine(this, wxID_ANY, pt, wxSize(m_calendar->GetSize().GetWidth(), 2));
sizer->Add(line);
pt.y += 6;
m_timeText = new wxTextCtrl(this, wxID_ANY, wxT("12:34:56"), pt);
sizer->Add(m_timeText);
SetSizer(sizer);
sizer->SetSizeHints(this);
return res;
}
1) How can I resize calendar to fit in the size of popup part?
2) How can I resize only popup part?
Thanks.
Re: Combined date and time picker
I think it seems obvious that the calendar cannof fit the current popup and you need to do it the other way around, i.e., fit the popup around the controls. Have you tried something like
Edit
I noticed that wxTextCtrl seems to not work in the pop-up: it cannot be interracted with. However, if I add wxTimePickerCtrl there it seems to work as expected? Probably a focus issue which may or may not be difficult to work around...
BTW, you probably noticed that absolute positions (and often sizes as well) are irrelevant when using sizers...
Code: Select all
wxSize wxCustomDateTimePickerPopup::GetAdjustedSize(int minWidth, int prefHeight, int maxHeight)
{
return GetSizer()->GetSize();
}
I noticed that wxTextCtrl seems to not work in the pop-up: it cannot be interracted with. However, if I add wxTimePickerCtrl there it seems to work as expected? Probably a focus issue which may or may not be difficult to work around...
BTW, you probably noticed that absolute positions (and often sizes as well) are irrelevant when using sizers...
-
- Earned some good credits
- Posts: 107
- Joined: Tue Aug 28, 2018 1:02 pm
- Location: Belarus
Re: Combined date and time picker
No I haven't tried. Will try it tomorrow. Also I will check your notice about wxTextCtrl.PB wrote:I think it seems obvious that the calendar cannof fit the current popup and you need to do it the other way around, i.e., fit the popup around the controls. Have you tried something likeCode: Select all
wxSize wxCustomDateTimePickerPopup::GetAdjustedSize(int minWidth, int prefHeight, int maxHeight) { return GetSizer()->GetSize(); }
Yes, I know. My first variant was with absolute positions and then I decided to use sizer and forgot remove absolute positions-related code.PB wrote:BTW, you probably noticed that absolute positions (and often sizes as well) are irrelevant when using sizers...
Thank you for your help!
Re: Combined date and time picker
The focus issue seems to be fixed by calling UseAltPopupWindow() before calling SetPopupControl(m_popup);
Edit
FWIW, I tried to implement very simple combined date and time picker, similar to that in the original post. Seems to work as expected on Windows 10 (except when I use <Alt+PrtScr> to screenshot, only the pop-up and not the whole frame are captured). Probably the only important thing missing is closing the pop-up after pressing <Enter>. For simplicity sake, all declarations, definitions, and demo are in a single file.
Edit
FWIW, I tried to implement very simple combined date and time picker, similar to that in the original post. Seems to work as expected on Windows 10 (except when I use <Alt+PrtScr> to screenshot, only the pop-up and not the whole frame are captured). Probably the only important thing missing is closing the pop-up after pressing <Enter>. For simplicity sake, all declarations, definitions, and demo are in a single file.
Code: Select all
#include <wx/wx.h>
#include <wx/calctrl.h>
#include <wx/timectrl.h>
#include <wx/combo.h>
#include <wx/settings.h>
class wxCustomDateTimePicker;
// wxCustomDateTimePickerPopup declaration
class wxCustomDateTimePickerPopup : public wxPanel, public wxComboPopup
{
public:
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;
static wxString GetDisplayDateTimeString(const wxDateTime& dateTime);
private:
wxCalendarCtrl* m_calendar;
wxTimePickerCtrl* m_timePicker;
wxCustomDateTimePicker* GetCustomDateTimePicker();
wxDateTime GetDateTime() const;
void SetDateTime(const wxDateTime& dateTime);
void OnOKButtonClicked(wxCommandEvent&);
};
// wxCustomDateTimePicker declaration
class wxCustomDateTimePicker : public wxComboCtrl
{
public:
wxCustomDateTimePicker(wxWindow* parent, const wxDateTime& dateTime);
wxDateTime GetDateTime() const { return m_dateTime; }
void SetDateTime(const wxDateTime& dateTime);
private:
wxDateTime m_dateTime;
wxCustomDateTimePickerPopup* m_popup;
};
// wxCustomDateTimePickerPopup definition
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* subSizer = new wxBoxSizer(wxHORIZONTAL);
m_calendar = new wxCalendarCtrl(this, wxID_ANY, wxDefaultDateTime,
wxDefaultPosition, wxDefaultSize, wxNO_BORDER);
mainSizer->Add(m_calendar, wxSizerFlags().Expand().Border(wxALL, FromDIP(2)));
m_timePicker = new wxTimePickerCtrl(this, wxID_ANY);
subSizer->Add(m_timePicker, wxSizerFlags(3).Expand().Border(wxALL, FromDIP(2)));
wxButton* OKButton = new wxButton(this, wxID_OK);
OKButton->SetDefault();
OKButton->Bind(wxEVT_COMMAND_BUTTON_CLICKED, &wxCustomDateTimePickerPopup::OnOKButtonClicked, this);
subSizer->Add(OKButton, wxSizerFlags(2).Expand().Border(wxALL, FromDIP(2)));
mainSizer->Add(subSizer, wxSizerFlags().Expand());
SetSizerAndFit(mainSizer);
return true;
}
wxString wxCustomDateTimePickerPopup::GetStringValue() const
{
return GetDisplayDateTimeString(GetDateTime());
}
wxSize wxCustomDateTimePickerPopup::GetAdjustedSize(int WXUNUSED(minWidth),
int WXUNUSED(prefHeight),
int WXUNUSED(maxHeight))
{
//@fixme: if possible, take into account the method parameters
return GetSize();
}
void wxCustomDateTimePickerPopup::OnPopup()
{
wxCustomDateTimePicker* picker = GetCustomDateTimePicker();
if ( picker )
SetDateTime(picker->GetDateTime());
}
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()
{
wxCHECK(IsCreated(), NULL);
return dynamic_cast<wxCustomDateTimePicker*>(GetComboCtrl());
}
void wxCustomDateTimePickerPopup::OnOKButtonClicked(wxCommandEvent&)
{
wxCustomDateTimePicker* picker = GetCustomDateTimePicker();
if ( picker )
picker->SetDateTime(GetDateTime());
Dismiss();
}
// wxCustomDateTimePicker definition
wxCustomDateTimePicker::wxCustomDateTimePicker(wxWindow* parent, const wxDateTime& dateTime)
: wxComboCtrl(parent, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxCB_READONLY),
m_dateTime(dateTime)
{
UseAltPopupWindow();
m_popup = new wxCustomDateTimePickerPopup();
SetPopupControl(m_popup);
SetDateTime(m_dateTime);
// make the combo control fit the date and time string
wxSize size = GetMinClientSize();
const wxString dateTimeStr = wxCustomDateTimePickerPopup::GetDisplayDateTimeString(m_dateTime);
size.SetWidth(GetSizeFromTextSize(GetTextExtent(wxString::Format(" %s ", dateTimeStr))).GetWidth());
SetMinClientSize(size);
}
void wxCustomDateTimePicker::SetDateTime(const wxDateTime& dateTime)
{
m_dateTime = dateTime;
SetValue(wxCustomDateTimePickerPopup::GetDisplayDateTimeString(m_dateTime));
}
class MyFrame : public wxFrame
{
public:
MyFrame() : wxFrame(NULL, wxID_ANY, "Test")
{
wxPanel* mainPanel = new wxPanel(this);
wxBoxSizer* mainSizer = new wxBoxSizer(wxVERTICAL);
wxDateTime dateTime = wxDateTime::Now();
wxCustomDateTimePicker* picker = new wxCustomDateTimePicker(mainPanel, dateTime);
mainSizer->Add(picker, wxSizerFlags().Border(wxALL, FromDIP(2)).CenterHorizontal());
mainPanel->SetSizer(mainSizer);
}
};
class MyApp : public wxApp
{
public:
bool OnInit()
{
(new MyFrame)->Show();
return true;
}
}; wxIMPLEMENT_APP(MyApp);
-
- Earned some good credits
- Posts: 107
- Joined: Tue Aug 28, 2018 1:02 pm
- Location: Belarus
Re: Combined date and time picker
Thanks a lot for you help.
I think that the topic can be closed as resolved. All the other features of the control I can implement by myself (at least I hope so)
I think that the topic can be closed as resolved. All the other features of the control I can implement by myself (at least I hope so)
-
- Earned some good credits
- Posts: 107
- Joined: Tue Aug 28, 2018 1:02 pm
- Location: Belarus
Re: Combined date and time picker
Unfortunately, one more question here.
I changed calendar type from wxCalendarCtrl to wxCalendarCtrlBase in order to create wxGenericCalendarCtrl. I need SetHighlightColours call to change default highlight colors and this method is only works for wxGenericCalendarCtrl. And now when I popup the control, the calendar is painted very slow so I can see the process of painting. The issues isn't reproduces when using wxCalendarCtrl - only with wxGenericCalendarCtrl.
Is it possible to change highlight colors in wxCalendarCtrl or is it possible to paint wxGenericCalendarCtrl as fast as it is done with wxCalendarCtrl?
Thanks.
I changed calendar type from wxCalendarCtrl to wxCalendarCtrlBase in order to create wxGenericCalendarCtrl. I need SetHighlightColours call to change default highlight colors and this method is only works for wxGenericCalendarCtrl. And now when I popup the control, the calendar is painted very slow so I can see the process of painting. The issues isn't reproduces when using wxCalendarCtrl - only with wxGenericCalendarCtrl.
Is it possible to change highlight colors in wxCalendarCtrl or is it possible to paint wxGenericCalendarCtrl as fast as it is done with wxCalendarCtrl?
Thanks.