softbreeze
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
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
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,aStre et: 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','12 3 street');
LoadItem(0,'Jack','ERR','2 23-4567',' 223 street');
LoadItem(0,'Bill','ERR','2 23-4567',' 223 street');
LoadItem(1,'Mary','OK','32 3-4567','3 23 street');
LoadItem(0,'Dick','ERR','4 23-4567',' 423 street');
LoadItem(1,'Spot','OK','52 3-4567','5 23 street');
LoadItem(1,'John','OK','62 3-4567','6 23 street');
end;
//======================== ========== ========== ========
//======================== ========== ========== ========
procedure TForm1.LoadItem(aState: Integer; aName,aStatus,aPhone,aStre et: 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].Disp layRect(dr Bounds);
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,Offse t,cIndent, Col,LI.Cap tion);
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,Offse t,cIndent, Col,LI.Sub Items[si]) ;
Offset := Offset + TLV.Columns.Items[Col].Wid th;
end;
end;
end;
//======================== ========== ========== ========
//======================== ========== ========== ========
procedure TForm1.DrawTextInRect(Send er: 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].Wid th - 1;
R.Bottom := Rect.Bottom;
if (TLV.Column[Col].Alignment <> taCenter) then
R.Left := R.Left + Indent;
DrawText(TLV.Canvas.Handle ,PCHar(Tex t),-1,R,WF ormat);
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
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,aStre
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
LoadItem(0,'Jack','ERR','2
LoadItem(0,'Bill','ERR','2
LoadItem(1,'Mary','OK','32
LoadItem(0,'Dick','ERR','4
LoadItem(1,'Spot','OK','52
LoadItem(1,'John','OK','62
end;
//========================
//========================
procedure TForm1.LoadItem(aState: Integer; aName,aStatus,aPhone,aStre
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].Disp
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,Offse
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,Offse
Offset := Offset + TLV.Columns.Items[Col].Wid
end;
end;
end;
//========================
//========================
procedure TForm1.DrawTextInRect(Send
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].Wid
R.Bottom := Rect.Bottom;
if (TLV.Column[Col].Alignment
R.Left := R.Left + Indent;
DrawText(TLV.Canvas.Handle
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
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
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,aStre et: 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','12 3 street');
LoadItem(0,'Jack','ERR','2 23-4567',' 223 street');
LoadItem(0,'Bill','ERR','2 23-4567',' 223 street');
LoadItem(1,'Mary','OK','32 3-4567','3 23 street');
LoadItem(0,'Dick','ERR','4 23-4567',' 423 street');
LoadItem(1,'Spot','OK','52 3-4567','5 23 street');
LoadItem(1,'John','OK','62 3-4567','6 23 street');
end;
procedure TForm1.LoadItem(aState: Integer; aName,aStatus,aPhone,aStre et: 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(Se nder: 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.Inde x],R,Offse t);
// Draw caption
LI := LV.Items[Item.Index];
DrawTextInRect(LV,R,Offset ,cIndent,0 ,LI.Captio n);
// 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,C ol,LI.SubI tems[si]);
Offset := Offset + LV.Columns.Items[Col].Widt h;
end;
end;
end;
procedure TForm1.DrawStateImage(Send er: 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,I tem.StateI ndex);
end;
end;
procedure TForm1.DrawTextInRect(Send er: 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].Wid th - 1;
R.Bottom := Rect.Bottom;
if (TLV.Column[Col].Alignment <> taCenter) then
R.Left := R.Left + Indent;
DrawText(TLV.Canvas.Handle ,PCHar(Tex t),-1,R,WF ormat);
end;
end.
//========================
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,aStre
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
LoadItem(0,'Jack','ERR','2
LoadItem(0,'Bill','ERR','2
LoadItem(1,'Mary','OK','32
LoadItem(0,'Dick','ERR','4
LoadItem(1,'Spot','OK','52
LoadItem(1,'John','OK','62
end;
procedure TForm1.LoadItem(aState: Integer; aName,aStatus,aPhone,aStre
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(Se
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
// Draw caption
LI := LV.Items[Item.Index];
DrawTextInRect(LV,R,Offset
// 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
Offset := Offset + LV.Columns.Items[Col].Widt
end;
end;
end;
procedure TForm1.DrawStateImage(Send
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,
end;
end;
procedure TForm1.DrawTextInRect(Send
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].Wid
R.Bottom := Rect.Bottom;
if (TLV.Column[Col].Alignment
R.Left := R.Left + Indent;
DrawText(TLV.Canvas.Handle
end;
end.
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