Entwickler-Ecke

Open Source Units - Apple OS X like Progressbar


Benjie - So 13.04.08 16:52
Titel: Apple OS X like Progressbar
Hey Leute

ich bastle immer wieder gerne Dinge nach. So auch die Progressbar wie sie in OS X Leopard vorkommt. Die sieht nämlich massiv schöner aus, als die in Windows. Sie ist recht gut gelungen und ich dachte mir, vielleicht nützt sie ja mal jemandem. Deshalb hab ich hier mal ein Beispiel mit dokumentierter Source hochgeladen.

Man braucht für die Progressbar eine paintbox und einen timer. Viel spass damit, wer's brauchen kann!

P.s.: sollte es bei jemandem nicht funktionieren, bitte melden.


Grietz, Benjie


Moderiert von user profile iconChristian S.: Topic aus Multimedia / Grafik verschoben am So 13.04.2008 um 19:05

Moderiert von user profile iconBenjie: Neue Version hochgeladen

Moderiert von user profile iconNarses: BMP in JPG konvertiert


Fabian E. - So 13.04.08 18:41

ja das sieht doch schon ganz nett aus. :)

vielleicht kannst du ja eine eigene komponente daraus machen, dann kann man es einfacher benutzen.

gruß


matze - So 13.04.08 19:00

Ganz meine Meinung. Es wäre cool, wenn du eine Komponente daraus bauen könntest und diese dann in der OpenSource Units Sektion vorstellen könntest.


Benjie - So 13.04.08 19:03

Jo! Danke für den Tipp! Das hatte ich mir auch schon gedacht. Nur: ich hab noch nie selber eine Komponente gemacht und weiss deshalb nich ganz, wie das läuft. Wie krieg ich denn die Paintbox und den TImer zusammen? Wäre voll cool, wenn jemand von euch mir da n bissl helfen könnte. Die eigene Komponente wäre nämlich mal was. :D

Grietz, Benjie


Fabian E. - Mo 14.04.08 19:49

ich hab zwar selber noch nie eine Koponente entwickelt, aner ich denke ich würde eine klasse machen und diese von der paintbox ableiten. die ist dann zum zeichen da. evtl auch einfach nur ne klassenvariable als paintbox. den timer würde ich genau in der klasse als vairable deklarieren.

gruß


Heiko - Mo 14.04.08 20:18

Oder die Timer-API selber nutzten. Dann kannste den Delphi-Timer dir sonst wohin schieben :mrgreen: .


Andreas L. - Mo 14.04.08 20:41

Folgendes ist wahrscheinlich ziemlich buggy und auf jedenfall erweiterbar. Naja, soll dir ja nur als kleinen Denkanstoß dienen.


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127:
128:
129:
130:
131:
132:
133:
134:
135:
136:
137:
138:
139:
140:
141:
142:
143:
144:
145:
146:
147:
148:
149:
150:
151:
152:
153:
154:
155:
156:
157:
158:
159:
160:
161:
162:
163:
164:
165:
166:
167:
168:
169:
unit AppleProgressBar;

interface

uses
  SysUtils, Classes, Controls, ExtCtrls, Graphics;

type
  TAppleProgressBar = class(TPaintBox)
  private
    FEnabled: Boolean;
    FAnim: Integer;
    FPosition: Integer;
    FAnimated: Boolean;
    FTimer: TTimer;
    FBar: TBitmap;
    FInactiveBar: TBitmap;
    FBarBGLeft: TBitmap;
    FBarBGRight: TBitmap;
    FBarBG: TBitmap;
  protected
    procedure SetEnabled(Value: Boolean);
    procedure SetPosition(Value: Integer);
    procedure SetAnimated(Value: Boolean);
    procedure DoTimer(Sender: TObject);
    procedure SetBar(Value: TBitmap);
    procedure SetInactiveBar(Value: TBitmap);
    procedure SetBarBGLeft(Value: TBitmap);
    procedure SetBarBgRight(Value: TBitmap);
    procedure SetBarBG(Value: TBitmap);
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    procedure Repaint; override;
  published
    property Enabled: Boolean read FEnabled write SetEnabled;
    property Position: Integer read FPosition write SetPosition;
    property Animated: Boolean read FAnimated write SetAnimated;
    property Bar: TBitmap read FBar write SetBar;
    property InactiveBar: TBitmap read FInactiveBar write SetInactiveBar;
    property BarBGLeft: TBitmap read FBarBGLeft write SetBarBGLeft;
    property BarBGRight: TBitmap read FBarBGRight write SetBarBGRight;
    property BarBG: TBitmap read FBarBG write SetBarBG;
  end;

