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

Tipy a triky v Delphi, díl 21. - Změna barev objektů v systému; Převod času v milisekundách na TDateTime; Přestupný rok a Velikonoce; Zalomení textu u tlačítek na více řádků; Efektní vypisování textu pomocí komponenty Edit

Jan Šindelář - 12.12.2001

Změna barev objektů v systému

Jistě víte, že se barvy většiny prvků v systému, jako je třeba titulek oken, barvy posuvníků či editačních polí a podobně, dají celkem bez problému nastavit přes ovládací panely k obrazu svému. Nyní si však ukážeme, jak se toho dá docílit též programově.

procedure TForm1.Button1Click(Sender: TObject);
var CIndex : Integer;
    CValue : Longint;
begin
CIndex := COLOR_ACTIVECAPTION;
CValue := clGreen;
SetSysColors(2, CIndex, CValue);
PostMessage(HWND_BROADCAST, WM_SYSCOLORCHANGE, 0, 0);
end;

Jak vidíte, o vše se postarají pouze dva parametry. Jeden uvádí barvu, kterou chcete nastavit, a druhý zase prvek, jehož parametry měníme. Tyto konstanty můžete například vyčíst při nastavování barev čehokoliv v Object Inspectoru. V naší ukázce měníme barvu titulku u aktivní aplikace.

Je třeba si uvědomit, že tím dojde ke změně barvy globálně v celém systému, takže se změní barvy nejen naší aplikace, ale i všech ostatních prvků.

Převod času v milisekundách na TDateTime

Možná vám bude tento tip připadat jako zbytečný, ale mnozí začátečníci se často potýkají s problémem vzájemných převodů různých časových jednotek, a jelikož je této oblasti v Delphi věnován poměrně velký počet funkcí, snadno se v nich může člověk ztratit. Pro náš příklad jsem vybral velice častý případ, kdy údaj v milisekundách potřebujeme zobrazit jako běžný čas převedením na typ TDateTime, se kterým se pak již pracuje poněkud pohodlněji než s milisekundami. V naší ukázce si necháme zobrazit v tomto standardním tvaru čas od startu systému.

procedure TForm1.Button1Click(Sender: TObject);
var DT : TDAteTime;
begin
DT := TimeStampToDateTime(MSecsToTimeStamp(GetTickCount));
ShowMessage(FormatDateTime(`d hh:nn:ss`, DT));
end;

Místo funkce GetTickCount můžete samozřejmě doplnit požadovaný čas v milisekundách, který bude poté převeden.

Přestupný rok a Velikonoce

Když už jsme se trošku zabývali časem, ukažme si dva výpočty z opravdu reálného života. Opět je jistě řada z vás bude znát. Alespoň ten první.

Nejprve tedy výpočet přestupného roku, který se nám může někdy v našich aplikacích hodit. Funkce je opravdu jednoduchá, parametrem je požadovaný rok:

function JePrestupny(Rok: integer) : boolean;
begin
Result := ((Rok mod 4 =0) and (Rok mod 100 <>0)) or (Rok mod 400 = 0);
end;

Tak to byla taková menší rozcvička. Následující výpočet již bude značně složitější. Ukážeme si jak vypočítat, na jaký den pro daný rok připadají Velikonoce, což je údaj, který se neustále mění, a pokud vytváříte například nějakou aplikaci typu kalendáře, tento výpočet se vám jistě bude hodit. Nechtějte po mně ovšem teoretické vysvětlení algoritmu, protože se vám rovnou přiznám, že nejsem žádný astronom.

Zde je tedy zdrojový kód, parametrem funkce je znovu rok, na výstupu se nám vrátí datum opět v podobě TDateTime.

function Velikonoce(Rok : integer) : TDateTime;
var R1, R2, R3, X, Y, Z: Double;
    Tmp : integer;

