3

如何检测用户是通过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 次。

4

2 回答 2

3

为了知道焦点是通过使用tab还是通过鼠标单击获得的,您需要做一些侦探工作。

  1. 这是在按 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;
  1. VTV 有两个事件用于焦点更改:OnFocusChanged以及OnFocusChanging除了标准OnEnterOnExit事件。
    我不知道其中哪一个最适合您的需求,您必须进行试验。

假设焦点始终是使用鼠标获得的,除非我们可以证明它是使用tab. 这是一个有点不稳定的假设,但没关系。

首先,我们使用插入器来覆盖WMKeyUp消息处理程序。
WMKeyUp是私有的,但幸运的是消息处理程序总是可以被覆盖,即使它们是私有的

插入器
您可以使用称为插入器的技巧来重新定义 VST 以满足我们的需要。
由于范围规则,“改进的”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;
于 2016-08-24T15:36:26.357 回答
2

因为通过单击实现的焦点总是会在 onEnter 事件之前生成 mousedown 事件,所以您可以在 mousedown 中设置一个事件,说 'gMousedown' := true 然后在 OnEnter 事件中您可以检查是否 mousedown。不要忘记在 onMouseUp 事件中将 gMousedown 重置为 false。

于 2016-08-25T05:12:11.747 回答