[Webinar] Streamline your web hosting managementRegister Today

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 2782
  • Last Modified:

TListView: changing background color for items...

Hello All,

I tried to use this code to change background color for items:
---
  with(Sender.Canvas)do begin
    if((Item.Index mod 2)=0)
    then Brush.Color:=clSilver
    else Brush.Color:=clWhite;
  end;
  DefaultDraw:=True;
---

This code normally works, but background colors is not for all item,
I mean that from left side and right side I have a white border...

How can I change this code to delete this border...

I need Listview view like Miranda IM listviews.

Thanks,
Dan
0
DanDaemon
Asked:
DanDaemon
  • 12
  • 8
  • 4
  • +2
1 Solution
 
DanDaemonAuthor Commented:
Need answer as soon as possible :)
0
 
Bart_ThomasCommented:
I assume that you use the "OnDrawItem" event.

var
  BoundsRectt: TRect;
begin
  BoundsRect := Item.DisplayRect(drSelectBounds);
  if Odd (Item.Index) then
    ListView1.Canvas.Brush.Color := clWhite
  else
    ListView1.Canvas.Brush.Color := clSilver;
  ListView1.Canvas.Brush.Style := bsSolid;
  ListView1.Canvas.FillRect(BoundsRect);
0
 
DanDaemonAuthor Commented:
strange, but your code does not work :(

all items are white.
0
Upgrade your Question Security!

Your question, your audience. Choose who sees your identity—and your question—with question security.

 
DanDaemonAuthor Commented:
Found bug, but this code has some other problem...

When you will move mouse pointer to some item and will wait, this item will be hiden... I mean text
0
 
Bart_ThomasCommented:
My mistake. Here is the complete code. Remember to set: OwnerDraw := True;

var
  OldBkMode: Integer;
  OldTextColor: TColor;
  i: Integer;
  BoundsRect,LabelRect: TRect;
begin
  BoundsRect := Item.DisplayRect(drSelectBounds);
  if Odd (Item.Index) then
    ListView1.Canvas.Brush.Color := clWhite
  else
    ListView1.Canvas.Brush.Color := clSilver;
  ListView1.Canvas.Brush.Style := bsSolid;
  ListView1.Canvas.FillRect(BoundsRect);

  (*
   * TOwnerDrawState = set of (odSelected, odGrayed, odDisabled, odChecked,
   *  odFocused, odDefault, odHotLight, odInactive, odNoAccel, odNoFocusRect,
   *  odReserved1, odReserved2, odComboBoxEdit);
   *)
  OldBkMode := GetBkMode (ListView1.Canvas.Handle);
  try
    OldTextColor := GetTextColor (ListView1.Canvas.Handle);
    try
      SetBkMode (ListView1.Canvas.Handle, TRANSPARENT);
      if (odSelected in State) then
      begin
        SetBkMode (ListView1.Canvas.Handle, OPAQUE);
        SetBkColor (ListView1.Canvas.Handle, clNavy);
        SetTextColor (ListView1.Canvas.Handle, clWhite);
      end;

      LabelRect := Item.DisplayRect(drLabel);
      OffsetRect (LabelRect, 1,0);
      InflateRect (LabelRect, -1,0);

      DrawText (ListView1.Canvas.Handle, PChar(Item.Caption),length(Item.Caption), LabelRect,
        DT_LEFT or DT_VCENTER or DT_SINGLELINE or DT_END_ELLIPSIS);

    finally
      SetTextColor (ListView1.Canvas.Handle, OldTextColor);
    end;

    SetBkMode (ListView1.Canvas.Handle, TRANSPARENT);
    LabelRect := Item.DisplayRect(drBounds);
    i := 0;
    while (i < Item.SubItems.Count) do
    begin
      OffsetRect (LabelRect, Columns[i].Width,0);
      LabelRect.Right := LabelRect.Left + Columns[1+i].Width;

      DrawText (ListView1.Canvas.Handle, PChar(Item.SubItems[i]),length(Item.SubItems[i]),
        LabelRect, DT_LEFT or DT_VCENTER or DT_SINGLELINE or DT_END_ELLIPSIS);

      inc (i);
    end;
  finally
    SetBkMode (ListView1.Canvas.Handle, OldBkMode);
  end;
0
 
vadim_tiCommented:
onDrawItem event not fired for tlistview , at least in delphi7
0
 
DanDaemonAuthor Commented:
Ok, this code works partially:

I used it for event OnCustomDrawItem with OwnerDraw in True.

1. These lines could not compile:
---
    while (i < Item.SubItems.Count) do
    begin
      OffsetRect (LabelRect, Columns[i].Width,0);
      LabelRect.Right := LabelRect.Left + Columns[1+i].Width;

      DrawText (ListView1.Canvas.Handle, PChar(Item.SubItems[i]),length(Item.SubItems[i]),
        LabelRect, DT_LEFT or DT_VCENTER or DT_SINGLELINE or DT_END_ELLIPSIS);
      //
      inc (i);
    end;
---

2. When I turned on OwnerDraw to true all items have had a very strange view.
0
 
DanDaemonAuthor Commented:
Probably this code is for Delphi version below 7?
0
 
Bart_ThomasCommented:
This is indeed D6. But it also works fine in D7.
I did set:
- ViewStyle to vsReport
- OwnerDraw to True
- RowSelect to True

Those lines contained a small error, here's the corrected part:

    while (i < Item.SubItems.Count) do
    begin
      OffsetRect (LabelRect, ListView1.Columns[i].Width,0);
      LabelRect.Right := LabelRect.Left + ListView1.Columns[1+i].Width;

      DrawText (ListView1.Canvas.Handle, PChar(Item.SubItems[i]),length(Item.SubItems[i]),
        LabelRect, DT_LEFT or DT_VCENTER or DT_SINGLELINE or DT_END_ELLIPSIS);

And the complete function again:

procedure TForm1.ListView1DrawItem(Sender: TCustomListView;
  Item: TListItem; Rect: TRect; State: TOwnerDrawState);
var
  OldBkMode: Integer;
  OldTextColor: TColor;
  i: Integer;
  BoundsRect,LabelRect: TRect;
begin
  BoundsRect := Item.DisplayRect(drSelectBounds);
  if Odd (Item.Index) then
    ListView1.Canvas.Brush.Color := clWhite
  else
    ListView1.Canvas.Brush.Color := clSilver;
  ListView1.Canvas.Brush.Style := bsSolid;
  ListView1.Canvas.FillRect(BoundsRect);

  (*
   * TOwnerDrawState = set of (odSelected, odGrayed, odDisabled, odChecked,
   *  odFocused, odDefault, odHotLight, odInactive, odNoAccel, odNoFocusRect,
   *  odReserved1, odReserved2, odComboBoxEdit);
   *)
  OldBkMode := GetBkMode (ListView1.Canvas.Handle);
  try
    OldTextColor := GetTextColor (ListView1.Canvas.Handle);
    try
      SetBkMode (ListView1.Canvas.Handle, TRANSPARENT);
      if (odSelected in State) then
      begin
        SetBkMode (ListView1.Canvas.Handle, OPAQUE);
        SetBkColor (ListView1.Canvas.Handle, clNavy);
        SetTextColor (ListView1.Canvas.Handle, clWhite);
      end;

      LabelRect := Item.DisplayRect(drLabel);
      OffsetRect (LabelRect, 1,0);
      InflateRect (LabelRect, -1,0);

      DrawText (ListView1.Canvas.Handle, PChar(Item.Caption),length(Item.Caption), LabelRect,
        DT_LEFT or DT_VCENTER or DT_SINGLELINE or DT_END_ELLIPSIS);

    finally
      SetTextColor (ListView1.Canvas.Handle, OldTextColor);
    end;

    SetBkMode (ListView1.Canvas.Handle, TRANSPARENT);
    LabelRect := Item.DisplayRect(drBounds);
    i := 0;
    while (i < Item.SubItems.Count) do
    begin
      OffsetRect (LabelRect, ListView1.Columns[i].Width,0);
      LabelRect.Right := LabelRect.Left + ListView1.Columns[1+i].Width;

      DrawText (ListView1.Canvas.Handle, PChar(Item.SubItems[i]),length(Item.SubItems[i]),
        LabelRect, DT_LEFT or DT_VCENTER or DT_SINGLELINE or DT_END_ELLIPSIS);

      inc (i);
    end;
  finally
    SetBkMode (ListView1.Canvas.Handle, OldBkMode);
  end;
end;

0
 
DanDaemonAuthor Commented:
Ok, thanks, but this code does not work in Delphi 7.

Same error with OffsetRect (LabelRect, ListView1.Columns[i].Width,0);

ERROR: Undeclared idintifier: 'Columns'
0
 
vadim_tiCommented:
Bart:

fine
row select was really missing
0
 
Bart_ThomasCommented:
This code was taken from a custom listview I created. Since I only needed to draw normal and focused items I never bothered to draw all the other states. If you want the other states it might take some work and recoding to get them all painted properly.
0
 
Pierre CorneliusCommented:
I put together some example for you to build on:

Source file:
~~~~~~~

unit main;

interface

uses
  Windows, Classes, Graphics, Controls, Forms,
  ComCtrls, StdCtrls, ExtCtrls, ImgList;

type
  TForm1 = class(TForm)
    ListView1: TListView;
    RadioGroup1: TRadioGroup;
    ImageList1: TImageList;
    procedure RadioGroup1Click(Sender: TObject);
    procedure ListView1DrawItem(Sender: TCustomListView; Item: TListItem;
      Rect: TRect; State: TOwnerDrawState);
  end;

var
  Form1: TForm1;

implementation

uses Types;

{$R *.dfm}

procedure TForm1.RadioGroup1Click(Sender: TObject);
begin
  Case Radiogroup1.ItemIndex of
    0: Listview1.ViewStyle:= vsIcon;
    1: Listview1.ViewStyle:= vsList;
    2: Listview1.ViewStyle:= vsReport;
    3: Listview1.ViewStyle:= vsSmallIcon;
  end;
end;

procedure TForm1.ListView1DrawItem(Sender: TCustomListView;
  Item: TListItem; Rect: TRect; State: TOwnerDrawState);
var r: TRect;
    i: integer;
begin
  with(Sender.Canvas)do begin
    if((Item.Index mod 2)=0)
    then Brush.Color:=clSilver
    else Brush.Color:=clWhite;
  end;
  Sender.Canvas.FillRect(Rect);
  ImageList1.Draw(Sender.Canvas, Rect.Left, Rect.Top, Item.ImageIndex);
  r:= Rect;
  r.Right:= Sender.Column[0].Width;
  r.Left:= Rect.Left+ImageList1.Width+5;
  Sender.Canvas.TextRect(r,r.Left,r.Top,Item.Caption);

  for i:= 0 to Item.SubItems.Count-1 do
  begin
    if (i+1 <= TListView(Sender).Columns.Count) then
    begin
      r.Left:= r.Right;
      r.Right:= r.Left + Sender.Column[i+1].Width;
      ImageList1.Draw(Sender.Canvas, R.Left+2, R.Top, Item.SubItemImages[i]);
      r.Left:= r.Left + ImageList1.Width + 5;
      Sender.Canvas.TextRect(r,r.Left,r.Top, Item.SubItems[i]);
    end;
  end;

  if odFocused in State then
  begin
    Sender.Canvas.Brush.Color:= clRed;
    Sender.Canvas.FrameRect(Rect);
  end;
end;

end.


DFM File:
~~~~~~

object Form1: TForm1
  Left = 192
  Top = 114
  Width = 696
  Height = 480
  Caption = 'Form1'
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'MS Sans Serif'
  Font.Style = []
  OldCreateOrder = False
  PixelsPerInch = 96
  TextHeight = 13
  object ListView1: TListView
    Left = 72
    Top = 64
    Width = 250
    Height = 121
    Columns = <
      item
      end
      item
      end
      item
      end>
    Items.Data = {
      EA0000000700000000000000FFFFFFFFFFFFFFFF000000000000000005497465
      6D3101000000FFFFFFFFFFFFFFFF0200000000000000054974656D3208537562
      4974656D31085375624974656D3202000000FFFFFFFFFFFFFFFF020000000000
      0000054974656D33085375624974656D31085375624974656D3203000000FFFF
      FFFFFFFFFFFF0000000000000000054974656D3404000000FFFFFFFFFFFFFFFF
      0000000000000000054974656D3505000000FFFFFFFFFFFFFFFF000000000000
      0000054974656D3606000000FFFFFFFFFFFFFFFF000000000000000005497465
      6D37FFFFFFFF00000100}
    LargeImages = ImageList1
    OwnerDraw = True
    SmallImages = ImageList1
    TabOrder = 0
    OnDrawItem = ListView1DrawItem
  end
  object RadioGroup1: TRadioGroup
    Left = 24
    Top = 240
    Width = 185
    Height = 105
    Caption = 'RadioGroup1'
    ItemIndex = 0
    Items.Strings = (
      'Icons'
      'List'
      'Report'
      'Small Icon')
    TabOrder = 1
    OnClick = RadioGroup1Click
  end
  object ImageList1: TImageList
    Left = 216
    Top = 24
    Bitmap = {
(* YOU MUST ADD YOUR OWN PICTURES *)
      }
  end
end



Kind Regards
Pierre
0
 
DanDaemonAuthor Commented:
Hello Pierre,

Was you resizing columns after launch your example?
Try it and you will see problems with your code.

Thanks,
Dan

P.S. I need code which is worked on 100% with Delphi 7.
0
 
Bart_ThomasCommented:
Okay, here's the entire test-unit I made
from my "component".

Regards
Bart Thomas

unit1.pas

unit Unit1;

interface

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

type
  TForm1 = class(TForm)
    ListView1: TListView;
    procedure ListView1DrawItem(Sender: TCustomListView; Item: TListItem;
      Rect: TRect; State: TOwnerDrawState);
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.ListView1DrawItem(Sender: TCustomListView;
  Item: TListItem; Rect: TRect; State: TOwnerDrawState);
var
  OldBkMode: Integer;
  OldTextColor: TColor;
  i: Integer;
  BoundsRect,LabelRect: TRect;
begin
  BoundsRect := Item.DisplayRect(drSelectBounds);
  if Odd (Item.Index) then
    ListView1.Canvas.Brush.Color := clWhite
  else
    ListView1.Canvas.Brush.Color := clSilver;
  ListView1.Canvas.Brush.Style := bsSolid;
  ListView1.Canvas.FillRect(BoundsRect);

  (*
   * TOwnerDrawState = set of (odSelected, odGrayed, odDisabled, odChecked,
   *  odFocused, odDefault, odHotLight, odInactive, odNoAccel, odNoFocusRect,
   *  odReserved1, odReserved2, odComboBoxEdit);
   *)
  OldBkMode := GetBkMode (ListView1.Canvas.Handle);
  try
    OldTextColor := GetTextColor (ListView1.Canvas.Handle);
    try
      SetBkMode (ListView1.Canvas.Handle, TRANSPARENT);
      if (odSelected in State) then
      begin
        SetBkMode (ListView1.Canvas.Handle, OPAQUE);
        SetBkColor (ListView1.Canvas.Handle, clNavy);
        SetTextColor (ListView1.Canvas.Handle, clWhite);
      end;

      LabelRect := Item.DisplayRect(drLabel);
      OffsetRect (LabelRect, 1,0);
      InflateRect (LabelRect, -1,0);

      DrawText (ListView1.Canvas.Handle, PChar(Item.Caption),length(Item.Caption), LabelRect,
        DT_LEFT or DT_VCENTER or DT_SINGLELINE or DT_END_ELLIPSIS);

    finally
      SetTextColor (ListView1.Canvas.Handle, OldTextColor);
    end;

    SetBkMode (ListView1.Canvas.Handle, TRANSPARENT);
    LabelRect := Item.DisplayRect(drBounds);
    i := 0;
    while (i < Item.SubItems.Count) do
    begin
      OffsetRect (LabelRect, ListView1.Columns[i].Width,0);
      LabelRect.Right := LabelRect.Left + ListView1.Columns[1+i].Width;

      DrawText (ListView1.Canvas.Handle, PChar(Item.SubItems[i]),length(Item.SubItems[i]),
        LabelRect, DT_LEFT or DT_VCENTER or DT_SINGLELINE or DT_END_ELLIPSIS);

      inc (i);
    end;
  finally
    SetBkMode (ListView1.Canvas.Handle, OldBkMode);
  end;
end;

procedure TForm1.FormCreate(Sender: TObject);
var
  ListItem: TListItem;
  i: Integer;
begin
  for i := 0 to 20 do
  begin
    ListItem := ListView1.Items.Add;
    ListItem.Caption := Format ('Caption(%d)', [i]);
    ListItem.SubItems.Add(Format ('Sub 1 (%d)', [i]));
    ListItem.SubItems.Add(Format ('Sub 2 (%d)', [i]));
    ListItem.SubItems.Add(Format ('Sub 3 (%d)', [i]));
  end;
end;

end.

unit1.dfm

object Form1: TForm1
  Left = 189
  Top = 107
  Width = 870
  Height = 640
  Caption = 'Form1'
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'MS Sans Serif'
  Font.Style = []
  OldCreateOrder = False
  OnCreate = FormCreate
  PixelsPerInch = 96
  TextHeight = 13
  object ListView1: TListView
    Left = 24
    Top = 8
    Width = 649
    Height = 545
    Columns = <
      item
        Caption = 'Column 1'
        Width = 100
      end
      item
        Caption = 'Column 2'
        Width = 100
      end
      item
        Caption = 'Column 3'
        Width = 100
      end
      item
        Caption = 'Column 4'
        Width = 100
      end>
    OwnerDraw = True
    RowSelect = True
    TabOrder = 0
    ViewStyle = vsReport
    OnDrawItem = ListView1DrawItem
  end
end
0
 
DanDaemonAuthor Commented:
hehe... Thank you Bart_Thomas,

But your code still has some problems, try to resize first column.

Thanks,
Dmitry
0
 
Bart_ThomasCommented:
Weird, there's nothing wrong here. I made the orginal code in D5 and tested it in D6 and D7. It works fine in all versions.
What exactly happes when you resize the first column?

Regards,
Bart Thomas
0
 
DanDaemonAuthor Commented:
0
 
Bart_ThomasCommented:
WOW! How did that happen.
Weirdly enough I can resize all I want and everything paints perfectly.

What Delphi version are you using? Paste your code please, so I can test it here.
Who knows, maybe there's a small difference somewhere between our versions.

Regards,
Bart Thomas
0
 
DanDaemonAuthor Commented:
WinXP+SP2 :)
D7+SP1+SP2
0
 
