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

前端 未结 3 762
太阳男子
太阳男子 2021-01-06 07:24

In my TEdit field I have text in the form ...

My idea is:

When a user enters the control using TAB from

相关标签:
3条回答
  • 2021-01-06 07:43
    1. you can catch a Tab press on a KeyDown event. (Happens before the KeyPress Event)
    2. in a KeyDown event you can set the Key to #0

    Oh and in a Key Press event you can set the Key to 0

    EDIT The following is a call stack capturing a KeyDown event for a TAB key

    Form1.TForm1.GetTab((45061, 9, 0, 983041, 0))
    :0101f444 TForm1.GetTab
    :004dca20 TWinControl.WndProc + $500
    :004ef754 TCustomForm.WndProc + $558
    :004d86b3 TControl.Perform + $27
    :004ded6a TWinControl.CNKeyDown + $D6
    :004dca20 TWinControl.WndProc + $500
    :004dc147 TWinControl.MainWndProc + $2F
    :004306ea StdWndProc + $16
    :7e418734 USER32.GetDC + 0x6d
    :7e418816 ; C:\WINDOWS\system32\USER32.dll
    :7e41b4c0 ; C:\WINDOWS\system32\USER32.dll
    :7e41b50c ; C:\WINDOWS\system32\USER32.dll
    :7c90eae3 ntdll.KiUserCallbackDispatcher + 0x13
    :7e42f3cc USER32.SendMessageA + 0x49
    

    As you can see it doesn go through KeyDown as normal keys do but instead calls BroadCast to send the message out....

    So you'll need a message catcher

    Procedure GetTab( var Message: TCMDialogkey ); message CM_DIALOGKEY;
    

    to catch it.

    0 讨论(0)
  • 2021-01-06 07:51

    You might want to look at TJvIPAddress in JvComCtrls. I guess searching for TabThroughFields and VK_TAB should put you on track.

    0 讨论(0)
  • 2021-01-06 08:04

    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.
    
    0 讨论(0)
提交回复
热议问题