我有一个后台线程向主线程发送消息,而主线程又像日志一样将消息添加到TListBox中。
问题是,这个后台线程非常快,我真的不需要更新日志那么快。我希望将消息添加到TStringList中,并设置一个计时器来每秒钟更新一次TListBox。
我试过用:
listBox1.Items := StringList1;或
listBox1.Items.Assign(StringList1);在OnTimer事件中,它可以工作。问题是,它从不让用户真正滚动或单击列表框,因为它每秒钟刷新一次。
我用的是德尔菲XE4
是否有更优雅的方法将列表框的内容与此背景StringList (或任何其他列表(如有必要)同步)?提前谢谢你!
发布于 2013-09-12 16:35:01
使用虚拟方法
将ListBox的ListBox属性设置为lbVirtual,并分配OnData事件,让它请求绘制控件所需的字符串,而不是拥有在每次更新时重置整个控件的字符串。说明性代码:
unit Unit1;
interface
uses
Windows, Messages, Classes, Controls, Forms, AppEvnts, StdCtrls, ExtCtrls;
type
TForm1 = class(TForm)
ApplicationEvents1: TApplicationEvents;
ListBox1: TListBox;
Timer1: TTimer;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure ListBox1Data(Control: TWinControl; Index: Integer;
var Data: String);
procedure ApplicationEvents1Idle(Sender: TObject; var Done: Boolean);
procedure Timer1Timer(Sender: TObject);
private
FStrings: TStringList;
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);
begin
FStrings := TStringList.Create;
FStrings.CommaText := 'A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z';
ListBox1.Count := FStrings.Count;
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
FStrings.Free;
end;
procedure TForm1.ListBox1Data(Control: TWinControl; Index: Integer;
var Data: String);
begin
Data := FStrings[Index];
end;
procedure TForm1.ApplicationEvents1Idle(Sender: TObject; var Done: Boolean);
begin
FStrings[Random(FStrings.Count)] := Chr(65 + Random(26));
end;
procedure TForm1.Timer1Timer(Sender: TObject);
begin
ListBox1.Invalidate;
end;
end.在本例中,我使用OnIdle组件的TApplicationEvents事件来模拟StringList的线程更新。注意,您现在可以滚动并选择ListBox中的项,尽管计时器有1秒的更新间隔。
同步项目计数
StringList的项计数的更改也需要反映在ListBox中。这需要由ListBox1.Count := FStrings.Count来完成,但是ListBox外观将再次被重置。因此,需要一种解决办法,暂时阻止它一起重新绘制/更新:
procedure TForm1.Timer1Timer(Sender: TObject);
begin
if Random(2) = 0 then
begin
FStrings.Add('A');
SyncListCounts;
end
else
ListBox1.Invalidate;
end;
procedure TForm1.SyncListCounts;
var
SaveItemIndex: Integer;
SaveTopIndex: Integer;
begin
ListBox1.Items.BeginUpdate;
try
SaveItemIndex := ListBox1.ItemIndex;
SaveTopIndex := ListBox1.TopIndex;
ListBox1.Count := FStrings.Count;
ListBox1.ItemIndex := SaveItemIndex;
ListBox1.TopIndex := SaveTopIndex;
finally
ListBox1.Items.EndUpdate;
end;
end;https://stackoverflow.com/questions/18768559
复制相似问题