Bart_ThomasCommented:
I have Win 2K and a regular D7. I don't think the service packs are the reason, or at least not very likely. More likely is Win XP. I've see very weird things with code that works fine in 2K and screws up in XP. Maybe in XP the new columnwidth isn't set. So the next lines are the problem:

      OffsetRect (LabelRect, ListView1.Columns[i].Width,0);
      LabelRect.Right := LabelRect.Left + ListView1.Columns[1+i].Width;

Can you check if the width of the columns changes after you resize them?

Regards,
Bart Thomas
0
 
joncmoraCommented:
This works for me in a lot of projects. You should use OnCustomDrawItem.

procedure TfrmMain.lstUsersCustomDrawItem(Sender: TCustomListView;
  Item: TListItem; State: TCustomDrawState; var DefaultDraw: Boolean);
begin
  if Odd(Item.Index) then
    Sender.Canvas.Brush.Color := $00F5F5F5
  else
    Sender.Canvas.Brush.Color := clWindow;
end;
0
 
joncmoraCommented:
OwnerDraw should be set to False
0
 
DanDaemonAuthor Commented:
2 joncmora,

Do you see difference between your method and what I need?
If not, please re-read this topic again.

Thanks,
Dan.
0
 
joncmoraCommented:
Ops!

"I mean that from left side and right side I have a white border..."

