Recent

Author Topic: Double Click = one Click in TDateEdit, and other key handling problems.  (Read 4036 times)

Nimral

  • Jr. Member
  • **
  • Posts: 92
Hi all,

what is the best method to change the default behaviour of the TDateEdit control? Per Default, when the calendar view is dropped down, it does need a double-clik to select a specific day.

I want a single click.

I tried myself, but is seems like the text field of the control and the dropped down calendar view share common onkey/up/down event handlers, so if I do some stuff tehre I affect both. And onClick fires only in the text field, but not in the calendar view?

Asked in a more general way, I am not very happy with the default key handling of the LCL library. I have a similar kind of problem in the ComboBox as well. The Combo drops down a list, from which I can select, but if I hit [Tab] to select the current entry and proceed to the next input, I end up in the ComboBoxe's own text field instead of, like expected, in the next focusabe control on the form.

Another issue related is that I'd like to re-map the [Enter] key entirely so that regardless of the focused control this key does always trigger a "Save" button. I can probably overwrite every control's onKey method ans do some magic there to fire up the Button's onClick handler, but isn't there a more global way so that I do this only once for all controls of a form?

Any clues welcome,

Armin.
« Last Edit: January 26, 2017, 03:59:43 pm by Nimral »
Lazarus 1.8 on Windows 10/7, VMWare Workstation 12

ASerge

  • Hero Member
  • *****
  • Posts: 1300
Re: Double Click = one Click in TDateEdit, and other key handling problems.
« Reply #1 on: January 26, 2017, 04:48:45 pm »
Per Default, when the calendar view is dropped down, it does need a double-clik to select a specific day.
I want a single click.
TDateTimePicker work by one click

Quote
I have a similar kind of problem in the ComboBox as well. The Combo drops down a list, from which I can select, but if I hit [Tab] to select the current entry and proceed to the next input, I end up in the ComboBoxe's own text field instead of, like expected, in the next focusabe control on the form.
Stay dropdown state in some field. For example in Tag, and do like this
Code: Pascal  [Select]
  1. procedure TForm1.ComboBox1DropDown(Sender: TObject);
  2. begin
  3.   ComboBox1.Tag := 1;
  4. end;
  5.  
  6. procedure TForm1.ComboBox1Exit(Sender: TObject);
  7. begin
  8.   ComboBox1.Tag := 0;
  9. end;
  10.  
  11. procedure TForm1.ComboBox1KeyUp(Sender: TObject; var Key: Word;
  12.   Shift: TShiftState);
  13. begin
  14.   if (Key = 9) and (ComboBox1.Tag > 0) then
  15.     SelectNext(ComboBox1, not (ssShift in Shift), True);
  16. end;

Quote
Another issue related is that I'd like to re-map the [Enter] key entirely so that regardless of the focused control this key does always trigger a "Save" button. I can probably overwrite every control's onKey method ans do some magic there to fire up the Button's onClick handler, but isn't there a more global way so that I do this only once for all controls of a form?
Put any button. Set Form.KeyPreview = True and do this:
Code: Pascal  [Select]
  1. procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
  2. begin
  3.   if (Key = 13) and (Shift = []) then
  4.     Button1.Click;
  5. end;

Nimral

  • Jr. Member
  • **
  • Posts: 92
Re: Double Click = one Click in TDateEdit, and other key handling problems.
« Reply #2 on: January 26, 2017, 05:24:23 pm »
Serge,

you're my hero, once more :-) If you ever come to Bavaria (Munich area), don't forget do drop me a PM some days before so we can meet and I'll drown you in Bavarian beer and Weißwurst.

Greetz

Armin.
Lazarus 1.8 on Windows 10/7, VMWare Workstation 12

Nimral

  • Jr. Member
  • **
  • Posts: 92
Re: Double Click = one Click in TDateEdit, and other key handling problems.
« Reply #3 on: February 03, 2017, 10:07:28 am »
Handling [Return] in a form's OnKeyUp handler seems to have unwanted side effects on messageboxes.

My Button.onClick handler has a confirmation dialog (MessageBox, MB_YESNO) at the end, "Do you really want to ....". the onKeyUp code causes and endless loop of messageboxes.

