Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I catch a VK_TAB key in my TEdit control and not let it lose the focus?

In my TEdit field I have text in the form <number1>..<number2>.

My idea is:

When a user enters the control using TAB from another control, number1 gets selected.

When my TEdit control has a focus and user presses TAB again, I want the number2 to get selected and number1 to be deselected.

And if current caret position is at the place where number2 is, pressing TAB should act normal and move the focus to the next control on the form.

I have 2 problems.

  1. I cannot catch the tab key press when the Edit field is active already. I can only catch it when this control is being entered/focused.

  2. I don't know if there is a key similar to #0 so I could turn the key into NoOP.

Any ideas, how to do it?

like image 484
user1651105 Avatar asked Dec 12 '22 23:12

user1651105


1 Answers

You are better to write your own TEdit descendant that processes WM_GETDLGCODE message. The general idea is:

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TMyEdit = class(TEdit)
    procedure WMGetDlgCode(var Message: TWMGetDlgCode); message WM_GETDLGCODE;
  end;

type
  TForm1 = class(TForm)
    Edit2: TEdit;
    procedure FormCreate(Sender: TObject);
    procedure FormKeyPress(Sender: TObject; var Key: Char);
  private
    { Private declarations }
    FMyEdit: TMyEdit;
    FDone: Boolean;
    procedure MyEditEnter(Sender: TObject);
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

{ TMyEdit }

procedure TMyEdit.WMGetDlgCode(var Message: TWMGetDlgCode);
begin
  inherited;
  Message.Result:= Message.Result or DLGC_WANTTAB;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  FMyEdit:= TMyEdit.Create(Self);
  FMyEdit.Left:= 40;
  FMyEdit.Top:= 40;
  FMyEdit.Parent:= Self;
  FMyEdit.Text:= '45..90';
  FMyEdit.OnEnter:= MyEditEnter;
  KeyPreview:= True;
end;

procedure TForm1.FormKeyPress(Sender: TObject; var Key: Char);
begin
  if (Key = #9) and (ActiveControl = FMyEdit) then begin
    if FDone then begin
      Perform(CM_DialogKey, VK_TAB, 0);
    end
    else begin
      FMyEdit.SelStart:= 4;
      FMyEdit.SelLength:= 2;
    end;
    FDone:= not FDone;
    Key:= #0;
  end;
end;

procedure TForm1.MyEditEnter(Sender: TObject);
begin
  FDone:= False;
  FMyEdit.SelStart:= 0;
  FMyEdit.SelLength:= 2;
end;

end.

Updated: The same idea without making a TEdit descendant class:

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Edit1: TEdit;
    Edit2: TEdit;
    procedure Edit2Enter(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormKeyPress(Sender: TObject; var Key: Char);
  private
    { Private declarations }
    FDone: Boolean;
    FOldWndProc: TWndMethod;
    procedure Edit2WindowProc(var Message: TMessage);
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Edit2Enter(Sender: TObject);
begin
  FDone:= False;
  Edit2.SelStart:= 0;
  Edit2.SelLength:= 2;
end;

procedure TForm1.Edit2WindowProc(var Message: TMessage);
begin
  if Message.Msg = WM_GETDLGCODE then
    Message.Result:= Message.Result or DLGC_WANTTAB
  else
    if Assigned(FOldWndProc) then FOldWndProc(Message);
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  KeyPreview:= True;
  Edit2.Text:= '45..90';
  FOldWndProc:= Edit2.WindowProc;
  Edit2.WindowProc:= Edit2WindowProc;
end;

procedure TForm1.FormKeyPress(Sender: TObject; var Key: Char);
begin
  if (Key = #9) and (ActiveControl = Edit2) then begin
    if FDone then begin
      Perform(CM_DialogKey, VK_TAB, 0);
    end
    else begin
      Edit2.SelStart:= 4;
      Edit2.SelLength:= 2;
    end;
    FDone:= not FDone;
    Key:= #0;
  end;
end;

end.
like image 125
kludg Avatar answered Apr 06 '23 18:04

kludg