Delphi:在列表视图中绘制自己的进度条

前端之家收集整理的这篇文章主要介绍了Delphi:在列表视图中绘制自己的进度条前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我有一个列表视图,并使用OwnerDraw绘制它.

如何绘制一个简单流畅的进度条,圆角,顶部有一条线,如下图所示?

我需要你的帮助才能将下面的代码应用到我的需求中(我的技能无法编辑).

//  TUbuntuProgress
//  Version 1.2

unit UbuntuProgress;

interface

uses
  Windows,SysUtils,Classes,Controls,Graphics,Math,ExtCtrls;

type
  TUbuntuProgressColorSets = (csOriginal,csBlue,csRed);
  TUbuntuProgressMode = (pmNormal,pmMarquee);
  TMarqueeMode = (mmToLeft,mmToRight);
  TMarqueeSpeed = (msSlow,msMedium,msFast);

  TUbuntuProgress = class(TGraphicControl)
  private
    FColorSet: TUbuntuProgressColorSets;
    FProgressDividers: Boolean;
    FBackgroundDividers: Boolean;
    FMarqueeWidth: Longint;
    FMax: Longint;
    FMode: TUbuntuProgressMode;
    FPosition: Longint;
    FShadow: Boolean;
    FSpeed: TMarqueeSpeed;
    FStep: Longint;
    FVisible: Boolean;
    Buffer: TBitmap;
    DrawWidth: Longint;
    MarqueeMode: TMarqueeMode;
    MarqueePosition: Longint;
    Timer: TTimer;
    procedure SetColorSet(newColorSet: TUbuntuProgressColorSets);
    procedure SetProgressDividers(newProgressDividers: Boolean);
    procedure SetBackgroundDividers(newBackgroundDividers: Boolean);
    procedure SetMarqueeWidth(newMarqueeWidth: Longint);
    procedure SetMax(newMax: Longint);
    procedure SetMode(newMode: TUbuntuProgressMode);
    procedure SetPosition(newPosition: Longint);
    procedure SetShadow(newShadow: Boolean);
    procedure SetSpeed(newSpeed: TMarqueeSpeed);
    procedure SetStep(newStep: Longint);
    procedure SetVisible(newVisible: Boolean);
    procedure MarqueeOnTimer(Sender: TObject);
    procedure PaintNormal;
    procedure PaintMarquee;
  protected
    procedure Paint; override;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    procedure SetBounds(ALeft,ATop,AWidth,AHeight: Integer); override;
    procedure StepIt;
  published
    property ColorSet: TUbuntuProgressColorSets read FColorSet write SetColorSet;
    property ProgressDividers: Boolean read FProgressDividers write SetProgressDividers;
    property BackgroundDividers: Boolean read FBackgroundDividers write SetBackgroundDividers;
    property MarqueeWidth: Longint read FMarqueeWidth write SetMarqueeWidth;
    property Max: Longint read FMax write SetMax;
    property Mode: TUbuntuProgressMode read FMode write SetMode;
    property Position: Longint read FPosition write SetPosition;
    property Shadow: Boolean read FShadow write SetShadow;
    property Speed: TMarqueeSpeed read FSpeed write SetSpeed;
    property Step: Longint read FStep write SetStep;
    property Height;
    property Visible: Boolean read FVisible write SetVisible;
    property Width;
  end;

procedure Register;

implementation
uses
  UbuntuProgressColors;

{$R UbuntuProgress.dcr}

procedure TUbuntuPRogress.SetColorSet(newColorSet: TUbuntuProgressColorSets);
  begin
    FColorSet := newColorSet;
    Invalidate;
  end;

procedure TUbuntuProgress.SetMarqueeWidth(newMarqueeWidth: Integer);
  var
    OldWidth: Longint;
  begin
    if (newMarqueeWidth < (Width-3)) and (newMarqueeWidth > 0) then
      begin
        OldWidth := FMarqueeWidth;
        FMarqueeWidth := newMarqueeWidth;
        if MarqueeMode = mmToRight then
          MarqueePosition := MarqueePosition - (newMarqueeWidth - OldWidth);
      end;
  end;

procedure TUbuntuProgress.SetProgressDividers(newProgressDividers: Boolean);
  begin
    FProgressDividers := newProgressDividers;
    Invalidate;
  end;

procedure TUbuntuProgress.SetBackgroundDividers(newBackgroundDividers: Boolean);
  begin
    FBackgroundDividers := newBackgroundDividers;
    Invalidate;
  end;

procedure TUbuntuProgress.SetMax(newMax: Integer);
  begin
    if newMax > 0 then
      FMax := newMax;
    if FPosition > FMax then
      FPosition := FMax;
    Invalidate;
  end;