I missed this part... hehehe...
0
 
joncmoraCommented:
OK, here you go...
EVENT: OnCustomDrawItem

-------------------------------------------
procedure TfrmMain.lstUsersCustomDrawItem(Sender: TCustomListView;
  Item: TListItem; State: TCustomDrawState; var DefaultDraw: Boolean);
var
  ItemRect: TRect;
begin
  if not (cdsSelected in State) then
  begin
    if (Item.Index mod 2) = 0 then
      Sender.Canvas.Brush.Color := clSilver
    else
      Sender.Canvas.Brush.Color := clWhite {do not use the same value as lstUsers.Color, clWindow looks weird...};
  end
  else
    Sender.Canvas.Brush.Color := clActiveCaption;
  ItemRect := Item.DisplayRect(drLabel);
  ItemRect.Left := ItemRect.Left - 2 {This may not be correct in another resolution, I'm using 1024x768};
  Sender.Canvas.FillRect(ItemRect);
end;
0
 
DanDaemonAuthor Commented:
2joncmora,

Thank you very much, but now you can move your cursor to this iteam and see what will happens when cursor will be there :)
Same problems that for Bart_Thomas code :(

Thanks,
Dan
0

Featured Post

[Webinar] Kill tickets & tabs using PowerShell

Are you tired of cycling through the same browser tabs everyday to close the same repetitive tickets? In this webinar JumpCloud will show how you can leverage RESTful APIs to build your own PowerShell modules to kill tickets & tabs using the PowerShell command Invoke-RestMethod.

  • 12
  • 8
  • 4
  • +2
Tackle projects and never again get stuck behind a technical roadblock.
Join Now