我有问题。在ListView
中使用含有500个项目的项目列表时,它不会滞后,但是当它包含超过1000个项目时,在滚动项目列表时会滞后。
以下是我的开始:
procedure thread.ListViewAdd;
begin
Item:=Form1.ListView1.Items.Add;
Item.SubItems.Add('2 column');
Item.SubItems.Add('3 column');
Item.SubItems.Add('4 column');
Item.SubItems.Add('5 column');
end;
然后我在thread.Execute
中同步了这个程序:
procedure thread.ListViewAdd;
begin
ListView.Items.BeginUpdate;
try
Item:=Form1.ListView1.Items.Add;
Item.SubItems.Add('2 column');
Item.SubItems.Add('3 column');
Item.SubItems.Add('4 column');
Item.SubItems.Add('5 column');
finally
ListView.Items.EndUpdate;
end;
已经解决了这个问题。问题出在这里:
procedure TForm1.ListView1CustomDrawItem(Sender: TCustomListView;
Item: TListItem; State: TCustomDrawState; var DefaultDraw: Boolean);
var
i:integer;
begin
for i:=0 to Form1.ListView1.Items.Count-1 do
begin
Form1.ListView1.Items[i].Caption:=IntToStr(i+1);
end;
end;
这段代码一直在更新项目,所以它落后了
答案 0 :(得分:2)
使用数据类和第二个线程进行UI通知。
uses
System.Generics.Collections,
System.Classes,
System.SyncObjs;
type
TNotifyItems<T> = procedure( Sender : TObject; AItems : TArray<T> ) of object;
TNotificationThread<T : class> = class( TThread )
private
// Synchroobjects
FCS : TCriticalSection;
FEvent : TEvent;
// Cache
FItems : TObjectList<T>;
// Event
FOnNotify : TNotifyItems<T>;
// Getter/Setter
function GetOnNotify : TNotifyItems<T>;
procedure SetOnNotify( const Value : TNotifyItems<T> );
// Notification
procedure DoNotifyItems;
protected
procedure Execute; override;
procedure TerminatedSet;
public
constructor Create;
destructor Destroy; override;
procedure EnqueueItem( AItem : T );
// Event
property OnNotify : TNotifyItems<T> read GetOnNotify write SetOnNotify;
end;
implementation
procedure TNotificationThread<T>.Execute;
begin
inherited;
while not Terminated do
begin
// waiting for 1000ms before next notify
if FEvent.WaitFor( 1000 ) = wrTimeOut
then
Synchronize( DoNotifyItems );
end;
end;
procedure TNotificationThread<T>.DoNotifyItems;
var
LItems : TList<T>;
LOnNotify : TNotifyItems<T>;
begin
LItems := TObjectList<T>.Create( true );
try
FCS.Enter;
try
// Get the Items and the event
FItems.OwnsObjects := False;
try
LItems.AddRange( FItems );
FItems.Clear;
finally
FItems.OwnsObjects := true;
end;
LOnNotify := FOnNotify;
finally
FCS.Leave;
end;
if Assigned( LOnNotify ) and ( LItems.Count > 0 )
then
LOnNotify( Self, LItems.ToArray );
finally
LItems.Free;
end;
end;
constructor TNotificationThread<T>.Create;
begin
inherited Create( False );
FCS := TCriticalSection.Create;
FEvent := TEvent.Create( nil, False, False, '' );
FItems := TObjectList<T>.Create;
end;
destructor TNotificationThread<T>.Destroy;
begin
inherited;
FItems.Free;
FEvent.Free;
FCS.Free;
end;
procedure TNotificationThread<T>.TerminatedSet;
begin
inherited;
FEvent.SetEvent;
end;
function TNotificationThread<T>.GetOnNotify : TNotifyItems<T>;
begin
FCS.Enter;
try
Result := FOnNotify;
finally
FCS.Leave;
end;
end;
procedure TNotificationThread<T>.SetOnNotify( const Value : TNotifyItems<T> );
begin
FCS.Enter;
try
FOnNotify := Value;
finally
FCS.Leave;
end;
end;
procedure TNotificationThread<T>.EnqueueItem( AItem : T );
begin
FCS.Enter;
try
FItems.Add( AItem );
finally
FCS.Leave;
end;
end;
现在从工作线程中向NotificationThread提供数据并继续工作。
procedure TWorkingThread.Execute;
begin
inherited;
while not Terminated do
begin
// do some work
...
// Notify progress, thats all here
FDataItemNotifier.EnqueueItem( TDataItem.Create( 'Caption', '2 column', '3 column' ) );
end;
end;
您的表单现在需要该通知事件的事件处理程序
procedure TMyForm.DataItemNotification( Sender : TObject; AItems : TArray<TDataItem> );
var
LItem : TDataItem;
LListItem : TListItem;
begin
// now updating the ListView with a bunch of data
ListView1.Items.BeginUpdate;
try
for LItem in AItems do
begin
LListItem := ListView1.Items.Add;
LListItem.Caption := LItem.Data1Str;
LListItem.SubItems.Add( LItem.Data2Str );
LListItem.SubItems.Add( LItem.Data3Str );
end;
finally
ListView1.Items.EndUpdate;
end;
end;