问题
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.
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.
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?
回答1:
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.
回答2:
You might want to look at TJvIPAddress in JvComCtrls. I guess searching for TabThroughFields and VK_TAB should put you on track.
回答3:
- you can catch a Tab press on a KeyDown event. (Happens before the KeyPress Event)
- 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.
来源:https://stackoverflow.com/questions/2363456/how-do-i-catch-a-vk-tab-key-in-my-tedit-control-and-not-let-it-lose-the-focus