Delphi:从虚拟字符串树中删除节点后更改焦点

我有一个TVirtualStringTree类型的组件(我们称它为VST )。 它具有列表形式的节点,即所有节点都处于同一级别。 我想在删除节点(使用DeleteNode方法)并使用OnFreeNode事件后更改焦点:

procedure TMyForm.VSTFreeNode(Sender: TBaseVirtualTree; Node: PVirtualNode);
var
  NewFocus: PVirtualNode;
begin
  NewFocus := VST.GetNext(Node);
  if not Assigned(newFocus) then
    NewFocus := VST.GetPrevious(Node);
  if Assigned(NewFocus) then
  begin
    VST.FocusedNode := NewFocus;
    VST.Selected[NewFocus] := True
  end;
end;

我还希望更改引起一些反应,例如设置按钮的Enabled属性:

procedure TMyForm.VSTFocusChanged(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex);
begin
  btn1.Enabled := Assigned(Node);
end;

但是解决方案存在一些问题。 例如,当使用“取消”按钮关闭窗体(表单使用ShowModal方法打开)时,节点将被释放, VSTFocusChanged被触发,并且由于nil按钮后者会引发异常。 当然,我可以检查按钮是否已分配,但是在删除没有这种不良效果(并且没有其他不良效果)的情况下更改焦点后,是否有更好的解决方案?


是否有内置的方法来始终选择一个节点?

就在这里。 从这些事件中删除你的代码,包括toAlwaysSelectNode选项树视图TreeOptions.SelectionOptions选项集(例如启用它的IDE)。 这个选项的评论说:

如果此标志设置为true,则树视图会尝试始终选择一个节点。

这也包括节点删除。


如何从VT事件安全地更新外部控制的启用状态?

您遇到的问题是,您正在从OnFreeNode事件手动关注节点,从而触发OnFocusChanged事件。 而且,由于节点在控制被销毁并且该按钮之前被销毁时也被释放,所以您试图访问被销毁的控件。 为避免将来出现这种情况,您可以使用RTL操作,因为即使具有csDestroying状态信号(包括像OnStructureChange这样的事件 ),并且操作是一种安全的解决方法,VT也会触发很多事件。

像这样的东西应该安全工作(我不是行动OnUpdate事件的粉丝):

procedure TMyForm.VSTStructureChange(Sender: TBaseVirtualTree; Node: PVirtualNode;
  Reason: TChangeReason);
begin
  { ActionDeleteNode is assigned to the button's Action property; SelectedCount
    is a bit paranoic here because if you use the toAlwaysSelectNode option, at
    least one node should be always selected, so RootNodeCount > 0 could do the
    same here }
  ActionDeleteNode.Enabled := Sender.SelectedCount > 0;
end;

没有RTL操作,您可以安全地更新该按钮状态,例如在执行操作之后,例如在删除节点之后:

VST.DeleteNode(VST.FocusedNode);
ButtonDeleteNode.Enabled := VST.SelectedCount > 0;

但有了这个,你可能会失去同步并编写更多的代码。 因此使用RTL操作是我喜欢的。

链接地址: http://www.djcxy.com/p/39835.html

上一篇: Delphi: Changing focus after deleting a node from a virtual string tree

下一篇: How to find the closest value in PHP