|
|
Béta tesztelés megkönnyítése
|
|
Példaprogram letöltése
15443 bájt
|
Ha egy nagyobb alkalmazáson dolgozunk és szeretnénk igénybe venni a teszteléshez más cégeket, szoftverfejlesztőket is a program béta teszteléséhez, akkor nem árt, ha a tesztelők életét, na meg a miénket is megkönnyítjük egy olyan lehetőséggel, hogy ha hibát találnak valamely ablakunknál, akkor erről egyszerűen tudjanak értesíteni bennünket.
A hiba leírásán kívül persze a tesztelőnek azt is meg kell adnia, hogy hol, melyik ablaknál történt a hiba. Ezt viszont nehezen tudja beazonosítani, főleg ha programunk több száz ablakot tartalmaz.
Hogy egyszerű legyen az azonosítás, létrehozunk egy olyan komponenst, mely képes egy tetszőleges szöveget megjeleníteni minden ablak fejlécén jobbra igazítva. Ha a felhasználó rákattint erre a szövegre, akkor a komponens segítségével generálhatunk egy e-mail-t, melybe rögtön beírásra kerül, hogy melyik program, melyik ablakáról van szó. Ezek után a tesztelőnek már csak a konkrét hibát kell leírnia és küldheti az e-mail-t részünkre.
A mellékelt példaprogram megnyitása előtt a CaptionLabel.pas-ban lévő komponenst telepítenie kell a Delphi alá.
A komponenst helyezzük el minden olyan Form-on, melynek fejlécére szeretnénk egy szöveget elhelyezni.
A megjelenítendő szöveget a komponens Caption property-ébe írhatjuk be.
Átmenetileg a Visible property-vel letilthatjuk a láthatóságát ennek a feliratnak.
A szöveg betűtípusát a Font property-n keresztül adhatjuk meg.
Amikor a felhasználó az egérrel rámutat a feliratra, akkor annak színe az ActiveColor property-ben megadott színűre változik.
Amikor kattintás történik az egérrel a szövegen, akkor jön létre az OnClick esemény.
Ebben az esetben, ha az AutoMail property igaz, akkor a komponens generál egy e-mail-t, melynek címzettje az EmailAddress property-ben megadott lesz, míg a levél tárgya az EmailSubject property-ben tárolt értéket kapja. A levél szövegébe bekerül az alkalmazásunk neve és annak a Form-nak neve is, melyen az aktuális komponens áll. Végül a komponens megnyitja az alapértelmezett levelező programot, ahol megjelenik ez az előkészített e-mail, így a felhasználónak már csak az észrevételeit kell leírnia és küldheti is a levelet.
A komponens működéséhez szükségünk lesz arra, hogy a Form néhány üzenetét elcsíphessük. Ilyen lesz például a CM_TEXTCHANGED, WM_NCPAINT, WM_NCACTIVATE, stb.
Mivel a komponensünk a TComponent-ből származik, így nem rendelkezik ablakkezelő eljárással és ezért az üzeneteket sem fogja megkapni. Új ablakkezelő eljárást létrehozhatnánk ugyan az AllocateHWND-vel, de ez sem lenne jó, mivel nekünk most annak a Form-nak az üzeneteire van szükségünk, melyen komponensünk áll.
Ehhez azt tesszük, hogy a deklarálunk egy belső ablakkezelő eljárást és ezzel cseréljük fel a Form-ét, majd amikor ez fut, meghívjuk a Form eredeti eljárását, így az is működőképes marad és a mi komponensünk is tudomást szerezhet az üzenetekről. A cserére a komponens konstruktoránál kerül sor.
constructor TCaptionLabel.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
...
FOldWndProc:=(AOwner as TForm).WindowProc;
(AOwner as TForm).WindowProc:=NewWndProc;
...
end;
Természetesen a cserét vissza kell állítanunk abban az esetben, ha a komponenst törölnénk a Form-ról. Ehhez a destruktort használjuk fel.
destructor TCaptionLabel.Destroy;
begin
if not FDestroying then begin
Visible:=false;
(Owner as TForm).WindowProc:=FOldWndProc;
end;
FFont.Free;
inherited Destroy;
end;
Amikor a saját ablakkezelő eljárásunk fut, akkor első lépésként meghívjuk a régi ablakkezelőt, melyet az FOldWndProc globális változóba eltároltunk.
procedure TCaptionLabel.NewWndProc(
var Msg: TMessage);
var
p: TPoint;
begin
FOldWndProc(Msg);
...
Amikor a CM_TEXTCHANGED, WM_NCPAINT, WM_NCACTIVATE üzeneteket kapjuk, akkor kell a megjelenítendő szöveget kirajzolnunk a Form fejlécére. Ehhez a RedrawLabel belső eljárásunkat hívjuk meg. Erről a későbbiekben még lesz szó bővebben.
...
case Msg.Msg of
CM_TEXTCHANGED, WM_NCPAINT,
WM_NCACTIVATE: begin
RedrawLabel(false);
end;
...
Ha WM_NCHITTEST üzenet érkezik, akkor kell ellenőriznünk, hogy az egér a szövegünk felett tartózkodik-e vagy sem. Első lépésként azt ellenőrizzük, hogy egyáltalán az ablak fejlécénél van-e az egér. Ez akkor igaz, ha az üzenet Result értéke htCaption-al egyenlő.
Ebben az esetben az egér koordinátáit vizsgálva ellenőrizzük, hogy az a szöveg felett van-e vagy sem. Bármely esetről is van szó, meghívjuk ismét a RedrawLabel-t. Paraméterként viszont vagy igaz, vagy hamis értéket adunk át, attól függően, hogy mi lett az egér koordináta kiértékelésének eseménye. Ugyanis amikor az egér a szöveg felett van, akkor azt más színnel (ActiveColor property) kell kirajzolnunk, mint alapesetben. Amikor felette van, akkor az üzenet visszatérési értékének egy egyedi számot adunk, melyet a messagenum változónkban tároltunk eddig és a komponens konstruktoránál hozzuk létre. Hogy ez miért szükséges, arra hamarosan fény derül.
...
WM_NCHITTEST: begin
if Msg.result=htCaption then begin
p.x:=LoWord(Msg.lParam);
ScreenToClient((Owner as TForm).Handle, p);
if (p.x>GetButtonRect.Left) and
(p.x<GetButtonRect.Right) then begin
RedrawLabel(true);
Msg.Result:=messagenum;
end else begin
RedrawLabel(false);
end;
end else begin
RedrawLabel(false);
end;
end;
...
A következő esemény, amire figyelnünk kell az az egérrel történő kattintás az adott szövegre. Az egér gomb lenyomását a WM_NCLBUTTONDOWN esemény jelzi. Ekkor, ha paraméterként megkapjuk a WM_NCHITTEST üzenetnél átadott értéket, akkor biztosak lehetünk abban, hogy az egér gomb lenyomása a szövegünk felett történt, mivel ezt a feltételt az imént már vizsgáltuk. Ebben az esetben a SetCapture hívásával a további egér eseményeket is a Form-unkhoz irányítjuk.
...
WM_NCLBUTTONDOWN: begin
if Msg.wParam=messagenum then begin
if not FMouseDown then begin
FMouseDown:=true;
SetCapture((Owner as TForm).Handle);
end;
end else begin
if FMouseDown then begin
FMouseDown:=false;
ReleaseCapture;
end;
end;
end;
...
Amikor az egér gombja felengedésre kerül, akkor hozzuk létre az OnClick eseményt és szükség esetén ekkor generáljuk az e-mail-t is a SendMail belső eljárásunk által.
...
WM_NCLBUTTONUP, WM_LBUTTONUP: begin
if FMouseDown then begin
FMouseDown:=false;
if Assigned(FOnClick) then begin
FOnClick(Self);
end;
if FAutoMail then begin
SendMail;
end;
end;
end;
...
Az e-mail küldéshez a HlinkNavigateString függvényt használjuk. Ennek második paraméterébe kell megadnunk egy sztringet, mely a következőképpen nézhet ki:
mailto:animare@animare.hu?subject=ide jön a tárgy&body=ide jön a levél szövege
A HlinkNavigateString értelmezi a kapott szöveget és létrehozva egy új e-mail-t a megfelelő szövegrészeket elhelyezi benne, majd megnyitja azt.
procedure TCaptionLabel.SendMail;
const
w: array[boolean] of char=('?', '&');
var
s, t: string;
b: boolean;
c: array[0..1023] of WideChar;
begin
s:='mailto:'+FEmailAddress;
b:=false;
if FEmailSubject<>'' then begin
s:=s+'?subject='+FEmailSubject;
b:=true;
end;
s:=s+w[b]+'body=';
if Assigned((Owner as TForm).ActiveControl) then begin
t:='.'+(Owner as TForm).ActiveControl.Name;
end;
s:=s+Application.ExeName+' ['+(Owner as TForm).Name+t+'] '+
FormatDateTime('yyyy. mm. dd. hh:nn:ss', Now)+
' Kérjük írja le az észrevételét:';
StringToWideChar(s, c, 1024);
HlinkNavigateString(nil, c);
end;
Fontos még megvizsgálnunk a már többször is hivatkozott RedrawLabel eljárásunkat, melynek segítségével egy tetszőleges szöveget jeleníthetünk meg egy Form fejlécén. Felhívnánk a figyelmet, hogy némi átalakítással az alábbi eljárás egy tetszőleges objektumot is kirajzolhat a fejlécre és nem csak egy egyszerű szöveget, mint jelen esetben.
A rajzoláshoz létrehozunk egy TCanvas objektumot. Mivel most a Form-ra kell rajzolnunk, így le kell kérnünk ennek azonosítóját, melyet a TCanvas Handle property-ének adunk értékül. Ettől kezdve a TCanvas-al képesek leszünk a Form területére rajzolni.
procedure TCaptionLabel.RedrawLabel(b: boolean);
var
c: TCanvas;
r: TRect;
begin
if FVisible then begin
c:=TCanvas.Create;
c.Handle:=GetWindowDC((Owner as TForm).Handle);
with c do begin
Brush.Style:=bsClear;
Font.Assign(FFont);
if b then begin
Font.Color:=FActiveColor;
end;
r:=GetButtonRect;
DrawText(Handle, PChar(FCaption), Length(FCaption),
r, DT_SINGLELINE);
end;
ReleaseDC((Owner as TForm).Handle, c.Handle);
c.Free;
end;
end;
Mellékelt példában, ha szerkesztési időben változtatja a komponens Caption property-ét, akkor ez a változás rögtön meg is jelenik a Form-on. Ez viszont csak úgy lehetséges, hogy ha megkérjük a Delphi-t arra, hogy minden változtatás azonnal érvényre is jusson, vagyis változzon a komponens FCaption változója, hiszen a kirajzolás is csak ekkor történik meg. Alapesetben, ha változtatunk egy property tartalmán, akkor ez csak akkor jut érvényre, ha átlépünk egy másik property-re vagy ha elhagyjuk az Object Inspector területét. Egy apró lépéssel viszont rávehetjük a Delphi-t, hogy azonnal frissítsen. Ehhez egy új property szerkesztő osztályt kell létrehoznunk és regisztrálnunk a Caption property-hez. A property szerkesztő osztályban csak a GetAttributes függvény felülírására van szükség. Ezen keresztül határozhatjuk meg az adott property tulajdonságát. Ha a már meglévő tulajdonságokhoz hozzáadjuk a paAutoUpdate konstanst is, akkor fenti kérésünk teljesül.
function TCaptionLabelPropertyEditor.GetAttributes:
TPropertyAttributes;
begin
result:=inherited GetAttributes+[paAutoUpdate];
end;
Most már csak regisztrálnunk kell a property szerkesztő osztályt. Erre a Register eljárásban kerülhet sor a RegisterPropertyEditor hívásával. Itt első paraméterként az adott property típusáról kell megadnunk a típusinformációt, melyet a TypeInfo szolgáltat, második paraméterként az adott komponenst, harmadikként pedig annak property-ét, amelyhez regisztráljuk a property szerkesztő osztályt, végül pedig ennek az osztálynak a típusát kell átadnunk.
procedure Register;
begin
RegisterComponents('DSO', [TCaptionLabel]);
RegisterPropertyEditor(TypeInfo(string), TCaptionLabel,
'Caption', TCaptionLabelPropertyEditor);
end;
|
Könyv
Ez a cikk megtalálható ebben a könyvben:
Delphi Software Offline 2001 évkönyv 153. oldal
Felhasználási feltételek
A Software Online szoftverfejlesztői magazin mindegyik cikke, minden megjelent képe, és egyéb publikált anyaga szerzői jog védelme alatt áll! Bármilyen formában történő másodlagos terjesztésük, közzétételük vagy felhasználásuk kizárólag a kiadó előzetes írásbeli engedélyével történhet!
|