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

Tipy a triky v Delphi, díl 11. - Kulaté okno; Obdélníkové okno se zakulacenými rohy; Animace okna při jeho otevření/zavření; Zmenšení okna na velikost titulkového pruhu

Jan Šindelář - 3.10.2001

Kulaté okno

A je to tady. Tento tip se objevuje v různých diskusních skupinách a fórech a dalo by se říci, že je to již natolik známé a "provařené" téma, že snad ani nemá cenu se jím zabývat. Ale proč ne, každý nemůže číst všechno, a proto ti, kteří o něm ještě nejsou informováni, nechť pokračují ve čtení. Ostatní mohou také, samozřejmě. :)

Oč se tedy jedná ? Každý ví, že běžná okna ve Windows mají tvar obdélníku nebo čtverce, proto také název "okno". Pokud pomineme dnes moderní skinovatelné aplikace, které toto pravidlo úmyslně porušují, je to celkem nuda. Tento fádní tvar však můžeme poměrně snadno nabourat, i když to nebude skin. Pozměníme jen tvar okna na tvar elipsy (kruhu). To má však jednu zjevnou nevýhodu – horní titulkový pruh s názvem aplikace a ovládacími tlačítky je z obou stran jaksi "uříznutý", a proto titulek ani tlačítka nejsou úplně vidět. Ve vlastnostech formuláře proto nastavíme, aby se horní titulek vůbec nezobrazoval, a druhou zjevnou nevýhodu plynoucí z tohoto řešení – nemožnost přesunu okna – odstraníme dalším trikem, který se naučíme. Trik způsobí, že okno půjde přemístit "uchopením" za jeho libovolnou (téměř) část. Tlačítka na uzavření nebo minimalizování aplikace musíte přidat sami, což však již není žádný problém.

Nejprve tedy změna tvaru okna. Stačí, když do události OnCreate příslušného okna přidáte následující kód:

procedure TForm1.FormCreate(Sender: TObject);
var
  region: HRgn;
begin
  region:=CreateEllipticRgn(1, 1, 500, 200);
  SetWindowRgn(handle, region, true);
end;

Parametry funkce CreateEllipticRgn si již upravte sami podle potřeby, mírnému experimentování se pravděpodobně nevyhnete.

Zbývá nám zařídit, aby šlo okno uchopit za libovolnou část. Tedy za libovolnou část podkladu, pochopitelně nelze uchopit okno např. za tlačítko. Opět k tomu využijeme zpráv systému a donutíme Windows "myslet si", že klikáme na titulkový pruh. Vlastní kód vypadá takto:

public
  { Public declarations }
  procedure WMNCHitTest(var M: TWMNCHitTest); message wm_NCHitTest;


procedure TForm1.WMNCHitTest(var M: TWMNCHitTest);
begin
inherited;
if  M.Result = htClient then M.Result := htCaption;
end;

A to je vlastně všechno. Snad jen malý dodatek. Protože okno ztratí svoje původní viditelné ohraničení, může se stát, že při přesunu přes jinou aplikaci okno najednou jakoby "zmizí", což je dáno samozřejmě stejnou barvou podkladu, jako mají jiná okna (hovoříme-li o "standardních" aplikacích). Řešením je prostě změna barvy vašeho okna, což je ale asi celkem předpokládaný postup, protože když už upravujeme tvar okna, pravděpodobně se asi ani nespokojíme s originální unifikovanou barvou oken a ovládacích prvků.

Pouhé eliptické okno a změna barvy sice úplně tak dokonalá změna, jako jsou skiny, není, ale jako jednoduché a rychlé řešení v určitých typech aplikací může stačit.

Obdélníkové okno se zakulacenými rohy

Další z možností jak změnit tvar okna je ponechat původní základní obdélníkový tvar a zakulatit pouze rohy. Tato změna není tak radikální jako v předchozím příkladě a vypadá poměrně efektně. Navíc je použitelná téměř pro všechny aplikace, což se o kulatém (eliptickém) okně říci nedá. Pro vše ostatní, jako je přesun okna, titulkový pruh nebo barva okna, platí totéž co v předchozím příkladě, takže nyní již jen samotný kód. Opět se jedná o událost OnCreate:

procedure TForm1.FormCreate(Sender: TObject);
var
  f: HRGN;
begin
  f := CreateRoundRectRgn(0, 0, clientwidth, clientheight, 40, 40);
  SetWindowRgn(Handle,f,True);
