在鼠标单击和键盘节点选择上执行代码 - 虚拟树视图

时间:2015-11-22 20:27:20

标签: delphi delphi-xe7 virtualtreeview

我有虚拟树视图,当用户点击节点时,我使用OnClick执行代码。为了在用户使用键盘从一个节点移动到另一个节点时也执行相同的代码,我使用OnFocusChanged。 在OnFocusChanged中,我调用OnClick,因此它总是执行相同的代码。

因此,当选择一个节点并且用户点击另一个节点时,两个事件都被称为OnClick和OnFocusChanges ......并且由于OnFocusChanged调用OnClick,我使用一个小技巧来避免OnClick的双重执行。我使用flag设置忽略OnClick的第二次调用。

以下是代码 - OnFocusChanged

procedure TForm1.VTVFocusChanged(Sender: TBaseVirtualTree;
  Node: PVirtualNode; Column: TColumnIndex);
begin
  gTVFocusHasJustChanged_SkipClickEvent := false; // enable executing  OnClick code
  VTVClick(Sender);
  gTVFocusHasJustChanged_SkipClickEvent := True; // disable executing OnClick code
end;

这是 OnClick

procedure TForm1.VTVClick(Sender: TObject);
var
  Data: ^rTreeData;
begin
  // skip second OnClick call!
  if gTVFocusHasJustChanged_SkipClickEvent then
  begin
    gTVFocusHasJustChanged_SkipClickEvent := false;
    Exit;
  end;

  ... // code to be executed when node selected

end;

这可以按预期工作,用户点击节点或使用键盘移动。

但是,有没有更好的方法来做到这一点,更容易维护或更有意义?

编辑:

我想我需要添加更多信息。当用户选择节点时,仅执行特定代码。使用鼠标,键盘,如果它是否聚焦,之前已选择一个节点,现在选择新节点...基本上在任何和所有事件中,只需要执行特定代码。我选择使用OnClick方法,我有这个代码,我可以使用从OnClick调用的另一个函数,但实际上是相同的。 我不会根据发生的情况执行不同的代码,无论是点击,还是键盘移动......都是一样的,没有区分代码被触发的地方。 我希望这能更好地了解正在发生的事情,并在需要帮助的地方提供更多信息。

编辑#2:

更新我的进度:我开始将所有代码从OnClick移动到单独的过程中,这样可以在选择节点(鼠标单击或键盘)或其他情况下提高可维护性并简化执行。下面的答案和评论让我向正确的方向发展,OnClick不是正确的地方,应该执行不基于OnClick事件的代码。

2 个答案:

答案 0 :(得分:3)

主要思想是为每个VirtualTree使用全局选择的节点。

以下是代码:

  TForm1 = class(TForm)
    ..........
  private
    fselectedVTNode : PVirtualNode;   // used as global selected node for VTV
    ..........
  public
    ..........
  end;


//========== Event for VTV.OnFocusChanged ===============
procedure TForm1.VTVFocusChanged(Sender: TBaseVirtualTree;
  Node: PVirtualNode; Column: TColumnIndex);
var
  Data: ^rTreeData;
begin
  if (fselectedVTNode <> Node) then begin
    fselectedVTNode := Node;

    // ....... code to be executed when node selected

  end;
end;

//========== Event for VTV.OnFreeNode ===============
procedure TForm1.VTVFreeNode(Sender: TBaseVirtualTree; Node: PVirtualNode);
begin
  if fselectedVTNode = Node then
    fselectedVTNode := nil; 

  // .......code to be executed when node freed
end;

//========== Event for VTV.OnEnter ===============
procedure TForm1.VTVEnter(Sender: TObject);
var
  VT:TBaseVirtualTree;
begin
  fselectedVTNode := nil; 
  VT:=TBaseVirtualTree(Sender); 
  VTVFocusChanged(VT, VT.FocusedNode, VT.FocusedColumn);
end;

答案 1 :(得分:0)

Saludos amigos,en lazarusesasí:

    TForm2 = class(TForm)
        ..........
      private
        fselectedVTNode : PVirtualNode;   // used as global selected node for VTV
        ..........
      public
        ..........
      End;


    // ESTE ES EL CODE PRINCIPAL PARA OBTENER LOS DATOS NECESARIOS
    procedure TForm2.VSTFocusChanged(Sender: TBaseVirtualTree; 
Node: PVirtualNode; Column: TColumnIndex);
        var
          Data: Pdata;
        begin
        //VST.Refresh;
          if (fselectedVTNode <> Node) then begin
            fselectedVTNode := Node;

            // ....... code to be executed when node selected
            Data := VST.GetNodeData(Node);
            //ShowMessage(Data^.Fnotes);  // funciona
            Memo_comentarios.Text:=Data^.Fnotes;  // funciona
          end;
        end; 


        procedure TForm2.VSTFreeNode(Sender: TBaseVirtualTree; Node: PVirtualNode);
        begin
              if fselectedVTNode = Node then
                fselectedVTNode := nil;

              // .......code to be executed when node freed
        end;

        procedure TForm2.VSTEnter(Sender: TObject);
          var
            VT:TBaseVirtualTree;
         begin
            fselectedVTNode := nil;
            VT:=TBaseVirtualTree(Sender);
            VSTFocusChanged(VT, VT.FocusedNode, VT.FocusedColumn);

         end;

Saludos:​​)