如何自画ListView的Item(XP效果)

关于VCL控件自画的代码先前ccrun发过很多,比如TListBox, TCheckListbox, TComboBox, TMenuItem等,下面的代码是自绘TListItem,也就是ListView在ViewStyle为vsReport时Item的自画。效果图如下:


首先定义几个我们需要用到的颜色,这里用的是Office 2003菜单的高亮条颜色:

#define MYCOLOR_BACK TColor(0x00CFB9B1)
#define MYCOLOR_BORDER clHighlight
#define MYCOLOR_ROW TColor(RGB(240, 240, 240))

一般来讲,VCL中提供了自画功能的控件都有类似OnDrawXX或OnCustomDrawXX的事件,ListView有四个类似的事件,这个例子中我们使用OnDrawItem事件。

在窗体的头文件中,声明一下自画函数,可以放在Form类的__published段内,需要注意的是,由IDE自动产生的ListViewOnDrawItem自画函数的参数和我们声明的这个略有不同,所以在设计界面上,ListView的OnDrawItem中是看不到这个函数的。

private:    // User declarations
    void __fastcall CrnDrawListViewItem(TCustomListView *Sender,
            TListItem *Item, TRect &Rect, TOwnerDrawState State);

下面是自画函数的具体实现代码:
//---------------------------------------------------------------------------
// 自画ListView的Item
// by ccrun(老妖) info#ccrun.com
// 欢迎光临 C++Builder研究 - http://www.ccrun.com
// 做人要厚道,转载要留名
//---------------------------------------------------------------------------

void __fastcall TForm1::CrnDrawListViewItem(TCustomListView *Sender,
      TListItem *Item, TRect &Rect, TOwnerDrawState State)
{
    TListView *lv = (TListView *)Sender;
    // Rect
    TRect rct(Rect.Left + 1, Rect.Top, Rect.Width() - 1, Rect.Bottom);
    // Fill background
    if(State.Contains(odFocused) || State.Contains(odSelected))
    {
        // With focus
        lv->Canvas->Brush->Color = MYCOLOR_BACK;
        lv->Canvas->FillRect(rct);
        lv->Canvas->Pen->Color = MYCOLOR_BORDER;
        lv->Canvas->Rectangle(rct);
    }
    else
    {
        lv->Canvas->Brush->Color = lv->Color;
        lv->Canvas->FillRect(Rect);
    }
    int nLeftOffset(0);   
    // With CheckBox?
    // 63 63 72 75 6E 2E 63 6F 6D
// 本文转自 C++Builder 研究 - http://www.ccrun.com/article.asp?i=656&d=qdc7kg
    if(lv->Checkboxes)
    {
        lv->Canvas->Pen->Color = clBlack;
        lv->Canvas->Pen->Width = 2;
        // Draw CheckBox Rect
        lv->Canvas->Rectangle(Rect.Left + 4, Rect.Top + 3, Rect.Left + 16, Rect.Bottom - 2);
        nLeftOffset = 16;
        if(Item->Checked)
        {
            // 画CheckBox的勾
            lv->Canvas->MoveTo(Rect.Left + 6, Rect.Top + 6);
            lv->Canvas->LineTo(Rect.Left + 8, Rect.Top + 11);
            lv->Canvas->LineTo(Rect.Left + 13, Rect.Top + 5);
        }
        lv->Canvas->Pen->Width = 1;
    }
    // Draw small Icon
    if(lv->SmallImages && Item->ImageIndex != -1)
    {
        lv->SmallImages->Draw(lv->Canvas, nLeftOffset + Rect.Left + 2,
            Rect.Top + (Rect.Height() - lv->SmallImages->Height) / 2 + 1,
            Item->ImageIndex, true);
        nLeftOffset += lv->SmallImages->Width; 
    }
    // Draw Text
    lv->Canvas->Font->Color = clBlack;
    lv->Canvas->TextOutA(Rect.Left + 4 + nLeftOffset,
            Rect.Top + (Rect.Height() - lv->Canvas->TextHeight("A")) / 2,
            Item->Caption);
    // Draw SubItem Text
    int nColOffset(0);
    for(int i=0; i<Item->SubItems->Count; i++)
    {
        nColOffset += lv->Column[i]->Width;
        lv->Canvas->TextOutA(nColOffset + Rect.Left + 4,
            Rect.Top + (Rect.Height() - lv->Canvas->TextHeight("A")) / 2,
            Item->SubItems->Strings[0]);
    }
}
// 自画代码结束

由于这个自画函数与IDE自动产生的不一样,所以需要动态指定ListView的OnDrawItem,同时,ListView还需要一些设置,当然,你可以在设计时直接在属性中更改。
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
        : TForm(Owner)
{
    ListView1->OwnerDraw = true;
    ListView1->RowSelect = true;
    ListView1->ReadOnly = true;
    ListView1->OnDrawItem =(TLVDrawItemEvent)&CrnDrawListViewItem;
}

这样就基本OK了,有兴趣的朋友可以测试一下。

.dfm文件内容(View as Text)
=============================================================================
object Form1: TForm1
  Left = 196
  Top = 131
  BorderStyle = bsDialog
  Caption = 'ListItem自画演示'
  ClientHeight = 168
  ClientWidth = 231
  Color = clBtnFace
  Font.Charset = GB2312_CHARSET
  Font.Color = clWindowText
  Font.Height = -12
  Font.Name = '宋体'
  Font.Style = []
  OldCreateOrder = False
  Position = poScreenCenter
  Visible = True
  PixelsPerInch = 96
  TextHeight = 12
  object Label1: TLabel
    Left = 40
    Top = 8
    Width = 144
    Height = 12
    Caption = 'by ccrun(老妖) QQ:165332'
  end
  object Label2: TLabel
    Left = 24
    Top = 144
    Width = 186
    Height = 12
    Caption = 'Welcome to http://www.ccrun.com'
  end
  object ListView1: TListView
    Left = 10
    Top = 27
    Width = 209
    Height = 105
    Columns = <
      item
      end
      item
        Width = 56
      end
      item
        Width = 80
      end>
    Items.Data = {
      EF0000000700000000000000FFFFFFFFFFFFFFFF020000000000000001610261
      610361616100000000FFFFFFFFFFFFFFFF020000000000000001620262620362
      626200000000FFFFFFFFFFFFFFFF020000000000000001630263630363636300
      000000FFFFFFFFFFFFFFFF020000000000000001640264640364646400000000
      FFFFFFFFFFFFFFFF020000000000000001650265650365656500000000FFFFFF
      FFFFFFFFFF020000000000000001660266660366666600000000FFFFFFFFFFFF
      FFFF0200000000000000016702676703676767FFFFFFFFFFFFFFFFFFFFFFFFFF
      FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF}
    TabOrder = 0
    ViewStyle = vsReport
  end
end

//---------------------

备注:转载老妖!

posted @ 2009-03-23 05:04  会游泳dě鱼  阅读(515)  评论(0编辑  收藏  举报