procedure Register;

implementation

procedure Register;
begin
  RegisterComponents('CapSystems', [TAppleProgressBar]);
end;

{ TAppleProgressBar }
constructor TAppleProgressBar.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  FEnabled := True;
  FPosition := 0;
  FAnimated := False;
  FTimer := TTimer.Create(Self);
  with FTimer do
  begin
    OnTimer := DoTimer;
    Enabled := False;
    Interval := 50;
  end;
  FAnim := 0;
  FBar := TBitmap.Create;
  FInactiveBar := TBitmap.Create;
  FBarBGLeft := TBitmap.Create;
  FBarBGRight := TBitmap.Create;
  FBarBG := TBitmap.Create;
end;

destructor TAppleProgressBar.Destroy;
begin
  FTimer.Free;
  FBar.Free;
  FBarBGLeft.Free;
  FBarBGRight.Free;
  FBarBG.Free;
  FInactiveBar.Free;
  inherited Destroy;
end;

procedure TAppleProgressBar.Repaint;
var
  i, p: Integer;
  tmpImage: TBitmap;
begin
  p := 0;
  Canvas.Draw(00, FBarBGLeft);
  Canvas.Draw(Width - 30, FBarBGRight);
  tmpImage := TBitmap.Create;
  if FEnabled then
    tmpImage.Assign(FBar)
  else
    tmpImage.Assign(FInactiveBar);

  for i := Width downto 1 do
  begin
    if (i - 8 - p * 7 - FAnim) > -16 then
      Canvas.Draw(i - 8 - p * 7 - FAnim, 0, tmpImage)
    else
      FAnim := FAnim - 8;
    Inc(p);
    if p = 8 then
      p := 0;
  end;
  tmpImage.Free;
  Canvas.StretchDraw(Rect(Round(Width div 100 * FPosition), 0, Width, 12), FBarBG);
end;

procedure TAppleProgressBar.SetEnabled(Value: Boolean);
begin
  FEnabled := Value;
  Repaint;
end;

procedure TAppleProgressBar.SetPosition(Value: Integer);
begin
  FPosition := Value;
  Repaint;
end;

procedure TAppleProgressBar.SetAnimated(Value: Boolean);
begin
  FAnimated := Value;
  FTimer.Enabled := Value;
  Repaint;
end;

procedure TAppleProgressbar.DoTimer(Sender: TObject);
begin
  if FAnimated then
  begin
    Inc(FAnim);
    Refresh;
  end;
end;

procedure TAppleProgressbar.SetBar(Value: TBitmap);
begin
  FBar.Assign(Value);
end;

procedure TAppleProgressbar.SetInactiveBar(Value: TBitmap);
begin
  FInactiveBar.Assign(Value);
end;

procedure TAppleProgressbar.SetBarBGLeft(Value: TBitmap);
begin
  FBarBGLeft.Assign(Value);
end;

procedure TAppleProgressbar.SetBarBgRight(Value: TBitmap);
begin
  FBarBGRight.Assign(Value);
end;

procedure TAppleProgressbar.SetBarBG(Value: TBitmap);
begin
  FBarBG.Assign(Value);
end;

end.


Wie man Komponenten installiert weiß tu ja?!?


Benjie - Mo 14.04.08 21:48

Cool! 8) Danke für "Denkanstoss" Andreas. Ich werd mich dransetzten, sobald ich mal Zeit habe. Wahrscheinlich zwar nicht vor Mittwoch, weil wir dann eine riesige Geologie-Prüfung schreiben müssen. Oh es gibt nichts spannenderes und wichtigeres als Gesteinsschichten auswendig zu lernen! :gruebel:

Danke nochmal! Grietz, Benjie


Benjie - Mi 16.04.08 20:00
Titel: Komponente Fertig!
Also. Ich habe nach dem Beispiel von Andreas die Komponente fertiggestellt. Es funktioniert alles und sie sieht auch ordentlich aus. Einzige Bedingung für das Ding ist, dass Doublebuffered im Parent auf true gestellt wird, sonst gibt's so ein hässliches Geflacker. Obwohl ich (fast) den ganzen Tag dran rumgebastelt hab, hab ich's nicht geschafft das Geflacker ohne doublebuffered wegzukriegen.

