Második számunkban az előzőekben általam eltervezettektől kicsit eltérünk ugyanis Olvasó kérdésre - is - válaszolunk. BALI kérdését preferáljuk, s lássunk is neki de rögvest: 

Első nemes kérdés: Hogyan lehet elmenteni a progit EXE formátumban ?

Nos tényleg az előző számban erről még nem ejtettünk szót, mert egyszerűnek tekintettem. De lássuk a választ: tudomásom szerint a Borland Delphi már 1.0-tól a futtatás (RUN) során automatikusan EXE-be fordítja az elkészített programot, persze ha nincs benne hiba és lefordítható. Ezt az EXE-t ha még nem mentettük el semmilyen néven a project-et akkor automatikusan a \Program Files\Borland\Delphi 3.0\BIN\ alkönyvtárban tárolja el project1.exe néven. Mielőtt először lefuttatnánk programunkat mentsük le egy külön könyvtárba az egész project-et (érdemes egy könyvtárba egy project-et). Figyeljünk arra, hogy nem lehet azonos a project neve és a unit-ok neve annak ellenére, hogy különböző a kiterjesztésük. És lám, az első futtatás után megjelenik ama könyvtárban a lefordított file EXE-je.

A második kérdés előtt viszont szükséges pár alapfogalom tisztázása:

Események ill. kezelésük

Lévén, hogy objektum-orientált nyelv a Delphi a vizuális komponensek ill. a felhasználó által generálható - generált események (ami lehet egy billentyű leütés, egér mozgatás, vagy ablak méretezés / becsukás, stb.) illik lekezelni. Részünkről amíg nem írunk új vizuális komponenseket az esemény kezelés nem ró vállunkra nagy terhet. Csupán annyit kell megtennünk, hogy teljesen vizuális módon társítjuk a végrehajtandó feladatot egy komponensben bekövetkezett eseményhez, pl. egy gomb lenyomásához.

Esemény rendelése egy gombhoz

Lássunk egy példát. Előző számunkban a TBitBnt típusú komponenst használtuk gombként. Ennek előnye, hogy már vannak eleve hozzátársított események, így láthattuk, hogy a Close feliratú gomb automatikusan meghívja a From Close metódusát. Most egy sima gombot használunk, s mi társítunk hozzá eseményeket:

A feladat felettébb primitív, a Delphi Standard vizuális komponensei közűl a sima TButton-ra (egy gomb a képe) duplán klikkantunk, majd az object inspector-ban átváltunk a tulajdonságok (properties) fülről az események (events) fülre, s hozzá társítjuk azt az eseményt mely a gomb lenyomásakor hívódik meg, ez az: OnClick. Egyes eseményeknél ha a combobox (ez a kis lenyitható lista) lefelé mutató nyilára klikkelünk automatikusan felajánl egy eseménykezelő rutin nevet, amennyiben nem, akkor a szöveg bekérő mezőre duplán klikkantva kapjuk a generált, hozzátársított nevet. Ezután a forráskódban megtalálható a Form1.Button1Click újonnan generált metódus. Ide írhatjuk be végrehajtandó parancsainkat. 

Ez legyen most simán: Close; Ez a Form bezáró metódusát hívja meg.

Dióhéjban a menükről

Most haladjunk tovább, s röpke pillanatok alatt tekintsük át a menükészítés mibenlétét. A Standard komponenscsoport legelső eleme, duplán klikkantsunk rá. Miután megjelent a form-on a menüt jelképező kis képecske, újfent klikkantsunk rá duplán, hogy elkészíthessük a menü-t, a főmenüket, s azoknak egyéb almenüit. Ekkor az alábbi képet kapjuk:

Az insert-tel hozhatunk létre új főmenüt (a menübár egyes bejegyzéseit főmenünek nevezzük), s az eslő insert után már a From1-en is megjelenik. Ha a Form1.MainMenu1 menüszerkesztőben a menüre megyünk akkor hasonlóan beállíthatjuk a feliratát, s egyéb jellemzőit, mint más objektumoknál az object inspector-ban. Pár fontos beállítás:

    Caption- ez maga a menü neve. Ha & jelet teszünk a névbe akkor az azt követő betű alá lesz húzva, s ezt a billentyűt megnyomva a menüben rögtön meghívódik a hozzá tartozó menüpont.

    Checked - Ez egy beállítás be vagy kikapcsolt állapotát mutathatja, ill. ha e menüre rámegyünk akkor a beállítás az ellentettére változik. Ez ilyen pipa: ü (Ez a megszokott mód Windows-ban, így illik megírni a menüt. Ezt egy egyszerű sorral meg is tehetjük: menüelem.Checked:=Not menüelem.Checked;)

    Default - kiemelt, bold font típusú lesz a menüpont felirata, ezt nevezik alapértelmezésű menüpontnak

    Hint - minden komponensnél létező tulajdonság, ha szöveget írunk e mezőbe, akkor az objektum felett egérrel elhaladva egy sárga téglalapban információt közölhetünk a felhasználóval, ha megnyomja pl. a gombot akkor mi fog történni. Most mondtam el mert máshol még nem tettem meg, de figyelem: minden komponensnél megtalálható.

    RadioItem - Használható MDI alkalmazásoknál a menük megfelelő csoportosítására, s könnyebb ablakok közötti hasonló menü kiépítésére.

    ShortCut - Forrókulcsot (pl. Ctrl+A) rendelhetünk egy menüponthoz.

    Visible - Ez is mindenhol használható tulajdonság, a vizuális komponenset tehetjük láthatóvá (ez az alapértelmezés - True) ill. rejtetté (False).

