TListView using vsReport resizing columns does not force draw of items

I have a TListView using vsReport with 4 columns that each contain text. I am also using the OnDrawItem event with OwnerDraw := TRUE to draw the icon and text and alternating row color.

When I resize a column the data is the rows does not get redrawn.  I want the rows to redraw as I resize the column.  What happens is that if you drag the column splitter to enlarge the column you get text from the adjacent column in the resized column.  I have a sample program if that would help.

I've tried using ListView.Repaint, ListView.Refresh, ListView.Update.

What message do I need to send to get the redraw real time?

I'm using Delphi 2005 w/update3 and XP w/sp2
LVL 1
softbreezeAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

MaasdrielCommented:
Don't use OwnerDraw := True. Set it to false.

You can still do custom drawing. When you set it to True, the VCL thinks your doing it al by yourself, that's not whta you want i guess.

Good Luck!

Greetings
Koen Pijnenburg
softbreezeAuthor Commented:
If I set the OwnerDraw := FALSE the column resize problem goes away. However, I need to have it set to TRUE so that the drawing I do during the OnDrawItem event.  

Below is my code.  The form has only a TListView component with Style set to vsReport and OwnerDraw set to TRUE. There are four columns.

Once the program is running pull any of the header column splitters to the right and you will see the problem I'm having.

//======================================
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ComCtrls, ImgList;

type
  TForm1 = class(TForm)
    LV: TListView;
    procedure LVDrawItem(Sender: TCustomListView; Item: TListItem; Rect: TRect;
      State: TOwnerDrawState);
    procedure FormCreate(Sender: TObject);
  private
    procedure LoadItem(aState: Integer; aName,aStatus,aPhone,aStreet: String);
    procedure DrawTextInRect(Sender: TCustomListView; Rect: TRect;
                                   Offset, Indent, Col: Integer; Text: String);
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

//====================================================
//====================================================
procedure TForm1.FormCreate(Sender: TObject);
begin
     LoadItem(1,'Bob','OK','123-4567','123 street');
     LoadItem(0,'Jack','ERR','223-4567','223 street');
     LoadItem(0,'Bill','ERR','223-4567','223 street');
     LoadItem(1,'Mary','OK','323-4567','323 street');
     LoadItem(0,'Dick','ERR','423-4567','423 street');
     LoadItem(1,'Spot','OK','523-4567','523 street');
     LoadItem(1,'John','OK','623-4567','623 street');
end;

//====================================================
//====================================================
procedure TForm1.LoadItem(aState: Integer; aName,aStatus,aPhone,aStreet: String);
var
   LI:    TListItem;
begin
     LI := LV.Items.Add;
     LI.StateIndex := aState;
     LI.Caption := aName;
     LI.SubItems.Add(aStatus);
     LI.SubItems.Add(aPhone);
     LI.SubItems.Add(aStreet);
end;

//====================================================
//====================================================
procedure TForm1.LVDrawItem(Sender: TCustomListView; Item: TListItem;
  Rect: TRect; State: TOwnerDrawState);
const
  cIndent = 5;
var
   R:            TRect;
   Stripe:       TColor;
   TLV:          TListView;
   LI:           TListItem;
   FontColor:    TColor;
   Offset:       Integer;
   Col:          Integer;
   si:           Integer;
begin
     TLV := (Sender as TListView);
     FontColor := TLV.Canvas.Font.Color;
     R := TLV.Items[Item.Index].DisplayRect(drBounds);
     Stripe := clWhite;
     if (Odd(Item.Index)) then Stripe := $EAEAD5;
     TLV.Canvas.Font.Color := clBlack;
     TLV.Canvas.Font.Name := 'Tahoma';
     TLV.Canvas.Brush.Color := Stripe;
     if (odSelected in State) then
       TLV.Canvas.Brush.Color := $EDEDA5;
     TLV.Canvas.FillRect(R);
     // Draw caption
     LI := TLV.Items[Item.Index];
     Col := 0;
     OffSet := 0;
     DrawTextInRect(TLV,R,Offset,cIndent,Col,LI.Caption);
     Offset := TLV.Columns[Col].Width;
     // Draw subitems
     if (LI.SubItems.Count > 0) then
       begin
       for si := 0 to LI.SubItems.Count - 1 do
         begin
         Col := si + 1;
         TLV.Canvas.Font.Color := FontColor;
         if ((Col = 1) and (Text = 'ERR')) then
            TLV.Canvas.Font.Color := clRed;
         DrawTextInRect(TLV,R,Offset,cIndent,Col,LI.SubItems[si]);
         Offset := Offset + TLV.Columns.Items[Col].Width;
         end;
       end;
