Jump to content
davornik

Detect click on calendar in TDateTimePicker

Recommended Posts

I am using DateTimePicker1.Format as ' ' to set the value to an empty string in TDateTimePicker (using it as dtkDate).

procedure TForm1.FormCreate(Sender: TObject);
begin
  DateTimePicker1.Format:=' ';
end;

procedure TForm1.DateTimePicker1Change(Sender: TObject);
begin
  DateTimePicker1.Format:='';
end;

procedure TForm1.btnResetClick(Sender: TObject);
begin
  DateTimePicker1.Format:=' '; //set as Empty
  DateTimePicker1.Date:=Date;
end;

Change event does not fire if I select today's date. How can I detect a click on the calendar if today's date is selected or clicked somewhere in the calendar itself?

Share this post


Link to post
4 hours ago, davornik said:

I am using DateTimePicker1.Format as ' ' to set the value to an empty string in TDateTimePicker (using it as dtkDate).


procedure TForm1.FormCreate(Sender: TObject);
begin
  DateTimePicker1.Format:=' ';
end;

procedure TForm1.DateTimePicker1Change(Sender: TObject);
begin
  DateTimePicker1.Format:='';
end;

procedure TForm1.btnResetClick(Sender: TObject);
begin
  DateTimePicker1.Format:=' '; //set as Empty
  DateTimePicker1.Date:=Date;
end;

Change event does not fire if I select today's date. How can I detect a click on the calendar if today's date is selected or clicked somewhere in the calendar itself?

The control (a Windows common control under the VCL surtace) has no real concept of an "empty" state. The usual way to use it is to set the shown date to Today (it does that by default if memory serves) and accept that if the user does not change it. If your requirements really need a way to detect that the user has entered a date you can use an additional TCheckbox that disables the picker unless it is checked.

Share this post


Link to post

You are setting the date to today thus after the user clicks to reset the value will remain. Change the code to:

 

procedure TForm1.btnResetClick(Sender: TObject);
begin
  DateTimePicker1.Format:=' ';
  DateTimePicker1.Date:=0;
end;

Now it will change when the user clicks on the today.

Share this post


Link to post
4 hours ago, PeterBelow said:

If your requirements really need a way to detect that the user has entered a date you can use an additional TCheckbox that disables the picker unless it is checked.

Or, use the TDateTimePicker.ShowCheckBox and TDateTimePicker.Checked properties instead.

Share this post


Link to post
4 hours ago, PeterBelow said:

The control (a Windows common control under the VCL surtace) has no real concept of an "empty" state. The usual way to use it is to set the shown date to Today (it does that by default if memory serves) and accept that if the user does not change it. If your requirements really need a way to detect that the user has entered a date you can use an additional TCheckbox that disables the picker unless it is checked.

I dont want to use checkbox, because it is not user frendly. Main problem is that OnChange event does not fire on every click on calendar but only if Date <> Today.

Share this post


Link to post
4 hours ago, Lajos Juhász said:

You are setting the date to today thus after the user clicks to reset the value will remain. Change the code to:

 


procedure TForm1.btnResetClick(Sender: TObject);
begin
  DateTimePicker1.Format:=' ';
  DateTimePicker1.Date:=0;
end;

Now it will change when the user clicks on the today.

Yes, but it will then show something like 1899 year. DateTimePicker1.Date must be :=Date; is because it needs to be on today's date for user convinience, when calendar drops down - it is user frendly to have view of current month.

Share this post


Link to post
Posted (edited)
16 minutes ago, davornik said:

I dont want to use checkbox, because it is not user frendly.

And yet, that is the way Microsoft wants you to use it.

16 minutes ago, davornik said:

Main problem is that OnChange event does not fire on every click on calendar but only if Date <> Today.

If you really want to detect a mouse click, you will likely have to subclass the window for the TDateTimePicker's  drop down calendar to handle WM_LBUTTON(DOWN|UP) messages directly.

Edited by Remy Lebeau

Share this post


Link to post
Posted (edited)
4 minutes ago, davornik said:

Yes, but it will then show something like 1899 year. DateTimePicker1.Date must be :=Date; is because it needs to be on today's date for user convinience, when calendar drops down - it is user frendly to have view of current month.

Then you are just going to have to do what Peter suggested.  Just assume today's Date is the default unless the user selects a different date, or else use another UI element to specify when the default Date should be ignored.

Edited by Remy Lebeau

Share this post


Link to post
2 minutes ago, Remy Lebeau said:

And yet, that is the way Microsoft wants you to use it.

If you really want to detect a mouse click, you will likely have to subclass the TDateTimePicker's window to handle WM_MOUSE(DOWN|UP) messages directly.

How to subclass TDateTimePicker's window on WM_MOUSE(DOWN|UP) messages?

Share this post


Link to post
Posted (edited)
35 minutes ago, davornik said:

How to subclass TDateTimePicker's window on WM_MOUSE(DOWN|UP) messages?

See Subclassing Controls on MSDN, and Safer subclassing on Raymond Chen's blog. For example:

uses
  Winapi.CommCtrl;

function CalendarSubclassProc(hWnd: HWND; uMsg: UINT; wParam: WPARAM; lParam: LPARAM;
  uIdSubclass: UINT_PTR; dwRefData: DWORD_PTR): LRESULT; stdcall;
begin
  case uMsg of
    WM_LBUTTONDOWN: begin
      TDateTimePicker(dwRefData).Format := '';
    end;
    WM_NCDESTROY: begin
      RemoveWindowSubclass(hWnd, @CalendarSubclassProc, uIdSubclass);
    end;
  end;
  Result := DefSubclassProc(hWnd, uMsg, wParam, lParam);
end;

procedure TForm1.DateTimePicker1DropDown(Sender: TObject);
var
  cal: HWND;
begin
  cal := DateTime_GetMonthCal(DateTimePicker1.Handle);
  SetWindowSubclass(cal, @CalendarSubclassProc, 1, DWORD_PTR(DateTimePicker1));
end;

 

Edited by Remy Lebeau
  • Like 1

Share this post


Link to post
18 hours ago, Remy Lebeau said:

Or, use the TDateTimePicker.ShowCheckBox and TDateTimePicker.Checked properties instead.

Oh, I'm farther behind the times than I was aware of :classic_dry:. Didn't know these properties exist now...

Share this post


Link to post
1 hour ago, PeterBelow said:

Oh, I'm farther behind the times than I was aware of :classic_dry:.

Well, you are so far behind, that you are already far far ahead    ....    in our cyclic universe :classic_biggrin:

Share this post


Link to post
7 hours ago, PeterBelow said:

Oh, I'm farther behind the times than I was aware of :classic_dry:. Didn't know these properties exist now...

Those properties have existed in TDateTimePicker since at least Delphi 5.

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×