Živě.cz o počítačích a internetu

Tipy a triky v Delphi, díl 142. – vlastní spořič

Jan Šindelář 9.6.2004

Dnešním dílem jemně navážeme na ten předchozí. Vytvoříme si opět další grafickou aplikaci, tentokrát to bude základ pro šetřič obrazovky a pracovně bych příklad nazval „míchání šachovnice“.

Jako šetřič obrazovky se občas používá efekt, kdy se pracovní plocha rozdělí na pomyslnou šachovnici a jednotlivé bloky (políčka) jsou poté náhodně přesouvána. Přesně tento efekt si dnes vytvoříme.

Stejně jako minule bude i tentokrát tvořit základ aplikace prázdný formulář, na který umístíme pouze komponentu Image a Timer. Komponenta Image bude opět zarovnána na celou plochu formuláře a Timer pak bude v jednotlivých krocích překreslovat obrazovku a přesouvat její části, takže nastavený interval určuje rychlost celé animace.

Kromě rychlosti je další klíčovou konstantou DELTA, která určuje, na kolik částí bude původní obraz rozdělen. Číslo 4 například znamená, že bude obraz rozdělen na čtyři sloupce a čtyři řádky. Rozměry jednotlivých bloků jsou pak dány podílem daného rozměru rozlišení obrazovky a právě zmiňované konstanty. Při rozlišení 1024x768 a konstantě 4 tak dostaneme 16 bloků o velikosti 256x192 bodů.

Samotný postup pak vypadá následovně. Nejprve provedeme snímek obrazovky a ten poté bude rozdělen na části. Jeden z bloků pak "vyhodíme" a nahradíme ho vlastním obrázkem. V našem případě to bude jednoduchý zelený obdélník s černým rámečkem. Tento speciální blok se pak bude posouvat po původním obraze tak, že se nejprve zvolí náhodně jeden ze čtyř možných směrů. Pak si v daném směru prohodí místo s příslušným blokem původního obrazu. Tímto způsobem tedy náš zelený obdélník putuje po obraze a míchá náhodně jeho jednotlivé části.

Ještě jsme ale neřekli to nejdůležitější, totiž jakým způsobem vůbec docílíme toho, abychom mohli rozházet takto na části pracovní plochu? Původní pracovní plocha zůstane samozřejmě netknutá. My jen docílíme toho, aby okno naší aplikace bylo zvětšené na celou plochu obrazovky. Zrušíme i titulkový pruh aplikace a nastavíme vlastnost "always on top". Komponenta Image, která vyplňuje celou plochu našeho formuláře, pak představuje viditelný obraz. S plochou komponenty Image si pak můžeme dělat co chceme a navenek to vypadá, jako bychom hýbali s pracovní plochou.

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ExtCtrls;

type
  TForm1 = class(TForm)
    Image1: TImage;
    Timer1: TTimer;
    procedure FormCreate(Sender: TObject);
    procedure Timer1Timer(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  DesktopBitmap: TBitmap;
  gx, gy: Integer;
  mRect: TBitmap;
  rW, rH: Integer;

const
  DELTA = 4;
  speed = 1;

implementation

{$R *.dfm}

procedure InitScreen;
begin
  DesktopBitmap := TBitmap.Create;
  with DesktopBitmap do
    begin
      Width := Screen.Width;
      Height := Screen.Height;
    end;
  BitBlt(DesktopBitmap.Canvas.Handle, 0, 0, Screen.Width,Screen.Height, GetDC(GetDesktopWindow), 0, 0, SrcCopy);
  //  DesktopBitmap.LoadFromFile(`test.bmp`);
  Form1.Image1.Picture.Bitmap := DesktopBitmap;
  Randomize;
  gx := Trunc(Random * DELTA);
  gy := Trunc(Random * DELTA);
  Form1.Image1.Canvas.CopyRect(Rect(rW * gx, rH * gy, rW * gx + rW, rH * gy + rH), mRect.Canvas, Rect(0, 0, rW, rH));
end;

procedure DrawScreen;
var
  r1, r2: TRect;
  Direction: integer;
begin
  r1 := Rect(rW * gx, rH * gy,  rW * gx + rW, rH * gy + rH);
  Direction := Trunc(Random*4);
  case Direction of
    0: gx := Abs((gx + 1) MOD DELTA);
    1: gx := Abs((gx - 1) MOD DELTA);
    2: gy := Abs((gy + 1) MOD DELTA);
    3: gy := Abs((gy - 1) MOD DELTA);
  end;
  r2 := Rect(rW * gx, rH * gy, rW * gx + rW, rH * gy + rH);
  with Form1.Image1.Canvas do
    begin
      CopyRect(r1, Form1.Image1.Canvas, r2);
      CopyRect(r2, mRect.Canvas, mRect.Canvas.ClipRect);
    end;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  rW := Screen.Width div DELTA;
  rH := Screen.Height div DELTA;
  mRect := TBitmap.Create;
  with mRect do
    begin
      Width := rW;
      Height := rH;
      Canvas.Brush.Color := clLime;
      Canvas.Brush.Style := bssolid;
      Canvas.Rectangle(0, 0, rW, rH);
    end;
  Timer1.Enabled := False;
  image1.Align := alClient;
  Visible := False;
  BorderStyle := bsNone;
  Top := 0;
  Left := 0;
  Width := Screen.Width;
  Height := Screen.Height;
  InitScreen;
  SetWindowPos(Handle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE + SWP_NOMOVE);
  Visible := True;
  Timer1.Interval := speed;
  Timer1.Enabled := True;
end;

procedure TForm1.Timer1Timer(Sender: TObject);
begin
  DrawScreen;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  DesktopBitmap.Free;
  mRect.Free;
end;

end.

Zbývá několik málo poznámek ke zdrojovému kódu. V konstantách najdete obě zmiňované hodnoty z úvodu, tedy DELTA, která určuje počet bloků a Speed, což není nic jiného než hodnota, která je posléze přiřazena Timeru (takže je to čas v milisekundách; čím menší číslo, tím rychlejší pohyb). Jelikož je okno aplikace zvětšeno na celou obrazovku a formulář vlastně ani nemá titulkový pruh, musíte běh programu ukončit notoricky známou klávesovou zkratkou ALT+F4.

Nabízí se dále několik možných modifikací či vylepšení. Náš jednoduchý pohyblivý zelený obdélník můžete nahradit pro pestrost například nějakým malým obrázkem (logem). Rovněž se nabízí varianta vůbec tento pohyblivý obdélník nepoužít a nechat místo něj posouvat původní, v našem případě "vypuštěný", blok. Poslední variantou pak může být to, že vůbec nepoužijeme obrázek pracovní plochy, ale do naší proměnné DesktopBitmap prostě načteme ze souboru libovolný obrázek (naznačeno v kódu v poznámce). Možností je jistě celá řada, takže se klidně pusťte do experimentování. Poté můžete kód použít jako slušný základ pro jednoduchý šetřič obrazovky.