Reputation: 3497
I try to do an action for each selected listitem but it won't work. This is what i tried:
var
TLsttem:TListItem;
begin
for TLsttem in form1.listview1.Selected do
begin
...
end;
end;
Now i get this error:
[dcc32 Error] MSGBox.pas(50): E2431 for-in statement cannot operate on collection type 'TListItem' because 'TListItem' does not contain a member for 'GetEnumerator', or it is inaccessible
How can i fix this?
EDIT: I now tried this script:
TLsttem := form1.ListView1.Selected;
while TLsttem <> nil do
begin
showmessage('Test');
TLsttem := form1.ListView1.GetNextItem(TLsttem, sdAll, [isSelected]);
end;
But i only get 1 message, how can i fix this?
Upvotes: 1
Views: 1846
Reputation: 34899
This example is from documentation, GetNextItem
:
procedure TForm1.Button1Click(Sender: TObject);
var
Item: TListItem;
begin
Item := ListView1.Selected;
while Item <> nil do
begin
ListBox1.Items.Add(Item.Caption);
Item := ListView1.GetNextItem(Item, sdAll, [isSelected]);
end;
end;
TListView.Selected
gets the first selected item, while GetNextItem
unwinds more selected items.
As noted by David, it is possible to wrap this logic into an enumerator, so that a for .. in
loop could be used.
The easiest thing is to put this enumeration into a class helper, much like the answer from @StefanGlienke
.
type
TSelectedListItemsEnumerator = record
private
FListView: TListView;
FItem: TListItem;
public
constructor Create(aListView: TListView);
function GetEnumerator: TSelectedListItemsEnumerator;
function MoveNext: Boolean;
property Current: TListItem read FItem;
end;
TListViewHelper = class helper for TListView
private
function GetSelectedItems: TSelectedListItemsEnumerator;
public
property SelectedItems: TSelectedListItemsEnumerator
read GetSelectedItems;
end;
{ TSelectedListItemsEnumerator }
constructor TSelectedListItemsEnumerator.Create(aListView: TListView);
begin
FListView := AListView;
end;
function TSelectedListItemsEnumerator.GetEnumerator: TSelectedListItemsEnumerator;
begin
FItem := nil;
Result := Self;
end;
function TSelectedListItemsEnumerator.MoveNext: Boolean;
begin
FItem := FListView.GetNextItem(FItem,sdAll,[isSelected]);
Result := (FItem <> nil);
end;
{ TListViewHelper }
function TListViewHelper.GetSelectedItems: TSelectedListItemsEnumerator;
begin
Result := TSelectedListItemsEnumerator.Create(Self);
end;
procedure TForm1.Button2Click(Sender: TObject);
var
Item: TListItem;
begin
for Item in ListView1.SelectedItems do
begin
Memo1.Lines.Add(Item.Caption);
end;
end;
Upvotes: 10
Reputation: 21713
While for this example it might be overkill here is a way to extend the TListView class with a SelectedItem property that is enumerable with a for-in loop.
In cases where the condition inside the loop might be more complex than just checking a property or by actually providing a filter delegate this can be very powerful.
type
TSelectedListItemsEnumerator = class(TListItemsEnumerator)
public
function MoveNext: Boolean;
end;
TSelectedListItemsEnumerable = record
private
FListItems: TListItems;
public
constructor Create(AListItems: TListItems);
function GetEnumerator: TSelectedListItemsEnumerator;
end;
TListViewHelper = class helper for TListView
private
function GetSelectedItems: TSelectedListItemsEnumerable;
public
property SelectedItems: TSelectedListItemsEnumerable
read GetSelectedItems;
end;
{ TSelectedListItemsEnumerator }
function TSelectedListItemsEnumerator.MoveNext: Boolean;
begin
repeat
Result := inherited;
until not Result or Current.Selected;
end;
{ TSelectedListItemsEnumerable }
constructor TSelectedListItemsEnumerable.Create(AListItems: TListItems);
begin
FListItems := AListItems;
end;
function TSelectedListItemsEnumerable.GetEnumerator: TSelectedListItemsEnumerator;
begin
Result := TSelectedListItemsEnumerator.Create(fListItems);
end;
{ TListViewHelper }
function TListViewHelper.GetSelectedItems: TSelectedListItemsEnumerable;
begin
Result := TSelectedListItemsEnumerable.Create(Items);
end;
You can then use it like this:
procedure TForm1.Button1Click(Sender: TObject);
var
item: TListItem;
begin
for item in ListView1.SelectedItems do
begin
ShowMessage(item.Caption);
end;
end;
Upvotes: 5
Reputation: 125687
This works perfectly fine for me in XE5 (VCL):
var
Item: TListItem;
begin
for Item in ListView1.Items do
begin
if Item.Selected then
begin
// Do something with the item
end;
end;
end;
Upvotes: 4