Thanks for your insight. I obviously have a lot to learn still. I used
DrawEdge instead of DrawFrameControl because it allows customizing of the 
border style.
The RGB values were used to draw the border color and a etched look when the 
control was disabled. I could have used hex values instead of RGB function, 
but I dont always think about those things. The sunken text is based on a 
TLabel and my prefered "disabled" look; however, I'm using DrawState 
function to do that now.


----- Original Message ----- 
From: "Rob Kennedy" <[EMAIL PROTECTED]>
To: "Delphi-Talk Discussion List" <delphi-talk@elists.org>
Sent: Sunday, December 18, 2005 1:10 PM
Subject: Re: custom progress bar


> Richard R wrote:
>> Hello. I recently made a custom progress bar, but it's kinda slow and I
>> figure I'd need to use assembly to speed it up. Even if assembly is used 
>> i'm
>> not sure if it'd do any good, what slows it down is the drawing of the
>> progress bar and the caption on it. During the increment phase, it has to
>> redraw all the graphics on the control. I had to turn on double buffering 
>> to
>> reduce flicker.
>
> That's because the Repaint function invalidates the entire control
> before painting it. A better way to go would be to use the setter for
> the Position property to determine how much of the control actually
> needs to be repainted. Then use InvalidateRect to invalidate only that
> portion. When the window next needs repainting, the OS will only accept
> commands that modify that small portion -- it silently ignores commands
> that affect areas outside the window's update region. To tell the window
> to paint itself, use update instead of Repaint. Update won't do anything
> if the current update region is still empty.
>
>> I did a bench mark with a TProgressBar and my
>> TtsxProgressBar and the timing ratio is 2:27 / 2:43 so mine was 16 
>> seconds
>> slower, at other tests it would be over a minute slower. But I think the
>> trade off is having a visual on the progress bar which works very well 
>> for
>> my project (the user can turn it off). Do you have any suggestions on how 
>> I
>> can increase performance? In my SetPos and StepIt code I call Repaint 
>> after
>> i do the calculation.
>
> At the very most, your control should only call Invalidate, not Repaint.
> Repaint forces the control to repaint everything, even if the program
> was just about to set the Position property to something else right
> away. Let the application be in charge of when its forms get painted.
>
>> Here is my Paint code. the Gradient function DrawImage paints a gradient
>> effect if turned on. It's rather fast since it uses math but I havnt 
>> noticed
>> any performance degrade between turning gradient on and off.
>>
>> procedure TtsxProgressBar.Paint;
>> var
>>   cx, cy, p: integer;
>>   r: TRect;
>>   t: string;
>> begin
>>   Inherited Paint;
>
> Does the painting code below leave any part of the window unpainted? If
> not, then you don't need the inherited call since you're just going to
> paint over everything anyway.
>
>>   with Canvas do begin
>>   // draw outer border
>>     Pen.Color:= RGB(150, 107, 48);
>
> What are these magic numbers for the color?
>
> If you're trying to draw a sunken 3D border, you can call the
> DrawFrameControl API function. It will automatically use the system's
> configured highlight and shadow colors. You can then skip all the
> line-drawing routines below.
>
>>     MoveTo(0, Height - 2);
>>     LineTo(0, 0);
>>     LineTo(Width - 2, 0);
>>     Pen.Color:= RGB(245, 241, 224);
>>     MoveTo(Width - 1, 0);
>
> You leave one pixel uncolored. The LineTo function does not paint the
> last pixel in the range. Why? Because it's leaving it for the next
> LineTo call to handle.
>
> If you want to paint the inside border of a rectangle, then the
> coordinates to use are (0,0), (Width-1,0), (Width-1,Height-1), 
> (0,Height-1).
>
>>     LineTo(Width - 1, Height - 1);
>>     LineTo(0, Height - 1);
>>   // draw progress
>>     p:= 0;
>
> What's p?
>
>>     r.Left:= 3;
>>     r.Top:= 2;
>>     r.Right:= Width - 3;
>>     r.Bottom:= Height - 3;
>>     case FOrientation of
>>       pbHorizontal:
>>         p:= Round((FPos - FMin) / (FMax - FMin) * (r.Right - r.Left) +
>> r.Left);
>>       pbVertical:
>>         p:= Round((FPos - FMax) / (FMin - FMax) * (r.Bottom - r.Top) +
>> r.Top);
>>     end;
>>     if Gradient.Apply then
>>       Gradient.DrawImage(Canvas, r)
>
> Since r is a rectangle based on the size of the control, r will not
> change unless the entire control is resized. Since the gradient is
> always drawn in the full dimensions of the control, you can just draw
> the gradient once to a bitmap of your own. Then, when it comes time to
> paint the control, just use Canvas.Draw to copy that bitmap to the
> canvas instead of recalculating the gradient image each time.
>
> You can calculate r and the gradient bitmap in your control's Resize
> method. You can also update it in the property setter for
> Gradient.Apply, so when the property is False, you just paint an
> FPColor-colored rectangle into your bitmap.
>
>>     else begin
>>       Brush.Color:= FPColor;
>>       FillRect(r);
>>     end;
>>     case FOrientation of
>>       pbHorizontal: r.Left:= p;
>>       pbVertical: r.Bottom:= p;
>>     end;
>>     Brush.Color:= Self.Color;
>>     FillRect(r);
>
> According to this, it appears as though you draw the entire "progress"
> portion of the control, and then you "unpaint" the part that shouldn't
> have been painted at all.
>
>>   // draw caption
>>     t:= Caption;
>>     if FShowValue then
>>       t:= t + ' : ' + Format('%d / %d', [FPos, FMax]);
>
> Include the " : " part of the string in your format string. There's no
> use having a Format call *and* two string concatenations.
>
> t := t + Format(' : %d / %d', [FPos, FMax]);
>
>>     Brush.Style:= bsClear;
>>     cx:= Width div 2 - TextWidth(t) div 2;
>>     cy:= Height div 2 - TextHeight(t) div 2;
>
> The TextWidth and TextHeight functions both call the TextSize function
> internally, which returns both the height and the width of the given
> text. If you use that function directly, you can cut the work in half.
>
> Better yet, you can use the DrawText API function. It can draw text that
> is horizontally and vertically centered in a given rectangle, so you
> don't need to do any calculations yourself.
>
>>     if (not Enabled) then begin
>>       Font.Color:= RGB(245, 241, 244);
>
> More magic numbers for the colors?
>
> Is disabled text still drawn sunken these days?
>
>>       cx:= cx + 1;
>>       cy:= cy + 1;
>>     end
>>     else
>>       Font.Color:= Self.Font.Color;
>>     TextOut(cx, cy, t);
>>     if (not Enabled) then begin
>>       cx:= cx - 1;
>>       cy:= cy - 1;
>>       Font.Color:= RGB(150, 107, 48);
>>       TextOut(cx, cy, t);
>>     end;
>>     Brush.Style:= bsSolid;
>>   end;
>> end;
>
>
> -- 
> Rob
> __________________________________________________
> Delphi-Talk mailing list -> Delphi-Talk@elists.org
> http://www.elists.org/mailman/listinfo/delphi-talk
> 
__________________________________________________
Delphi-Talk mailing list -> Delphi-Talk@elists.org
http://www.elists.org/mailman/listinfo/delphi-talk

Reply via email to