Link to home
Start Free TrialLog in
Avatar of softbreeze
softbreezeFlag for United States of America

asked on

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
Avatar of Maasdriel
Maasdriel
Flag of Netherlands image

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
Avatar of softbreeze

ASKER

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
ASKER CERTIFIED SOLUTION
Avatar of Maasdriel
Maasdriel
Flag of Netherlands image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
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.