加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

delphi – 如何在使用TreeNode.MoveTo时修复TTreeView错误?

发布时间:2020-12-15 09:35:01 所属栏目:大数据 来源:网络整理
导读:使用TreeNode.MoveTo(…)方法有时无法正常工作并引发“访问冲突”异常. 大多数时候有效,有些时候没有. 大多数时候’模块COMCTL32.DLL中的访问冲突.读取地址FEEEFEFA’并程序崩溃/冻结. 这是我的代码. procedure TForm1.FormShow(Sender: TObject);var I,sect
使用TreeNode.MoveTo(…)方法有时无法正常工作并引发“访问冲突”异常.

大多数时候有效,有些时候没有.

大多数时候’模块COMCTL32.DLL中的访问冲突.读取地址FEEEFEFA’并程序崩溃/冻结.

这是我的代码.

procedure TForm1.FormShow(Sender: TObject);
var
  I,sectioncount: Integer;
  parent,child: TTreeNode;
begin
  sectioncount := 0;
  for I := 0 to 19 do
  begin

    if I mod 5 = 0 then
    begin
      parent := TreeView1.Items.AddChild(nil,'Section: ' + IntToStr(sectioncount));
      Inc(sectioncount);
    end;

    child := TreeView1.Items.AddChild(parent,'Child: ' + IntToStr(I));

  end;

  TreeView1.Items[0].Expand(True);
end;

procedure TForm1.TreeView1DragDrop(Sender,Source: TObject; X,Y: Integer);
var src,dst : TTreeNode;
I : Integer;
begin
   dst := TreeView1.DropTarget;

   for I := 0 to TreeView1.SelectionCount - 1 do
   begin
     src := TreeView1.Selections[I];

     src.MoveTo(dst,naInsert);
   end;

end;

procedure TForm1.TreeView1DragOver(Sender,Y: Integer;
  State: TDragState; var Accept: Boolean);
begin
Accept := true;
end;

添加一个from到一个项目,添加一个树视图集树视图dragmode dmAutomatic和multiselect true.

然后

使用ctrl选择具有以下顺序的3个连续节点.
选择中间节点,
选择底部节点,
选择顶级节点.
并将第一个节点的节点拖到另一个可以看到AV错误的地方.

或从上到下选择三个节点并从底部节点AV拖动出现.

或者用控制键按以下顺序选择三个节点: – 首先’子1’然后’子2’然后’子0’最后通过选择’子0’拖放节点

解决方法

一个明显的问题是当你调用MoveTo时,你会使for循环失效.

for I := 0 to TreeView1.SelectionCount - 1 do
 begin
   src := TreeView1.Selections[I];
   src.MoveTo(dst,naInsert);
 end;

调用MoveTo后,您会发现SelectionCount不再是您进入循环时的状态.例如,我正在查看一个案例,其中SelectionCount在循环开始时为3,但在第一次调用MoveTo后为1.这意味着Selections [I]的子序列使用超出范围.

您需要首先记下所选节点,然后再移动它们来解决问题.

procedure TForm1.TreeView1DragDrop(Sender,Y: Integer);
var
  i: Integer;
  src,dst: TTreeNode;
  nodesToMove: TArray<TTreeNode>;
begin
  dst := TreeView1.DropTarget;
  SetLength(nodesToMove,TreeView1.SelectionCount);
  for i := 0 to high(nodesToMove) do
    nodesToMove[i] := TreeView1.Selections[i];
  for src in nodesToMove do
    src.MoveTo(dst,naInsert);
end;

除了这个问题,我可以重现访问冲突.似乎需要以非常特定的顺序移动项目.您似乎需要先移动底部节点,然后移动下一个前一个节点,最后移动顶部节点.此代码似乎解决了这个问题:

procedure TForm1.TreeView1DragDrop(Sender,dst: TTreeNode;
  nodesToMove: TList<TTreeNode>;
begin
  dst := TreeView1.DropTarget;
  nodesToMove := TList<TTreeNode>.Create;
  try
    for i := TreeView1.Items.Count-1 downto 0 do
      if TreeView1.Items[i].Selected then
        nodesToMove.Add(TreeView1.Items[i]);
    for src in nodesToMove do
      src.MoveTo(dst,naInsert);
  finally
    nodesToMove.Free;
  end;
end;

但这并不是很令人满意,而且我很清楚我还没有理解这里发生了什么.

我现在无法进一步研究这个问题,但我会在这里留下答案,因为我认为这将有助于其他回答者深入挖掘.希望有人能够解释AV的情况.

好的,我挖得更深了一点.问题似乎与MoveTo中的代码有关,该代码试图保持正在移动的节点的选择状态.我还没有深入研究问题所在,但在我看来,除了接管选择保留的实施之外,你无法从外部做很多事情来避免这个问题.

因此,我提出以下解决方案作为我提出的最佳方法:

procedure TForm1.TreeView1DragDrop(Sender,TreeView1.SelectionCount);
  for i := 0 to high(nodesToMove) do
    nodesToMove[i] := TreeView1.Selections[i];
  TreeView1.ClearSelection;
  for src in nodesToMove do
  begin
    src.MoveTo(dst,naInsert);
    TreeView1.Select(src,[ssCtrl]);
  end;
end;

我们在这里做以下事情:

>记下所选节点,需要移动的节点.>清除选择.>将每个节点移动到新目标,移动后,将移动的节点添加到选择中.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读