end;

Poslední dva parametry funkce CreateRoundRectRgn nás zajímají nejvíce, protože určují výšku a šířku elipsy (či kruhu), která tvoří rohy okna. Opět se vyplatí experimentovat, než si definitivně zvolíte dané parametry.

Animace okna při jeho otevření/zavření

Dalším efektem, kterým můžeme odlišit naše aplikace, bude animování okna při jeho objevení nebo zavření. Princip je vlastně velice jednoduchý. Nejprve zjistíme, jak má být okno velké, a poté měníme jeho rozměry od maličkého okna až do onoho požadovaného rozměru vždy po malém kroku a po vhodném časovém intervalu, aby vznikl dojem určité "animace". Fantazii se meze nekladou, a tak si můžete vymyslet spoustu jiných způsobů, jak se má okno objevit (např. narolovat z jedné ze čtyř stran, v kruhu apod.). Vše záleží jen na vašich nápadech, protože princip je opravdu jednoduchý. V našem příkladu se po stisku tlačítka objeví další okno výše popsaným způsobem. Úplně stejně můžete zařídit, aby se okno animovalo i při jeho uzavření, ale samozřejmě musíte použít opačný postup, tj. z původní velikosti jej zmenšovat, až úplně zmizí.

Zde tedy malá ukázka, kterou se můžete nechat inspirovat při vlastních pokusech:

procedure TForm1.Button1Click(Sender: TObject);

var maxx,maxy:integer;

begin
maxx:=form2.width;
maxy:=form2.height;
form2.width:=112;
form2.height:=27;
form2.Left:=(screen.Width-form2.Width) div 2;
form2.Top:=(screen.Height-form2.Height) div 2;
form2.show;

repeat
  if form2.height+(maxy div 5)>=maxy then form2.height:=maxy
  else form2.height:=form2.Height+(maxy div 5);

  if form2.Width+(maxx div 5)>=maxx then form2.width:=maxx
  else form2.width:=form2.Width+(maxx div 5);

  form2.Left:=(screen.Width-form2.Width) div 2;
  form2.Top:=(screen.Height-form2.Height) div 2;

  sleep(10);

until (form2.width=maxx) and (form2.height=maxy);
end;

Zmenšení okna na velikost titulkového pruhu

Dnešní aplikace mají samozřejmě kromě svého hlavního okna spousty dalších, a tak je někdy obrazovka hezky zaplněna a i na velkých monitorech mírně nepřehledná. Pokud nechcete okna jednoduše minimalizovat, mám pro vás následující možnost. Což takhle kdyby se okno např. po stisku pravého tlačítka myši na titulkovém pruhu aplikace "zmenšilo" nebo chcete-li vyrolovalo (i když v našem příkladu o animaci nepůjde) nahoru a byl vidět právě jen a pouze onen titulkový pruh? Po opětovném kliknutí se okno opět objeví v plné velikosti. S použitím předchozích tipů o animaci oken při jejich zobrazení si můžete vylepšit i tento příklad a dosáhnout tak opravdového vyrolování nahoru.

Určitým omezením tohoto příkladu je použití pouze na okna typu bsSizeable a bsDialog.

private
    { Private declarations }
    PuvodniVyska : Integer;
    procedure WMNCRButtonDown(var Msg : TWMNCRButtonDown); message WM_NCRBUTTONDOWN;

.
.
.

procedure TForm1.WMNCRButtonDown(var Msg : TWMNCRButtonDown);
begin
  if (Msg.HitTest = HTCAPTION) then
    if (ClientHeight = 0) then
      begin
        ClientHeight := PuvodniVyska;
        Application.ProcessMessages;
      end
    else
      begin
        PuvodniVyska := ClientHeight;
        ClientHeight := 0;
        Application.ProcessMessages;
      end
end;

Na úplný závěr snad jen jedno malé doporučení. Všechny tyto a další vizuální tipy, které jste si dnes či v jiném dílu přečetli, používejte s rozumem a jenom tehdy, když to má smysl a účel. Nemá cenu snažit se uživateli předvádět tím, co všechno umíme, a snažit se do aplikace nacpat všechny efekty najednou. Vždy by mělo jít hlavně o funkci programu a ne o pouťové atrakce kolem.

A to je pro dnešek všechno. Příště si opět trošku pohrajeme s pracovní plochou, naučíme se měnit tapetu, vytvářet zástupce a další tipy.