问题
I have a treeview and a listview, and a button that should move selected items from the treeview to the listview. The selection and the transfer are happening perfectly fine, but deleting the items from the treeview is not. It only works if I select a single item under the treeview. When I have TreeView1.MultiSelect := True
, then there is a problem.
Here is the code I am using:
For i := 0 to TreeView1.Items.Count-1 do Begin
If TreeView1.Items[i].Selected then
Begin
Itm := ListView1.Items.add;
.....
TreeView1.Items[i].Delete
The above code gives an invalid index after certain selection. Not perfect sometimes only one out of two selected are added.
Tried:
For i := TreeView1.Items.Count to 1 do Begin
- Populated listview first and then tried to delete from treeview, instead of simulatainously doing it. Same error.
- Tried to store Parent and Child in an array and then later delete them with the name. Problem is particular item not selected in treeview.
This is the code which is not working when I select the last element all of the elements in the parent node get copied
for Itr := TreeView1.Items.Count-1 downto 0 do Begin
if TreeView1.Items[Itr].Selected then
begin
Str := TreeView1.Items[Itr].Parent.Text + ' ,' + TreeView1.Items[Itr].Text;
TrimLeft(Str);
for k := 0 to SaveList.Count -1 do Begin
If ansipos(Str, SaveList[k]) > 0 Then Begin
Value := StringReplace(SaveList[k], Str, '',[rfReplaceAll, rfIgnoreCase]);
End;
End;
Itm := ListView1.Items.Add;
Itm.Caption := TreeView1.Items[Itr].Parent.Text;
Itm.SubItems.Add(TreeView1.Items[Itr].Text);
Itm.SubItems.Add(Value);
TreeView1.Items[Itr].Delete
end;
End;
回答1:
Change your for loop as:
For i := TreeView1.Items.Count-1 downto 0 do
....
Edit after new code presented
You did not show the actual error message, nor on which line it happens, but I assume it is on this line
Str := TreeView1.Items[Itr].Parent.Text + ' ,' + TreeView1.Items[Itr].Text;
for a TreeView item at the root level. Those don't have a parent (IOW Item[itr].Parent
is nil
) and the result is an Access violation
error. You need to check that the item has a parent before attempting to access the parent.
If your error is something else, please clarify.
Edit, added workaround
As @MBo reported, the reason is that the selection changes during deletion. To prevent this, you can use the following workaround.
Declare a boolean field, say, TreeView1_Deleting
in your form and an OnChanging
event for the tree view.
type
TForm1 = class(TForm)
TreeView1: TTreeView;
Button1: TButton;
...
procedure TreeView1Changing(Sender: TObject; Node: TTreeNode;
var AllowChange: Boolean);
private
TreeView1_Deleting: boolean;
end;
and the implementation of the OnChanging
event:
procedure TForm1.TreeView1Changing(Sender: TObject; Node: TTreeNode;
var AllowChange: Boolean);
begin
if TreeView1_Deleting then
AllowChange := False;
end;
Finally, in the procedure where you delete the selected nodes
begin
TreeView1_Deleting := True; // Add this line
for i := TreeView1.Items.Count-1 downto 0 do
begin
if TreeView1.Items[i].Selected then
begin
// copy values to listview
// and finally delete the node
TreeView1.Items[i].Delete;
end;
end
TreeView1_Deleting := False; // Add this line
end;
Remember what I said earlier regarding accessing the Parent
property of a root level node.
回答2:
I can confirm that this code really clears the whole branch or all the tree (if the last element is chosen) (XE3, Win7/32):
for I := TreeView1.Items.Count - 1 downto 0 do begin
if TreeView1.Items[i].Selected then begin
Memo1.Lines.Add(TreeView1.Items[i].Text);
TreeView1.Items[i].Delete;
end;
end;
And it outputs both selected node label and parent labels up to root level - so selection jumps level up during deletion (I don't see a reason in treeview sources)
Workaround: mark selected nodes, remove selection, delete marked:
var
i: Integer;
Node: TTreeNode;
begin
for I := TreeView1.SelectionCount - 1 downto 0 do begin
Node := TreeView1.Selections[i];
Memo1.Lines.Add(Node.Text);
Node.Data := Pointer(-1);
end;
TreeView1.Selected := nil;
for I := TreeView1.Items.Count - 1 downto 0 do
if TreeView1.Items[i].Data = Pointer(-1) then
TreeView1.Items[i].Delete;
来源:https://stackoverflow.com/questions/36725780/how-do-i-avoid-invalid-index-errors-when-removing-user-selected-items-from-a-tre