我有一个列表视图,并使用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 tip和Sertac Akyuz’s answer.