procedure TUbuntuProgress.SetMode(newMode: TUbuntuProgressMode);
  begin
    FMode := newMode;
    if FMode = pmNormal then
      Timer.Enabled := False
    else
      Timer.Enabled := True;
    Invalidate;
  end;

procedure TUbuntuProgress.SetPosition(newPosition: Integer);
  begin
    if (newPosition >= 0) and (newPosition <= FMax) then
      FPosition := newPosition;
    Invalidate;
  end;

procedure TUbuntuProgress.SetShadow(newShadow: Boolean);
  begin
    FShadow := newShadow;
    if FShadow then
      Height := 19
    else
      Height := 18;
    Invalidate;
  end;

procedure TUbuntuProgress.SetSpeed(newSpeed: TMarqueeSpeed);
  begin
    FSpeed := newSpeed;
    case FSpeed of
      msSlow: Timer.Interval := 50;
      msMedium: Timer.Interval := 20;
      msFast: Timer.Interval := 10;
    end;
  end;

procedure TUbuntuProgress.SetStep(newStep: Integer);
  begin
    if (newStep > 0) and (newStep <= (FMax)) then
      FStep := newStep;
  end;

procedure TUbuntuProgress.SetVisible(newVisible: Boolean);
  begin
    FVisible := newVisible;
    if FVisible then
      Invalidate
    else
      Parent.Invalidate;
  end;

procedure TUbuntuProgress.MarqueeOnTimer(Sender: TObject);
  begin
    if not (csDesigning in ComponentState) then
      Invalidate;
  end;

procedure TUbuntuProgress.PaintNormal;
  var
    POverlay: Longint;
    PJoist: Longint;
    PDistance: Extended;
    i,k: Longint;
  begin
    POverlay := Floor((DrawWidth-3)/FMax*FPosition);
    PJoist := Floor((Width-3)/16);
    PDistance := (Width-3)/PJoist;
    with Buffer.Canvas do
      begin
        //3D-Effekt Fortschritt
        Brush.Color := UbuntuProgressColorSets[FColorSet].Progress[0];
        FillRect(Rect(1,1,POverlay+1,2));
        Brush.Color := UbuntuProgressColorSets[FColorSet].Progress[1];
        FillRect(Rect(1,2,3));
        Brush.Color := UbuntuProgressColorSets[FColorSet].Progress[2];
        FillRect(Rect(1,3,4));
        Brush.Color := UbuntuProgressColorSets[FColorSet].Progress[3];
        FillRect(Rect(1,4,5));
        Brush.Color := UbuntuProgressColorSets[FColorSet].Progress[4];
        FillRect(Rect(1,5,6));
        Brush.Color := UbuntuProgressColorSets[FColorSet].Progress[5];
        FillRect(Rect(1,6,7));
        Brush.Color := UbuntuProgressColorSets[FColorSet].Progress[6];
        FillRect(Rect(1,7,8));
        Brush.Color := UbuntuProgressColorSets[FColorSet].Progress[7];
        FillRect(Rect(1,8,9));
        Brush.Color := UbuntuProgressColorSets[FColorSet].Progress[8];
        FillRect(Rect(1,9,12));
        Brush.Color := UbuntuProgressColorSets[FColorSet].Progress[9];
        FillRect(Rect(1,12,13));
        Brush.Color := UbuntuProgressColorSets[FColorSet].Progress[10];
        FillRect(Rect(1,13,14));
        Brush.Color := UbuntuProgressColorSets[FColorSet].Progress[11];
        FillRect(Rect(1,14,15));
        Brush.Color := UbuntuProgressColorSets[FColorSet].Progress[12];
        FillRect(Rect(1,15,16));
        Brush.Color := UbuntuProgressColorSets[FColorSet].Progress[13];
        FillRect(Rect(1,16,17));
        //Balken Fortschritt
        if FProgressDividers then
          begin
            for i := 1 to PJoist-1 do
              begin
                if Round(PDistance*i)<=POverlay then
                  for k := 0 to 15 do
                      Pixels[Round(PDistance*i),k+1] := UbuntuProgressColorSets[FColorSet].JoistLeft[k];
                if Round(PDistance*i)+1<=POverlay then
                  for k := 0 to 15 do
                      Pixels[Round(PDistance*i)+1,k+1] := UbuntuProgressColorSets[FColorSet].JoistRight[k];
              end;
          end;
      end;
  end;

procedure TUbuntuProgress.PaintMarquee;
...
  end;

