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

Tipy a triky v Delphi, díl 15. - Rámeček kolem okna aplikace; Položka menu zcela vpravo; Přidání vlastních položek do systémového menu; Jak umístit ProgressBar na StatusBar

Jan Šindelář - 31.10.2001

Rámeček kolem okna aplikace

Prvním grafickým vylepšením, které si teď ukážeme, bude orámování okna aplikace rámečkem dané tloušťky a barvy. Pokud zvolíme přiměřenou tloušťku a vhodnou (například černou) barvu, dosáhneme celkem pozoruhodného zvýraznění daného okna. Parametry volte s rozvahou a vkusem. Přílišná tloušťka rámečku nevypadá dobře (mírně řečeno) a červená barva asi také nebude úplně to pravé (tedy jak se to vezme, pro chybové hlášení by to nemuselo být špatné). Zvolte zkrátka takovou kombinaci, která bude vhodně doplňovat grafický ráz vaší aplikace. Ukažme si tedy vlastní kód:

.
.
.

private
{ Private declarations }
procedure WMNCPaint(var Msg: TWMNCPaint); message WM_NCPAINT;

.
.
.


procedure TForm1.WMNCPaint(var Msg:TWMNCPaint);
var
dc: hDc;
Pen: hPen;
OldPen: hPen;
OldBrush: hBrush;

begin
inherited;
dc := GetWindowDC(handle);
Msg.Result := 1;
Pen := CreatePen(PS_SOLID, 3, RGB (0,0,0));
OldPen := SelectObject(dc, Pen);
OldBrush := SelectObject(dc, GetStockObject(NULL_BRUSH));
Rectangle(dc, 0, 0, Form1.Width, Form1.Height);
SelectObject(dc, OldBrush);
SelectObject(dc, OldPen);
DeleteObject(Pen);
ReleaseDC(Handle, Canvas.Handle);
end;

Důležitá je pro nás funkce CreatePen. První parametr určuje typ výplně čáry (zde nastavena plná výplň, jiná se asi pro rámeček moc nehodí). Druhý parametr (v našem příkladu je to číslo 3) udává tloušťku rámečku a třetím parametrem je barva v klasické RGB trojkombinaci, tj. hodnoty 0–255 (v naší ukázce je to konkrétně černá). Vrhněte se tedy do experimentování.

Položka menu zcela vpravo

Další lahůdka se bude týkat rozložení prvků hlavního menu. Některé aplikace (například oblíbený Windows Commander) mají své hlavní menu upraveno tak, že jedna z položek – obvykle nápověda – je vytěsněna zcela k pravému okraji menu. Mně osobně se tento způsob líbí, připadá mi logický, a nápověda se tak neztratí mezi ostatními položkami (pokud ji ovšem právě kvůli odsunutí na pravou stranu nepřehlédnete, ale to by se stát snad nemělo). Pokud se budete snažit dosáhnout tohoto efektu "přemlouváním" standardní komponenty MainMenu a nastavováním různých parametrů, příliš úspěšní nebudete (to jste možná při pokusech zjistili). Ukážeme si teď spolehlivý způsob, jak na to.

Náš příklad předpokládá, že máte na svém formuláři komponentu MainMenu a jedna z jejích položek má jméno Help1 (její titulek - Caption - může být pochopitelně libovolný). Celý kód přidejte do události OnCreate hlavního formuláře.

procedure TForm1.FormCreate(Sender: TObject);
var
Itm: TMenuItemInfo;
Buf: Array[0..79] of Char;
begin
ZeroMemory(@Itm, SizeOf(Itm));
with Itm do
begin
  cbSize := 44;
  fMask := MIIM_TYPE;
  dwTypeData := Buf;
  cch := SizeOf(Buf);
end;
if GetMenuItemInfo(MainMenu1.Handle, Help1.MenuIndex, True, Itm) then
begin
  Itm.fType := Itm.fType or MFT_RIGHTJUSTIFY;
  if SetMenuItemInfo(MainMenu1.Handle, Help1.MenuIndex, True, Itm) then DrawMenuBar(MainMenu1.WindowHandle);
end;
end;

Přidání vlastních položek do systémového menu

Systémové menu, které se zobrazí po kliknutí na ikonku aplikace v jejím titulkovém pruhu (a nebo kliknutím pravého tlačítka na libovolné místo titulkového pruhu), lze velmi snadno obohatit o své vlastní položky. Využití ponechám čistě na vaší fantazii, namátkou mě třeba napadá položka minimalizace do Tray (ikonky vedle hodin) nebo informace o programu. V naší ukázce si právě o tyto dvě položky menu obohatíme, aby byl jasný princip.

Nejprve si utvoříme seznam konstant, které nám budou identifikovat jednotlivé přidané položky. V události OnCreate hlavního formuláře nejprve přidáme naše položky do menu (a oddělíme je od ostatních oddělovačem). Poté budeme pomocí odchytávání zprávy WMSysCommand zjišťovat, zda došlo k vybrání právě některé z našich položek, a adekvátně na to reagovat. V naší ukázce se pro jednoduchost a ilustraci zobrazí pouze informační okno.

const Info = 100;
      TrayIko = 101;

.
.
.
public
{ Public declarations }
hSysMenu: hmenu;
procedure WMSysCommand(var Message: TMessage); message WM_SYSCOMMAND;
.
.
.

procedure TForm1.WMSysCommand(var Message : TMessage);
begin
if Message.WParam = Info then ShowMessage(`Kliknuto na položku Info`);
if Message.WParam = TrayIko then ShowMessage(`Kliknuto na položku Minimalizace do tray...`);
inherited;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
hSysMenu := GetSystemMenu(Form1.Handle, False);
AppendMenu(hSysMenu, MF_SEPARATOR, 0, ``);
AppendMenu(hSysMenu, MF_STRING, Info, `&Info`);
AppendMenu(hSysMenu, MF_STRING, TrayIko, `Minimalizuj do &hlavního panelu`);
end;

Jak umístit ProgressBar na StatusBar

Standardní komponenta StatusBar není příliš přívětivá při pokusu umístit na ni jiné komponenty. Dalo by se říct, že se na ni běžným způsobem nedá umístit v podstatě nic (hovořím o komponentě, která je součástí Delphi 5; nevím, jak to vypadá v nové verzi). Ukážeme si, jak na ni "umístit" komponentu ProgressBar. No, vlastně se nejedná tak docela o umístění v pravém slova smyslu, spíše překryjeme StatusBar komponentou ProgressBar. To můžeme provést právě v okamžiku nějaké činnosti, kdy se bude zobrazovat její průběh, a po skončení necháme ProgressBar "zmizet" a opět se objeví "pod ním skrytý" StatusBar. Jelikož se v naší ukázce nastavují rozměry ProgressBaru jen jednou jako událost stisku tlačítka (kvůli zjednodušení; ve vašem kódu pochopitelně budete přepínat mezi ProgressBarem a StatusBarem ve vhodnou chvíli programově), při změně rozměru okna se dostane ProgressBar jaksi mimo svou původní polohu (nebude přesně překrývat StatusBar). Proto musíte buď sami zajistit, aby se jeho rozměr aktualizoval při změně rozměru okna, nebo zajistit to, aby se rozměry okna měnit nemohly. To záleží na typu vaší aplikace a na vašem uvážení.

procedure TForm1.Button1Click(Sender: TObject);
begin
with ProgressBar1 do
begin
  Parent := StatusBar1;
  Left := 0;
  Top := 0;
  Height := StatusBar1.Height;
  Width := StatusBar1.Width;
end;
end;

A to bude pro dnešek všechno. Příště se podíváme trošku na grafiku.