bs20103
bs20103

Reputation: 21

ListView Column Resize in Delphi XE4

I face a issue with dynamically resizing the column width of a TJVListview in Delphi XE4 (in Windows 7 environment). Application takes longer time for column resize and sometimes throws access violation if there are huge data on the listview. We are using the below code for resizing the columns.

for i := 0 to LV.Columns.Count -1 do
begin
  if LV.Columns.Items[i].Tag = 0 then
  begin
    LV.Columns.Items[i].Width := ColumnTextWidth;
    LV.Columns.Items[i].Width := ColumnHeaderWidth;
  end;
end;

Previously the same code used to work fine with Delphi 2009. The problem I noticed only when we are using customdrawitem event(Where we are placing images inside the listview). For the normal listview with only text display the above code is working fine.

I tried using the Column AutoSize property by setting it true, but it is of no use.

Any suggestion on how to overcome this issue. Actually, we are using the TJVlistview component in number of places in our application.

Regards, Siran.

cODE :

1) In my form I have a JVListview, Button and imagelist. Button for loading into List view. 2) in Advancecustomdrawitem, I try to place a BMP control and also perform alternative row color change...

procedure TForm1.Button1Click(Sender: TObject);
var
  i, ii: Integer;
  ListItem: TListItem;
  strVal : String;
begin
  strVal := 'Test String';
  try
    ListView.Items.BeginUpdate;
    LockWindowUpdate(listview.handle);
    try
      ListView.Clear;
      for i := 1 to 15 do
      begin
        ListItem := ListView.Items.Add;
        ListItem.SubItems.Add(strVal +'_' +IntToStr(i));
        ListItem.SubItems.Add(strVal +'_' +IntToStr(i));
        ListItem.SubItems.Add(strVal +'_' +IntToStr(i));
        ListItem.SubItems.Add(strVal +'_' +IntToStr(i));
        ListItem.SubItems.Add(strVal +'_' +IntToStr(i));
     end;
    finally
      // for resizing the columns based on the text size
      FitToTextWidth(ListView);
      ListView.Items.EndUpdate;
      LockWindowUpdate(0);
    end;
  except
    on E: Exception do
      MessageDlg(PWideChar(E.Message), TMsgDlgType.mtError, [TMsgDlgBtn.mbOK], 0);
  end;
end;


procedure TForm1.FitToTextWidth(LV: TListView);
var
i : integer;
begin
  // Set the Column width based on based on textwidth and headerwidth
  for i := 0 to LV.Columns.Count -1 do
  begin
    if LV.Columns.Items[i].Tag = 0 then
    begin
      LV.Columns.Items[i].Width := ColumnTextWidth;
      LV.Columns.Items[i].Width := ColumnHeaderWidth;
    end;
  end;
end;

procedure TForm1.LISTVIEWAdvancedCustomDrawItem(Sender: TCustomListView;
  Item: TListItem; State: TCustomDrawState; Stage: TCustomDrawStage;
  var DefaultDraw: Boolean);
       Var
R   : TRect;
C : TCanvas;
B : TBitMap;
begin
  // Set C
  C := (Sender as TListView).Canvas;
  // Set R
  R := Item.DisplayRect(drLabel);
  B := TBitMap.Create;
  B.Transparent := True;
  B.TransparentColor := clWhite;
  // based on item index set the image and change the row color
  if odd(item.Index) = true then
  begin
     ImageList.GetBitmap(0,B);
     TJvListItem( Item ).Brush.Color := clWhite;
     TJvListItem( Item ).Font.Color  := clBlack;
  end
  else
  begin
    ImageList.GetBitmap(1,B);
    TJvListItem( Item ).Brush.Color := clMoneyGreen;
    TJvListItem( Item ).Font.Color  := clBlack;
  end;
  C.Draw(R.Left + 5 ,R.Top, B);
  B.Free;
end;

The above code works well with Delphi 2009... but currently trying migrating to XE4 in Win 7 environment.. my problem here is, it takes lot of time in loading the list view (When performing column resizing dynamically by calling FitToTextWidth method) .. but without this method it is working fine but without column resizing...

Upvotes: 0

Views: 3315

Answers (1)

Sertac Akyuz
Sertac Akyuz

Reputation: 54832

When you set the width of a column to any one of the automatic constants, the control have to evaluate the length of the items/subitems to be able to calculate the necessary width. This takes time.

Also, when you set the width of a column, the VCL ListView updates all columns.

You have six columns, setting the width of any one of them involves 6 column updates, together with the spurious call in your FitToTextWidth procedure, your code is causing reading all items/subitems of a column 42 times (due to the code path in VCL: 1 time for 1st col, 2 times for 2nd -> 21 times for setting the width of 6 columns). Enclose your width setting in Begin/EndUpdate calls and remove the extra call, and you'll finish it in 6 rounds.

procedure TForm1.FitToTextWidth(LV: TListView);
var
i : integer;
begin
  // Set the Column width based on based on textwidth and headerwidth
  LV.Columns.BeginUpdate;
  try
    for i := 0 to LV.Columns.Count -1 do
    begin
      if LV.Columns.Items[i].Tag = 0 then
      begin
//        LV.Columns.Items[i].Width := ColumnTextWidth;
        LV.Columns.Items[i].Width := ColumnHeaderWidth;
      end;
    end;
  finally
    LV.Columns.EndUpdate;
  end;
end;


As I don't get any AV with your test case, I cannot comment on that.

Upvotes: 1

Related Questions