Egy menüponton állva abban további almenüket hozhatunk létre a Create submenu paranccsal. (Lásd a fenti ábrát.)

Miután elkészítettük álmaink menüjét, így azokhoz is eseményeket rendelhetünk. Az esemény hozzárendelése felettébb egyszerű, a Form-ban a menüben járkálva kiválasztjuk azon menüpontot melyhez eseményt akarunk rendelni, s egyszerűen csak rá megyünk, mintha a programból használnák. Ekkor generálódik hozzá egy eseménykezelő rutin, mely rögtön megjelenik a forráskód ablakban.

Ha már a menüknél tartunk elmondom, hogyan lehet bármely komponenshez tartozó jobb-gombbal előhívható pop-up menüt készíteni. A standard komponensek közűl a másodikat a TPopupMenu típusú objektumot hozzuk létre. Hasonlóan a menühöz létrehozzuk a menüszerkezetet. Majd a kívánt komponens property-jében (az object inspector-ral) a pop-up menü részen beállítjuk. Így:

Nézzük meg a szabványos Win3.1-es file - könyvtár - drive ablak összeállítását:

Válasszuk ki a Win3.1-es komponens fület a Delphi-ben, s hozzunk létre egy FileListBox, DirectoryListBox, ill. DriveComboBox-ot. Ezekez helyezzük el szépen a Form-on a megszokott módon, valahogy így:
 
 

Az ábrán látható módon a drivecombobox-nál a DirList tulajdonságnál lehet beállítani a drivebox-hoz tartozó DirectoryListBox-ot. Erre azért van szükség hogyha drive-ot váltunk akkor az ahhoz tartozó könyvtárstruktúra jelenjen meg a dirlistbox-ban. Ezt a tulajdonságot is természetesen legegyszerűbben az object editor-ral állíthatjuk be. A DirectoryListBox-nak is van egy a FileListBox-ra mutató eleme, a FileList elem. Amint az ábrán láthatjuk meg kell adni a dirlist-nek is a FileListBox nevét, hogy azt könyvtár váltás után frissíteni tudja. Ez a Win3.1-es konvenció file kijelzése, de látható, hogy a hosszú file-neveket is kiírja. Az igazi szép a Windows Explorer-hez (Intéző) hasonló kijelzés. 

Most már nekiállhatunk a második kérdés megválaszolásához:

2., Ha én egy meglévő adat / file tömeg köré szeretnék egy keretprogramot, ami átláthatóvá, és a keretprogiból indíthatóvá teszi a különböző file-okat, hogyan lehet a különböző gombokhoz, menüpontokhoz párosítani file-okat ?

Az esemény társítást már áttekintettük, de lássuk egy file elindítását, vagy egy mappa kinyitását, sőt a Windows-hoz tartozó AboutBox-ot is az alábbi DLL segítségével nyithatjuk meg.

A Windows beépített DLL-je a SHELL32.DLL. (A DLL-ről dióhéjban: A DLL, mint neve is mutatja - Dinamic Link Library - egy rutin könyvtár, melyet dinamikusan tölt be a program, ha szüksége van az abban a DLL-ben tárolt rutinra. A DLL további előnye, hogy nem tölti be minden program külön - külön magának, hanem ha már egy példány a memóriában van, akkor azt használják mindannyian.) Ezt a SHELL32.DLL-t könnyedén használhatjuk egy már megírt Delphi-s Unit-tal. (A Delphi unit-jainak használata, direktívái megegyeznek a Pascal-éval, és ezt az előző szám :PC-XUSER\DELPHI\PASCAL\ megfelelő könyvtárában leírtam.) Ez az előre definiált unit a ShellAPI. Ezt csak be kell szúrni a project-ünk uses sorába.

A ShellAPI unit számunkra fontos használható függvényei:

    ShellExecute()

    ShellAbout()

Az első függvény mely betölt egy file-t:

