O czym bΩdzie ten artyku│? Ot≤┐ o Hintach, czyli
tzw. dymk≤w podpowiedzi, kt≤re pojawiaj▒ siΩ gdy nasuniesz kursor
nad jaki╢ komponent.
W Delphi mo┐na to bardzo │atwo stworzyµ, ale je┐eli chcemy uzyskaµ
jakie╢ bardziej skomplikowane kszta│ty to trzeba trochΩ popisaµ
:)
Zacznijmy od rzeczy prostszych, czyli...
Standardowe Hinty
Po pierwsze musisz zmieniµ w│a╢ciwo╢µ ShowHint na
True. Ka┐dy widoczny komponent posiada tak▒ w│a╢ciwo╢µ. Je┐eli ju┐
j▒ zmienisz to odnajd╝ pole Hint. Tutaj trzeba wpisaµ swoj▒ podpowied╝
- wpisz obojΩtnie jaki tekst. Teraz uruchom program i najed╝ kursorem
na komponent - wy╢wietli siΩ dymek podpowiedzi.
Teraz co╢ trudniejszego. Chcia│by╢ np., aby osobny
tekst pojawia│ siΩ w dymku i osobny na komponencie. Mo┐esz u┐yµ do
tego celu komponentu StatusBar, zmieniµ jego w│a╢ciwo╢µ SimpleBar
na True oraz AutoHint na True.
Teraz ustawiaj▒c pole Hint jakiego╢ komponentu tekst
podpowiedzi musisz wpisaµ w dw≤ch czΩ╢ciach oddzielaj▒c go od
siebie znakiem | ( znak stawia siΩ naciskaj▒c klawisz Shift + \
).
Np. tekst podpowiedzi m≤g│by wygl▒daµ nastΩpuj▒co:
Jestem etykiet▒ | To jest etykieta na kt≤rej przechowuje siΩ tekst
Tekst po lewej oddzielony znakiem | wy╢wietli│ by siΩ
w dymku, a tekst po prawej na komponencie StatusBar.
Je┐eli chcia│by╢, aby tekst wy╢wietli│ siΩ gdzie
indziej trzeba napisaµ kod :) W sekcji private umie╢µ taki oto nag│≤wek:
procedure MyCoolHint(Sender: TObject);
Teraz uzupe│nij ten kod w sekcji Implementation:
procedure TMainForm.MyCoolHint(Sender: TObject);
begin
{
Jezeli dlugosc podpowiedzi bedzie dluzsza niz 0 to wyswietl
podpowiedz na pasku tytulowym formy.
}
if Length(Application.Hint) > 0 then
Caption := Application.Hint;
end;
Jak widzisz klasa Application posiada w│a╢ciwo╢µ
Hint, kt≤ra okre╢la w│a╢nie dymek podpowiedzi. Zawiera ona tak┐e
inne ciekawe opcje:
W│a╢ciwo╢µ |
Opis |
HintColor |
Okre╢la kolor t│a
podpowiedzi. |
HintHidePause |
Definiuje okre╢la czasu, w kt≤rym
podpowied╝ zostaje ukryta. Domy╢lnie jest to 2500 milisekund. |
HintPause |
Okre╢la czas jaki mija od chwili
zatrzymania kursora nad komponentem do tego w jakim zostanie
pokazana podpowied╝. Domy╢lnie 500 milisekund. |
HintShortPause |
Je┐eli przemieszczasz siΩ
kursorem pomiΩdzy kilkoma komponentem to nastΩpuje pewien
czas, w kt≤rym stara podpowied╝ zostaje schowana, a nowa
pokazana - to w│a╢nie definiuje ta w│a╢ciwo╢µ. Warto╢µ
domy╢lna: 50 milisekund. |
Zaawansowane "dymki"
To wymaga trochΩ wiΩcej kodu. Delphi posiada klasΩ THintWindow, kt≤ra
odpowiedzialna jest za dymki. Nale┐y wiΩc zdefiniowaµ klasΩ pochodn▒
do THintWindow:
TMyHint = class(THintWindow)
private
FRegion: THandle;
procedure FreeRegion;
public
destructor Destroy; override;
procedure ActivateHint(ARect: TRect; const AHint: string); override;
procedure Paint; override;
end;
Zauwa┐, ┐e wiΩkszo╢µ metod jest przedefiniowana tzn., ┐e
istniej▒ w klasie bazowej. [ je┐eli nie wiesz o co chodzi radzΩ
przeczytaµ artyku│ Klasy ].
W tym przyk│adzie stworzymy bardziej zaawansowan▒ klasΩ, kt≤ra
zamiast prostok▒ta wy╢wietli elipsΩ z tekstem 3D. Do tego celu bΩdziemy
musieli u┐yµ region≤w, aby stworzyµ kszta│t elipsy za pomoc▒
funkcji API. Najpierw wygenerujmy procedurΩ ActivateHint - to w niej bΩdzie
siΩ odbywaµ tworzenie nowego regionu:
procedure TMyHint.ActivateHint(ARect: TRect; const AHint: string);
begin
{ Ustaw dodatkowy margines po prawej stronie }
with ARect do
Right := Right + Canvas.TextWidth('XXXXX');
BoundsRect := ARect; // przypisz zmienna do w│a╢ciwo╢ci
FreeRegion; // zwolnij dotychczasowy region
with BoundsRect do
{
Stworz nowy region w postaci elipsy.
}
FRegion := CreateRoundRectRgn(0, 0, Width, Height, Width, Height);
if FRegion <> 0 then
SetWindowRgn(Handle, FRegion, True); // ustaw nowy region
inherited ActivateHint(ARect, AHint); // wywolaj procedure z klasy bazowej
end;
Na pocz▒tku z prawej strony dodawany jest dodatkowy margines.
Funkcja TextWidth przelicza na piksele d│ugo╢µ tekstu podanego w nawiasie.
NaastΩpnie do zmiennej BoundsRect, kt≤ra jest typu TRect zostaje
przypisana zmienn▒ ARect, kt≤ra okre╢la rozmiary regionu -
podpowiedzi. Najwa┐niejsze jednak nastΩpuje w linii, w kt≤rej
tworzona zostaje elipsa. Zostaje ona przypisana do zmiennej FRegion.
NastΩpnie przy pomocy polecenia SetWindowRgn zostaje ustawiony nowy
region w postaci elipsy - mamy ju┐ konstrukcjΩ dymku.
Tylko konstrukcjΩ bowiem nale┐y w tym dymku umie╢ciµ jaki╢
tekst:
procedure TMyHint.Paint;
var
R: TRect;
begin
R := ClientRect; // pobierz rozmiary okna dymku
Inc(R.Left, 1); // przesun o piksel w lewo
Canvas.Font.Color := clSilver; // ustaw czcionke na bial
{ narysuj tekst wysrodkowany w pionie i w poziomie }
DrawText(Canvas.Handle, PChar(Caption), Length(Caption), R,
DT_NOPREFIX or DT_WORDBREAK or DT_CENTER or DT_VCENTER);
Inc(R.Left, 2); // przesun o kolejne dwa piksele
Canvas.Brush.Style := bsClear; // ustaw na przezroczyste
Canvas.Font.Color := clBlack; // zmien czcionke na czarna
{ narysuj tekst ponownie inna czcionka z przesunieciem - daje efekt cienia }
DrawText(Canvas.Handle, PChar(Caption), Length(Caption), R,
DT_NOPREFIX or DT_WORDBREAK or DT_CENTER or DT_VCENTER);
end;
Tutaj wszystko odbywa siΩ za pomoc▒ funkcji API - DrawText. Jest to
polecenie, kt≤re umo┐liwia narysowanie tekstu wycentrowanego w pionie
jak i w poziomie.
Wszystko jest rysowane dwa razy, aby daµ efekt cienia. Pierwszy tekst
rysowany jest z czcionk▒ koloru srebrnego, a drugi raz koloru czarnego
z minimalnym przesuniΩciem.
To w│a╢ciwie wszystko co najwa┐niejsze. Trzeba jeszcze napisaµ
jedn▒ procedurΩ zwi▒zan▒ z regionami, a mianowicie zwalniaj▒ca owy
region.
procedure TMyHint.FreeRegion;
begin
if FRegion <> 0 then // Czy region nie jest uzywany?
begin
SetWindowRgn(Handle, 0, True); // ustaw na brak regionu
DeleteObject(FRegion); // usun region
FRegion := 0;
end;
end;
Ok - wykorzystanie nowej klasy mo┐esz ju┐ sprawdziµ. Umie╢µ w
module sekcje initialization i jako klase podpowiedzi ( HintWindowClass
) przypisz przed chwil▒ stworzon▒ klasΩ:
initialization
HintWindowClass := TMyHint; // przypisz nowa klase podpowiedzi
Application.HintColor := clWhite; // ustaw tlo Hinta na bialy
Gotowe. Oto ca│y kod programu:
(****************************************************************)
(* *)
(* THintWindow test programme *)
(* Copyright (c) 2001 by Adam Boduch <28.05.2001> *)
(* HTTP://PROGRAMOWANIE.OF.PL *)
(* E - mail: boduch@poland.com *)
(* *)
(****************************************************************)
unit MainFrm;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, ExtCtrls;
type
TMainForm = class(TForm)
Label1: TLabel;
procedure FormCreate(Sender: TObject);
private
{ procedura wyswietlajca podpowiedz na pasku formy }
procedure MyCoolHint(Sender: TObject);
end;
{ nowa klasa podpowiedzi dziedziczaca z klasy THintWindow }
TMyHint = class(THintWindow)
private
FRegion: THandle;
procedure FreeRegion;
public
destructor Destroy; override;
procedure ActivateHint(ARect: TRect; const AHint: string); override;
procedure Paint; override;
end;
var
MainForm: TMainForm;
implementation
{$R *.DFM}
destructor TMyHint.Destroy;
begin
FreeRegion; // wywolaj procedure
inherited Destroy;
end;
procedure TMyHint.FreeRegion;
begin
if FRegion <> 0 then // Czy region nie jest uzywany?
begin
SetWindowRgn(Handle, 0, True); // ustaw na brak regionu
DeleteObject(FRegion); // usun region
FRegion := 0;
end;
end;
procedure TMyHint.ActivateHint(ARect: TRect; const AHint: string);
begin
{ Ustaw dodatkowy margines po prawej stronie }
with ARect do
Right := Right + Canvas.TextWidth('XXXXX');
BoundsRect := ARect; // przypisz zmienna do wlasciwosci
FreeRegion; // zwolnij dotychczasowy region
with BoundsRect do
{
Stworz nowy region w postaci elipsy.
}
FRegion := CreateRoundRectRgn(0, 0, Width, Height, Width, Height);
if FRegion <> 0 then
SetWindowRgn(Handle, FRegion, True); // ustaw nowy region
inherited ActivateHint(ARect, AHint); // wywolaj procedure z klasy bazowej
end;
procedure TMyHint.Paint;
var
R: TRect;
begin
R := ClientRect; // pobierz rozmiary okna dymku
Inc(R.Left, 1); // przesun o piksel w lewo
Canvas.Font.Color := clSilver; // ustaw czcionke na bial
{ narysuj tekst wysrodkowany w pionie i w poziomie }
DrawText(Canvas.Handle, PChar(Caption), Length(Caption), R,
DT_NOPREFIX or DT_WORDBREAK or DT_CENTER or DT_VCENTER);
Inc(R.Left, 2); // przesun o kolejne dwa piksele
Canvas.Brush.Style := bsClear; // ustaw na przezroczyste
Canvas.Font.Color := clBlack; // zmien czcionke na czarna
{ narysuj tekst ponownie inna czcionka z przesunieciem - daje efekt cienia }
DrawText(Canvas.Handle, PChar(Caption), Length(Caption), R,
DT_NOPREFIX or DT_WORDBREAK or DT_CENTER or DT_VCENTER);
end;
procedure TMainForm.MyCoolHint(Sender: TObject);
begin
{
Jezeli dlugosc podpowiedzi bedzie dluzsza niz 0 to wyswietl
podpowiedz na pasku tytulowym formy.
}
if Length(Application.Hint) > 0 then
Caption := Application.Hint;
end;
procedure TMainForm.FormCreate(Sender: TObject);
begin
// ustaw procedure podpowiedzi na wczesniej zdefiniowana
Application.OnHint := MyCoolHint;
end;
initialization
HintWindowClass := TMyHint; // przypisz nowa klase podpowiedzi
Application.HintColor := clWhite; // ustaw tlo Hinta na bialy
end.
Oczywi╢cie mo┐esz tworzyµ bardziej skomplikowane kszta│ty ( w procedurze
ActivateHint ) lub w samym dymku podpowiedzi umieszczaµ np. bitmapkΩ (
procedura Paint ).
Klikaj▒c na poni┐szy link mo┐esz ╢ci▒gn▒µ gotowy program
wykorzystuj▒cy napisan▒ wcze╢niej klasΩ.
HintWindow.zip
( 3 kB )
Adam Boduch