检测用户是通过选项卡还是通过单击获得组件的焦点
Detect if user get focus of a component by tab or by click
如何检测用户是通过 tab
键还是通过鼠标 click
进入组件?
更新 1
实际上是关于 TVirtualStringTree
的,顺便说一句,它正在获得焦点,它打开一个专注于一个或另一列的自定义编辑器。
更新 2
查看下面的代码。
procedure TForm1.Tree1Click(Sender: TObject);
var
Tree: TVirtualStringTree;
Click: THitInfo;
HitNode: PVirtualNode;
HitColumn: TColumnIndex;
col: Integer;
begin
Tree:= Sender as TVirtualStringTree;
Tree.GetHitTestInfoAt(Mouse.CursorPos.X-Tree.ClientOrigin.X, Mouse.CursorPos.Y-Tree.ClientOrigin.Y, True, Click);
HitNode:= Click.HitNode;
if not Assigned(Click.HitNode) and Assigned(Tree.FocusedNode) then
HitNode:= Tree.FocusedNode;
HitColumn:= Click.HitColumn;
//get first visible and editable column
if (HitColumn <= NoColumn) or
((HitColumn > NoColumn) and
(not (coVisible in Tree.Header.Columns.Items[HitColumn].Options) or
not (coEditable in Tree.Header.Columns.Items[HitColumn].Options))) then
if Tree.Header.Columns.Count > 0 then
for col := 0 to Tree.Header.Columns.Count - 1 do
if (coVisible in Tree.Header.Columns.Items[col].Options) and
(coEditable in Tree.Header.Columns.Items[col].Options) then
begin
HitColumn:= col;
Break;
end;
if Assigned(HitNode) and (HitColumn > NoColumn) then
{if (Tree.IsEditing and (HitNode <> Tree.FocusedNode)) or
((not Tree.IsEditing) and (HitNode = Tree.FocusedNode)) then}
Tree.EditNode(HitNode,HitColumn);
end;
procedure TForm1.Tree1Enter(Sender: TObject);
var
Tree: TVirtualStringTree;
Click: THitInfo;
HitNode: PVirtualNode;
HitColumn: TColumnIndex;
col: Integer;
begin
Tree:= Sender as TVirtualStringTree;
HitNode:= Tree.FocusedNode;
if not Assigned(Tree.FocusedNode) then
HitNode:= Tree.GetFirstVisible;
HitColumn:= NoColumn;
//get first visible and editable column
if Tree.Header.Columns.Count > 0 then
for col := 0 to Tree.Header.Columns.Count - 1 do
if (coVisible in Tree.Header.Columns.Items[col].Options) and
(coEditable in Tree.Header.Columns.Items[col].Options) then
begin
HitColumn:= col;
Break;
end;
if Assigned(HitNode) and (HitColumn > NoColumn) then
Tree.EditNode(HitNode,HitColumn);
end;
我想做的是:
- 如果用户通过
Tab
键或 输入,则编辑焦点节点的第一列
- 编辑鼠标点击的对应栏目
click
如果我点击组件,OnEnter
首先被触发,然后 OnClick
,所以问题是编辑节点被触发了 2 次。
为了知道焦点是通过使用 tab 还是通过鼠标单击获得的,您需要做一些侦探工作。
- 这是在按 Tab 键时确保焦点的代码。
procedure TBaseVirtualTree.WMKeyUp(var Message: TWMKeyUp);
begin
inherited;
case Message.CharCode of
VK_SPACE:
.... [snip] ....
VK_TAB:
//This method causes a flurry of event handlers to be called.
EnsureNodeFocused();
end;
end;
- VTV 除了标准
OnEnter
和 OnExit
事件外,还有两个焦点更改事件:OnFocusChanged
和 OnFocusChanging
。
我不知道哪一个最适合您的需求,您必须进行试验。
我们假设焦点始终是使用鼠标获得的,除非我们可以证明它是使用 tab 获得的。这是一个有点不稳定的假设,但没关系。
首先我们使用插入器覆盖 WMKeyUp
消息处理程序。
WMKeyUp
是私有的,but luckily message handlers can always be overriden, even if they are private。
内插器
您可以使用 a trick called an interposer 重新定义 VST 以满足我们的需要。
由于范围规则,'improved' TVST 取代了默认 VST。这不会干扰流媒体或表单创建或任何事情。它只是工作。
type
TVirtualStringTree = class(VirtualTrees.TVirtualStringTree)
private
FTabPressed: boolean;
protected
procedure WMKeyUp(var Message: TWMKeyUp); message WM_KEYUP;
property TabPressed: boolean read FTabPressed;
end;
TForm56 = class(TForm)
VirtualStringTree1: TVirtualStringTree;
....
procedure TVirtualStringTree.WMKeyUp(var Message: TWMKeyUp);
begin
case Message.CharCode of
VK_TAB: FTabPressed:= true;
else FTabPressed:= false;
end; {case}
inherited;
FTabPressed:= false;
end;
焦点事件处理程序
使用这 两个 三个事件处理程序之一。
//use the standard onEnter....
procedure TForm56.VirtualStringTree1Enter(Sender: TObject);
begin
if VirtualStringTree1.TabPressed then .....
else ....
end;
//... or use this event, or...
procedure TForm56.VirtualStringTree1FocusChanged(Sender: TBaseVirtualTree;
Node: PVirtualNode; Column: TColumnIndex);
begin
if VirtualStringTree1.TabPressed then .....
else ....
end;
//.... this event if you want to mess with the focus.
procedure TForm56.VirtualStringTree1FocusChanging(Sender: TBaseVirtualTree;
OldNode, NewNode: PVirtualNode; OldColumn, NewColumn: TColumnIndex;
var Allowed: Boolean);
begin
Allowed:= VirtualStringTree1.TabPressed; //just a silly example.
end;
因为通过单击获得焦点总是会在 onEnter 事件之前生成 mousedown 事件,您可以在 mousedown 中设置一个事件说 'gMousedown' := true 然后在 OnEnter 事件中您可以检查 mousedown。不要忘记在 onMouseUp 事件中将 gMousedown 重置为 false。
如何检测用户是通过 tab
键还是通过鼠标 click
进入组件?
更新 1
实际上是关于 TVirtualStringTree
的,顺便说一句,它正在获得焦点,它打开一个专注于一个或另一列的自定义编辑器。
更新 2
查看下面的代码。
procedure TForm1.Tree1Click(Sender: TObject);
var
Tree: TVirtualStringTree;
Click: THitInfo;
HitNode: PVirtualNode;
HitColumn: TColumnIndex;
col: Integer;
begin
Tree:= Sender as TVirtualStringTree;
Tree.GetHitTestInfoAt(Mouse.CursorPos.X-Tree.ClientOrigin.X, Mouse.CursorPos.Y-Tree.ClientOrigin.Y, True, Click);
HitNode:= Click.HitNode;
if not Assigned(Click.HitNode) and Assigned(Tree.FocusedNode) then
HitNode:= Tree.FocusedNode;
HitColumn:= Click.HitColumn;
//get first visible and editable column
if (HitColumn <= NoColumn) or
((HitColumn > NoColumn) and
(not (coVisible in Tree.Header.Columns.Items[HitColumn].Options) or
not (coEditable in Tree.Header.Columns.Items[HitColumn].Options))) then
if Tree.Header.Columns.Count > 0 then
for col := 0 to Tree.Header.Columns.Count - 1 do
if (coVisible in Tree.Header.Columns.Items[col].Options) and
(coEditable in Tree.Header.Columns.Items[col].Options) then
begin
HitColumn:= col;
Break;
end;
if Assigned(HitNode) and (HitColumn > NoColumn) then
{if (Tree.IsEditing and (HitNode <> Tree.FocusedNode)) or
((not Tree.IsEditing) and (HitNode = Tree.FocusedNode)) then}
Tree.EditNode(HitNode,HitColumn);
end;
procedure TForm1.Tree1Enter(Sender: TObject);
var
Tree: TVirtualStringTree;
Click: THitInfo;
HitNode: PVirtualNode;
HitColumn: TColumnIndex;
col: Integer;
begin
Tree:= Sender as TVirtualStringTree;
HitNode:= Tree.FocusedNode;
if not Assigned(Tree.FocusedNode) then
HitNode:= Tree.GetFirstVisible;
HitColumn:= NoColumn;
//get first visible and editable column
if Tree.Header.Columns.Count > 0 then
for col := 0 to Tree.Header.Columns.Count - 1 do
if (coVisible in Tree.Header.Columns.Items[col].Options) and
(coEditable in Tree.Header.Columns.Items[col].Options) then
begin
HitColumn:= col;
Break;
end;
if Assigned(HitNode) and (HitColumn > NoColumn) then
Tree.EditNode(HitNode,HitColumn);
end;
我想做的是:
- 如果用户通过
Tab
键或 输入,则编辑焦点节点的第一列
- 编辑鼠标点击的对应栏目
click
如果我点击组件,OnEnter
首先被触发,然后 OnClick
,所以问题是编辑节点被触发了 2 次。
为了知道焦点是通过使用 tab 还是通过鼠标单击获得的,您需要做一些侦探工作。
- 这是在按 Tab 键时确保焦点的代码。
procedure TBaseVirtualTree.WMKeyUp(var Message: TWMKeyUp); begin inherited; case Message.CharCode of VK_SPACE: .... [snip] .... VK_TAB: //This method causes a flurry of event handlers to be called. EnsureNodeFocused(); end; end;
- VTV 除了标准
OnEnter
和OnExit
事件外,还有两个焦点更改事件:OnFocusChanged
和OnFocusChanging
。
我不知道哪一个最适合您的需求,您必须进行试验。
我们假设焦点始终是使用鼠标获得的,除非我们可以证明它是使用 tab 获得的。这是一个有点不稳定的假设,但没关系。
首先我们使用插入器覆盖 WMKeyUp
消息处理程序。
WMKeyUp
是私有的,but luckily message handlers can always be overriden, even if they are private。
内插器
您可以使用 a trick called an interposer 重新定义 VST 以满足我们的需要。
由于范围规则,'improved' TVST 取代了默认 VST。这不会干扰流媒体或表单创建或任何事情。它只是工作。
type
TVirtualStringTree = class(VirtualTrees.TVirtualStringTree)
private
FTabPressed: boolean;
protected
procedure WMKeyUp(var Message: TWMKeyUp); message WM_KEYUP;
property TabPressed: boolean read FTabPressed;
end;
TForm56 = class(TForm)
VirtualStringTree1: TVirtualStringTree;
....
procedure TVirtualStringTree.WMKeyUp(var Message: TWMKeyUp);
begin
case Message.CharCode of
VK_TAB: FTabPressed:= true;
else FTabPressed:= false;
end; {case}
inherited;
FTabPressed:= false;
end;
焦点事件处理程序
使用这 两个 三个事件处理程序之一。
//use the standard onEnter....
procedure TForm56.VirtualStringTree1Enter(Sender: TObject);
begin
if VirtualStringTree1.TabPressed then .....
else ....
end;
//... or use this event, or...
procedure TForm56.VirtualStringTree1FocusChanged(Sender: TBaseVirtualTree;
Node: PVirtualNode; Column: TColumnIndex);
begin
if VirtualStringTree1.TabPressed then .....
else ....
end;
//.... this event if you want to mess with the focus.
procedure TForm56.VirtualStringTree1FocusChanging(Sender: TBaseVirtualTree;
OldNode, NewNode: PVirtualNode; OldColumn, NewColumn: TColumnIndex;
var Allowed: Boolean);
begin
Allowed:= VirtualStringTree1.TabPressed; //just a silly example.
end;
因为通过单击获得焦点总是会在 onEnter 事件之前生成 mousedown 事件,您可以在 mousedown 中设置一个事件说 'gMousedown' := true 然后在 OnEnter 事件中您可以检查 mousedown。不要忘记在 onMouseUp 事件中将 gMousedown 重置为 false。