I can terminate the messagebox without loop if I use the mouse, or if I press [Space] instead of [Return] in the Messagebox. Seems that, if the user presses [Enter] in the Messagebox, this keystroke goes to the form's onKeyUp handler as well, this causing an endless loop of "Button.click" calls.

I made several attempts to fix this:

Code: Pascal  [Select]
  1. procedure TForm1.FormKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
  2. begin
  3.   if (Key = VK_Return) then
  4.     if not Flag then        // attempt #4
  5.       if Application.ModalLevel = 0 then;     // attempt #2
  6.         ButtonSave.Click;
  7. end;
  8.  
  9. procedure TForm1.ButtonSaveClick(Sender: TObject);
  10. begin
  11. // Attempt #3:  if Widgetset.MessageBox(Form1.Handle,PChar('Are you sure you know what you are doing?'),PChar('Please confirm'),MB_YESNO) = idYES then
  12.   Self.KeyPreview := false;   // attempt #1
  13.   Flag := true;              // Attempt #4
  14.   if Application.MessageBox('Are you sure you know what you are doing?','Please confirm',MB_YESNO) = idYES then
  15.     StatusBar1.SimpleText:='Then go with it, and live with the consequences'
  16.   else
  17.    StatusBar1.SimpleText:='better safe than sorry, eh?';
  18.   Flag := false;              // Attempt #4
  19.   Self.KeyPreview := true;    // attempt #1
  20. end;
  21.  
  22. procedure TForm1.FormCreate(Sender: TObject);
  23. begin
  24.   Flag := false;  // attempt #4
  25. end;
  26.  

But none succeeded. The problem has, in various forms, also hit others who use a form based key handler and a messagebox, like http://stackoverflow.com/questions/28684686/c-builder-how-to-clear-keys-pressed-during-messagebox.

Any ideas how I can get my Enter key handler working, and why my attempts to fix the issue didn't work?

Thx, Armin.
« Last Edit: February 03, 2017, 10:09:28 am by Nimral »
Lazarus 1.8 on Windows 10/7, VMWare Workstation 12

GetMem

  • Hero Member
  • *****
  • Posts: 3467
Re: Double Click = one Click in TDateEdit, and other key handling problems.
« Reply #4 on: February 03, 2017, 10:59:53 am »
@Nimral

If I understood the issue correctly, when the user press the Enter key to close the MessageBox, the FormKeyUp event is fired, which calls again the ButtonSaveClick...and so on. I'm I right? If yes then all you have to do is declare a boolean variable in the private section, then:

Code: Pascal  [Select]
  1. procedure TForm1.FormKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
  2. begin
  3.   if FBreakTheLoop then  //add this if
  4.   begin
  5.     FBreakTheLoop := False;
  6.     Exit;
  7.   end;
  8.  
  9.  if (Key = VK_Return) then
  10.    ButtonSave.Click;
  11. end;
  12.  
  13. procedure TForm1.ButtonSaveClick(Sender: TObject);
  14. begin
  15.   if Application.MessageBox('Are you sure you know what you are doing?','Please confirm',MB_YESNO) = idYES then
  16.   begin
  17.     FBreakTheLoop := True; //add this line
  18.     StatusBar1.SimpleText:='Then go with it, and live with the consequences';    
  19.   end;
  20.   else
  21.    StatusBar1.SimpleText:='better safe than sorry, eh?';
  22. end;

Zoran

  • Hero Member
  • *****
  • Posts: 1421
    • http://wiki.lazarus.freepascal.org/User:Zoran
Re: Double Click = one Click in TDateEdit, and other key handling problems.
« Reply #5 on: February 03, 2017, 11:19:49 am »
Let's start with TDateTime Picker. It has an annoying behaviour regarding the focus: if you use a date format like dd.mm.yyyy, and leave the control while either the mm or yyyy part is focused, and you [tab] back to the TDateTimePicker control, the focus will return to where the control was left last. Instead, it should always focus the leftmost input field (dd in my example).