end;

//====================================================
//====================================================
procedure TForm1.DrawTextInRect(Sender: TCustomListView; Rect: TRect;
                                   Offset, Indent, Col: Integer; Text: String);
const
  WDefault = DT_END_ELLIPSIS or DT_SINGLELINE or DT_VCENTER or DT_NOPREFIX;
var
   TLV:           TListView;
   WFormat:       Cardinal;
   R:             TRect;
begin
     TLV := Sender as TListView;
     WFormat := WDefault;
     case TLV.Column[Col].Alignment of
       taLeftJustify:    WFormat := WFormat or DT_LEFT;
       taRightJustify:   WFormat := WFormat or DT_RIGHT;
       taCenter:         WFormat := WFormat or DT_CENTER;
       end;
     R.Left := Rect.Left+Offset;
     R.Top := Rect.Top;
     R.Right := R.Left + TLV.Columns.Items[col].Width - 1;
     R.Bottom := Rect.Bottom;
     if (TLV.Column[Col].Alignment <> taCenter) then
       R.Left := R.Left + Indent;
     DrawText(TLV.Canvas.Handle,PCHar(Text),-1,R,WFormat);
end;

end.

// Form:
object Form1: TForm1
  Left = 0
  Top = 0
  Width = 474
  Height = 248
  Caption = 'Form1'
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'Tahoma'
  Font.Style = []
  OldCreateOrder = False
  OnCreate = FormCreate
  PixelsPerInch = 96
  TextHeight = 13
  object LV: TListView
    Left = 12
    Top = 10
    Width = 437
    Height = 199
    Columns = <
      item
        Caption = 'Name'
        Width = 100
      end
      item
        Alignment = taCenter
        Caption = 'Status'
      end
      item
        Caption = 'Phone'
        Width = 110
      end
      item
        AutoSize = True
        Caption = 'Street'
      end>
    FlatScrollBars = True
    GridLines = True
    OwnerDraw = True
    ReadOnly = True
    RowSelect = True
    TabOrder = 0
    ViewStyle = vsReport
    OnDrawItem = LVDrawItem
  end
end
MaasdrielCommented:
Set the Ownerdraw to False

Try to do your drawing in the OnCustomDrawItem instead of the DrawItem of the listview.

If you set the OwnerDraw property to True and you call the OnDrawItem event you will override the function.

Greetings
Koen Pijnenburg

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
softbreezeAuthor Commented:
Here is the working code if others can benefit from it:  OwnerDraw := FALSE

//========================================
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ComCtrls, ImgList;

type
  TForm1 = class(TForm)
    DefImages: TImageList;
    LV: TListView;
    procedure LVCustomDrawItem(Sender: TCustomListView; Item: TListItem;
      State: TCustomDrawState; var DefaultDraw: Boolean);
    procedure FormCreate(Sender: TObject);
  private
    procedure LoadItem(aState: Integer; aName,aStatus,aPhone,aStreet: String);
    procedure DrawStateImage(Sender: TCustomListView; Item: TListItem;
                                   Rect: TRect; var Offset: Integer);
    procedure DrawTextInRect(Sender: TCustomListView; Rect: TRect;
                                   Offset, Indent, Col: Integer; Text: String);
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}
const
  cIndent = 5;
  cStripe = $EAEAD5;
  cHighlight = $EDEDA5;

