user7415109
user7415109

Reputation:

Delphi Firemonkey TListView.selected is always nil in onItemsChange

Firemonkey App, Windows and MacOS target.

I need to know what item is selected when a user scroll with the cursor keys or click with the mouse a listview item.

I can react to the mouse click via the onItemClick event, thats fine, also the onItemsChange event is fired when I move the selection with the cursor keys, but the selected property of the listview stays always at nil within that event.

Is this a bug or is there something I miss?

How do I know what item is selected when user use the cursor keys within the control?

Upvotes: 1

Views: 2060

Answers (2)

Nasreddine Galfout
Nasreddine Galfout

Reputation: 2591

I really do not understand the down votes they are really a ??? to me. However I decided to update my answer and try to make it clearer

First: You need to realize that the OnChange event is not the only event that you can do this on. The real question is why the GetSelected getter method fail on the OnItemsChange event and returns nil.

The declaration of the selected property is this

property Selected: TListItem read GetSelected write SetSelected;

The check for its getter method is this:

if (FItemIndex >= 0) and (FItemIndex < Adapter.Count) then 
    return code
else
    result := nil;

so clearly something is happening

in the documentation

List item that is currently selected on the list view. This property is nil if no item is selected.

by selected they mean the check above. which raise the following question how this event is fired in the first place. In the documentation it says

Event that occurs after a list of items has been changed.

it means when you alter the existence of the items (delete, add and not change the height or width I have checked this). Furthermore the selected property does not return nil if the event does not alter the selection

the following test could be used

in a form add the following

  • TListView
  • TCheckBox
  • a TButton

In the button OnClick event add this

procedure TForm5.Button1Click(Sender: TObject);
var
  I: Integer;
begin
for I := 1 to 10 do
listview1.items.add;
end;

In the OnItemsChange event add this

procedure TForm5.ListView1ItemsChange(Sender: TObject);
begin
caption := 'fired'+datetimetostr(now);
if checkbox1.IsChecked then
caption := 'selected item index: '+ inttostr(listview1.Selected.index);
end;

You get the following results

  • first time you add an item (nothing selected because there is no items) with CheckBox.IsChecked = True you will get an AV because there is nothing to be selected
  • After you successfully add an item with the check box not checked select it and check the box then add another item. Voila no AV

From my view I think you were in the first case (which is very strange that you did not investigate why).

Putting aside what the documentation says about the OnChange event. As long as you ensure that an item is selected before calling the GetSelected method you will not have an AV.

Finally: I find it really disappointing that people don't go the extra mile to answer the Why question.

If you don't know why it is failing then how to ensure it will not fail again?.

Upvotes: -1

You are using the wrong event. The OnItemsChange event is an

Event that occurs after a list of items has been changed.

as the documentation states. Do you change the list of items? No, you don't.

What you are looking for is the OnChange event:

Occurs when the ItemIndex property changes as a result of a user selecting a different item. Write an OnChange event handler to respond to changes of the ItemIndex property. OnChange allows a response once the list has been successfully changed.

See the documentation for more details.

Upvotes: 2

Related Questions