procedure TUbuntuProgress.Paint;
  var
    PJoist: Longint;
    PDistance: Extended;
    i: Longint;
  begin
    inherited;
    if Visible or ((not Visible) and (csDesigning in ComponentState)) then
      begin
        if FShadow then
          DrawWidth := Width
        else
          DrawWidth := Width + 1;
        PJoist := Floor((Width-3)/16);
        PDistance := (Width-3)/PJoist;
        Buffer.Width := Width;
        Buffer.Height := Height; //19
        with Buffer.Canvas do
          begin
            Brush.Style := bsSolid;
            Pen.Style := psSolid;
            //Eckpixel
            Pixels[0,0] := $00C6C7CE;{-}
            Pixels[DrawWidth-2,17] := $00C6C7CE;{-}
            Pixels[0,17] := $00C6C7CE;{-}
            //Ьbergang
            Pixels[1,0] := $00737584;{-}
            Pixels[DrawWidth-3,0] := $00737584;{-}
            Pixels[DrawWidth-2,1] := $00737584;{-}
            Pixels[DrawWidth-2,16] := $00737584;{-}
            Pixels[DrawWidth-3,17] := $00737584;{-}
            Pixels[1,17] := $00737584;{-}
            Pixels[0,16] := $00737584;{-}
            Pixels[0,1] := $00737584;{-}
            //Seitenlinien
            Pen.Color := $00636973;{-}
            MoveTo(2,0);
            LineTo(DrawWidth-3,0);
            MoveTo(DrawWidth-2,2);
            LineTo(DrawWidth-2,16);
            MoveTo(DrawWidth-4,17);
            LineTo(1,17);
            MoveTo(0,15);
            LineTo(0,1);
            //Schatten
            if FShadow then
              begin
                Pixels[0,18] := $00E7EBEF;{-}
                Pixels[1,18] := $00DEE3E7;{-}
                Pixels[DrawWidth-3,18] := $00DEE3E7;{-}
                Pixels[DrawWidth-2,18] := $00E7EBEF;{-}
                Pixels[DrawWidth-1,17] := $00E7EBEF;{-}
                Pixels[DrawWidth-1,16] := $00DEE3E7;{-}
                Pixels[DrawWidth-1,1] := $00DEE3E7;{-}
                Pixels[DrawWidth-1,0] := $00E7EBEF;{-}
                Pen.Color := $00D6D7DE;{-}
                MoveTo(2,18);
                LineTo(DrawWidth-3,18);
                MoveTo(DrawWidth-1,15);
                LineTo(DrawWidth-1,1);
              end;
            //3D-Effekt Innen
            Brush.Color := $00F7F7F7;{-}
            FillRect(Rect(1,DrawWidth-2,3));
            Brush.Color := $00F7F3F7;{-}
            FillRect(Rect(1,5));
            Brush.Color := $00EFF3F7;{-}
            FillRect(Rect(1,8));
            Brush.Color := $00E7E7EF;{-}
            FillRect(Rect(1,9));
            Brush.Color := $00E7EBEF;{-}
            FillRect(Rect(1,12));
            Brush.Color := $00EFEFE7;{-}
            FillRect(Rect(1,13));
            Brush.Color := $00EFF3F7;{-}
            FillRect(Rect(1,14));
            Brush.Color := $00EFEFF7;{-}
            FillRect(Rect(1,16));
            Brush.Color := $00F7F7FF;{-}
            FillRect(Rect(1,17));
            //Balken Innen
            for i := 1 to PJoist-1 do
              if FBackgroundDividers then
                begin
                  Pen.Color := $00DEDBDE;{-}
                  MoveTo(Round(PDistance*i),1);
                  LineTo(Round(PDistance*i),17);
                  Pen.Color := $00D8D5E0;{-}
                  MoveTo(Round(PDistance*i),8);
                  LineTo(Round(PDistance*i),13);
                  Pen.Color := $00FCF5FC;{-}
                  MoveTo(Round(PDistance*i)+1,1);
                  LineTo(Round(PDistance*i)+1,17);
                  Pen.Color := $00EDEDF5;{-}
                  MoveTo(Round(PDistance*i)+1,8);
                  LineTo(Round(PDistance*i)+1,13);
                end;
          end;
        case FMode of
          pmNormal: PaintNormal;
          pmMarquee:
            begin
              if not (csDesigning in ComponentState) then
                PaintMarquee;
              end;
        end;
        BitBlt(Canvas.Handle,Width,19,Buffer.Canvas.Handle,SRCCOPY);
      end;
  end;

procedure TUbuntuProgress.SetBounds(ALeft: Integer; ATop: Integer; AWidth: Integer; AHeight: Integer);
  begin
    if AWidth < 100 then
      AWidth := 100;
    if FShadow then
      inherited SetBounds(ALeft,19)
    else
      inherited SetBounds(ALeft,18);
  end;

procedure TUbuntuProgress.StepIt;
  begin
    if FMode = pmNormal then
      begin
        FPosition := FPosition+FStep;
        if FPosition > FMax then
          FPosition := 0;
        Invalidate;
      end;
  end;

constructor TUbuntuProgress.Create(AOwner: TComponent);
  begin
    inherited Create(AOwner);
    ControlStyle := ControlStyle + [csFixedHeight,csOpaque];
    Buffer := TBitmap.Create;
    Timer := TTimer.Create(Self);
    Timer.Enabled := False;
    Timer.Interval := 20;
    Timer.OnTimer := MarqueeOnTimer;
    FColorSet := csOriginal;
    FProgressDividers := True;
    FBackgroundDividers := True;
    FMarqueeWidth := 30;
    FMax := 100;
    FMode := pmNormal;
    FPosition := 50;
    FShadow := True;
    FSpeed := msMedium;
    FStep := 1;
    MarqueeMode := mmToRight;
    MarqueePosition := 0;
    Height := 19;
    Width := 150;
    Visible := True;
  end;

destructor TUbuntuProgress.Destroy;
  begin
    Timer.Free;
    Buffer.Free;
    inherited;
  end;

procedure Register;
begin
  RegisterComponents('Ubuntu',[TUbuntuProgress]);
end;

end.

谢谢!

解决方法

可以这样的吗?
uses
  CommCtrl,Themes;

const
  StatusColumnIndex = 2;

procedure DrawStatus(DC: HDC; R: TRect; State: TCustomDrawState; Font: TFont;
  const Txt: String; Progress: Single);
var
  TxtRect: TRect;
  S: String;
  Details: TThemedElementDetails;
  SaveBrush: HBRUSH;
  SavePen: HPEN;
  TxtFont: TFont;
  SaveFont: HFONT;
  SaveTextColor: COLORREF;
begin
  FillRect(DC,R,0);
  InflateRect(R,-1,-1);
  TxtRect := R;
  S := Format('%s %.1f%%',[Txt,Progress * 100]);
  if ThemeServices.ThemesEnabled then
  begin
    Details := ThemeServices.GetElementDetails(tpBar);
    ThemeServices.DrawElement(DC,Details,nil);
    InflateRect(R,-2,-2);
    R.Right := R.Left + Trunc((R.Right - R.Left) * Progress);
    Details := ThemeServices.GetElementDetails(tpChunk);
    ThemeServices.DrawElement(DC,nil);
  end
  else
  begin
    SavePen := SelectObject(DC,CreatePen(PS_NULL,0));
    SaveBrush := SelectObject(DC,CreateSolidBrush($00EBEBEB));
    Inc(R.Right);
    Inc(R.Bottom);
    RoundRect(DC,R.Left,R.Top,R.Right,R.Bottom,3);
    R.Right := R.Left + Trunc((R.Right - R.Left) * Progress);
    DeleteObject(SelectObject(DC,CreateSolidBrush($00FFC184)));
    RoundRect(DC,3);
    if R.Right > R.Left + 3 then
      Rectangle(DC,R.Right - 3,R.Bottom);
    DeleteObject(SelectObject(DC,SaveBrush));
    DeleteObject(SelectObject(DC,SavePen));
  end;
  TxtFont := TFont.Create;
  try
    TxtFont.Assign(Font);
    TxtFont.Height := TxtRect.Bottom - TxtRect.Top;
    TxtFont.Color := clGrayText;
    SetBkMode(DC,TRANSPARENT);
    SaveFont := SelectObject(DC,TxtFont.Handle);
    SaveTextColor := SetTextColor(DC,GetSysColor(COLOR_GRAYTEXT));
    DrawText(DC,PChar(S),TxtRect,DT_SINGLELINE or DT_CENTER or
      DT_VCENTER or DT_END_ELLIPSIS or DT_NOPREFIX);
    SetBkMode(DC,TRANSPARENT);
  finally
    DeleteObject(SelectObject(DC,SaveFont));
    SetTextColor(DC,SaveTextColor);
    TxtFont.Free;
  end;
end;

procedure TForm1.ListView1CustomDrawSubItem(Sender: TCustomListView;
  Item: TListItem; SubItem: Integer; State: TCustomDrawState;
  var DefaultDraw: Boolean);
var
  ListView: TListView absolute Sender;
  R: TRect;
begin
  DefaultDraw := SubItem <> StatusColumnIndex;
  if not DefaultDraw then
  begin
    ListView_GetSubItemRect(ListView.Handle,Item.Index,SubItem,LVIR_BOUNDS,@R);
    DrawStatus(ListView.Canvas.Handle,State,ListView.Font,'Downloading',Random(101) / 100);
  end;
end;

感谢David Heffernan’s tipSertac Akyuz’s answer.

猜你在找的Delphi相关文章