procedure TForm1.FormCreate(Sender: TObject);
begin
     LoadItem(1,'Bob','OK','123-4567','123 street');
     LoadItem(0,'Jack','ERR','223-4567','223 street');
     LoadItem(0,'Bill','ERR','223-4567','223 street');
     LoadItem(1,'Mary','OK','323-4567','323 street');
     LoadItem(0,'Dick','ERR','423-4567','423 street');
     LoadItem(1,'Spot','OK','523-4567','523 street');
     LoadItem(1,'John','OK','623-4567','623 street');
end;

procedure TForm1.LoadItem(aState: Integer; aName,aStatus,aPhone,aStreet: String);
var
   LI:    TListItem;
begin
     LI := LV.Items.Add;
     LI.StateIndex := aState;
     LI.Caption := aName;
     LI.SubItems.Add(aStatus);
     LI.SubItems.Add(aPhone);
     LI.SubItems.Add(aStreet);
end;

procedure TForm1.LVCustomDrawItem(Sender: TCustomListView; Item: TListItem;
  State: TCustomDrawState; var DefaultDraw: Boolean);
var
   LV:         TListView;
   LI:         TListItem;
   R:          TRect;
   Stripe:     TColor;
   Offset:     Integer;
   si:         Integer;
   Col:        Integer;
   FontColor:  TColor;
begin
     DefaultDraw := FALSE;
     R := Item.DisplayRect(drBounds);
     LV := Sender as TListView;
     Stripe := clWhite;
     FontColor := LV.Canvas.Font.Color;
     if (Odd(Item.Index)) then Stripe := cStripe;
     if (cdsSelected in State) then Stripe := cHighlight;
     LV.Canvas.Brush.Color := Stripe;
     LV.Canvas.FillRect(R);
     // Draw state image
     DrawStateImage(LV,LV.Items[Item.Index],R,Offset);
     // Draw caption
     LI := LV.Items[Item.Index];
     DrawTextInRect(LV,R,Offset,cIndent,0,LI.Caption);
     // Draw caption and subitems
     Offset := LV.Columns[0].Width;
     if (LI.SubItems.Count > 0) then
       begin
       for si := 0 to LI.SubItems.Count - 1 do
         begin
         Col := si + 1;
         LV.Canvas.Font.Color := FontColor;
         if ((Col = 1) and (Text = 'ERR')) then
            LV.Canvas.Font.Color := clRed;
         DrawTextInRect(LV,R,Offset,cIndent,Col,LI.SubItems[si]);
         Offset := Offset + LV.Columns.Items[Col].Width;
         end;
       end;
end;

procedure TForm1.DrawStateImage(Sender: TCustomListView; Item: TListItem;
                                   Rect: TRect; var Offset: Integer);
var
   TLV:           TListView;
   StateImg:      TCustomImageList;
begin
     TLV := Sender as TListView;
     StateImg := TLV.StateImages;
     if (StateImg <> nil) then
       begin
       Offset := StateImg.Width;
       if (Item.StateIndex <> -1) then
         DefImages.Draw(TLV.Canvas,Rect.Left,Rect.Top,Item.StateIndex);
       end;
end;

procedure TForm1.DrawTextInRect(Sender: TCustomListView; Rect: TRect;
                                   Offset, Indent, Col: Integer; Text: String);
const
  WDefault = DT_END_ELLIPSIS or DT_SINGLELINE or DT_VCENTER or DT_NOPREFIX;
var
   TLV:           TListView;
   WFormat:       Cardinal;
   R:             TRect;
begin
     TLV := Sender as TListView;
     WFormat := WDefault;
     case TLV.Column[Col].Alignment of
       taLeftJustify:    WFormat := WFormat or DT_LEFT;
       taRightJustify:   WFormat := WFormat or DT_RIGHT;
       taCenter:         WFormat := WFormat or DT_CENTER;
       end;
     R.Left := Rect.Left+Offset;
     R.Top := Rect.Top;
     R.Right := R.Left + TLV.Columns.Items[col].Width - 1;
     R.Bottom := Rect.Bottom;
     if (TLV.Column[Col].Alignment <> taCenter) then
       R.Left := R.Left + Indent;
     DrawText(TLV.Canvas.Handle,PCHar(Text),-1,R,WFormat);
end;

end.
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Delphi

From novice to tech pro — start learning today.