I am surprised that you find this annoying - I would always prefer this behaviour as it is now - for me it is nice to have DateTimePicker remember where the selection was when I left it.
I could easily implement this (when DateTimePicker gets focus, the selected part would be the first item), or I could add a boolean property (I can't think how it should be named), which would control this behaviour.
But I will not do it unless you convince me that most people would like this. Now I'm just afraid that you are alone in this, and too many properties which have little use makes mess.

You can change the source of datetimepicker.pas - find procedure TCustomDateTimePicker.DoEnter and add line "FSelectedTextPart := 1;", so that it becomes:
Code: Pascal  [Select]
  1. procedure TCustomDateTimePicker.DoEnter;
  2. begin
  3.   inherited DoEnter;
  4.   FSelectedTextPart := 1;
  5.   Invalidate;
  6. end;

This seems to be the same in Delphi, there is a workaround described for Delphi (change the DateFormat to dfLong and back to dfShort), see http://stackoverflow.com/questions/23628192/returning-focus-to-first-part-of-delphi-tdatetimepicker-control, but this cannot be done in Lazarus, there is no DateTime Member in TDateTimePicker.

I tried variations of this trick with various other members of TDateTimePicker, but none reset the focus to the leftmost field.

One way to do such workaround here could be to set this procedure to each DateTimePicker's OnEnter event:
Code: Pascal  [Select]
  1. procedure TForm1.DateTimePicker1Enter(Sender: TObject);
  2. var
  3.   Kind: TDateTimeKind;
  4. begin
  5.   DisableAutoSizing; // prevent flicker
  6.   try
  7.     Kind := TDateTimePicker(Sender).Kind;
  8.     try
  9. // yes, you do need both these lines, written in this order, to work for any original kind:
  10.       TDateTimePicker(Sender).Kind := dtkTime;
  11.       TDateTimePicker(Sender).Kind := dtkDate;
  12.     finally
  13.       TDateTimePicker(Sender).Kind := Kind;
  14.     end;
  15.   finally
  16.     EnableAutoSizing;
  17.   end;
  18. end;
  19.  


Nimral

  • Jr. Member
  • **
  • Posts: 92
Re: Double Click = one Click in TDateEdit, and other key handling problems.
« Reply #6 on: February 03, 2017, 04:57:20 pm »
Hi Zoran,

thanks for your valuabele Input, I will build this in my code in a minute.

Code: Pascal  [Select]
  1.       TDateTimePicker(Sender).Kind := dtkTime;
  2.       TDateTimePicker(Sender).Kind := dtkDate;
  3.  

(hit me on my forehed really hard, I didn't try this because I was focused on displaying a Date, set the field type to dtkTime didn't come to my mind)

Regarding the "keep focus" thing, well, contrary of what you say, I cannot imagine any situation where I'd find it useful, but there is at least one common use (mine ...) where it is an annoyance :-)

But there is absolutely no reason to go into discussions about matters of taste, I can get what I want with a minor code change, may others be happy with TDateTime Picker exactly like it is :-)

Thanks,

Armin.

P.S: Workaround tried ... worls exactly like I wanted.
« Last Edit: February 03, 2017, 06:17:50 pm by Nimral »
Lazarus 1.8 on Windows 10/7, VMWare Workstation 12

wittbo

  • Jr. Member
  • **
  • Posts: 55
@Zoran:
I also find this behaviour annoying, since it happens with BackTab and Tab.
I have a simple form to collect appointments using one edit field, one TDateTimePicker for the date and one for the time. After having collected these three Dates for one appointment, the user clicks "Save" and starts the next collection cycle immediatly. And then it is really annoying if the datepicker focus is not the first element.
Thanks for the hint you gave. I will change the behaviour of the component.
-wittbo-
Lazarus 2.0.0  with FPC 3.0.4
MacOS 10.14.3 MacOS 10.13

Zoran

  • Hero Member
  • *****
  • Posts: 1421
    • http://wiki.lazarus.freepascal.org/User:Zoran
Okay, you convinced me. :)
I added option dtpoResetSelection, see http://wiki.freepascal.org/DateTimeCtrls_Package#Options:_TDateTimePickerOptions