我有虚拟树视图,当用户点击节点时,我使用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
事件的代码。
答案 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:)