Delphi - Végtelenített ProgressBar kontrol készítése

forráskód letöltése
Készítünk most egy olyan színátmenetes ProgressBar-hoz hasonló kontrolt, mely folyamatosan működik. Ezt olyan folyamatok jelzésére használhatjuk alkalmazásunkban, melyben nem lehet meghatározni, hogy meddig tart az adott művelet, de azért szeretnénk valamilyen módon jelezni a felhasználó felé, hogy alkalmazásunk még működik, nem fagyott le.
A mellékelt példaprogram megnyitása előtt az EndlessProgress.pas-ban lévő komponenst telepítenie kell a Delphi alá. Ehhez válassza a Component - Install Component menüpontot.
A kontrol használatához a Color1, Color2 property-kben állítsuk be a két kívánt színt, melyek között a színátmenet megvalósul. A Step property-ben minél nagyobb a megadott szám, annál gyorsabban mozog a színátmenet.
A színátmenet rajzolásához szükségünk lesz a GradientFill függvényre, melyet az msimg32.dll-ben találunk, így ezt deklaráljuk külsőként.
function GradientFill(Handle: HDC; pVertex: pointer; dwNumVertex: DWORD; pMesh: pointer; dwNumMesh: DWORD; dwMode: DWORD): DWORD; stdcall; external 'msimg32.dll';
A komponens konstruktorában létrehozunk egy TTimer komponenst, mellyel az időzítést fogjuk megoldani, ami a folyamatosan változó színátmenethez kell. Az időzítő a DoTimer eljárásunkat hívja meg rendszeres időközönként.
constructor TEndlessProgress.Create(AOwner: TComponent);
begin
  ...
  FTimer:=TTimer.Create(nil);
  with FTimer do begin
    Interval:=20;
    OnTimer:=DoTimer;
    Enabled:=true;
  end;
end;
A DoTimer feladata csupán annyi, hogy növeljen egy belső számlálót (FPoisition) és ha ennek értéke túl nagy, akkor állítsa be a kiinduló értékre, végezetül az Invalidate hívásával újrarajzoltatjuk a komponensünk területét.
procedure TEndlessProgress.DoTimer(Sender: TObject);
begin
  inc(FPosition, FStep);
  if FPosition>Width*2 then begin
    FPosition:=-Width;
  end;
  Invalidate;
end;
A rajzolást a felülírt Paint eljárás futásakor kell megtennünk. Itt feltöltünk két TVERTEX struktúrát a kezdő, illetve a befejező színnel, majd a GradientFill függvényt meghívva kirajzoljuk azt a komponens egyik felére.
procedure TEndlessProgress.Paint;
begin
  with Canvas do begin
    gr.UpperLeft:=0;
    gr.LowerRight:=1;
    with vert[0] do begin
      x:=-Width;
      y:=0;
      Red:=GetRValue(FColor1)*256;
      Green:=GetGValue(FColor1)*256;
      Blue:=GetBValue(FColor1)*256;
      Alpha:=0;
    end;
    with vert[1] do begin
      x:=FPosition;
      y:=Height;
      Red:=GetRValue(FColor2)*256;
      Green:=GetGValue(FColor2)*256;
      Blue:=GetBValue(FColor2)*256;
      Alpha:=0;
    end;
    GradientFill(Handle, @vert, 2, @gr, 1, GRADIENT_FILL_RECT_H);
Ezt követően megfordítjuk a színátmenetet és most a komponens másik felére rajzoljuk ugyanazzal a módszerrel. Így előáll egy olyan színátmenet, mely a Color1-ből indul és átmegy a Color2-be, majd a ismét visszatér a Color1-be.
    with vert[0] do begin
      x:=FPosition;
      y:=0;
      Red:=GetRValue(FColor2)*256;
      Green:=GetGValue(FColor2)*256;
      Blue:=GetBValue(FColor2)*256;
      Alpha:=0;
    end;
    with vert[1] do begin
      x:=Width*2;
      y:=Height;
      Red:=GetRValue(FColor1)*256;
      Green:=GetGValue(FColor1)*256;
      Blue:=GetBValue(FColor1)*256;
      Alpha:=0;
    end;
    GradientFill(Handle, @vert, 2, @gr, 1, GRADIENT_FILL_RECT_H);
  end;
end;