自画
TlistView
带进度条的
Item
TListView的Item条一般是由系统自画的,但电驴就实现了自画,使之看起来很漂亮,我们用DELPHI也可以实现!
首先要引用
CommCtrl
单元,这是TListView底层控制单元:
uses
CommCtrl;
//
画状态条
procedure
DrawSubItem(LV: TListView; Item: TListItem; SubItem: Integer;
Prosition: Single; Max, Style: Integer; IsShowProgress: Boolean;
DrawColor: TColor =
$00005B00
;
FrameColor: TColor =
$00002F00
);
//
获取
SubItem
的区域
function
GetItemRect(LV_Handle, iItem, iSubItem: Integer): TRect;
var
Rect: TRect;
begin
ListView_GetSubItemRect(LV_Handle, iItem, iSubItem, LVIR_LABEL, @Rect);
Result := Rect;
end
;
var
PaintRect, r: TRect;
i, iWidth, x, y: integer;
S:
string
;
begin
try
with
lv
do
begin
//LockPaint := True;
PaintRect := GetItemRect(LV.Handle, Item.Index, SubItem);
r := PaintRect;
// if SubItem = DrawSubItem then
Begin
//
这一段是算出百分比
if
Prosition >= Max
then
Prosition :=
100
else
if
Prosition <=
0
then
Prosition :=
0
else
Prosition := Round((Prosition / Max) *
100
);
if
(Prosition =
0
)
and
(
not
IsShowProgress)
then
begin
//
如果是百分比是
0
,就直接显示空白
Canvas.FillRect(r);
end
else
begin
//
先直充背景色
Canvas.FillRect(r);
Canvas.Brush.Color := Color;
// Canvas.FillRect(r);
//
画一个外框
InflateRect(r, -
2
, -
2
);
Canvas.Brush.Color := FrameColor;
//$00002F00;
Canvas.FrameRect(R);
Canvas.Brush.Color := Color;
InflateRect(r, -
1
, -
1
);
// Canvas.FillRect(r);
InflateRect(r, -
1
, -
1
);
//
根据百分比算出要画的进度条内容宽度
iWidth := R.Right - Round((R.Right - r.Left) * ((
100
- Prosition) /
100
));
case
Style
of
0
:
//
进度条类型,实心填充
begin
Canvas.Brush.Color := DrawColor;
r.Right := iWidth;
Canvas.FillRect(r);
end
;
1
:
//
进度条类型,竖线填充
begin
i := r.Left;
while
i < iWidth
do
begin
Canvas.Pen.Color := Color;
Canvas.MoveTo(i, r.Top);
Canvas.Pen.Color := DrawColor;
canvas.LineTo(i, r.Bottom);
Inc(i,
3
);
end
;
end
;
end
;
//
画好了进度条后,现在要做的就是显示进度数字了
Canvas.Brush.Style := bsClear;
if
Prosition = Round(Prosition)
then
S := Format(
'%d%%'
, [Round(Prosition)])
else
S := FormatFloat(
'#0.0'
, Prosition);
with
PaintRect
do
begin
x := Left + (Right - Left +
1
- Canvas.TextWidth(S))
div
2
;
y := Top + (Bottom - Top +
1
- Canvas.TextHeight(S))
div
2
;
end
;
SetBkMode(Canvas.handle, TRANSPARENT);
Canvas.TextRect(PaintRect, x, y, S);
end
;
//
进度条全部画完,把颜色设置成默认色了
Canvas.Brush.Color := Color;
end
end
;
except
end
;
end
;
上面是画进度条的,现在要给
TlistView
处理
Item
重绘的消息,事件是
On
CustomDrawItem
,
需要说明的是,如果想要随心所欲的自画
Item
,那么就要全部自己来完成,不再需要系统来处理:
procedure
TForm1.ListView1CustomDrawItem(
Sender: TCustomListView; Item: TListItem; State: TCustomDrawState;
var
DefaultDraw: Boolean);
var
BoundRect, Rect: TRect;
i: integer;
TextFormat: Word;
LV: TListView;
//
这个子过程是用来画
CheckBox
和
ImageList
的
procedure
Draw_CheckBox_ImageList(r: TRect; aCanvas: TCanvas; Checked: Boolean);
var
R1: TRect;
i: integer;
begin
if
Sender.Checkboxes
then
begin
aCanvas.Pen.Color := clBlack;
aCanvas.Pen.Width :=
2
;
//
画
CheckBox
外框
aCanvas.Rectangle(r.Left +
2
, r.Top +
2
, r.Left +
14
, r.Bottom -
2
);
if
Checked
then
begin
//
画
CheckBox
的勾
aCanvas.MoveTo(r.Left +
4
, r.Top +
6
);
aCanvas.LineTo(r.Left +
6
, r.Top +
11
);
aCanvas.LineTo(r.Left +
11
, r.Top +
5
);
end
;
aCanvas.Pen.Width :=
1
;
end
;
//
开始画图标
i := PDownLoadListItem(Item.Data)^.StatsImageIndex;
if
i > -
1
then
begin
//
获取图标的
RECT
if
Boolean(ListView_GetSubItemRect(sender.Handle, item.Index,
0
, LVIR_ICON, @R1))
then
begin
ImageList_Stats.Draw(LV.Canvas, R1.Left, R1.Top, i);
if
item.ImageIndex > -
1
then
LV.SmallImages.Draw(LV.Canvas, R1.Right +
2
, R1.Top, item.ImageIndex);
end
;
end
;
end
;
begin
LV
:= ListView1;
BoundRect := Item.DisplayRect(drBounds);
InflateRect(BoundRect, -
1
,
0
);
//
这个地方你可以根据自己的要求设置成想要的颜色,实现突出显示
LV.Canvas.Font.Color := clBtnText;
//
查看是否是被选中
if
Item.Selected
then
begin
if
cdsFocused
in
State
then
begin
LV.Canvas.Brush.Color :=
$00ECCCB9
;
// //clHighlight;
end
else
begin
LV.Canvas.Brush.Color :=
$00F8ECE5
;
//clSilver;
end
;
end
else
begin
if
(Item.Index
mod
2
) =
0
then
LV.Canvas.Brush.Color := clWhite
else
LV.Canvas.Brush.Color :=
$00F2F2F2
;
end
;
LV.Canvas.FillRect(BoundRect);
//
初始化背景
for
i :=
0
to
LV.Columns.Count -
1
do
begin
//
获取
SubItem
的
Rect
ListView_GetSubItemRect(LV.Handle, Item.Index, i, LVIR_LABEL, @Rect);
case
LV.Columns[i].Alignment
of
taLeftJustify:
TextFormat :=
0
;
taRightJustify:
TextFormat := DT_RIGHT;
taCenter:
TextFormat := DT_CENTER;
end
;
case
i
of
0
:
//
画
Caption
,
0
就是表示
Caption
,这不是
Subitems[0]
begin
//
先画选择框与图标
Draw_CheckBox_ImageList(BoundRect, LV.Canvas, Item.Checked);
//
再画
Caption
的文字
InflateRect(Rect, -(
5
+ ImageList_Stats.Width),
0
);
//
向后移
3
个像素
,
避免被后面画线框时覆盖
DrawText(
LV.Canvas.Handle,
PCHAR(Item.Caption),
Length(Item.Caption),
Rect,
DT_VCENTER
or
DT_SINGLELINE
or
DT_END_ELLIPSIS
or
TextFormat);
end
;
1
..MaxInt:
//
画
Subitems[i]
begin
if
i -
1
=
2
then
//
显示状态条
begin
//
开始处理进度条了,这个示例是第
3
栏显示进度条,可以自己随便定义
DrawSubItem(TListView(Sender),
item,
i,
StrToFloatDef(Item.SubItems[i -
1
],
0
),
100
,
0
,
True,
//
这里用了一个
Lable
来选颜色,你自己可以使用一个变量来代替
LableProgressColor.Color,
//
进度条外框颜色
LableProgressColor.Color
//
进度条颜色
);
end
else
//
画
SubItem
的文字
if
i -
1
<= Item.SubItems.Count -
1
then
DrawText(
LV.Canvas.Handle,
PCHAR(Item.SubItems[i -
1
]),
Length(Item.SubItems[i -
1
]),
Rect,
DT_VCENTER
or
DT_SINGLELINE
or
DT_END_ELLIPSIS
or
TextFormat);
end
;
end
;
end
;
LV.Canvas.Brush.Color := clWhite;
if
Item.Selected
then
//
画选中条外框
begin
if
cdsFocused
in
State
then
//
控件是否处于激活状态
LV.Canvas.Brush.Color :=
$00DAA07A
// $00E2B598; //clHighlight;
else
LV.Canvas.Brush.Color :=
$00E2B598
;
//$00DAA07A // clHighlight;
LV.Canvas.FrameRect(BoundRect);
//
end
;
DefaultDraw := False;
//
不让系统画了
with
Sender.Canvas
do
if
Assigned(Font.OnChange)
then
Font.OnChange(Font);
end
;
function ReDrawItem(HwndLV: HWND; ItemIndex: integer): boolean;
begin
Result := ListView_RedrawItems(HwndLV, ItemIndex, ItemIndex);
end;
//使用:
item:=ListView1.Selected;
item.subitems[1]:='30';//设置为30%
//然后刷新这个item
ReDrawItem(ListView1.handle,Item.index);
不用进度条时的效果图: