使用这个构件吧,是我们论坛上的某位大虾写的(我忘了):
包你所有的问题都解决!
unit quickkey;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, Grids, ExtCtrls, typinfo, math;
type
TMoveOptions = set of (moEditDeliver, moListDeliver,
moComboDeliver,moGridDeliver, moButtonDeliver,moRadioDeliver);
TQuickKey = class(TComponent)
private
// FComponents: TList;
FActive: boolean;
FOwnerKeyEvents : TMessageEvent;
FOptions : TMoveOptions;
FEdit : Boolean;
FList : Boolean;
FGrid : boolean;
FCombo : boolean;
FButton : boolean;
FRadio: boolean;
function MoveUpSide(Sender: TWinControl;Key: word):boolean;
function MoveDownSide(Sender: TWinControl;Key: word):boolean;
function MoveLeftSide(Sender: TWinControl;Key: word):boolean;
function MoveRightSide(Sender: TWinControl;Key: word):boolean;
function MoveNextSide(Sender: TWinControl;Key: word):boolean;
procedure GetControl(Sender: TWinControl;Direct: integer);
function CanEnterKey(Sender: TWincontrol): boolean;
function HasProperty(Sender: TObject; AProperty: string):boolean;
function TestProperty(Sender: TObject; AProperty: string;
Value: integer): boolean;
function GetPropertyValue(Sender: TObject; AProperty: string): integer;
protected
{ Protected declarations }
public
procedure NewKeyDown(var Msg: TMsg; var Handled: boolean);
{ Public declarations }
constructor Create(AOwner : TComponent); override;
destructor Destroy; override;
published
{ Published declarations }
property Active: boolean read FActive write FActive;
property Options : TMoveOptions read FOptions write FOptions
default [moEditDeliver, moListDeliver,
moGridDeliver, moButtonDeliver];
end;
procedure Register;
implementation
procedure Register;
begin
RegisterComponents('freeware', [TQuickKey]);
end;
constructor TQuickKey.Create(AOwner: TComponent);
var
Loop: integer;
begin
for Loop:=0 to AOwner.ComponentCount-1 do
if AOwner.Components[Loop] is TQuickKey then raise
EInvalidOperation.Create(
'TQuickKey can have only one instance per form');
// Create component and set default properties
inherited Create(AOwner);
FActive:=false;
FOptions:=[moEditDeliver, moListDeliver,
moComboDeliver,moGridDeliver, moButtonDeliver, moRadioDeliver];
FOwnerKeyEvents:=Application.OnMessage;
Application.OnMessage:=NewKeyDown;
end;
destructor TQuickKey.Destroy;
begin
Application.OnMessage:=FOwnerKeyEvents;
inherited;
end;
procedure TQuickKey.NewKeyDown(var Msg: TMsg; var handled: boolean);
var
v: TWinControl;
f: TForm;
begin
if FActive then
begin
f:=self.owner as TForm;
if f.Active and (Msg.message=WM_KEYDOWN) then
if
(Msg.wParam = VK_RETURN) or
(Msg.wParam = VK_LEFT) or
(Msg.wParam = VK_RIGHT) or
(Msg.wParam = VK_UP) or
(Msg.wParam = VK_DOWN) then begin
v:=f.ActiveControl;
FEdit := v is TCustomEdit;
FList := v is TCustomListBox;
FGrid := v is TDrawGrid;
FCombo := v is TCustomComboBox;
FButton := v is TButtonControl;
FRadio := v is TRadioGroup;
{ FEdit:=HasProperty(v,'Text');
FList:=HasProperty(v,'Items');
FGrid:=HasProperty(v,'ColCount') or HasProperty(v,'RowCount');
FButton:=v is TButtonControl;
}
case Msg.wParam of
VK_UP: Handled:=MoveUpSide(v, Msg.wParam);
VK_DOWN: Handled:=MoveDownSide(v, Msg.wParam);
VK_LEFT: Handled:=MoveLeftSide(v, Msg.wParam);
VK_RIGHT: Handled:=MoveRightSide(v, Msg.wParam);
VK_RETURN: Handled:=MoveNextSide(v, Msg.wParam);
end;
end;
end;
if assigned(FOwnerKeyEvents) then FOwnerKeyEvents(Msg,handled);
end;
function TQuickKey.MoveUpSide(Sender: TWinControl; Key: word):boolean;
var
v: boolean;
begin
v:=false;
if FList then
if moListDeliver in FOptions then
if (Sender as TCustomListBox).ItemIndex=0 then
v:=true
else
else
else if FCombo then
if moComboDeliver in FOptions then
if (Sender as TCustomComboBox).ItemIndex=0 then
v:=true
else
else
else if FButton then
if moButtonDeliver in FOptions then
v:=true
else
else if FRadio then
if moRadioDeliver in FOptions then
if (Sender as TRadioGroup).ItemIndex = 0 then
v:=true
else
else
else if FEdit then
if moEditDeliver in FOptions then
if CanEnterKey(Sender) then
if HasProperty(Sender, 'Lines') then
if (Sender as TCustomEdit).SelStart
+(Sender as TCustomEdit).SelLength=0 then
v:=true
else
else
v:=true
else
v:=true
else
else if FGrid then
if moGridDeliver in FOptions then
if (not CanEnterKey(Sender))
and ((Sender as TDrawGrid).row<=
GetPropertyValue(Sender,'FixedRows')
)
then
v:=true;
if v then
begin
GetControl(Sender,1);
end;
result:=v;
end;
function TQuickKey.MoveDownSide(Sender: TWinControl;
Key: word):boolean;
var
v: Boolean;
begin
v:=false;
if FList then
if moListDeliver in FOptions then
if (Sender as TCustomListBox).ItemIndex=
(Sender as TCustomListBox).Items.Count-1
then
v:=true
else
else
else if FCombo then
if moComboDeliver in FOptions then
if (Sender as TCustomComboBox).ItemIndex=
(Sender as TCustomComboBox).Items.Count-1
then
v:=true
else
else
else if FButton then
if moButtonDeliver in FOptions then
v:=true
else
else if FRadio then
if moRadioDeliver in FOptions then
if (Sender as TRadioGroup).ItemIndex =
(Sender as TRadioGroup).Items.Count-1
then
v:=true
else
else
else if FEdit then
if moEditDeliver in FOptions then
if CanEnterKey(Sender) then
if HasProperty(Sender, 'Lines') then
if (Sender as TCustomEdit).SelStart
+(Sender as TCustomEdit).SelLength>=
length((Sender as TCustomEdit).text)-1
then
v:=true
else
else
v:=true
else
v:=true
else
else if FGrid then
if moGridDeliver in FOptions then
if (not CanEnterKey(Sender))
and ((Sender as TDrawGrid).Row>=
GetPropertyValue(Sender, 'RowCount')-1)
then
v:=true;
if v then
begin
GetControl(Sender,3);
end;
result:=v;
end;
function TQuickKey.MoveLeftSide(Sender: TWinControl;
key: word):boolean;
var
v: boolean;
begin
v:=false;
if FList then
if moListDeliver in FOptions then
if (Sender as TCustomListBox).ItemIndex= 0
// (Sender as TCustomListBox).Items.Count-1
then
v:=true
else
else
else if FCombo then
if moComboDeliver in FOptions then
if CanEnterKey(Sender) then
if (Sender as TCustomCombobox).selstart
+(Sender as TCustomComboBox).SelLength = 0 then
v:=true
else
else
v:=true
else
else if FButton then
if moButtonDeliver in FOptions then
v:=true
else
else if FRadio then
if moRadioDeliver in FOptions then
if (Sender as TRadioGroup).ItemIndex = 0
// (Sender as TRadioGroup).Items.Count-1
then
v:=true
else
else
else if FEdit then
if moEditDeliver in FOptions then
if CanEnterKey(Sender) then
if (Sender as TCustomEdit).SelStart
+(Sender as TCustomEdit).SelLength=0
// length((Sender as TCustomEdit).text)-1
then
v:=true
else
else
v:=true
else
else if FGrid then
if moGridDeliver in FOptions then
if (not CanEnterKey(Sender))
and ((Sender as TDrawGrid).Col<=
GetPropertyValue(Sender,'FixedCols'))
then
v:=true;
if v then
begin
GetControl(Sender,0);
end;
result:=v;
end;
function TQuickKey.MoveRightSide(Sender: TWinControl;
Key: word):boolean;
var
v: boolean;
begin
v:=false;
if FList then
if moListDeliver in FOptions then
if (Sender as TCustomListBox).ItemIndex=
(Sender as TCustomListBox).Items.Count-1
then
v:=true
else
else
else if FCombo then
if moComboDeliver in FOptions then
if CanEnterKey(Sender) then
if (Sender as TCustomComboBox).SelStart
+(Sender as TCustomComboBox).SelLength>=
length((Sender as TComboBox).text)
then
v:=true
else
else
v:=true
else
else if FButton then
if moButtonDeliver in FOptions then
v:=true
else
else if FRadio then
if moRadioDeliver in FOptions then
if (Sender as TRadioGroup).ItemIndex =
(Sender as TRadioGroup).Items.Count-1
then
v:=true
else
else
else if FEdit then
if moEditDeliver in FOptions then
if CanEnterKey(Sender) then
if (Sender as TCustomEdit).SelStart
+(Sender as TCustomEdit).SelLength>=
length((Sender as TCustomEdit).text)
then
v:=true
else
else
v:=true
else
else if FGrid then
if moGridDeliver in FOptions then
if (not CanEnterKey(Sender))
and ((Sender as TDrawGrid).col>=
GetPropertyValue(Sender,'ColCount')-1)
then
v:=true;
if v then
begin
GetControl(Sender,2);
end;
result:=v;
end;
function TQuickKey.MoveNextSide(Sender: TwinControl;
Key: word):boolean;
var
v: boolean;
begin
v:=false;
if FList then
if moListDeliver in FOptions then
if (Sender as TCustomListBox).ItemIndex=
(Sender as TCustomListBox).Items.Count-1
then
v:=true
else
else
else if FCombo then
if moComboDeliver in FOptions then
if CanEnterKey(Sender) then
if (Sender as TCustomComboBox).SelStart
+(Sender as TCustomComboBox).SelLength>=
length((Sender as TComboBox).text)
then
v:=true
else
else
v:=true
else
else if FRadio then
if moRadioDeliver in FOptions then
if (Sender as TRadioGroup).ItemIndex =
(Sender as TRadioGroup).Items.Count-1
then
v:=true
else
else
else if FEdit then
if CanEnterKey(Sender) then
if HasProperty(Sender, 'Lines') then
if (Sender as TCustomEdit).SelStart
+(Sender as TCustomEdit).SelLength>=
length((Sender as TCustomEdit).text)
then
v:=true
else
else
v:=true
else
v:=true;
if v then
begin
// GetControl(Sender,4);
(Sender.Owner as TForm).Perform(WM_NEXTDLGCTL,0,0);
end;
result:=v;
end;
function TQuickKey.CanEnterKey(Sender: TWinControl): boolean;
begin
if hidecaret(0) then
begin
showcaret(0);
result:=true;
if HasProperty(Sender,'ReadOnly')
and (not TestProperty(Sender,'ReadOnly',0))
then
result:=false;
end
else
result:=false;
end;
function TQuickKey.HasProperty(Sender:TObject; AProperty: string):boolean;
begin
result:=(GetPropInfo(Sender.ClassInfo, AProperty)<>nil);
end;
function TQuickKey.TestProperty(Sender:TObject; AProperty: string;
Value: integer): boolean;
var
T
PropInfo;
begin
T:=GetPropInfo(Sender.ClassInfo, AProperty);
result:=(GetOrdProp(Sender,T) = Value);
end;
procedure TQuickKey.GetControl(Sender:TWinControl;Direct:integer);
var
i: integer;
scs: TRect;
sc1,sc2: TRect;
wc: TWinControl ;
f:TForm;
begin
wc:=nil;
f:= Sender.Owner as TForm;
{ scs := Sender.BoundsRect;
scs.TopLeft :=
(Sender.Parent as TWinControl).ClientToScreen(sc1.TopLeft);
scs.BottomRight :=
(Sender.Parent as TWinControl).ClientToScreen(sc1.BottomRight);
}
scs := Sender.ClientRect;
scs.TopLeft :=
(Sender as TWinControl).ClientToScreen(scs.TopLeft);
scs.BottomRight :=
(Sender as TWinControl).ClientToScreen(scs.BottomRight);
{ }
case Direct of
0:
begin
scs.Right:=scs.Left-1;
scs.Left:=-3000;
end;
1:
begin
scs.Bottom:=scs.Top-1;
scs.Top:=-3000;
end;
2:
begin
scs.Left:=scs.Right+1;
scs.Right:=3000;
end;
3:
begin
scs.Top:=scs.bottom+1;
scs.Bottom:=3000;
end;
end;
for i:= 0 to f.ComponentCount-1 do
begin
if (f.Components
<> Sender)
{ and (
(f.Components is TWinControl) and
(HasProperty(f.Components,'Text') or
HasProperty(f.Components,'Items') or
HasProperty(f.Components,'ColCount')
) )}
and (f.Components is TWinControl)
and (
(not HasProperty(f.Components,'ControlCount'))
or (
HasProperty(f.components,'ControlCount')
and TestProperty(f.Components,'ControlCount',0)
)
)
and (f.Components as TWinControl).CanFocus
then
begin
{
sc1:=(f.components as TWinControl).BoundsRect;
sc1.TopLeft:=
((f.Components as TWinControl).Parent as TWinControl).ClientToScreen(sc1.TopLeft);
sc1.BottomRight:=
((f.Components as TWinControl).Parent as TWinControl).ClientToScreen(sc1.BottomRight);
}
sc1:=(f.components as TWinControl).ClientRect;
sc1.TopLeft:=
(f.Components as TWinControl).ClientToScreen(sc1.TopLeft);
sc1.BottomRight:=
(f.Components as TWinControl).ClientToScreen(sc1.BottomRight);
{}
if IntersectRect(sc2,scs,sc1) then
begin
wc:=f.Components as TWinControl;
case Direct of
0: scs.Left:=sc2.Right+1;
1: scs.Top:=sc2.Bottom+1;
2: scs.Right:=sc2.Left-1;
3: scs.Bottom:=sc2.Top-1;
end;
if (scs.Top>scs.Bottom) or (scs.Left>scs.Right) then
break;
end;
end;
end;
if wc<>nil then
postmessage(f.Handle,WM_NEXTDLGCTL,wc.Handle,1)
else if Direct<=1 then
postmessage(f.handle,WM_NEXTDLGCTL,1,0)
else
postmessage(f.handle,WM_NEXTDLGCTL,0,0);
end;
function TQuickKey.GetPropertyValue(Sender:TObject; AProperty:string):integer;
var
TPropInfo;
begin
T:=GetPropInfo(Sender.ClassInfo,AProperty);
if T<>nil then
result:=GetOrdProp(Sender,T)
else
result:=-1;
end;
end.