Jump to content
giomach

Behaviour of TListView (Delphi XE)

Recommended Posts

This simple test program places a number of strings in a single-column ListView.  I don't understand why it behaves differently in virtual and non-virtual modes.

 

In non-virtual mode, the strings are added directly to the ListView.  In virtual mode, they are placed in a StringList, and linked from there to the ListView.

 

When the strings are in place, the first item of the ListView is assigned to a local TListItem variable.  Then another item (the 7th for example) is accessed (its caption is read and displayed).

Then we look at the local TListItem again.

 

In non-virtual mode, it has not changed.  But in virtual mode, it now contains the 7th item, not the first. 

 

Is this expected behaviour?  If so, why?  Source and output attached.

 

LV.thumb.jpg.be8e90d5212c16b1bf3679869a51c09e.jpg

WNExploreUnit.pas  [Sorry this file was wrong. See further message for the right file.]

Edited by giomach
Error in attachment

Share this post


Link to post

your code is just

 

Ahm, I see, virtual mode is like the component is a hole to the memory and the hole is being moved, but the size is always the same.

Edited by Attila Kovacs

Share this post


Link to post
Guest
2 hours ago, giomach said:

The right source file this time — hopefully.

WNExploreUnit.pas

 

you need inform new "ITEM" for your var:

procedure TWNExploreForm.Test;
var
  s       : string;
  ListItem: TListItem;
  i       : integer;
begin
  WordRichEdit.Visible := true;
  //
  { non-virtual use }
  DisplayLine('Non-virtual use of TListView');
  ... 
  WordListView.OnData := nil; // <--- who fill next items?
  //
  ListItem := WordListView.Items[0];
  DisplayLine('Local TListItem has index ' + inttostr(ListItem.Index) + ', caption "' + ListItem.Caption + '"');
  //
  ListItem := WordListView.Items[6];  <------  please, Hey... look at me!
  //
  DisplayLine(WordListView.Items[6].Caption);
  DisplayLine('Local TListItem has index ' + inttostr(ListItem.Index) + ', caption "' + ListItem.Caption + '"');
  DisplayLine('');

 

Edited by Guest

Share this post


Link to post

Why are you trying to access the list views items when in virtual mode? That's directly against the concept of virtual mode. 

Edited by David Heffernan

Share this post


Link to post
6 hours ago, David Heffernan said:

Why are you trying to access the list views items when in virtual mode? That's directly against the concept of virtual mode. 

I see now ... I should be working with the StringList rather than with ListView.Items.  That never occurred to me.

 

In virtual mode, what about code like

    ListItem := WordListView.FindCaption (0, 'a', true, true, false);
   WordListView.Scroll (0, ListItem.DisplayRect (drBounds).Top);

For example, do I need to replace FindCaption by a search of the StringList?

 

By way of explanation, it was while trying to debug such code that I became concerned about what was happening to ListItem, leading me to display its Index value.  Although I no longer need to do this, it is still disconcerting that (in virtual mode) its value can change in the way that my test program showed.

 

Thanks for pointing me in the right direction.

 

@emailx45: I didn't explain it well.  I am happy with non-virtual mode.  My problem was with virtual mode, the change in value of ListItem between the two lines where its value was displayed.

Share this post


Link to post

Yeah in virtual mode you can't query the control, because it does not hold the data. You just query the data structure that does hold the data, a string list in your case. 

Share this post


Link to post

In non-virtual mode, each list item has its own physical TListItem object in memory, and their respective data is stored directly in the ListView control itself (well, in its HWND, anyway).

 

In virtual mode, all data is held in the user's code instead.  There is only 1 physical TListItem created, used internally by the TListView, where its content is reset each time an operation is performed that requires a physical TListItem object.  For instance, when reading the TListView.Items[index] property, or calling method that takes a TListItem as input or returns a TListItem as output.

 

IN MOST CASES, this design allows non-virtual code to continue working the same way as in non-virtual mode, just with the addition of the OnData... event handlers.  But there are some corner cases to be aware of where this design does not work as expected, for instance doing tasks that require access to more than 1 TListItem at the same time.  Your example demonstrates this when by causing an operation that resets the TListItem that is being observed.

Edited by Remy Lebeau

Share this post


Link to post

Thanks for taking the trouble to give this explanation.

 

I've also noticed that, in virtual mode, every item of a ListView has the same Top value of maxint.  So its not possible to scroll to a numbered item by using their Items[index].Top property, but the method using DisplayRect (drBounds).Top, mentioned earlier in this thread, works.

Share this post


Link to post
2 hours ago, giomach said:

I've also noticed that, in virtual mode, every item of a ListView has the same Top value of maxint.

Reading the TListItem.Top property calls TListItem.GetPosition() and returns its Y value.  GetPosition() calls ListView_GetItemPosition(), which should work the same in virtual and non-virtual modes.  The ListView knows the position and sizes of its list items, it just does not know what data they contain in virtual mode.  If you call ListView_GetItemPosition() directly, does it return TRUE or FALSE?

2 hours ago, giomach said:

So its not possible to scroll to a numbered item by using their Items[index].Top property

I use TListView in vsReport style in virtual mode, and I find it better (and more efficient) to use the Win32 API directly rather than using TListItem for most operations.  To scroll to a specific item, I call ListView_EnsureVisible(), then if I want that item to appear at a specific position then I call ListView_GetItemRect() (which TListItem.DisplayRect() calls) and ListView_GetTopItem(), and then TListView.Scroll() for the difference.

2 hours ago, giomach said:

but the method using DisplayRect (drBounds).Top, mentioned earlier in this thread, works.

Right, because I said above, a ListView knows the position and size of its items, in virual and non-virtual modes alike.

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×