|
|
A Delphi továbbfejlesztése saját funkciókkal
|
|
Példaprogram letöltése
25590 bájt
|
A feladat a következő: egészítsük ki a Delphi menürendszerét egy új menüponttal, az erre való kattintáskor pedig jelenjen meg egy dialógus ablak, ahol olyan funkciókat használhatunk, melyek különféle módosításokat végeznek az aktuálisan szerkesztett forráskódon, segítve a programozási munkáinkat.
Ismerős az alábbi forráskód részlet?
if Assigned(FOnChange) then begin
FOnChange(Self);
end;
Ennek előállításához a mellékelt példában csak az FOnChange szöveget kell begépelni és kijelölni, majd egy kattintással létrehozható a fenti forráskód. A példa alapján persze tetszőleges funkciót is készíthetünk igény szerint.
A mellékelt példa kipróbálásához a következő lépésekre van szükség:
- nyissa meg az AnimareService.dpk-t
- ha nem a Delphi 4-es verzióját használja, akkor nyomja le az F12-t, ekkor megjelenik az AnimareService.dpk forráskódja, itt a 40. sorban írja át a vcl40-et vcl50-re Delphi 5 esetén, illetve vcl60-ra Delphi 6 esetén.
- kattintson az Install gombra, ekkor fordítás után megjelenik a Help menüpont előtt egy Animare menüpont
- nyissa meg a Sample könyvtárban lévő Project1.dpr-t
- jelölje ki a Unit1.pas 41. sorában lévő FOnChange szót
- válassza az Animare - Tools menüpontot
- a megjelenő ablakban kattintson az Assigned gombra, ennek hatására a kijelölt FOnChange szöveg megváltozik a bevezetőben említett forráskódra
Mellékelt példa akkor működik helyesen, ha a Tools - Environment Options - Editor ablakában a Block ident és a Tab Stops értéke egyaránt kettő. Ettől eltérő érték esetén a beszúráskor a szöveg elcsúszhat. Ennek korrigálása megoldható, ha javítjuk a forráskódot azokon a pontokon, ahol a Space nevű belső függvényünk kerül meghívásra. Itt szabályozhatjuk, hogy hány szóköz kerüljön beszúrásra az egyes sorok esetén.
Amint az az eddigiekből is látható jelentős kiegészítéseket vihetünk véghez a Delphi fejlesztő környezetén, kiegészítve saját funkcióinkkal, melyek teljesen egyediek lehetnek és így a sokszor ismétlődő feladatainkat automatizálhatják. A Delphi lehetőséget biztosít a menürendszere kiegészítésére, a forráskód, sőt még akár a Form-ok manipulálására is. A lehetőségeink korlátlanok, csak tudnunk kell, hogy mit hogyan valósíthatunk meg.
Nézzük most, hogy miként hozhatjuk létre a mellékelt példában szereplő funkciót.
Első lépésként hozzunk létre egy új komponens csomagot: File - New - Package. Ezt célszerű rögtön el is menteni valamilyen névvel. Szükségünk lesz még egy DataModule-ra is (File - New - DataModule). Létrehozás után ezt is mentsük, majd vegyük fel a már létrehozott Package-be az Add gombbal.
A DataModule forráskódjában deklaráljunk egy speciális osztályt, mely a TInterfacedObject és az IOTAWizard osztályból származik.
TWizard=class(TInterfacedObject, IOTAWizard)
public
procedure AfterSave;
procedure BeforeSave;
procedure Destroyed;
procedure Modified;
procedure Execute;
function GetState:TWizardState;
function GetIDString:string;
function GetName:string;
constructor Create;
destructor Destroy; override;
end;
Ez biztosítja, hogy hozzáférjünk a Delphi-hez és azt saját funkcióinkkal egészítsük ki.
Helyezzünk el a procedure Register; deklarációját is a unit interface részében, mintha csak egy komponenst szeretnénk installálni. Most viszont a Register eljárásában nem komponenst telepítünk, hanem itt installáljuk a saját funkciónkat a Delphi-be. Ehhez a RegisterPackageWizard függvényt kell használnunk. Paraméterként egy olyan objektumot kell átadnunk, mely TInterfacedObject és az IOTAWizard osztályból származik, vagyis amit az imént létrehoztunk TWizard néven. Mivel itt már egy létező objektumra van szükség, így rögtön meghívjuk az objektum konstruktorát a Create-et.
procedure Register;
begin
RegisterPackageWizard(TWizard.Create);
end;
Nézzük a TWizard osztályunk metódusait, melyek közül jelen példánkhoz csak kettőre lesz szükségünk, méghozzá konstruktorra és destruktorra. Az egyiknél létrehozunk egy példányt a TDataModule-ból, míg a másiknál megszüntetjük azt.
constructor TWizard.Create;
begin
DataModule1:=TDataModule1.Create(nil);
end;
destructor TWizard.Destroy;
begin
DataModule1.Free;
inherited;
end;
Amikor a Delphi elindul, akkor töltődik be a TWizard osztályunk. Ennek ekkor fut a konstruktora, mely létrehozza a TDataModule-t. Nézzük mi is történik ekkor. A TDataModule konstruktoránál hozzuk létre a Delphi menürendszerébe az új, saját menüpontunkat. Ennek megvalósításához tegyünk egy TPopupMenü komponenst a TDataModul-ra. Ide vegyük fel a szokásos módszerrel a szükséges menüpontokat, rendeljünk hozzá OnClick eseménykezelőt, stb. Ha ez megvan, akkor a TDataModule létrejöttekor, vagyis annak konstruktorában már csak át kell másolnunk ezeket a menüpontokat a Delphi menürendszerébe. Ehhez azonban le kell kérdeznünk ezt a menürendszert, melyet a BorlandIDEServices változóban tárolt objektum segítségével tehetünk meg. Ha adott a menürendszer, akkor már csak a TPopupMenu-ben tárolt menüpontok áthelyezése marad.
procedure TDataModule1.DataModuleCreate(Sender: TObject);
var
m: TMenuItem;
begin
m:=(BorlandIDEServices as INTAServices).MainMenu.Items;
PopupMenu1.Items.Caption:='Animare';
m.Insert(m.Count-1, PopupMenu1.Items);
end;
Ezzel az új menüpont meg is jelenik a Delphi menürendszerében. Hogy ez hol jelenjen meg, azt az Insert eljárás első paraméterében adjuk meg. A Count-1 azt jelenti, hogy az új menü beszúrása az utolsó előtti helyre történjen, vagyis a Help menüpont elé.
Amikor erre a menüpontra kattintunk, akkor kell megnyitni a saját dialógus ablakunkat.
procedure TDataModule1.item1Click(Sender: TObject);
begin
if not Assigned(ToolsDlg) then begin
ToolsDlg:=TToolsDlg.Create(Application);
end;
ToolsDlg.Show;
end;
Ehhez persze nem árt, ha készítünk egy dialógus ablakot. Mellékelt példában ezt a Dlg.pas-ban találhatjuk meg. A dialóg létrehozása után ezt az állományt is fel kell vennünk a Package-be.
Ha tehát az új menüpontra kattintunk, akkor megnyílik ez az ablak, mintha az csak a Delphi része lenne. Itt tetszőleges komponenseket, funkciókat használhatunk, mintha csak egy hagyományos alkalmazást készítenénk.
Mellékelt példában csak egy nyomógombot helyeztünk el. Ennek azt a feladatot szánjuk, hogy ha van egy kijelölt szövegrész a forráskódban, akkor azt cserélje ki az alábbira:
if Assigned(xxx) then begin
xxx(Self);
end;
Ráadásul ezt a cserét úgy oldja meg, hogy az xxx helyére a kijelölt szót másolja be.
Nézzük a megvalósítást. Első lépésként tudnunk kell, hogy melyik az aktuális forráskód, mivel a Delphi-ben egy időben több megnyitott PAS is lehet. Ezt könnyedén megtudhatjuk a ToolServices változóban tárolt objektum segítségével, melynek a GetCurrentFile függvénye egy olyan sztringet ad vissza, mely közli velünk az aktuálisan szerkesztett állomány nevét elérési útvonallal együtt. Ha nincs nyitott állomány, akkor nullsztringet kapunk vissza.
var
CurrentFile: string;
...
CurrentFile:=ToolServices.GetCurrentFile;
Következő lépésként a modul interfészt kell lekérdezni a GetModuleInterface függvénnyel. Paraméterként az előbb kapott állománynevet kell átadnunk.
var
ModuleInterface: TIModuleInterface;
...
ModuleInterface:=ToolServices.GetModuleInterface(CurrentFile);
Ha nem nil-t kapunk eredményül, akkor a lekérdezés sikeres volt, továbbléphetünk. Következő feladat a szerkesztő osztály interfészének meghatározása. Ehhez az imént kapott TIModuleInterface GetEditorInterface függvénye használható.
var
EditorInterface: TIEditorInterface;
...
EditorInterface:=ModuleInterface.GetEditorInterface;
A lekérdezések sorának még ezzel sincs vége: a kapott interfész segítségével meg kell határoznunk azt az osztályt, mely a Delphi szövegszerkesztőjét képviseli az aktuális forráskódhoz. Erre a GetView függvény szolgál.
var
EditView: TIEditView;
...
EditView:=EditorInterface.GetView(0);
A feladat most az, hogy meghatározhassuk azt a szöveget, mely kijelölt a szövegszerkesztőben. Ehhez le kell kérdeznünk a szövegkijelölés kezdő illetve végső pozícióját. Ezeket az EditorInterface osztály BlockStart és BlockAfter property-éből tudhatjuk meg. Ezeket az értékeket rögtön konvertáljuk is az EditView osztály CharPosToPos függvényével longint típusúra. Így egyetlen számmal leírható a kijelölés kezdőpontja és egy másikkal a végpontja. Ezeket az értékeket tároljuk el az endpos és pos lokális változókba.
var
endpos, pos: longint;
...
pos:=EditView.CharPosToPos(EditorInterface.BlockStart);
endpos:=EditView.CharPosToPos(EditorInterface.BlockAfter);
Ebből a két számból számítható, hogy hány karakter van kijelölve.
var
count: integer;
Text: string;
...
count:=endpos-pos;
SetLength(Text, count);
A szöveg kiolvasásához létre kell hoznunk egy olyan objektumot, mely képes arra, hogy olvassa a Delphi forráskódját. Ehhez az EditorInterface objektum CreateReader függvénye használható. A létrejött objektum GetText függvényével lekérdezhető a forráskód tetszőleges területe. Nekünk most a pos változóban tárolt karaktertől kezdve kell tudnunk a szöveget, méghozzá a count változóban tárolt karakter számig. A lekért szöveget a Text lokális változóban tároljuk.
var
EditReader: TIEditReader;
...
EditReader:=EditorInterface.CreateReader;
EditReader.GetText(pos, PChar(Text), count);
EditReader.Free;
...
Most, hogy a kijelölt szöveget már ismerjük a Text változóban, már csak az van vissza, hogy az új szöveget beszúrjuk az aktuális forráskódba. Ehhez egy olyan osztályra lesz szükségünk, mely képes a forráskód módosítására. Az EditorInterface CreateUndoableWriter függvényének hívásával kaphatunk egy ilyet. A kijelölt szöveget először törölnünk kell a forráskódból a DeleteTo hívásával, majd az Insert-el beszúrni az új szöveget.
var
EditView: TIEditView;
...
EditWriter:=EditorInterface.CreateUndoableWriter;
if EditWriter<>nil then begin
try
EditWriter.CopyTo(pos);
EditWriter.DeleteTo(endpos);
EditWriter.Insert(PChar('if Assigned('+Text+') then begin'#13''+
Space(lpos+2)+Text+'(Self);'#13''+Space(lpos)+'end;'));
finally
EditView.Free;
EditWriter.Free;
end;
end;
Ezzel a feladatot teljesítettük.
Az ilyen jellegű munkák elvégzése közben figyeljünk arra, hogy amikor változtatunk a forráskódon, akkor újrafordítás előtt zárjuk be az éppen készítendő dialóg ablakot. Ha ezt nem tesszük, akkor gyakorlati tapasztalatunk alapján elmondhatjuk, hogy a Delphi igen sűrűn le fog fagyni, mindenféle érdekes hibaüzenetek közepette. Ez a probléma a Delphi eddig megjelent összes verziójánál jelentkezett. Ha viszont a dialóg ablakunkat nem nyitjuk meg, akkor bátran módosíthatunk rajta.
|
Könyv
Ez a cikk megtalálható ebben a könyvben:
Delphi Software Offline 2001 évkönyv 54. 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!
|