giomach 1 Posted November 13, 2020 (edited) 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. WNExploreUnit.pas [Sorry this file was wrong. See further message for the right file.] Edited November 14, 2020 by giomach Error in attachment Share this post Link to post
giomach 1 Posted November 13, 2020 Sorry, wrong source file. The right one will be posted asap. Share this post Link to post
giomach 1 Posted November 13, 2020 The right source file this time — hopefully. WNExploreUnit.pas Share this post Link to post
Attila Kovacs 629 Posted November 13, 2020 (edited) 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 November 13, 2020 by Attila Kovacs Share this post Link to post
Guest Posted November 14, 2020 (edited) 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 November 14, 2020 by Guest Share this post Link to post
David Heffernan 2345 Posted November 14, 2020 (edited) Why are you trying to access the list views items when in virtual mode? That's directly against the concept of virtual mode. Edited November 14, 2020 by David Heffernan Share this post Link to post
giomach 1 Posted November 14, 2020 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
David Heffernan 2345 Posted November 14, 2020 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
Remy Lebeau 1393 Posted November 16, 2020 (edited) 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 November 16, 2020 by Remy Lebeau Share this post Link to post
giomach 1 Posted November 20, 2020 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
Remy Lebeau 1393 Posted November 21, 2020 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