检测用户是否通过选项卡或单击获得组件的焦点

时间:2016-08-24 08:41:17

标签: delphi events virtualtreeview tvirtualstringtree

如何通过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次。

2 个答案:

答案 0 :(得分:2)

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

  1. 这是在按Tab键时确保焦点的代码。
  2. 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. 除了标准的OnFocusChangedOnFocusChanging事件外,VTV还有两个重点更改事件:OnEnterOnExit。 我不知道哪个最适合你的需求,你必须进行实验。
    2. 让我们假设使用鼠标总是获得焦点,除非我们能够证明它是使用 tab 获得的。这是一个不稳定的假设,但没关系。

      首先,我们使用内插器来覆盖WMKeyUp消息处理程序 WMKeyUp是私有的,but luckily message handlers can always be overriden, even if they are private

      插播者
      您可以使用a trick called an interposer重新定义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;
      

答案 1 :(得分:1)

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