function ShellExecute(hWnd: HWND; Operation, FileName, Parameters, Directory: PChar; ShowCmd: Integer): HINST;

    Első paramétere a hWnd, egy ablakra mutató handle, magyarázatát másik cikkben részletezzük, e paraméternek csak adjuk meg a Form1-handle-jét, írjuk be: handle.

    A második paraméter, hogy milyen műveletet akarunk végezni a következő paraméterben megadható file, ill. mappával. Ez a paraméter egy string-re mutat mely a végzendő műveletet írja le szövegként. A string értéke kétféle lehet: "open" ez a file / mappa megnyitását végzi el, míg a "print" parancs a file-t nyomtatja ki. Amennyiben ennek a mezőnek nil (NULL) értéket adunk akkor az alapértelmezés az "open".

    FileName a harmadik paraméter így itt adhatjuk meg annak a string-nek, pontosabban PChar()-nek a címét mely a file-nevet tartalmazza.

    A Parameters a futtatható file-nak paramétereket ad át ezen a string-en keresztül. (persze lehet nil is, ha nincs rá szükség)

    A Directory a program alapértelmezett könyvtárát adja meg, ha nem szükséges akkor nil.

    Az utolsó paraméter (ShwCmd) az elindított program állapotát adja meg. Az alábbi állapotok definiáltak:

      SW_HIDE: Elrejti az ablakot, s más program ablaka lesz látható. 

      SW_MAXIMIZE: Maximalizálja a megadott ablakot.

      SW_MINIMIZE: Minimalizálja a megadott ablakot, s a Z koordináta szerinti következő ablak lesz az aktív.

      SW_RESTORE: Aktiválja és kijelzi az ablakot, ha minimalizálva vagy maximalizálva volt akkor eredeti méretét és helyét veszi fel.

      SW_SHOW: Aktiválja az ablakot az jelenlegi méretben és pozícióban.

      SW_SHOWMAXIMIZED: Aktivizálja a megadott ablakot, és maximális méretben jeleníti meg.

      SW_SHOWMINIMIZED: Aktivizálja a megadott ablakot, és minimális méretben jeleníti meg.

      SW_SHOWMINNOACTIVE: Az ablakot minimalizáltan jeleníti meg, s az eddig aktuális ablak a program elindítása után is aktuális marad.

      SW_SHOWNA: Az ablakot saját méretében nyitja meg úgy, hogy az eddig aktuális ablak a program elindítása után is aktuális marad.

      SW_SHOWNOACTIVE: Az ablakot saját méretében jeleníti meg, s az eddig aktuális ablak a program elindítása után is aktuális marad.

      SW_SHOWNORMAL: Megnyitja a megadott ablakot, ha az maximalizált vagy minimalizált volt akkor eredeti méretét és pozícióját adja neki. Meghatározható egy flag ha először indul el a program adott ablakja.

Nos ezek közül az utolsót használjuk.

Pl.: ShellExecute( handle, nil, 'C:\WIN95\Calculator.exe', nil, nil, SW_SHOWNORMAL );

A másik használt függvény a ShellAPI-ból a:

    function ShellAbout(Wnd: HWND; szApp, szOtherStuff: PChar; Icon: HICON): Integer;
Ez a függvény valósítja meg a Windows alapértelmezés szerinti aboutbox-ának megjelenítését.
    Első paramétere a Form handle-jére mutató handle.

    a második az ablak címe,

    a harmadik az egyéb készítők neve,

    s végül megadhatunk a Win95 ill. WinNT ikonja helyett egy sajátot. (ha nem akarunk mást megadni akkor 0-t adjunk meg)

Pl.: ShellAbout(handle, 'PC-X User''s about box', 'László Bérczi, R4s', 0);

A fent elmondottak szerint készült a példaprogram mely az egész cikk témáját bemutatja.
Lássunk pár adalékot a példa megértéséhez:

    A USES-ban ne felejtsük el megadni a ShellAPI unit nevét

    Az OpendDialog-ról nem beszéltem ez is a Windows alapértelmezés szerinti open dialógusát hívja meg. Vizuális beállíthatjuk az object inspector-ral, hogy milyen file-okat akarunk megnyitni stb. A dialógust az Execute; paranccsal nyithatjuk meg, s ha ez True (Boolean típusú) értékkel tér vissza akkor kijelöltünk egy file-t. Meg lehet adni, hogy csak létező file-t engedjen megnyitni (lásd object manager), így a OpenDialog.FileName mező ahol a megnyitott file neve található, akkor biztosan valós értéket szolgáltat.

    Az Open menüpont checked tulajdonságának állítása a menüpont Click metódusában: Open1.Checked:=Not Open1.Checked;

    Végül de nem utolsó sorban, a File- és Directorylistbox által lekérdezhető az aktuális file útvonala és neve: 

      DirectoryListBox1.Directory+'\'+
      FileListBox1.Items[FileListBox1.ItemIndex]
    Ahol a Directory szolgáltatja a drive betűt + a path-t, ill. az ItemIndex az aktuális elem 
    száma, s az Items[] tömbből ezáltal elérhető.
Az elkészített program képe:

Mai számunkba ennyi fért, remélem sikerült megválaszolni az Olvasói kérdést. Amint láthatjátok elég intenzíven válaszolunk nagyszámú leveleitekre így bátran írjatok ha szükségetek van valamire.