Ja. Probiert die Kompo doch mal aus und meldet es mir, wenn was nicht funktionieren sollte (oder eine Datei fehlt: ich war mir nicht ganz sicher, was ich alles mitreinpacken muss). Ich hab sie zusammen mit den Bildern in ein Ziparchiv gepackt. Selbstverständlich kann man aber auch andere Bilder nehmen.

Danke nochmal für die Tipps! :D

Grietz, Benjie


Heiko - Mi 16.04.08 20:15

Hallo Benjie,

ich hab mal kurz in den Code reingeguckt bzgl. DoubleBuffering. Die Ursache liegt in deiner Paint-Methode.

Zur Behebung (sollte man bei Canvas immer nehmen, egal mit welchem Ziel): Nimm ein Zwichenbitmap auf dem du alles zeichnest. Aber wirklich alles. Übertrage es anschließend in einem Schwung.


Benjie - Mi 16.04.08 21:35

Hallo Heiko,

danke für deinen Tipp. Ich hab's mit nem Bitmap probiert, aber es flackert immer noch ohne doublebuffered. Mach ich da was falsch?


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
procedure TAppleProgressBar.paint;
var i,p:integer;
    tmpImage:TBitmap;
begin
  p:=0;
  tmpcanvas.width := width;
  tmpcanvas.height := FbarBG.Height;
  //Draw the left bar Background graphic:
  tmpcanvas.canvas.Draw(0,0,FbarBGleft);
  //Draw the right bar Baclground graphic:
  tmpcanvas.canvas.Draw(Width-3,0,FbarBGRight);
  //Load and draw the Progressbar graphic:
  tmpImage := TBitmap.Create;
  if FColorMode=Blue then
    tmpImage.Assign(FBar)
  else
    tmpImage.Assign(FInactiveBar);

  for i:=Width downto 1 do  BEGIN
    if (i-bar.Width-p*(bar.Width-1)-FAnim)>-bar.Width*2 then tmpcanvas.canvas.Draw(i-bar.Width-p*(bar.Width-1)-FAnim,0,tmpimage) else FAnim:=FAnim-bar.Width;
    inc(p);
    if p=bar.Width then p:=0;
 end;

 tmpImage.Free;
  //Ddraw the middle bar graphic stretched:
  tmpcanvas.Canvas.StretchDraw(rect(round(Width/100*FPosition),0,Width,12),FbarBG);
  Canvas.Draw(0,0,tmpcanvas);
end;



Grietz, Benjie


Heiko - Mi 16.04.08 21:44

Hallo Benjie,

auf den ersten Blick nicht. Es könnte noch an der Delphi-Kapselung liegen. Ich werde am Wochenende mir es vlt. mal genauer anschauen. Jetzt habe ich wahrscheinlich nicht genug Nerven dafür.

PS: Sollte ichs vergessen, erinnere mich mal (hab Monatg meinen letzten Schultag, wes wegen ich soetwas ggf. erfolgreich verdränge :mrgreen: )


Benjie - Do 17.04.08 13:17

Ich hab vielleicht heute noch ein bissl Zeit, um dran runmzubasteln. Vielleicht krieg ich es ja hin. Wenn nicht, werde ich dich dran erinnern, wenn du's vergisst! :zwinker:

was denkt ihr, könnte das Geflacker an der Procedur-art liegen (TAppleProgressBar.paint;)? Man könnte sie ja auch zu einem anderen Ereignis aufrufen...

Grietz, Benjie


Benjie - Do 17.04.08 21:20

Also. Ich hab's es flackert jetzt auch ohne doublebuffered nicht mehr. Es lag tatsächlich an der Procedur-art: Ich hab sie vom Paint- Ereignis zum Repaint-Ereignis geändert - Fertig! Hab die neue Version gleich mal hochgeladen. Bei mir läufts, bin gespannt, ob es bei auch tut.

Grietz, Benjie


Heiko - Fr 18.04.08 07:09

Du kannst die Message hier abfangen:


Delphi-Quelltext
1:
2:
3:
4:
procedure TSBControl.WMEraseBkgnd(var Msg: TWMEraseBkgnd);
begin
  Msg.Result:=1;
