XE中FMX操作ListBox,添加上千条记录(含图片)
我之前是想在ListBox的每个Item上添加一个图片,Item上所有的内容都是放在Object里赋值,结果发现加载一百条记录耗时四五秒:
procedure TMainForm.AddItem; var o : TListBoxItem; o1 : TFrm; begin o := TListBoxItem.Create(self); // 创建对象 o.Height := 128; o1 :=TFrm.Create(o); // 创建TFrm o1.Parent:=o; ListBox1.AddObject(o); end; var s, temp: string; x: IMember; begin if FJV <> Value then begin FJV := Value; for x in Value do begin // x为遍历所有Item框架上的组件的值 s := x.AsString; if x.Name = 'IPNR' then IPNR .Text := s else if x.Name = 'IPNColor' then IPNColor .Text := s else if x.Name = 'ITime' then ITime .Text := s else if x.Name = 'OTime' then OTime .Text := s else if x.Name = 'PName' then PName .Text := s else if x.Name = 'IGateName' then IGateName.Text := s else if x.Name = 'OGateName' then OGateName.Text := s else if x.Name = 'IMobileNo' then IMobileNo.Text := s else if x.Name = 'State' then timer1.Enabled := True; ; end;
end;
这里加载图片,我还是用线程异步加载的,速度还是不行:
procedure TMainForm.DrawImg(); var i: integer; o: TImage; fn:string; begin // 取 TThread.CreateAnonymousThread(procedure var y : IMember; begin i:=length(bmps); if(i<>FNs.Count)and(FNs.Count>0) then begin SetLength(bmps,FNs.Count); for y in FNs do if y.AsInteger=-1 then begin bmps[i]:=TBitmap.CreateFromFile(y.Name); FNs.I[y.Name]:=i; inc(i); end; end; // 显示 TThread.Synchronize(TThread.CurrentThread, procedure var z: IMember; begin i:=0; for z in JV do begin o :=TFrm(ListBox1.ListItems[i].FindComponent('Frm')).Image1; fn:=z.AsObject.S['IImagePath']; o.Visible := FNs.Contains(fn); if(o.Visible) then o.Bitmap.Assign(bmps[FNs.I[fn]]); inc(i); end; end); end).Start; end;
然后我将图片压缩,压缩后倒是快了那么一两秒,但是如果数据量大的话,还是有很明显的延迟效果:
uses Vcl.Imaging.jpeg;
{fn1为压缩前的图片路径,fn2为压缩后的图片路径} procedure CutImg(fn1:string; fn2:string); var jpg: TJpegImage; bmp: TBitmap; begin jpg := TJpegImage.Create; bmp := TBitmap.Create; try if FileExists(fn1) then begin jpg.LoadFromFile(fn1); if jpg.Width > 320 then begin bmp.Width := 320; //jpg.Width; 经测试的宽度 bmp.Height:= 256; //jpg.Height; bmp.Canvas.StretchDraw(bmp.Canvas.ClipRect, jpg); jpg.Assign(bmp); jpg.CompressionQuality := 30; jpg.Compress; //压缩 jpg.SaveToFile(fn2); end; end; finally bmp.Free; jpg.Free; end; end;
最后通过别人那里知道XE中ListBox有style模板,看XE自带的原码,目录在C:\Users\Public\Documents\Embarcadero\Studio\14.0\Samples\Object Pascal\FireMonkey Desktop\CustomListBox\CustomListBox.dpr;
这个例子就是导入一千条记录,简直就只需要一秒,速度太快了,XE支持这个功能真是太好了。然后我把之前的框架换成了style(style用XE6还是有很多bug的,后来我换成了XE8,这里自己摸),速度提高了几倍:
for x in jo do with item do begin s := x.AsString.Replace('/', '\'); if x.Name = 'IPNR' then StylesData['IPNR.Text' ] := s else if x.Name = 'IPNColor' then StylesData['IPNColor.text' ] := s else if x.Name = 'ITime' then StylesData['ITime.text' ] := s else if x.Name = 'OTime' then StylesData['OTime.text' ] := s else if x.Name = 'PName' then StylesData['PName.text' ] := s else if x.Name = 'IGateName' then StylesData['IGateName.text' ] := s else if x.Name = 'OGateName' then StylesData['OGateName.text' ] := s else if x.Name = 'IMobileNo' then StylesData['IMobileNo.text' ] := s else if x.Name = 'IImagePath' then if s <> '' then StylesData['Image1.Bitmap' ] := bmps[s] else
bmps为TDictionary<string, TBitmap>类;需要uses Generics.Collections;
这是泛型,存放一个key,和key对应的Value:
t:=1; o:=FileToStream('c:/123.jpg');
bmps.Add(t, o);
取值时为 Image1.Bitmap := bmps[s]
这样简单了很多,少了很多代码,快了很多时间。