begin
R1 := Rok mod 19;
R2 := Rok mod 4;
R3 := Rok mod 7;
X := 19 * R1 + 24;
Y := X - (Int(x / 30) * 30);
Z:=(5 + 2 * R2 + 4 * R3 + 6 * Y);
Tmp := Trunc((Z - (Int(Z / 7) *7)) + Y + 22);
if Tmp <= 31 then Result := EncodeDate(Rok, 3, Tmp)
else
begin
if Tmp -31 >= 26 then Tmp := 19
else Dec(Tmp, 31);
Result := EncodeDate(Rok, 4, Tmp);
end;
end;

Zalomení textu u tlačítek na více řádků

Pokud potřebujete u komponent třídy TButton, jako je samotné tlačítko, ale také CheckBox a RadioButton, zalomit delší text popisku na více řádek, pomůže vám v tom následující užitečná funkce:

function Zalomit(CTRL: TButtonControl): boolean;
var style : dword;
begin
style := GetWindowLong(CTRL.Handle, GWL_STYLE);
SetLastError(0);
SetWindowLong(CTRL.Handle, GWL_STYLE, Style or BS_MULTILINE);
Result := (GetLastError = 0);
if result then CTRL.Repaint;
end;

Pomocí této funkce můžeme dosáhnout u požadovaných objektů zalomení řádku. Daný objekt je předáván jako parametr a musí být typu TButtonControl. Nejvhodnější bude umístit toto nastavení přímo do události OnCreate hlavního formuláře:

procedure TForm1.FormCreate(Sender: TObject);
begin
Button1.Caption:=`Tlačítko s popisem na více řádek`;
Zalomit(Button1);
end;

Pochopitelně musíte dané tlačítko či radiobutton dostatečně zvětšit na výšku, aby se tam kompletní text vešel. Jinak bude vidět samozřejmě jen část.

Efektní vypisování textu pomocí komponenty Edit

Na závěr si teď ukážeme zajímavý efekt s vypisováním textu. Nevím, jak jej nazvat, tak ho alespoň popíšu, protože ho jistě znáte a vybaví se vám. Jedná se o postupné vypisování daného textu znak po znaku, připomínající psaní na psacím stroji nebo snad dálnopisu. Vše se bude vypisovat do komponenty edit, se kterou si můžete dokonale vyhrát. Nejprve bych doporučil změnit barvu podkladu textu na barvu samotného okna, poté ještě nastavte v Object Inspectoru vlasnost BorderStyle na BsNone, takže již není komponenta vůbec vidět. Ještě nastavte vhodnou velikost (délku) podle délky vypisovaného textu. Pokud bude délka řekněme podstatně kratší než text, získáme navíc ještě efekt horizontálního scrollování. Případně upravte font.

A zde je samotný kód:

procedure TForm1.Button5Click(Sender: TObject);
var Cnt : integer;
    Txt : string;
begin
txt := `Sem doplňte váš vlastní text, který bude vypisován`;
for cnt := 1 to length(txt) do
begin
Edit2.Perform(WM_CHAR, Ord(Txt[Cnt]), 0);
Edit2.Update;
if Cnt < Length(txt) then
  begin
  Sleep(50);
  Application.ProcessMessages;
  end;
end;
end;

Jak vidíte, kromě samotného zobrazovaného textu je neméně důležitou součástí i pauza mezi jednotlivými "úhozy". Zde je pro jednoduchost použita funkce Sleep doplněná o Application.ProcessMessages, aby při vypisování nedošlo ke "kousnutí" programu. Samozřejmě můžete použít jinou konstrukci, experimentovat s délkou pauzy a podobně.

Pozorní čtenáři možná přijdou na jednu drobnou vadu na kráse celého efektu. Jelikož je využívána pro zjednodušení komponenta Edit, může do ní uživatel během vypisování textu samozřejmě psát a celý efekt tak zkazit. Při vhodné úpravě parametrů sice není vizuálně poznat, že se jedná o Edit, přesto musíte s touto možností počítat, a pokud jste perfekcionisté, ošetřit tuto situaci v kódu. Předem upozorňuji, že nastavení vlastnosti na ReadOnly problém neřeší, protože pak se samozřejmě zakáže i naše automatické vypisování a z celého efektu nezbude nic. :)