end;


Diese eine Zeile fügt man bei OpenGL-Apps meistens ein.


Benjie - Sa 19.04.08 13:17

Hallo Heiko.

Sorry, aber ich blick grad nicht mehr durch: Welche Message soll ich mit dieser Procedur Abfangen?
Und wiese OpenGL? Ich hab echt keine Ahnung, was du damit meinst. :gruebel:

Grietz, Benjie


Heiko - Sa 19.04.08 14:06

Zur Message siehe MSDN [http://msdn2.microsoft.com/en-us/library/ms648055(VS.85).aspx].

@OpenGl: Da fängt man die Message standardmäßig ab, wenn man nur beim OnPaint-Ereignis was zeichnet, um die CPU zu entlasten, da dieser Nachricht immer OnPaint folgt, weswegen man diese ingorieren kann ;).


Fabian E. - Sa 19.04.08 15:03

Also ich habe mir das jetzt schonmal angeschaut. Sieht alles schon recht gut aus, das die einzigen zwei sachen die mich stören sind, dass man die grafiken per hand aussuchen muss und dass man die größe der paintbox zwar verändern kann die bar aber genauso bleibt. also entweder das anpassen oder die größe unveränderbar machen.

zu der sache mit den grafiken... diese könntest du ja in einer res datei speichern und dann auch im lib verzeichnis von delphi kopieren lassen. dann wäre das erledigt.

gruß


Karlson - So 20.04.08 17:57

Toll! Gefällt mir sehr gut!


Benjie - Mi 23.04.08 18:26

Hallo ihr. Ich war in einem Musiklager, daher schreib ich erst heute wieder...
Ein paar Antworten auf eure posts:

@ Fabian E.: Das mit den Grafiken wäre sehr schön in der res-datei, nur sind die bei mir maximal 256 farben, was echt sch...lecht aussieht. Deshalb das umständliche gesuche. Aber wenn man mal eine Progressbar gemacht hat, kann man sie ja einfach kopieren.
Das mit der Höhe: Die ist natürlich immer genau so hoch, wie die Grafik des hintergrundes. Nur weiss ich nicht, wie man Eigenschaften von vorgängerkomponenten enfernen kann. Wenn mir das jemand schreiben könnte, würd ich es sofort ändern.

@ Karlson: Danke! :D

Grietz, Benjie


Silas - Mi 23.04.08 21:22

user profile iconBenjie hat folgendes geschrieben:
Das mit den Grafiken wäre sehr schön in der res-datei, nur sind die bei mir maximal 256 farben, was echt sch...lecht aussieht.
Wenn du statt dem Bildeditor z.B. Suche in der Entwickler-Ecke RESED verwendest, kannst du auch Bitmaps mit 24 Bit einfügen.

user profile iconBenjie hat folgendes geschrieben:
Nur weiss ich nicht, wie man Eigenschaften von vorgängerkomponenten enfernen kann.
AFAIK leitet man neue Komponenten nie von "fertigen" ab, sondern immer von der Vorgänger- ("Custom"-) Version, in dem Fall also IIRC TCustomPaintBox. Dann musst du unter published die Properties einfügen, die du im OE haben willst. Wenn du nur mit Canvas arbeitest kannst du noch eine "niedrigere", also "näher" an TComponent gelegene Klasse (Oder gleich TComponent verwenden).


Benjie - Do 24.04.08 12:55

Hey Silas, danke für die beiden Tipps. Werde sie versuchen umzusetzten.

Andere Frage: Ich bin grad dran eine zweite Apple-like Kompo zu programmieren: Die AppleStringlist (kennt ihr vielleicht ausm iTunes --> Die liste dort hat immer blau/weisse zeilen und eine schöne scrollbar). Nun wollte ich erst das ganze auf einer Paintbox aufbauen (mit zeichnen, textout und so), was eigentlich auch funzen würde. Nur krieg ich probleme mit der Scrollbar. Die möchte ich nämlich als eigene paintbox in der Hauptpaintbox realisieren (wegen dem umherschieben: mousedown, mousemove..).
Ich kriegs nur leider nicht hin, die Hauptpaintbox als parent der Scrollpaintbox zu definieren. Und ich finde es irgendwie mühsam, wenn beide die form als parent haben.

Vielleicht weiss ja wer was... :)

Grietz, Benjie