ListView 实现进度条显示

listview

代码参考互联网,本人在Win10 + Delphi 10.3.2 社区版中测试通过,现将测试通过的代码分享如下:

<
unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ComCtrls,
  System.ImageList, Vcl.ImgList;

type
  TForm1 = class(TForm)
    lv1: TListView;
    btn1: TButton;
    procedure lv1CustomDrawItem(Sender: TCustomListView; Item: TListItem;
      State: TCustomDrawState; var DefaultDraw: Boolean);
    procedure btn1Click(Sender: TObject);
  private
    procedure DrawSubItem(ALV: TListView; AItem: TListItem; ASubItem: Integer;
                          APosition: Single; AMax, AStyle: Integer; AIsShowProgress: Boolean;
                          ADrawColor: TColor = $00005B00; AFrameColor: TColor = $00002F00);
    function ReDrawItem(AHwndLV: HWND; AItemIndex: integer): boolean;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation
uses
  Winapi.CommCtrl;
{$R *.dfm}

procedure TForm1.btn1Click(Sender: TObject);
var
  NewColumn: TListColumn;
  NewItem: TListItem;
  i: Integer;
begin
  lv1.Items.Clear;
  lv1.Columns.Clear;
  NewColumn := lv1.Columns.Add; NewColumn.Caption := '名称';
  NewColumn := lv1.Columns.Add; NewColumn.Caption := '进度';
  NewColumn := lv1.Columns.Add; NewColumn.Caption := '进度条';

  for I := 0 to 10 do
  begin
    NewItem := lv1.Items.Add;
    NewItem.Caption := IntToStr(i);
    NewItem.SubItems.Add(IntToStr(i * 10));
    NewItem.SubItems.Add(IntToStr(i * 10));
  end;
end;

procedure TForm1.DrawSubItem(ALV: TListView; AItem: TListItem; ASubItem: Integer;
                             APosition: Single; AMax, AStyle: Integer; AIsShowProgress: Boolean;
                             ADrawColor: TColor = $00005B00; AFrameColor: TColor = $00002F00);
var
 PaintRect, r: TRect;
 i, iWidth, x, y: integer;
 S: string;
 function GetItemRect(LV_Handle, iItem, iSubItem: Integer): TRect;
 var
   Rect: TRect;
 begin
   ListView_GetSubItemRect(LV_Handle, iItem, iSubItem, LVIR_LABEL, @Rect);
   Result := Rect;
 end;
begin
  with ALV do
  begin
    PaintRect := GetItemRect(ALV.Handle, AItem.Index, ASubItem);
    r := PaintRect;
    //这一段是算出百分比
    if APosition >= AMax then
      APosition := 100
    else
      if APosition <= 0 then
        APosition := 0
      else
        APosition := Round((APosition / AMax) * 100);

    if (APosition = 0) and (not AIsShowProgress) then
    begin
      //如果是百分比是0,就直接显示空白
      Canvas.FillRect(r);
    end else begin
      //先直充背景色
      Canvas.FillRect(r);
      Canvas.Brush.Color := Color;
      //画一个外框
      InflateRect(r, -2, -2);
      Canvas.Brush.Color := AFrameColor; //$00002F00;
      Canvas.FrameRect(R);
      Canvas.Brush.Color := Color;
      InflateRect(r, -1, -1);
      InflateRect(r, -1, -1);
      //根据百分比算出要画的进度条内容宽度
      iWidth := R.Right - Round((R.Right - r.Left) * ((100 - APosition) / 100));
      case AStyle of
        0: //进度条类型,实心填充
          begin
            Canvas.Brush.Color := ADrawColor;
            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 := ADrawColor;
              canvas.LineTo(i, r.Bottom);
              Inc(i, 3);
            end;
          end;
      end;
      //画好了进度条后,现在要做的就是显示进度数字了
      Canvas.Brush.Style := bsClear;
      if APosition = Round(APosition) then
        S := Format('%d%%', [Round(APosition)])
      else
        S := FormatFloat('#0.0', APosition);

      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; // end of if (Prosition = 0) and (not IsShowProgress) then
     //进度条全部画完,把颜色设置成默认色了
    Canvas.Brush.Color := Color;

  end; // end of with LV do
end;

procedure TForm1.lv1CustomDrawItem(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 //画CheckBox的钩
//      begin
//        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 := 2; //ImageIndex的值,可以任意
//    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 := TListView(Sender);
  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 := DT_LEFT;
      taRightJustify:
        TextFormat := DT_RIGHT;
      taCenter:
        TextFormat := DT_CENTER;
    else
      TextFormat := DT_CENTER;
    end;
    case i of
      0: //画Caption,0表示Caption,不是Subitem
        begin
          //先画选择框和图标
          //Draw_CheckBox_ImageList(BoundRect, LV.Canvas, Item.Checked);
          InflateRect(Rect, -(5 + 0), 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: //画SubItem[i]
        begin
          if (i - 1) = 1 then //显示状态条,本示例是第三栏显示,
          begin
            DrawSubItem(LV, Item, i, StrToFloatDef(Item.SubItems[i - 1], 0), 100, 0, True, clMedGray);
          end
          else
          begin
            //画SubItem的文字
            InflateRect(Rect, -2, -2);

            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; //end case
  end; //end for
  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 TForm1.ReDrawItem(AHwndLV: HWND; AItemIndex: integer): boolean;
begin
  Result := ListView_RedrawItems(AHwndLV, AItemIndex, AItemIndex);
end;

end.

posted on 2019-12-15 19:22  pchmonster  阅读(1217)  评论(0编辑  收藏  举报

导航