Performance issue with TImageList

Performanceissue with TImageList

Update: This problem is solved with Delphi 10.1 Berlin

(Deutsche übersetzung im nachfolgenden Blog Eintrag)

Description of the problem:

Adding pictures to a Imagelist within a VCL application is very slow after a the change to Delphi 10 Seattle.

Usually adding pictures is very fast – as long as you act like this:

... 
iml: TImageList; 
...  
iml.BeginUpdate; 
try   
  for x in BigList do begin     
    iml.Add(x);
  end; 
finally   
  iml.EndUpdate; 
end;

One reason for a long time to add many pictures is, that clients of the imagelist get informed about every change on the list. To send this information just once and just at the end of all inserts we use BeginUpdate and EndUpdate.

This BeginUpdate and EndUpdate does not work like it should with Delphi 10 Seattle.

To understand this we look at the source coude:

Inheritance ot the TImageList:

Base is TBaseImageList in System.ImageList.

For FMX in Unit FMX.ImgList we have TCustomImageList >> TImageList

For VCL according in Unit VCL.ImgList: TCustomImageList >> TImageList

The methods BeginUpdate and EndUpdate in the base class looks like this:

 
procedure TBaseImageList.BeginUpdate; 
begin   
  if FUpdateCount = 0 then     
    Updating;   
    Inc(FUpdateCount); 
  end;  

procedure TBaseImageList.EndUpdate; 
begin   
  if FUpdateCount > 0 then begin
     Dec(FUpdateCount);
     if FUpdateCount = 0 then
       Updated;   
     end;
 end;

Both methods does what we expect.

Unfortunately the class TCustomImageList overwrite this for VCL (not override, not virtual!):

 
procedure TCustomImageList.BeginUpdate;
 begin
   Inc(FUpdateCount);
 end;

procedure TCustomImageList.EndUpdate;
begin   
  if FUpdateCount > 0 then 
    Dec(FUpdateCount);
  if FChanged then begin     
    FChanged := False;     
    Change;
  end;
end;

Updateing and Updated is not set anymore. UpdateCount is reintroduced and is not used further. The change method of the base class will call DoChange on every add – our BeginUpdate does not have effect.

Comparison to older sources of the VCL show that something went wrong here.

The solution of this problem indeed is easy: We just use the „good“ method of the base class.

Only problem: You have to check on further delphi versions, if there are may changes in the VCL method, which we do not want to skip, cause we do not execute them from now on.

I think this dephi bug will be solved in future – so we can go back to the original code.

...
iml: TImageList;
...
TBaseImageList(iml).BeginUpdate;
try
   for x in BigList do begin
     iml.Add(x);
   end;
 finally
   TBaseImageList(iml).EndUpdate;
 end;

Schreibe einen Kommentar