delphi – 如何在使用TreeNode.MoveTo时修复TTreeView错误?
使用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拖动出现. 或者用控制键按以下顺序选择三个节点: – 首先’子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; 我们在这里做以下事情: >记下所选节点,需要移动的节点.>清除选择.>将每个节点移动到新目标,移动后,将移动的节点添加到选择中. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |