View Issue Details

IDProjectCategoryView StatusLast Update
0007749LazarusLCLpublic2014-05-22 05:45
ReporterSeth GroverAssigned ToDmitry Boyarintsev 
PrioritynormalSeverityfeatureReproducibilityalways
Status closedResolutionfixed 
Product Version0.9.18Product Build 
Target Version0.9.30Fixed in Version0.9.29 (SVN) 
Summary0007749: ability to make TListView "virtual"
DescriptionIn porting a Delphi application to Lazarus, I noticed that the TListView component doesn't have the ability to be virtual, ie., the ability to set an OwnerData property and specify a handler for the OnData event. This is useful when using a listview to display a *lot* of data because you can keep the data in your own structures instead of forcing the listview to load it all into memory.

This would be a nice feature to have implemented.
TagsNo tags attached.
Fixed in Revision21524,22789
LazTarget0.9.30
WidgetsetGTK
Attached Files
  • lazarus_tlistview_ownerdata.txt (1,952 bytes)
    
    ---------comctrls.pp-----------------------------------------------
    
    
    TListItems = class(TPersistent)
      protected
        procedure SetCount(Value: Integer); // for LV OwnerData
      public    
        property Count: Integer read GetCount write SetCount; // SetCount for LV OwnerData
        
        
    { TCustomListView }
    
      TLVOwnerDataEvent = procedure(Sender: TObject; Item: TListItem) of object; // OwnerData
      
      
    TCustomListView = class(TWinControl)
      private    
        FOnData: TLVOwnerDataEvent; // OwnerData  
      protected
        function OwnerDataFillItem(Item: TListItem): Boolean; // OwnerData    
        property OnData: TLVOwnerDataEvent read FOnData write FOnData; // OwnerData
        
            
    -----------listitems.inc--------------------------------------------
    
    procedure TListItems.SetCount(Value: Integer); 
    begin
      if FOwner <> nil
      then FOwner.SetAllocBy(Value);
    end;
    
    function TListItems.GetItem(const AIndex: Integer): TListItem;
    begin
      if (FCacheIndex <> -1) and (FCacheIndex = AIndex)
      then begin
        Result := FCacheItem;
        Exit;
      end;
      
      if FItems.Count - 1 < AIndex
      then Result := nil
      else begin
        if assigned(FOwner) and (FOwner.OwnerData) then // OwnerData
        begin
          // create new item
          result := TListItem.create(self);
          SetItem(AIndex, result);                      
          FOwner.OwnerDataFillItem(Result);       
          SetItem(AIndex, result);                  
        end else
        begin  
          Result := TListItem(FItems.Items[AIndex]);      
        end;
        FCacheItem := Result;
        FCacheIndex := AIndex;
      end;
    end;
    
    ---------------customlistview.inc------------------------------------------
    
    function TCustomListView.OwnerDataFillItem(Item: TListItem): Boolean; // OwnerData
    begin
      if Assigned(FOnData) then
      begin    
        FOnData(Self, Item); // this event sets the item's caption
        Result := True;
      end
      else Result := False;
    end;
    
    
    
  • delphi7_virtuallistview_sample.zip (248,123 bytes)
  • virtuallistbox.patch.zip (6,315 bytes)

Relationships

related to 0007129 closedDmitry Boyarintsev TListview does not have a OwnerData property 
related to 0007130 closedDmitry Boyarintsev TListview does not have a OnData method 
related to 0007131 feedbackZeljan Rikalo TListview does not have a OnDataFind method 

Activities

George Lober

2006-11-04 04:44

reporter   ~0009663

I noticed this too :) , that's why I submitted bugs 7129(OwnerData), 7130(OnData) and 7131(OnDataFind). These would be enough for me use my existing working Delphi code, but by the looks of what's floating around on the web, some code may also need OnDataHint and OnDataStateChange.

Boguslaw Brandys

2006-11-04 11:13

developer   ~0009664

OwnerData already is in place but it's not used. I think that adding OnData event wouldn't be too difficult when somebody explain where/when it should be called.It must be somewhere in code just before drawing single listview item.Just put OnData event definition to tListView and call something similiar to :

if not OwnerData then Exit;
if Assigned(FOnData) then FOnData(...);

Leslie Kaye

2009-02-05 16:23

reporter   ~0025144

The "virtual" list view was introduced by M$ for Win 2000
A virtual list view is a list-view control that has the LVS_OWNERDATA style. This style enables the control to handle millions of items because the owner receives the burden of managing item data. This allows you to use the virtual list-view control with large databases of information, where specific methods of data access are already in place.
http://msdn.microsoft.com/en-us/library/bb774735(VS.85).aspx
What cross platform support is there for this if any?

Jonas Schäfer

2009-02-06 19:13

reporter   ~0025165

If you do only need the lsReport ListStyle, I would recommend to try with the VirtualTreeView. Disabling the tree lines and using header columns, you can build a really nice virtual detail-listview. I am working with it that way and cannot complain.
That just in case this cannot be implemented for some reason...

greetings
Lord Horazont

Alexander Grau

2009-03-11 21:16

reporter   ~0026061

Last edited: 2009-06-17 18:43

For implementing the OwnerData feature, the following must be solved:

1. The listview widgetset must trigger a WM_NOTIFY (with NMHdr.code LVN_GETDISPINFO) at the time when new items are visible in the listview (due to scrollbars, keys etc.) or some at least some other event (e.g. LVN_ITEMCHANGED) that in turn calls 2. to set the new listitem data. This must happen in all widgetsets (Carbon, Win32, GTK etc.). Win32 does already trigger this event.

2. When the listview triggerd the event, a new TListItem must be created and filled by the OnData event property and finally this item need to be set to the listview's listitems list.

This is some sort of lazy item setting - it is extremely fast if thousands of items have to be added to the the listview.

I can already implement 2. (and 1. for Win32), but I have no idea how to solve it for the other widgetsets - the problem is that there is currently no event that is triggered when new items get into the view - e.g. there are events when the selected item changed (LVN_ITEMCHANGED), but that is not the event that is needed for 1. If you have any ideas, please let me know :-)

06-17-2009 Update: I have added two bounties for implementing this feature ( http://wiki.lazarus.freepascal.org/Bounties )

06-17-2009: Update: I have uploaded some notes for the required modifications as well as a sample app - For the Win32 widgetset the widget creation style need to be modified like this:

win32wscustomlistview.inc:
  TWin32WSCustomListViewCreateHandle
  ...
  if TListView(AWinControl).ownerdata then flags := flags OR LVS_OWNERDATA;

Then the message mentioned above (LVN_GETDISPINFO) should be triggered!

Thanks,
Alexander

2009-06-17 17:28

 

lazarus_tlistview_ownerdata.txt (1,952 bytes)

---------comctrls.pp-----------------------------------------------


TListItems = class(TPersistent)
  protected
    procedure SetCount(Value: Integer); // for LV OwnerData
  public    
    property Count: Integer read GetCount write SetCount; // SetCount for LV OwnerData
    
    
{ TCustomListView }

  TLVOwnerDataEvent = procedure(Sender: TObject; Item: TListItem) of object; // OwnerData
  
  
TCustomListView = class(TWinControl)
  private    
    FOnData: TLVOwnerDataEvent; // OwnerData  
  protected
    function OwnerDataFillItem(Item: TListItem): Boolean; // OwnerData    
    property OnData: TLVOwnerDataEvent read FOnData write FOnData; // OwnerData
    
        
-----------listitems.inc--------------------------------------------

procedure TListItems.SetCount(Value: Integer); 
begin
  if FOwner <> nil
  then FOwner.SetAllocBy(Value);
end;

function TListItems.GetItem(const AIndex: Integer): TListItem;
begin
  if (FCacheIndex <> -1) and (FCacheIndex = AIndex)
  then begin
    Result := FCacheItem;
    Exit;
  end;
  
  if FItems.Count - 1 < AIndex
  then Result := nil
  else begin
    if assigned(FOwner) and (FOwner.OwnerData) then // OwnerData
    begin
      // create new item
      result := TListItem.create(self);
      SetItem(AIndex, result);                      
      FOwner.OwnerDataFillItem(Result);       
      SetItem(AIndex, result);                  
    end else
    begin  
      Result := TListItem(FItems.Items[AIndex]);      
    end;
    FCacheItem := Result;
    FCacheIndex := AIndex;
  end;
end;

---------------customlistview.inc------------------------------------------

function TCustomListView.OwnerDataFillItem(Item: TListItem): Boolean; // OwnerData
begin
  if Assigned(FOnData) then
  begin    
    FOnData(Self, Item); // this event sets the item's caption
    Result := True;
  end
  else Result := False;
end;


2009-06-17 18:01

 

delphi7_virtuallistview_sample.zip (248,123 bytes)

Seth Grover

2009-07-30 20:56

reporter   ~0029412

For whoever is working on this, I don't know if this would help or not, bug the Orpheus port (http://web.fastermac.net/~MacPgmr/OrphPort/OrphStatus.html) has a TOvcVirtualListBox which "sort of works." It might be helpful to look at.

Dmitry Boyarintsev

2009-08-09 19:21

developer   ~0029678

here's virtualization patch... win32 only for now.

Dmitry Boyarintsev

2009-08-31 12:49

developer   ~0030268

Paul Ishenin, i've updated the patch.
Win32 or LCL modifications are still the same,
Carbon modifications are included.

2009-08-31 12:50

 

virtuallistbox.patch.zip (6,315 bytes)

Paul Ishenin

2009-09-01 18:50

manager   ~0030296

I have commited it with minor changes in declarations. But I really dislike FOwnerDataItem which is always present. Also gtk2 and qt implementations are not present and therefore this issue can't be resolved.

Dmitry Boyarintsev

2009-09-01 22:41

developer   ~0030301

maybe it should be split into two issues:
Virtual List view for gtk
Virtual List view for qt?

Sebastian Willenborg

2009-09-17 16:59

reporter   ~0030797

At the moment LVN_ITEMCHANGED is blocked by "if OWnerData then Exit;".
I replaced it with the following code to enable the OnSelectItem-Event.
if OwnerData then begin
  if nm^.iItem = -1 then Exit;
  FOwnerDataItem := TOwnerDataListItem.Create(FListItems);
  FOwnerDataItem.SetDataIndex(nm^.iItem);
  DoGetOwnerData(FOwnerDataItem);
  item := TListItem(FOwnerDataItem);
end else
  Item := Items[nm^.iItem];

Paul Ishenin

2009-11-26 09:50

manager   ~0032488

Gtk2 is implemented now. Please test and close if ok.

Issue History

Date Modified Username Field Change
2006-11-03 20:18 Seth Grover New Issue
2006-11-03 20:18 Seth Grover Widgetset => GTK
2006-11-04 04:44 George Lober Note Added: 0009663
2006-11-04 11:13 Boguslaw Brandys Note Added: 0009664
2006-12-02 11:14 Vincent Snijders LazTarget => post 1.0
2006-12-02 11:14 Vincent Snijders Status new => acknowledged
2007-01-10 12:37 Vincent Snijders Relationship added related to 0007129
2007-01-10 12:37 Vincent Snijders Relationship added related to 0007130
2007-01-10 12:37 Vincent Snijders Relationship added related to 0007131
2009-02-05 16:23 Leslie Kaye Note Added: 0025144
2009-02-06 19:13 Jonas Schäfer Note Added: 0025165
2009-03-11 21:16 Alexander Grau Note Added: 0026061
2009-06-17 16:22 Alexander Grau Note Edited: 0026061
2009-06-17 16:22 Alexander Grau Note Edited: 0026061
2009-06-17 16:47 Dmitry Boyarintsev Status acknowledged => assigned
2009-06-17 16:47 Dmitry Boyarintsev Assigned To => Dmitry Boyarintsev
2009-06-17 17:28 Alexander Grau File Added: lazarus_tlistview_ownerdata.txt
2009-06-17 18:01 Alexander Grau File Added: delphi7_virtuallistview_sample.zip
2009-06-17 18:43 Alexander Grau Note Edited: 0026061
2009-07-30 20:56 Seth Grover Note Added: 0029412
2009-08-09 19:21 Dmitry Boyarintsev Note Added: 0029678
2009-08-09 19:22 Dmitry Boyarintsev File Added: viruallistview.zip
2009-08-19 18:07 Dmitry Boyarintsev File Deleted: viruallistview.zip
2009-08-19 18:07 Dmitry Boyarintsev File Added: virtuallistboxpatch.zip
2009-08-31 12:48 Dmitry Boyarintsev File Deleted: virtuallistboxpatch.zip
2009-08-31 12:49 Dmitry Boyarintsev Note Added: 0030268
2009-08-31 12:50 Dmitry Boyarintsev File Added: virtuallistbox.patch.zip
2009-09-01 18:50 Paul Ishenin Fixed in Revision => 21524
2009-09-01 18:50 Paul Ishenin LazTarget post 1.0 => -
2009-09-01 18:50 Paul Ishenin Note Added: 0030296
2009-09-01 22:41 Dmitry Boyarintsev Note Added: 0030301
2009-09-17 16:59 Sebastian Willenborg Note Added: 0030797
2009-11-26 09:50 Paul Ishenin Fixed in Revision 21524 => 21524,22789
2009-11-26 09:50 Paul Ishenin LazTarget - => 0.9.30
2009-11-26 09:50 Paul Ishenin Status assigned => resolved
2009-11-26 09:50 Paul Ishenin Fixed in Version => 0.9.29 (SVN)
2009-11-26 09:50 Paul Ishenin Resolution open => fixed
2009-11-26 09:50 Paul Ishenin Note Added: 0032488
2009-11-26 09:51 Paul Ishenin Target Version => 0.9.30
2009-12-01 18:32 Seth Grover Status resolved => closed