3

I have a perhaps simple question:

I have a TStringGrid in Delphi 10.4, and a TDatePicker there, with which I want to select a date in the FixedCol. When I click on the header cell, the TDatePicker opens and also shows today's date. I've pre-selected today's date in the TForm.OnCreate event for the TDatePicker. Furthermore, I have an OnCloseUp event for the TDatePicker, which writes the selected date into the cell.

However, it does this both when I confirm with the tick and when I cancel with the X.

How can I query whether the user has clicked Cancel so that I don't then enter a value?

DatePicker

My code is more or less like this:

procedure TForm1.DatePicker1CloseUp(Sender: TObject);
begin
  //if DatePicker.Cancel ?? then
  //   exit;
  StringGrid1.Cells[col, row] := FormatDateTime(dateformat, DatePicker1.Date);
end;

I only found, that if I select a date and click OK, I get the selected date. Selecting another date and clicking Cancel returns the predefined date.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
Syndi
  • 31
  • 4
  • You can use [`OnChange`](https://docwiki.embarcadero.com/Libraries/en/Vcl.WinXPickers.TBasePickerControl.OnChange) event to respond to picking a date by the user. Note that the event is invoked also when you set date in code. – Peter Wolf Feb 03 '23 at 11:24
  • Yes, but with the onChange-Event I don't get when the user wants to accept the preselected todays date since he just clicks the ok button and doesn't change / pick a date – Syndi Feb 03 '23 at 12:49
  • It seems the `TDatePicker` might be the wrong control (the way it is implemented). Otoh, maybe you can rethink the process: When form is initially shown, initialize the date picker with today's date and automatically load today's data (as that is the usual use case). Then if user wants to see another day, they use the `TDatePicker`, which now would have a valid reference for the judgement regarding changed - not changed. – Tom Brunberg Feb 03 '23 at 13:51
  • yeah, seems so if there is no way to get from the TDatePicker which button is clicked. But thank you all. – Syndi Feb 03 '23 at 14:57
  • 3
    In that case you can subclass `TDatePicker` and override its `AcceptDropDown` method. If you don't want to introduce new component, then you can use [interposer class](https://zarko-gajic.iz.hr/delphi-interceptor-classes-tbutton-classtbutton/). – Peter Wolf Feb 03 '23 at 16:29

2 Answers2

1

Internally the control (TDatePicker) uses the Date property to store the Value. Before you change the value on component you can load this value and store it. At the end you can see if there are changes in the Date property, with respect to the initial value.

If there are no changes, it may be due to:

  • Change has been canceled.
  • The same date has been selected.

In both cases there is no need to update the TStringGrid.

Test something like this:

...
private
  oldValue:tDate;
...

procedure TForm3.DatePicker1Click(Sender: TObject);
begin
  oldDate := DatePicker1.Date;
end;

procedure TForm3.DateTimePicker1CloseUp(Sender: TObject);
begin
  if DatePicker1.Date <> OldDate then
    StringGrid1.Cells[col, row] := FormatDateTime('dd/mm/yyyy', DatePicker1.Date);
end;
  • thank you, that is right. But I start with an empty StringGrid-Cell which should be filled with a date. Usually the user qould select todays date. Therefore I wanted to preselect that date. But with that I can't distinguish between a cancelation and selecting todays date. Is there no chance to get which button is clicked without the stored Date value? – Syndi Feb 03 '23 at 12:23
  • `DatePicker1` vs `DateTimePicker1`? [`TDatePicker`](https://docwiki.embarcadero.com/Libraries/en/Vcl.WinXPickers.TDatePicker) and [`TDateTimePicker`](https://docwiki.embarcadero.com/Libraries/en/Vcl.ComCtrls.TDateTimePicker) are completely different components. Which one did you actually look at? – Remy Lebeau Feb 03 '23 at 17:33
  • 1
    @Syndi "*Is there no chance to get which button is clicked without the stored Date value?*" - [Peter's suggestion](https://stackoverflow.com/questions/75334060/tdatetime-oncloseup-cancel-return#comment132936583_75334060) seems to be the only reliable way to make that distinction. – Remy Lebeau Feb 03 '23 at 17:40
0

After trying I found a solution at least for Mouse Input:

GetCursorPos(MausPos);
MausPos := DatePicker1.ScreenToClient(MausPos);
if (MausPos.X > DatePicker1.Width / 2)  then
  ShowMessage('Cancel')
else
  ShowMessage('OK');

I take the Cursor position relative to the TDatePicker. If the X-Coordinate is on the right half, the cancel Button is pressed and I can exit the function without writing the date to the StringGrid.

Syndi
  • 31
  • 4
  • 3
    Note that `GetCursorPos()` gets the mouse's *current* position, not the position where it was at when the click event was generated. You can use [`GetMessagePos()`](https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getmessagepos) for that. – Remy Lebeau Feb 03 '23 at 17:38