Content extract
Delphi gyakorló feladatok Összeállította: Vámossy Zoltán Budapest, 1996. 1. Téma: About dialógusablak készítése - komponensek kezelése formokon Megismerendő eszközök Ez a feladat a Delphi azon alapvető fogalmaival ismertet meg, amelyek formok és komponensek formokon való használatához szükséges: 1. formok tulajdonságainak beállítása, 2. komponens (component) elhelyezése a formon (form), 3. komponens kiválasztása a formon, 4. komponensek csoportba szervezése, 5. komponensek kivágás (cutting), másolása (copying) és beillesztése (pasting), 6. komponens törlése, 7. komponensek elrendezése A feladat meghatározása Az elkészítendő About dialógusablak a következő: • Az új projekt kezdéséhez válasszuk a File menü New Project menüpontját, vagy használjuk a megfelelő gyorsító ikont. (Ha a Project Gallery funkció be van kapcsolva, akkor az üres projekt (Blank Project) típust válasszuk.) • A feladat első részében a dialógus
ablak formjának tulajdonságait (properties) állítjuk be. Tulajdonság (property) Érték Name (azonosító) Caption (felirat) BorderStyle (keret stílus) Position (pozíció) AboutBox About bsDialog poScreenCenter Megjegyzések: A bsDialog form keret stílus az ablak Minimalizáló és Maximalizáló gombjait eltávolítja és a méretét sem módosíthatjuk. Ezek a változások csak futási időben észlelhetőek. A komponensnek egyedi nevénél (Name) az Object Pascal azonosítóra vonatkozó szabályait kell követnünk. Komponens elhelyezés a formon A komponens-palettán kiválasztott komponenst a form közepére lehet helyezni, ha egyszerűen duplán klikkelünk a komponensre. (A további komponensek mindig egy kicsit jobbra és lefele tolódnak.) Amennyiben speciális helyre szeretnénk elhelyezni a komponensünket, akkor a kiválasztás után az egérkurzort abba a pozícióba mozgatjuk, ahol a komponens bal feslő sarkát szeretnénk majd látni és a formra
klikkelünk. Ekkor is alapértelmezett méretben jelenik meg a komponens, de ekkor a kiválasztott pozícióba kerül. • Helyezzünk egy BitBtn gombot az AboutBox aló részének közepére. A Delphi automatikusan elvégzi a megfelelő bejegyzéseket a form típusdeklarációjában. Erről a forrásba tekintve meggyőződhetünk. (<F12>, vagy az editor fül használatával válthatunk a formról a szövegszerkesztőbe.) Ha egymásután többször ugyanazt a komponens fajtát szeretnénk elhelyezni a formon, akkor nyomjuk le a <Shift> billentyűt, válasszuk ki klikkeléssel a komponenst, majd helyezzük el a formra a példányokat. E műveletet a Mutató (Pointer) ikonra való kattintással fejezhetjük be. Komponens méretezése elhelyezés közben Ha nem az alapértelmezett nagyságra szeretnénk a komponenseinket beállítani elhelyezés közben, akkor a következőt tehetjük: 1. Kiválasztjuk a komponenst a palettáról 2. Az egérkurzorral meghatározzuk a bal
felső sarkának a helyét a formon és anélkül, hogy a baloldali gombot felengednénk, húzással a kívánt méretet állítjuk be, majd felengedjük az egérgombot. • Helyezzünk egy kép (Image) komponenst az ablak bal alsó sarkába és méretezzük húzással. (Később majd elmozgatjuk a helyére.) Komponens kiválasztása a formon A komponensek kiválasztása érdekében az alábbiak közül válasszuk az egyik megoldást: 1. Klikkeljünk a komponensre 2. Az Objektum Kezelő (Object Inspector) tetején elhelyezkedő Objektum Kiválasztó (Object Selector) segítségével válasszuk ki a kívánt komponenst. 3. A <Tab> használatával is fókuszálhatunk a komponensre. Ha egy komponenst kiválasztottunk, akkor fekete úgynevezett méretkezelő téglalap jelenik meg a határán. Több komponenst is kiválaszthatunk egyszerre: 1. Vagy a <Shift> folyamatos lenyomása mellet az egyes elemekre klikkelünk, 2. vagy a formon klikkelünk a komponenseken kívül és
húzással kijelöljük azt a téglalapot, amelyen belül helyezkednek el a kiválasztott komponensek. Az összes komponens kiválasztását az Edit menü Select All parancsával valósíthatjuk meg. Komponens újraméretezése Egy komponens átméretezésére használjuk a méretkezelő téglalapot és húzással állítsuk be a kívánt nagyságot. Ha több komponens méreteit akarjuk szabályozni, akkor a kiválasztások után alkalmazzuk az Edit menü Size dialógusát. • Helyezzünk el egy Panel komponenst a formon. úgy, hogy az a form nagy részét kitöltse. hogy a form marad minden egyes komponens tulajdonosa (owner). Általában a konténer komponenst helyezzük elsőként a formra, majd utána helyezzük a konténerbe azokat a komponenseket, melyeket majd egy csoportként szeretnénk használni. Megjegyzések: 1. Ha egy komponens már a formon volt, akkor kivágással és beillesztéssel is a gyűjtőkonténerhez adhatjuk. 2. Ha duplán kattintunk egy komponensre a
palettán, akkor vagy a form vagy egy konténer komponens közepére kerül, attól függően, hogy mi volt éppen kiválasztva a formon. 3. Ha a komponenst a gyűjtő komponens valamely részére helyezzük, akkor nem kell előre kiválasztottnak lennie a konténernek. • Helyezzünk el két címke (Label) komponenst a Panel konténerre. • Helyezzünk két Címke (Label) komponenst a form jobb alsó sarkára, úgy, hogy azok egymás mellé kerüljenek. Komponensek csoportba sorolása A Delphin belül több olyan komponens is van, amely más komponenst tartalmazhat. Ilyen pl a Panel, a GroupBox, a NoteBook, TabbedNoteBook és a ScrollBox. Ezeket a komponenseket konténer (container) komponenseknek is nevezzük. Azért alkalmazzuk ezeket, hogy tervezési időben a segítségükkel olyan csoportokat hozzunk létre, amelyek egy egységként viselkednek. Példa a konténer komponens használatára a gyorsító gombok, a kiválasztó gombok, vagy a Panel segítségével gyakran
elkészítendő eszköztárak, státusz sorok. Amikor egy komponenst a konténer komponensbe helyezzünk, akkor egy új szülőgyermek kapcsolatot hozunk létre a konténer és a benne elhelyezkedő komponens között. A tervezési időben a konténeren (vagy szülőn) elvégzett olyan műveletek, mint mozgatás, másolás, vagy törlés minden olyan komponensre hatással vannak, amely a konténer gyermek komponensei. Fontos megjegyezni azonban, Komponensek kivágása, másolása és beillesztése Komponenseket kivághatunk, másolhatunk és beilleszthetünk formok között, form és konténer komponensek között, stb. Amikor komponenst másolunk, akkor a tulajdonságai átmásolódnak, de a komponenshez tartozó események nem duplikálódnak, hanem az új komponens megfelelő eseménye a forrás megfelelő eseményéhez kapcsolódó kódját hívja. A kivágás, másolás, beillesztés műveleteknek három általános szabálya van: 1. Több komponenst is kivághatunk, vagy
másolhatunk egyszerre, de a kiválasztott komponenseknek csak pontosan egy szülő komponense lehet (konténer vagy form). Ha különböző szülők gyermek komponenseit vágjuk ki, vagy másoljuk, akkor a beillesztésnél csak azok a komponensek kerülnek beillesztésre, amely elsőként kiválasztott komponens szülőjével van szülő - gyermek kapcsolatban. 2. Komponens(eke)t beilleszthetünk minden olyan komponensbe, amely a fókuszba helyezhető (kiválasztható). 3. Amikor kivágunk, másolunk, vagy beillesztünk egy komponenst, akkor a hozzátartozó eseménykezelő kódok nem duplikálódnak, hanem az új komponens a forrás komponens eseménykezelőjére hivatkozik. vagy az Alignment dialog box (Igazítás dialógus ablakot) használhatjuk. A fenti műveleteket mind a megfelelő menüelem kiválasztásával, mind a szokásos gyorsbillentyűk segítségével megvalósíthatjuk. • Vágjuk ki a formon lévő 2 címke (Label) komponenst és illesszük a panelra, majd az
Image komponenst vágjuk ki és illesszük a panel bal felső sarkához. Ha a komponensek egy csoportját szeretnénk igazítani, akkor az elsőként kiválasztott komponens lesz az, amelyhez az igazítás történik. • Igazítsuk az első két címke bal oldalát, majd a második két címke bal oldalát egymáshoz! Komponensek törlése és visszaállítása Kijelölt komponenseket vagy a <Del> billentyű segítségével, vagy az Edit menü Delete almenüjével törölhetünk. A visszaállítás csak akkor lesz sikeres az Undelete almenüvel, ha más műveletet még nem hajtottunk végre a törlés óta. Komponensek elrendezése, igazítása Komponenseket elrendezhetünk egymáshoz képest is, vagy a formhoz igazíthatjuk azokat. A kiválasztott komponensek pozíciójának beállítására vagy az Alignment palette (Igazítás palettát), A form rácsozatának használata elrendezéshez Tervezési időben a formon pontokból álló rácsozat jelenik meg. E rács segíti a
komponensek igazítását. Beállítástól függően a komponens bal felső sarka vagy mindig igazodik a legközelebbi rácspontra, vagy nem. A rácsozat sűrűsége állítható. Ha a komponensek végleges helyét megtaláltuk, akkor a véletlen elmozgatások ellen az Edit menü Lock Controls almenüje védelmet nyújt. Komponens tulajdonságok (properties) beállítása • Az objektum felügyelő (Object Inspector) segítségével állítsuk be az alábbi értékeket: Komponens Panel Image Label1 Label2 Label3 Label4 Bitbtn Tulajdonság Érték Name BackgroundPanel BevelOuter bvLowered Caption Name ProgramIcon Name ProductName Name Version Name Copyright Name Comments AutoSize False WordWrap True Name OKButton Kind bkOK Az objektum felügyelőről (Object Inspector) A kiválasztott komponenstől függően az objektum felügyelő (Object Inspector) automatikusan megjeleníti a komponens jellemzőit. Ha kiválasztjuk valamely tulajdonságot, akkor ez a tulajdonság marad
folyamatosan kiválasztott az objektum felügyelőben (Object Inspector), ha új komponenst helyezünk a formra, vagy kiválasztunk egy már meglévőt. Amennyiben a kiválasztott komponensnek nincs ugyanolyan tulajdonsága, akkor a Caption property-re, ha az sincs, akkor a Name tulajdonságra helyeződik az input fókusz. Ha egyszerre több komponenst jelölünk ki, akkor az objektum felügyelőben (Object Inspector) csak a közös tulajdonságok jelennek meg. Az érték mezőkben vagy az alapértelmezett, vagy az elsőként kiválasztott komponenshez tartozó értékek jelennek meg. Természetesen ez alól kivétel a Name mező, hiszen ez mindig egyedi. Több komponens adott, közös jellemzőjét gyorsan beállíthatjuk e módszerrel. Megjegyzés: Az objektum felügyelőben (Object Inspector) történő mozgást a <Tab> és a tulajdonság kezdőbetű kombináció gyorsíthatja. • Válasszuk ki az AboutBox Bitbtn (bitmap nyomógomb) komponensét, majd a <Shift>
lenyomása mellett a Panel komponenst. Tekintsük meg, hogy az objektum felügyelő (Object Inspector) miként jeleníti meg a közös tulajdonságokat. • Ezután készítsük el az alkalmazás MainForm-ját. A File menü New Form elemével hozzunk létre egy üres formot (Blank Form). Helyezzünk rajta el egy nyomógombot, és a másolás, majd beillesztés műveletekkel készítsünk egy másik gombot. Figyeljük meg, hogy mindkét gomb felirata (Caption) ugyanaz marad: Button1, de a neve (Name) automatikusan megváltozik: Button1 illetve Button2. • Változtassuk meg a form nevét Form2-ről MainForm-ra. A tulajdonság szerkesztő (Property Editor) használata Az objektum felügyelő (Object Inspector) különböző lehetőségeket biztosít a tulajdonság (property) tervezési időben történő beállítására. Eddig az értékek direkt begépelését és az előzetesen már létező listából történő választás eszközét alkalmaztuk. Bizonyos tulajdonságok
(properties) esetében ha duplán kattintunk az érték (Value) oszlopban, akkor egy tulajdonságot beállító párbeszéd ablak (dialog box) jelenik meg. Általában jelöli e tulajdonságokat. Az Image komponens Picture tulajdonsága például ilyen típusú. Ha duplán klikkelünk a Value oszlopban, vagy ugyanilyen hatású, ha magára az Image komponensre, akkor a kép szerkesztő (Picture Editor) párbeszéd ablak jelenik meg. Ez a dialógus ablak a megjelenítendő kép meghatározására szolgál. A Load gomb megnyomására egy újabb dialógus ablak jelenik meg, mely lehetővé teszi bitmap, ikon és metafile formátumú képek közüli választást. A kiválasztott kép az <OK> megnyomására jelenik meg a formon. • Válasszuk ki az About form Image komponensét és töltsünk be egy képet az előbb ismertetett módszer segítségével! A kiválasztott kép vagy a komponens újraméretezhető: 1. Vagy a kép importálása előtt a Delphi Image editorával (Tools
menü Image Editor almenü), 2. vagy a grafika méretét állíthatjuk, nyújthatjuk a komponens méreteire a Stretch tulajdonság (property) True értékre állításával, 3. vagy a komponens méretét igazíthatjuk a kép méretéhez az AutoSize tulajdonság beállításával. Megjegyzendő, hogy az ikon képek mérete nem nyújtható. • Állítsuk be a Stretch tulajdonságot, hogy a kép kitöltse az Image komponenst! A projekt elmentése A formot illetve a hozzákötődő unit állományt a File, Save File menüvel, az egész projektet pedig a File, Save Project menüvel menthetjük el. Alkalmazhatjuk az eszköztár gyorsító gombjait is e műveletekre. Minden esetben célszerű a Delphi által generált alapértelmezett fájlneveket módosítani egyedi elnevezésekre. • Mentsük el az eddig eredményeinket a következő nevek használatával: Default név Új név UNIT1.PAS UNIT2.PAS PROJECT1.DPR ABOUT.PAS MAINFORM.PAS MYPROJ.DPR Futás időben történő tulajdonság
állítás Mindazok a tulajdonságok, amelyek tervezési időben beállíthatóak, módosíthatóak futási időben is. Sőt vannak olyan tulajdonságok (runtime-only properties), melyek csak az utóbbi esetben állíthatóak. A futási idejű tulajdonság beállítás a már ismert lépéseket követi: komponens és tulajdonság kiválasztás, valamint az új érték hozzárendelése. Például ha azt szeretnénk, hogy az About dialógus ablak több programhoz is felhasználható módon mindig az adott program nevét tartalmazza fejlécként, akkor futás időben kell a fejléc (Caption) tulajdonságot beállítani. A következő részben a Delphi kódszerkesztőjét ismerjük meg, valamint azt, hogy miként kell eseménykezelőket (event handlers) készíteni és módosítani. A kódszerkesztő (Code Editor) használata Delphiben majdnem minden kód, amit írunk és futtatunk, közvetlenül, vagy közvetve valamilyen eseményhez kapcsolódik (esemény vezérelt programozás). Az
ilyen kódot, pontosabban eljárásokat eseménykezelőknek (event handler) nevezzük. Általában az objektum felügyelőt (Object Inspector) használjuk az eseménykezelők készítésére. Természetesen készíthetünk manuálisan is eseménykezelőket, de az objektum felügyelő (Object Inspector) használata rengeteg előnyt rejt magában, mivel bizonyos változtatásokat automatikusan lekezel a forráskódban (pl. eseménykezelő nevének a módosítása, stb.) Az alapértelmezett eseménykezelő (default event handler) készítése A komponensek zöméhez készíthetünk úgy eseménykezelőt, hogy duplán kattintunk rá. Ez a komponens úgynevezett default event handler-e és általában ez ahhoz az eseményhez kapcsolódik, amelyet a leginkább használunk az adott komponens esetében. Például a nyomógombokra való klikkelés (OnClick) eseménye a nyomógomb alapértelmezett eseménye. Megjegyzés: Bizonyos komponenseknek nincs ilyen eseménye (Timer), más esetekben mint
például az Image komponensnél, a dupla kattintás dialógus ablakot nyit meg. Az About dialógus megjelenítése a főprogramból (MainForm) Az About dialógushoz hasonló ideiglenes ablakok csak akkor lesznek általában láthatóak, ha a felhasználó megnyitja azokat. Ezzel szemben az alkalmazás úgynevezett main formja (fő form) a program indulásakor megjelenik. Eddig az About form volt az alkalmazás main formja, tehát futtatható volt kód írása nélkül. Ahhoz, hogy a valós alkalmazásokhoz hasonlóan az About ablak csak mint egy szokásos dialógus jelenjék meg módosítani kell a projektünk bejelentkező formját. • Válasszuk ki az Options menü Project elemét és a Forms lapon állítsuk be a Main form melletti legördülő listából a mi MainForm nevű formunkat. Az alkalmazásunkban akkor fog megjelenni az About dialógus, ha a főprogramban klikkelünk az egyik gombon. (Valós programokban általában menüelemhez kötött ez a funkció.) Mivel már
elhelyeztünk nyomógombot a formra, csak egy eseménykezelőt kell generálnunk és azt a rövid kódot megírnunk, amely az About ablak megjelenítését végzi. • Váltsunk a MainForm-ra, ehhez használhatjuk a View menü Forms, vagy Window List elemét, vagy egyszerűen mozgassuk úgy az ablakokat, hogy az egérkurzorral kijelölhető legyen a form. • Kattintsunk duplán a Button1 nevű nyomógombra és az automatikusan generált eseménykezelő eljárás törzsébe írjuk a következő kódot: AboutBox.ShowModal; A ShowModal metódus megjeleníti az About ablakot és a felhasználónak be kell zárnia azt mielőtt bármilyen más tevékenységgel folytatná a munkáját (modal). • Ahhoz azonban, hogy a főprogram számára elérhető legyen az About nevű unit, a MainForm uses-ai közé kell illeszteni a nevét. • Ezután fordítsuk le az alkalmazást és teszteljük. Az <OK> gombra való kattintás bezárja az ablakot, hiszen a gomb Kind tulajdonságát bkOK-ra
állítottuk, a stílusa (Style) pedig bsDialog. Munka a kódszerkesztővel Amikor egy új projektet nyitunk, akkor a Delphi automatikusan készít egy új lapot a kezdő form unit fájlja számára a kódszerkesztőben (Code Editor). Ha egy új formot, unit-ot adunk a projekthez, akkor is új kódlapot készít a rendszer. Amikor a szerkesztőben dolgozunk, akkor egyszerűen áttérhetünk másik kódlapra például a lap fülén történő kattintással, a View menü Units dialógus menüjének használatával, vagy a gyorsító gombok segítségével. Hasonlóan gyorsan és egyszerűen áttérhetünk a kódlaphoz tartozó formra, kattintással, ha látható a form, vagy a View menü Form dialógusával, esetleg gyorsító gombok használatával vagy az <F12> gomb lenyomásával. A már elkészített eseménykezelőt is egyszerű megtalálni a kódszerkesztőben. Ehhez ki kell jelölni a komponenst, az objektum felügyelőben (Object Inspector) az események (Events) lap
választása után az események oszlopban duplán kell arra az eseményre kattintani, amelyet szerkeszteni szeretnénk. Ha alapértelmezett eseménykezelőt (default event handler) akarunk megkeresni, akkor a dupla klikkelés a létrehozáshoz hasonlóan automatikusan biztosítja a szerkesztő lap megfelelő helyen való megjelenését. • Válasszuk ki dupla klikkeléssel a MainForm Button1 gombjának alapértelmezett eseménykezelőjét, a Button1OnClick eljárást. • Módosítsuk az eseménykezelőt úgy, hogy az About ablak fejlécében a projekt neve is megjelenjen. procedure TForm1.Button1Click(Sender: Tobject); begin AboutBox.Caption := About + Application.Title; AboutBox.ShowModal; end • Futassuk a programot! Az alkalmazás Title tulajdonsága (property) jelenik meg akkor is ha ikonizáljuk a programot. E tulajdonság alapértelmezésben megegyezik a projekt nevével, de módosítható a projektre vonatkozó adatok beállításánál az Options menüben. A Sender
paraméter használata Egy eseménykezelőben a Sender paraméter informálja a kezelőt, hogy mely komponenstől érkezik az esemény. • Egészítsük ki a MainForm.Button1 gombjának OnClick eseménykezelőjét a következőkkel: procedure TMain1.Button1Click(Sender: Tobject); begin if Sender = Button1 then AboutBox.Caption := About + Application.Title else AboutBox.Caption := ; AboutBox.ShowModal; end; • Rendeljük hozzá a módosított eseménykezelőt MainForm.Button2 gombjához a következő módon: 1. A formon válasszuk ki a komponenst 2. Az objektum felügyelőben (Object Inspector) az Events lapot jelenítsük meg és jelöljük ki azt az eseményt, amihez társítani szeretnénk a kezelő kódot. 3. A lefele mutató nyílra klikkelve a legördülő listából válasszuk ki azt az eseménykezelőt, amelyet használni szeretnénk. (A lista csak a lehetséges eseménykezelők neveit sorolja fel.) Ha a kódszerkesztőt megtekintjük, láthatjuk, hogy a kód nem
duplikálódik, hanem ugyanaz az eseménykezelő hívódik. • Futassuk a programot és teszteljük a kódot. Meglévő eseménykezelő más eseményhez való hozzárendelése Osztott (közös) események megjelenítése és készítése Gyakran előfordul egy programban, hogy ugyanazt a kódot kell futtatni, ha egy menüt választunk ki, vagy ha például egy gyorsító gombra klikkelünk, vagy az eszköztárat használjuk. Ha már megírtuk az eseménykezelőt, akkor egyszerűen hozzárendelhetjük más eseményekhez is. A megoldás bemutatása érdekében módosítani fogjuk a MainForm.Button1 gombjának OnClick kódját és a MainForm.Button2 gombjához fogjuk rendelni. Hasonlóan a közös tulajdonságokhoz (property), az eseménykezelők esetében is megjeleníthetjük, elkészíthetjük, módosíthatjuk több komponens közös eseménykezelőjét. A megjelenítés érdekében kiválasztjuk a komponenseket és az Events lapra klikkelünk az objektum felügyelőben (Object
Inspector). Ekkor csak a közös események jelennek meg. Ha eseménykezelőt szándékozunk megosztani komponensek között, akkor ki kell jelölnünk a komponenseket, majd az objektum felügyelőben (Object Inspector) a megfelelő esemény kiválasztása után a legördülő listából válaszuk ki az eseménykódot, és üssünk egy <Enter>-t. Abban az esetben pedig ha készíteni szeretnénk közös eseménykezelőt, akkor hasonlóan eljárhatunk, mint az előbb, de vagy begépeljük a kezelő kód azonosítóját, vagy ha duplán klikkelünk a kezelő (Handler) oszlopra, akkor a Delphi generál egy azonosító nevet és az eseménykezelőt. A kurzort pedig a beginend blokkba pozícionálja. (Az automatikus generálás esetében, az elsőként kiválasztott komponens neve alapján készül az azonosító.) • Helyezzünk el egy gyorsító gombot (Speed Button) a MainForm-on. • Válasszuk ki Button1 azonosítójú gombot és az objektum felügyelőben (Object Inspector)
az Events lapra váltsunk. • A <Shift> lenyomásával és tartásával válasszuk ki a gyorsító gombot. Ekkor csak a közös eseményekre szűkül az objektum felügyelőben az események sora. • Válasszuk ki az OnClick eseményt és a legördülő listából a Button1Click kezelőt. A gyorsító gomb OnClick eseményét is ezentúl Button1Click-nek fogják hívni. • Futtassuk a programot. Közös eseménykezelő módosítása Amikor módosítjuk több komponens közös eseménykezelőjét, akkor sosem szabad megfeledkeznünk arról, hogy az nem csak egy komponenshez tartozhat. Ezért célszerű ilyenkor is kijelölni a komponenseket és az objektum felügyelőben (Object Inspector) duplán kattintani a megfelelő eseménynél, hogy ezután a kódszerkesztőben megváltoztathassuk a forráskódot. • Módosítsuk a Button1Click eseménykezelőt a ShowModal metódus hívása előtt a következő kód hozzáadásával: AboutBox.ProgramIconPictureLoadFromFile(D
ELPHIBINTDW.ICO); A futási időben történő beállítás módosítja a tervezési időben történő képbetöltést. Eseménykezelő törlése Ha törlünk egy komponenst, akkor a Delphi eltávolítja a hivatkozást a form típus deklarációs részéből. De a komponens törlése az eseménykezelők, vagy más hozzátartozó metódusok eltávolítását nem végzi el, hiszen e kódok más komponensek által is hívhatóak. Ha a komponenshez tartozó kódot is törölni szeretnénk, akkor azt manuálisan kell megoldanunk. Delphi gyakorló feladatok Összeállította: Vámossy Zoltán Budapest, 1996. 2. Téma: Az általános célú dialógusablakok használata ShowMessage, MessageDlg, InputBox, InputQuerry Megismerendő eszközök Az általunk elkészített dialógusablakok használatán kívül lehetőség van általános célú párbeszédablakok alkalmazására. A Delphi Dialogs unit olyan egyszerűen használható, előre megtervezett általános célú
dialógusablakokat tartalmaz, melyek alkalmazása a paraméterek beállításával szabályozható. Ezen témakör keretében megismerjük, hogy 1. miként jeleníthetünk meg üzenet box-ot, 2. készíthetünk beviteli input formulákat, 3. szűrhetjük az input adatokat maszk segítségével Üzenetek megjelenítése Az üzenet box-okat (Message box) szövegek megjelenítésére használjuk. A felhasználónak nyugtáznia kell az üzenet érkezését. Általában az alábbi esetekben alkalmazzuk az üzenet ablakokat: 1. Figyelmeztetések megjelenítése 2. Hibaüzenetek közlése a felhasználóval 3. Megerősítések igénylése A ShowMessage eljárás Ez az eljárás a legegyszerűbb módját biztosítja rövid üzenetek megjelenítésének. Az eljárás egy modális dialógusablakot helyez a képernyő közepére, azzal a paraméterrel, amit paraméterként adunk az eljárásnak. Az <OK> gomb lenyomásával zárhatjuk be a dialógust Az eljárás szintaxisa:
ShowMessage(const Msg: string); • A ShowMessage dialógus használatával készítsünk el egy üzenetablakot: • Nyissunk meg egy új üres projektet, és helyezzünk el egy gombot a form-ra. • A gomb OnClick eseménykezelője a következő legyen: ShowMessage(A laborok látogatása kötelező! ); A MessageDlg függvény A MessageDlg függvény egy olyan dialógusablakot jelenít meg, amely tartalmazza azt az üzenetet, amit megadtunk (Msg), választhatóan fejlécszöveget, szimbólumokat és gombokat. A szintaxis a következő: function MessageDlg(const Msg: string; AType: TMsgDlgType; AButtons: TMsgDlgButtons; HelpCtx: LongInt) : Word; A táblázat a paraméterek jelentését foglalja össze. Paraméter Jelentés Megjegyzés Msg akkor nem A dialógus box-ban megjelenítendő szöveg Ha elhagyjuk a paramétert, AType meg jelenik meg szöveg. A fejléc szövegét és a szimbólumot meghatározó típus Ha elhagyjuk, akkor nem jelenik AButtons meg A
dialógusablakban megjelenő gombok típusai fejlécszöveg. Ha elhagyjuk, akkor nem jelenik HelpCtx A help témához kapcsolat gomb. Nem kötelező. Az AType paraméter lehetséges értékei a következők: Érték Jelentés mtWarning mtError mtInformation mtConfirmation mtCustom Sárga figyelmeztető felkiáltójelet tartalmaz a box. Piros stopjel, a hiba jele. Kék színű "i" jelöli a figyelmeztetést. A zöld kérdőjel megerősítésre várakozást jelent. Nem tartalmaz képet. A képes gombok az alábbiak közül kerülhetnek ki: mbYes, mbNo, mbOK, mbCancel, mbHelp, mbAbort, mbRetry, mbIgnore, és mbAll. Ugyanakkor néhány előre definiált konstans egyszerre több gomb megjelenítését is meghatározhatja: mbYesNoCancel, mbOkCancel, mbAbortRetryIgnore. A függvény visszatérési értéke a lenyomott gombra utaló konstans az alábbi halmazból: mrNone, mrAbort, mrYes, mrOk, mrRetry, mrNo, mrCancel, mrIgnore, mrAll. • Készítsük el az alábbi
eseménykezelőt a fenti módosításával: MessageDlg(Mentsük el a változásokat?, mtConfirmation, MbYesNoCancel, 0); A kód paramétereinek változtatásával vizsgáljuk a többi dialógusablak típust is. Az üzenetdialógus az képernyő közepén jelenik meg. Az üzenetablak elkészítése mellett a pozícióját is meghatározza a MessageDlgPos függvény. A fenti paramétereken kívül a bal felső sarok helyzete a kiegészítő paraméter. Egyszerű beviteli dialógus készítése Amíg a MessageDlg függvény csak információt jelenít meg és gomblenyomásra vár, addig a Dialogs unit további két függvényt biztosít, amelyek megjelenítenek egy form-ot és a felhasználótól egysoros inputot várnak. A két függvény a következő: function InputBox(const ACaption, APrompt, ADefault: string): string; function InputQuery(const ACaption, APrompt: string; var Value: string): Boolean; Mindkét alprogram <OK> és <Cancel> gombot tartalmazó
dialógusablakot készít. Az InputBox függvény használatakor a felhasználó által begépelt stringgel tér vissza a függvény, ha az <OK> gombot nyomta meg, és az alapértelmezett stringgel, ha a <Cancel> gombot nyomjuk meg, vagy <ESC> leütésével zártuk a dialógust. Az ACaption a dialógusablak fejlécszövegét határozza meg, az APrompt a bekérendő adatra utaló segédszöveg, míg az ADefault a bekérendő string alapértéke. Az InputQuery visszatérési értéke logikai változó, mely azt határozza meg, hogy <OK> leütésével, vagy más módon zártuk be az ablakot. A címszerinti Value paraméter szolgáltatja a visszatérési értéket • Az InputBox működését szemlélteti a következő példa: Indítsunk egy új üres projektet. • Helyezzünk a form-ra egy címkét (Label) és egy nyomógombot (Button). • A Button1 gomb eseménykezelője az alábbi legyen: procedure TForm1.Button1Click(Sender: Tobject); begin Label1.Caption :=
InputBox(Jelszóbekérő dialógusablak, Kérem a jelszót!, ) end; • Teszteljük a program működését! Input karakterek kimaszkolása A sajátkészítésű dialógusablakokban maszkolhatjuk azokat a karaktereket, amit a felhasználó begépel az edit mezőbe. A PasswordChar tulajdonságot kihasználva meghatározhatjuk, hogy milyen karakter jelenjen meg a begépelt helyett. Általában a * vagy a # a leggyakoribb jel. • A következő példa segítségével vizsgáljuk a módszert. • Indítsunk egy új üres projektet. • A File menü Add File almenüjének használatával a DELPHIGALLERY alkönyvtárból válasszuk ki a PASSWORD.PAS fájlt • A View|Forms menüben a PasswordDlg form-ot válasszuk. Ennek hatására megjelenik egy előre elkészített sablon. • Az Edit komponenst aktivizálva láthatjuk, hogy PasswordChar tulajdonság (property) már *-ra van állítva. Így a felhasználó által begépelt szöveg helyett a maszk karakterei látszódnak majd a
futtatáskor. • A Password dialógusablak használata érdekében: • Adjunk egy gombot a Form1 ablakmodellra, és készítsük el az alábbi OnClick eseménykezelőt: procedure TForm1.Button1Click(Sender: Tobject); begin PasswordDlg.ShowModal; end; • A Unit1 forrásprogramjának uses mezejébe szúrjuk be a Password unitot. • Futtatáskor a gomb lenyomásával tesztelhetjük a programunkat. A TApplication komponens MessageBox metódusa Minden Delphi alkalmazás automatikusan használja a TApplication komponenst, amely magába foglalja az alkalmazást. Az alkalmazásunk (Application) a Delphi által deklarált TApplication típusú változó, amely nem más mint a komponens egy példánya. Az alkalmazásunk fő form-ja az a form, melyet a TApplication komponens MainForm tulajdonsága (property) tartalmaz. Számtalan tulajdonsága, eseménye és metódusa közül a MessageBox függvényt az ért emeljük ki, mert a segítségével a Windows API (Application Programing
Interface) dialógusát használhatjuk bizonyos egyszerűsítésekkel (nem kell az ablakkezelőt használni). function MessageBox(Text, Caption: PChar; Flags: Word): Integer; A MessageBox metódus általános dialógus box-ot jelenít meg egy vagy több gombbal. A Text paraméter az üzenet szövegét tartalmazza, amely akár 255 karakternél is hosszabb lehet és automatikusan tördelésre kerülnek. A Caption a dialógus ablak fejlécében jelenik meg, de 255 karakternél hosszabb szöveg esetén sem kerül tördelésre. A Flags paraméter a message box gombjait és viselkedését szabályozza. Értékei kombinálhatóak a Windows API MessageBox TextType paraméterének előredefiniált értékei szerint. Konstans Jelentés MB ABORTRETRYIGNORE MB APPLMODAL <Abort>, <Retry>, és <Ignore> gombokat tartalmaz a dialógusablak Modális megjelenítést biztosít, a felhasználótól választ vár. Más alkalmazásra áttérhetünk. Az első gomb az alapértelmezett. A
második gomb az alapértelmezett. A harmadik gomb az alapértelmezett. Ugyanaz mint MB ICONINFORMATION. Felkiáltójel ikon jelenik meg a dialógusablakban. Ugyanaz mint MB ICONSTOP. "I" karaktert tartalmazó ikon jelenik meg. Kérdőjel ikon jelenik meg a dialógusablakban. A Stop-jel ikon jelenik meg. <OK> nyomógombot tartalmaz az ablak. <OK> és <Cancel> gombokat tartalmaz az ablak. <Retry> és <Cancel> gombok. Általában komoly hiba esetén használandó modális üzenetablak. Ugyanaz mint MB APPLMODAL. (Az eltérést lásd a Help-ben) <Yes> és <No> gombok jelennek meg. <Yes>, <No>, és <Cancel> gombok jelennek meg. MB DEFBUTTON1 MB DEFBUTTON2 MB DEFBUTTON3 MB ICONASTERISK MB ICONEXCLAMATION MB ICONHAND MB ICONINFORMATION MB ICONQUESTION MB ICONSTOP MB OK MB OKCANCEL MB RETRYCANCEL MB SYSTEMMODAL MB TASKMODAL MB YESNO MB YESNOCANCEL A visszatérési érték 0, ha nem volt elég memória a
dialógusablak létrehozásához, egyébként pedig: Azonosító Érték Megjegyzés IDABORT IDCANCEL IDIGNORE IDNO IDOK IDRETRY IDYES 3 2 5 7 1 4 6 <Abort> gomb került választásra. <Cancel> gomb került választásra. <Ignore> gomb került választásra. <No> gomb került választásra. <OK> gomb került választásra. <Retry> gomb került választásra. <Yes> gomb került választásra. • Egy új form-ra helyezzünk egy gombot (Button) és egy címkét (Label). • A gomb OnClick eseménykezelője a következő legyen: procedure TForm1.Button1Click(Sender: TObject); var Button: Integer; begin {üzenet megjelenítés, <OK> és <Cancel> beállítással, az input gomb lekérdezésével} end; Button := Application.MessageBox(Welcome to Delphi!, Message Box, mb OKCancel + mb DefButton1 + mb IconInformation); if Button = IDOK then Label1.Caption := <OK>-t választottál; if Button = IDCANCEL then Label1.Caption :=
<Cancel>-t választottál; • Teszteljük az Application.MessageBox metódus használatát más paraméterek esetén is Delphi gyakorló feladatok Összeállította: Vámossy Zoltán Budapest, 1996. 3. Téma: Egyedi dialógusablakok készítése Megismerendő eszközök Az előre megtervezett, egyszerű dialógusablakokon, form sablonokon kívül, a Delphi számos dialógusablak komponenst tartalmaz. Ezek a komponens paletta dialógusok (Dialogs) lapján helyezkednek és olyan komponenseket jelentenek, amelyek a Windows általános dialógus box-ait jelenítik meg. Azonban rendkívül fontos megismerni az egyedi készítésű dialógusablakok tervezését és elkészítését is. Ezen feladat során azokkal a problémákkal és megoldási technikákkal ismerkedünk meg, amelyek minden dialógusablak tervezésekor felvetődnek: 1. 2. 3. 4. 5. Modális és nem modális dialógusablak készítése A form tulajdonságainak (properties) beállítása dialógusablak
készítésekor Parancs gombok készítése A tabulálás sorrendjének beállítása és tesztelése Az inputfókusz beállítása, komponensek ideiglenes letiltása Modális és nem modális dialógusablak készítése Tervezési időben a dialógusablakok egyszerűen beállított form-ok. Futási időben lehetnek azonban modálisak vagy nem modálisak. Ha modális egy form, akkor a felhasználónak be kell zárnia azt mielőtt tovább szeretné folytatnia a munkát. A másik esetben a felhasználó más form-okon is dolgozhat anélkül, hogy bezárná a megjelenő nem modális form-ot. (Ha olyan nem modális dialógusablakot szeretnénk készíteni, amely mindig legfelül van akkor állítsuk a form FormStyle tulajdonságát (property) fsStayOnTop-ra.) A form-okat két metódus segítségével jeleníthetjük meg futási időben a fenti kritériumokat figyelembevéve: a Show method-dal, vagy a ShowModal method-dal. A következő példa a Delphi About box form-sablonját jeleníti
meg a Show és a ShowModal metódusokkal. Az About box nem modális használata érdekében: • Készítsünk egy üres projektet. • Helyezzünk el egy gombot rajta és készítsük el hozzá a következő eseménykezelőt: procedure TMainForm.Button1Click(Sender: TObject); begin AboutBox.Show; end; • A Unit1 uses-ai között soroljuk fel a Unit2-t. • A File|New Form menüt használva válasszuk ki az About Box sablont a Browse Gallery-ből. • Futtassuk a programot és használjuk a Button1 gombot, aminek a hatására a dialógusablak megjelenik és ha a form-ra kattintuk, akkor eltűnik. • Zárjuk be az About dialógusablakot a vezérlőmenüjének használatával. A modális használatot a következő módon próbálhatjuk ki: • Változtassuk meg az OnClick eseménykezelőt: procedure TMainForm.Button1Click(Sender: Tobject); begin AboutBox.ShowModal; end; • Futtassuk és teszteljük a mintafeladatot. Az <OK> gomb segítségével zárjuk az About ablakot A
dialógusablak tulajdonságainak (property) beállítása Alapértelmezés szerint a form-oknak Maximalizáló és Minimalizáló gombjaik vannak, átméretezhetőek, és a vezérlő (Control) menüjük más méretező módszereket is biztosít. A nem modális dialógusablaknak ez fontos jellemzője, a modálisaknak azonban egyáltalán nincs rá szüksége. A BorderStyle tulajdonság bsDialog-ra állításának a következő hatásai vannak 1. A Minimalizáló és Maximalizáló gombok eltűnnek 2. A Control menü csak Move és Close opciókkal rendelkezik 3. A form nem lesz átméretezhető, a keret megjelenése is módosul A táblázat néhány form-tulajdonság lehetséges értékeit jeleníti meg különböző dialógusablakok esetére. Property BorderIcons biSystemMenu biMinimize biMazimize BorderStyle Beállítás Hatás False False False Control (System) menü eltávolítása Minimalizáló gomb eltávolítása Maximalizáló gomb eltávolítása bsSizeable bsSingle bsNone
Átméretezhető határok Egyszerű keretes, nem átméretezhető határ Nem átméretezhető, keret nélküli dialógusablak Megjegyzés: Ezen beállítások hatásai csak futási időben láthatóak. A dialógusablak fejléce A Windows-alapú alkalmazásokban a dialógusablak fejlécében elhelyezkedő szöveg a dialógusablak elsődleges funkcióját írja le. A Caption tulajdonság megváltoztatásával állíthatjuk be a kívánt címet Parancs gombok készítése és a szabványos parancsgombok A dialógusablakokban gyakran alkalmazunk <OK>, <Close>, <No>, <Yes>, stb. feliratú gombokat Ezek a gombok vagy a bezárást szolgálják, vagy választási lehetőséget biztosítanak. A programnak kell lekezelnie az egyes választások következményeit. A gomb (Button) komponens bizonyos tulajdonságainak beállításával lehetőség nyílik, hogy <Enter>, vagy <ESC> billentyű használatakor speciális eseménykezelők induljanak el. Ha a
Cancel property True-ra van állítva, akkor <ESC> leütésekor az az eseménykezelő kezdi el tevékenységét, amely a gomb OnClick eseményéhez tartozik. (Cancel típusú gomb) Ha a gomb Default tulajdonsága True, és <Enter>-t ütünk, akkor szintén az OnClick eseménykezelő aktivizálódik, (hacsak nem más gomb volt az inputfókuszban.) A dialógusablak bezárása sok esetben függ attól, hogy a felhasználó mely gombot nyomta le. A lenyomott gombnak megfelelő konstans érték, mely a gomb ModalResult property-jében kerül tárolásra, a form ModalResult tulajdonságát írja felül. Ha ez az érték nem 0, akkor a dialógusablak záródik (A bkCustom, bkHelp és bkClose esetében a ModalResult értéke mrNone marad és nem záródik automatikusan az ablak.) A BitBtn (képes gomb) komponens Kind tulajdonságának beállításával a gomb ModalResult értékét is automatikusan állítjuk. A részleteket a táblázat tartalmazza Ha egyszerű nyomógombot
alkalmazunk, akkor a megfelelő ModalResult érték beállításáról nekünk kell gondoskodnunk. A BitBtn gombtípusok és a hozzájuk tartozó (ModalResult) beállítások Kind érték Hatás Megjelenés bkAbort Cancel gomb Abort felirattal Caption := ‘Abort’ ModalResult := mrAbort bkAll OK gomb All felirattal Caption := ‘&All’ ModalResult := 8 bkCancel Cancel gomb Caption := ‘Cancel’ Cancel := True ModalResult := mrCancel bkClose Close gomb Caption := ‘&Close’ bkCustom Egyedi beállítású és megjelenésű gomb bkHelp Help feliratú gomb Caption := ‘&Help’ bkIgnore A változások elnyomására gomb Caption := ‘&Ignore’ ModalResult := mrIgnore bkNo Cancel gomb No felirattal Caption := ‘&No’ Cancel := True ModalResult := mrNo bkOK Creates an OK button Caption := ‘OK’ Default := True ModalResult := mrOK bkRetry speciális hatást jelző gomb Caption := ‘&Retry’ ModalResult := mrRetry
bkYes OK gomb Yes felirattal Caption := ‘&Yes’ Default := True ModalResult := mrYes Ekvivalens tulajdonság beállítás(ok) A komponensek bejárási sorrendjének meghatározása A <Tab> gomb ismételt lenyomásakor az inputfókusz az egyik komponensről a másikra áthelyeződik. Ez a lehetőség csak akkor él, ha a komponens TabStop tulajdonsága True-ra van állítva. A bejárási sorrend alapértelmezésben az a sorrend, ahogy a komponenseket a form-ra helyeztük. Ha ezt meg szeretnénk változtatni, akkor használjuk a TabOrder tulajdonságot minden egyes komponens esetén, vagy az Edit|Tab Order dialógusablakot. Megjegyzések: A bejárási sorban első komponens TabOrder értéke 0. Az éppen nem látható, vagy nem engedélyezett komponensekre az inputfókusz nem helyeződik át. • Egy üres form-ra helyezzünk négy gombot. • A TabOrder és TabStop tulajdonságok különböző beállításait teszteljük. Komponens engedélyezése és tiltása
Gyakran előfordul, hogy a program állapotától függően bizonyos, máskor elérhető komponenseket az adott helyzetben nem teszünk a felhasználó számára elérhetővé, annak csak szürke képe jelenik meg. Ez a beállítás mind tervezéskor, mind futtatáskor a komponens Enabled tulajdonságának False-ra állításával biztosítható. • Készítsük el a következő eseménykezelőt, amely a Button2 elérhetőségét meghiúsítja. • procedure TForm1.Button1Click(Sender: Tobject); begin Button2.Enabled := False; end; Inputfókusz beállítása Egy dialógusablakban mindig csak egyetlen komponens lehet fókuszban. Az alapértemezettként aktív komponenst a form ActiveControl tulajdonsága határozza meg. Futásidőben az inputfókuszt a SetFocus metódussal állíthatjuk. • Egy üres form-ra helyezzük el az alábbi komponenseket és állítsuk be tulajdonságaikat a következők szerint: Komponens Tulajdonság Érték Hint ActiveControl Caption Ez a form Edit1
ListBox Demo Hint Caption Default ShowHint TabOrder Item felvétel &Add True True 0 Hint Minden elemet Caption ShowHint TabOrder &Clear True 3 Hint Szerkesztő ShowHint TabOrder True 4 Hint ShowHint Sorted TabOrder A lista elemei True True 5 Hint Caption ShowHint TabOrder Item törlése &Delete True 1 Hint Caption ShowHint TabOrder Item keresése &Find True 2 Form1:TForm AddBtn: TButton ClearBtn: TButton töröl Edit1: TEdit mező ListBox1: TListBox • Az eseménykezelők a következők legyenek. procedure TForm1.AddBtnClick(Sender: TObject); begin if ListBox1.ItemsIndexOf(Edit1Text)=-1 then {Ha nincs meg ilyen elem a listaban, felvesszuk.} begin ListBox1.Itemindex:=-1; ListBox1.ItemsAdd(Edit1Text); end; Edit1.SetFocus; end; procedure TForm1.ClearBtnClick(Sender: TObject); begin ListBox1.ItemsClear; Edit1.SetFocus; end; procedure TForm1.DeleteBtnClick(Sender: TObject); begin if ListBox1.ItemsIndexOf(Edit1Text)<>-1 then begin
ListBox1.Itemindex:=-1; ListBox1.ItemsDelete(ListBox1ItemsIndexOf(Edit1Text) ); end; Edit1.SetFocus; end; procedure TForm1.FindBtnClick(Sender: TObject); begin if ListBox1.ItemsIndexOf(Edit1Text)<>-1 then DeleteBtn: TButton ListBox1.Itemindex:=ListBox1ItemsIndexOf(Edit1Text); Edit1.SetFocus; end; FindBtn: TButton Megjegyzések a listakezelést megvalósító funkciókhoz: - A ListBox.ItemIndex az aktuális elem kiválasztását végzi -1 esetén nincs kiválasztás - A ListBox.ItemsIndexOf(string) a string indexét adja vissza a lista elemei közül 0 az első elem indexe. - A ListBox Sorted tulajdonsága szabályozza az elemek (item-ek) sorrendjét. Form sablonként történő elmentése Ha elkészítettünk egy form-ot, akkor lehetőségünk van azt a továbbiakban újra felhasználni. A form sablonként való elmentése hasonló ahhoz, amikor egy form-ot új névre másolunk. Azonban a sablonként elmentett form-ok megjelennek a Browse Gallery form kiválasztó
dialógusban. A sablonként történő mentést a form gyorsmenüjének (jobb egérgomb kattintása a form-ra) Save As Template parancsa végzi. Formok ASCII szövegként történő mentése és visszatöltése A Delphi lehetőséget biztosít .DFM form fájlok ASCII szövegkénti mentésére Ezután tetszőleges texteditor használatával módosíthatjuk a form-ot. Az így módosított ASCII fájl természetesen bináris .DFM formátumúvá alakítható vissza Az ASCII formába való konvertálás érdekében nyissuk meg a .DFM fájlt, majd mentsük el TXT kiterjesztéssel. Megjegyzés: Nem lehet ugyanaz a form vizuális és text állapotban egyidejűleg nyitva A visszakonvertálás érdekében válasszuk a File|Open File menüvel a megfelelő .TXT állományt Majd a File|Save File As menüben a form fájl beállítást használjuk a combobox-ban. A fájl elnevezése után <OK> - val zárjuk a dialógusablakot. Delphi gyakorló feladatok Összeállította: Vámossy Zoltán
Budapest, 1996. 5. Téma: Több ablakos szövegszerkesztő készítése Megismerendő eszközök A feladat megoldása során un. Multiple Document Interface (MDI) szövegszerkesztőt fogunk készíteni Felhasználjuk a Windows általános dialógusablakait: a file open, save, és print párbeszédablakokat. Az alábbi nagyobb egységek a munkánk főbb lépéseit tartalmazzák: 1. 2. 3. 4. 5. 6. Multiple Document Interface (MDI) alkalmazások jellemzői A gyermek ablakok használata A Memo komponens alkalmazása szövegszerkesztésre A Windows általános dialógusablakainak alkalmazása Szöveges file nyomtatása Kilépés az alkalmazásból Multiple Document Interface (MDI) alkalmazások A Multiple Document Interface azt jelenti, hogy ugyanazon az alkalmazáson belül egyszerre nyithatunk meg és használhatunk két vagy több file-t. Ilyen típusú program az Excel, vagy a Winword is A megvalósítás nagy előnye, hogy az állományok közötti adatcsere és a közös
megtekintés igen hatékony lehet. Az MDI alkalmazások közös munkatere a szülőablak, vagy keret (parent, frame) A Delphiben az MDI alkalmazás kerete mindig a fő ablak (main form). A keretablakon belül nyithatóak meg a gyermek (child) ablakok. Minden gyermek ablak ugyanúgy jelenik meg és viselkedik. Az alkalmazás dokumentumai, vagy adatai ezekben a gyermek-ablakokon belül kerülnek megnyitásra. A tervezés során az MDI keret (frame) form-ot, mint az alkalmazás főablakát készítjük el, a gyermek-ablakoknak pedig a mintáját, sablonját határozzuk meg. Ezen minták lehetnek eltérőek is, de az MDI csak pontosan egyfajta keret form-ot használhat. Az MDI alkalmazás alapjainak elkészítése a következőket fogja jelenteni: 1. MDI keret (frame) form készítése 2. MDI gyermek (child) form létrehozása 3. Az alkalmazás menüjének elkészítése 4. A menük illesztése (menu merging) az MDI gyermek ablakok futtatásához 5. A gyermek ablakok létrehozása
futási időben MDI keret (frame) form készítése Az MDI alkalmazás keret-ablakának elkészítése a szövegszerkesztő program megvalósításának első lépése. • A File|New Project menüben válasszuk a Blank project lehetőséget. A FormStyle meghatározza, hogy egy form MDI szülő-, MDI gyermek-ablak, vagy esetleg egyik sem. A FormStyle tulajdonságot tervezési időben állíthatjuk csak be. Az MDI frame form létrehozásához a főform-ot válasszuk mindig ki. Az objektum felügyelőben (Object Inspector) állítsuk be a FormStyle-t fsMDIForm-ra. (A főform meghatározása az Options|Project menü Forms lapján történhet, alapértelmezés szerint az elsőként elkezdett ablakmodell a főform.) • A szövegszerkesztő elkészítése céljából: a FormStyle, Caption és Name tulajdonságokat az alábbiak szerint állítsuk be: Tulajdonság Name Caption FormStyle Érték FrameForm Text Editor fsMDIForm MDI gyermek (child) form készítése A gyermek form-ot
tervezési időben, mint a futtatáskor megjelenő ablak sablonjaként, mintájaként hozzuk létre. Mivel a gyermek ablakok alapértelmezés szerint láthatóak, ezért az alkalmazásnak kell futási időben létrehoznia azokat és a Delphi nem készítheti el automatikusan. A mi feladatunkban például mindig egy gyermekablak példányt kell készíteni mindannyiszor, ahányszor a felhasználó a File|New menüpontot választja. • A gyermek MDI ablak létrehozásának és az automatikusan létrehozandó ablakok listájáról történő eltávolításának a lépései az alábbiak: • Válasszuk a File|New Form menüben az üres (Blank) form opciót. • A form alábbi tulajdonságait állítsuk be Tulajdonság Érték Name EditForm Caption (üres) FormStyle fsMDIChild • Válasszuk ki az Options|Project menüben a Forms Auto-Create listáját. • Az Auto-Create formok listájából az MDI gyermek form-ot az elérhető (Available) formok listájába mozgassuk át. •
<OK>-val zárjuk a dialógust. Az alkalmazás menüjének elkészítése A keret (frame) form menüsora szolgál az alkalmazás főmenüjének (main application menu). Ha a gyermek form menüsort tartalmaz, akkor minden egyes menüelemét illeszteni, ragasztani kell a keret menüjéhez a futtatás során. A File és a Window menü a kerethez tartozik, hiszen azok elsősorban a szülőablak jellemzőit vezérlik. Az Edit és a Character menü a gyermek form-hoz tartozik, mivel ezek a menük a gyerek ablakot és annak tartalmát szabályozzák. Ezeket a menüelemeket kell illeszteni majd Megjegyzés: Elterjedtebb, hogy a legtöbb MDI alkalmazásban a keret és a gyermek menüket nem illesztik, hanem helyettesítik. A keret (frame) form menüje A keret menüelemei lehetőséget nyújtanak a gyermekablak futásidejű manipulálására. • A File és Window menük menüelemei az alábbiak legyenek. (A Caption elsőnként történő meghatározásakor a Delphi generálja az
azonosítót (Name property).) &File &New &Open . – (kötőjel) E&xit &Window &Tile &Cascade &Arrange Icons A gyermek (child) form menüje A futtatáskor a gyermek-ablakhoz (EditForm) elkészített File menü sablonnal fogjuk helyettesíteni a keret (FrameForm) File menüjét. • Az EditForm gyermekablak menüjének létrehozása érdekében használjuk a Delphi File menü sablonját, és készítsük el a többi menüelemet úgy, ahogy azt az alábbiak mutatják. Megint a Caption értéket határozzuk meg először és a Name generálódjék. &Edit Cu&t &Copy &Paste De&lete – (kötőjel) Select &All (Edit menü gyorsító billentyűk) Ctrl+X Ctrl+C Ctrl+V Ctrl+D &Character &Left &Right &Center – (kötőjel) &Word Wrap – (kötőjel) &Font . • Mentsük el a projektet a következő nevek használatával: Alapértelmezett név Save as UNIT1.PAS MDIFRAME.PAS UNIT2.PAS MDIEDIT.PAS PROJECT1.DPR
TEXTEDIT.DPR A menük illesztése Amikor elindul a program csak a keret form - főform (FrameForm) menüelemei jelennek meg. Ha a felhasználó megnyitja a gyermek ablakot, akkor az EditForm menüelemeinek be kell illeszkedniük automatikusan az MDI alkalmazás főmenüjébe. Ezt a GroupIndex tulajdonság beállításával biztosíthatjuk. • Állítsuk be a GroupIndex tulajdonságot a következők szerint: Form FrameForm FrameForm EditForm EditForm EditForm Menü cím File Window File Edit Character GroupIndex beállítás 0 9 0 1 1 Mivel ugyanazt a (0) GroupIndex értéket állítottuk be az EditForm File menüjéhez és a FrameForm File menüjéhez, ezért az eredeti majd helyettesítésre kerül, (és mindig az első helyen jelenik meg a File menü). A Window menü mindig a legutolsó lesz a menüsorban, az Edit és a Character menük pedig a File és a Windows menü közé szúródnak be. A gyermekablak megnyitása futáskor A menürendszerek elkészítése után
begépelhetjük azt kódot, amely az EditForm példányait futási időben létrehozza. Az EditForm Create metódusát fogjuk használni a FrameForm File|New menü kiválasztásakor. • Készítsük el a következő eseménykezelőt FrameForm File|New menüjének OnClick eseményéhez (Figyelem! Az eseménykezelő neve NewChild legyen!) procedure TFrameForm.NewChild(Sender: TObject); var EditForm: TEditForm; {a gyermek form deklarálása} begin EditForm := TEditForm.Create(Self); {a gyermekablak létrehozása} end; • Az EditForm File|New click eseményéhez a következő eseménykezelőt írjuk meg: procedure TEditForm.New1Click(Sender: TObject); begin FrameForm.NewChild(Sender); { a FrameForm eseménykezelőjét hívja} end; Hivatkozások más unit-ra • A megoldás során másik unit-ra hivatkozunk, ezért a MDIFrame file uses-ai között fel kell sorolnunk az MDIEdit file nevet az interface résznél. uses Sysutils, . Menus, MDIEdit; • Mivel kölcsönösen (körkörösen)
kell, hogy hivatkozzon a két unit egymásra, ezért az MDIEdit implementation részében soroljuk fel az MDIFrame file nevet. Figyeljük meg, hogy az egyébként tiltott körkörös hivatkozás problémáját úgy oldja fel a Delphi, hogy az egyik unit-ban az implementation részben kell elhelyezni a másik egységre való hivatkozást, a másikban az interface rész előtt. • uses MDIFrame; • Az alkalmazás futtatásakor nyissuk meg a gyerekablakot. Nyitott gyermekablakok használata Gyermekablakok elrendezése és elérése Az MDI alkalmazások lehetőséget nyújtanak arra, hogy több gyermekablak egy munkatéren belül helyezkedjék el. Ezért az MDI alkalmazásoknak mindig kell hogy legyen Window (vagy más) menüje, amely tartalmazza a következőket: 1. A gyermek ablakok Tile, Cascade (tapéta-mozaik, illetve átlapolt) elrendezése, és Arrange Icons (ikonméretre minimalizált gyermekablakok elrendezése). 2. A nyitott dokumentum ablakokról egy lista, amely
lehetőséget nyújt a gyors váltásra A fókuszban elhelyezkedő ablakot jelölni szokták. A Window menü parancsainak kódja • A Tile, Cascade és Arrange Icons menük használata érdekében készítsük el a következő OnClick eseménykezelőket: procedure TFrameForm.Tile1Click(Sender: TObject); begin Tile; end; procedure TFrameForm.Cascade1Click(Sender: TObject); begin Cascade; end; procedure TFrameForm.ArrangeIcons1Click(Sender: TObject); begin ArrangeIcons; end; A nyitott ablakok megjelenítése a Window menüben Annak érdekében, hogy a keret form menüjében megjelenjék a nyitott gyerekablakok listája a következőt kell csak beállítani, (a megjelenítés a beállítás után automatikussá válik): 1. Válasszuk ki a keret form objektum felügyelőjében (Object Inspector) a Properties lapot 2. A WindowMenu tulajdonság legördülő listájából válasszuk ki azt a menüt, ami alatt a listát szerepeltetni szeretnénk. (Például: Window, vagy View menü)
Megjegyzés: A kiválasztott azonosítónak a menüsoron elhelyezkedőnek kell lennie. • Rendeljük a Window1 menüt a FrameForm WindowMenu tulajdonságához. A szövegszerkesztéshez szükséges terület biztosítása A Memo komponens alkalmazásával egyszerűen olvashatunk, megjeleníthetünk többsoros szöveget. Sőt a szerkesztés, a file-ban történő eltárolás és a Clipboard használata is könnyen megoldódik. A tulajdonságok beállításával a sorok tördelését, a gördítősáv használatát, a keret stílusát és a Memo komponens form-on belüli elhelyezkedését határozzuk meg. • Helyezzünk egy Memo komponenst az EditForm-ra és állítsuk be tulajdonságait. Property Align BorderStyle ScrollBars WordWrap Érték alClient bsNone ssBoth False Az Align tulajdonság alClient értéke meghatározza, hogy a Memo mindig kitöltse a form egész kliensterületét. A bsNone érték a Memo határait teszi láthatatlanná A szöveg manipulálása a Memo
komponensben Alapvető követelmény szövegszerkesztéskor, hogy olyan általános lehetőségeket biztosítsunk, mint igazítás, sortördelés be-, illetve kikapcsolhatósága, kivágás, másolás és beillesztés. Mindezt eseménykezelők használatával fogjuk megvalósítani. Szövegigazítás és sortörés beállítása A szövegszerkesztőben szövegigazítás és sortörés beállításait a Character menü megfelelő elemeinek segítségével biztosítjuk majd futási időben. A menüelem mellett megjelenő jel fogja mutatni a kiválasztás aktív állapotát. Az Alignment (igazítás) és a WordWrap (sortörés) két állandó tulajdonsága a Memo komponensnek. A menüelemek Checked tulajdonsága azt határozza meg, hogy ha kiválasztott az item, akkor jelenjen meg egy jel mellette. A szövegigazítás parancs az EditForm Character menüjében a következő eseménykezelő segítségével valósítható meg. A Sender értékétől (balra, jobbra középre igazítás
menük választásától) függően beállítódik az igazítás és a jel a menün, vagy sem. • Készítsük el a Character|Left menüelemhez a balra igazításhoz eseménykezelőjét. (Ezt az eseménykezelőt a többi igazítás menüelemmel megosztjuk majd): procedure TEditForm.AlignClick(Sender: TObject); begin Left1.Checked := False; Right1.Checked := False; Center1.Checked := False; with Sender as TMenuItem do Checked := True; with Memo1 do if Left1.Checked then Alignment := taLeftJustify else if Right1.Checked then Alignment := taRightJustify else if Center1.Checked then Alignment := taCenter; end; • A Right és Center menüelemekhez osszuk meg az eseménykezelő eljárást. • Teszteljük a programot. Görgetősávok (scroll bars) dinamikus használata Mivel a tervezés során a Memo komponens ScrollBars tulajdonságát beállítottuk, ezért az alkalmazás futtatásakor a Memo mind a vízszintes, mind a függőleges görgetősávot megjeleníti. Az alapértelmezésben
nem kiválasztott sortörést ha átállítjuk, akkor csak a függőleges görgetősáv marad látható, mert a felhasználónak nem kell jobbra scroll-oznia az ablakot az egész szöveg megtekintéséhez. A Character|WordWrap menüelem OnClick eseménykezelője fogja beállítani a Memo komponens WordWrap tulajdonságának az értékét. Ha a felhasználó a WordWrap menüparancsot választja, akkor a WordWrap tulajdonság érétke az ellentétére változik. Az eseménykezelő függőleges, illetve mindkét görgetősávot bekapcsolja a Memo WordWrap property-je alapján. Végül a menüjel beállítása történik (Checked property), ami ugyanazt az értéket veszi fel, mint a WordWrap. • Készítsük el a következő eseménykezelőt a Character|WordWrap menüelem OnClick eseményéhez: procedure TEditForm.SetWordWrap(Sender: TObject); begin with Memo1 do begin WordWrap := not WordWrap; if WordWrap then ScrollBars := ssVertical else ScrollBars := ssBoth; end; end;
WordWrap1.Checked := WordWrap; A Clipboard (Vágólap) használata szöveg esetén A legtöbb szövegszerkesztő lehetőséget biztosít a kiválasztott szövegek átmozgatására, vagy átmásolására. A Delphi Clipboard objektuma biztosítja azokat a metódusokat, amelyek a Windows Clipboard-jának használatához szükségesek: a kivágást, másolást és a beillesztést (cutting, copying, pasting). A Clipboard objektum a CLIPBRDPAS unit file-ban van deklarálva, ezért a használata előtt a unit hívások között fel kell sorolni a CLIPBRD-t is. A mi programunkban az MDIEdit unit hívja a Clipboard objektumot. • Adjuk a Clipbrd unit-ot az MDIEdit unit interface részéhez. Szöveg kiválasztása A Clipboard használata előtt ki kell választani a szöveget. Mivel a Memo és az Edit komponenseknek automatikusan ilyen a viselkedése, ezért nem kell külön kódot írnunk emiatt. Megjegyzés: A Stdctrls unit különböző lehetőségeket biztosít a kiválasztott
szövegekkel kapcsolatban. SelText tulajdonság tartalmazza az adott komponensben kiválasztott szöveget. A SelectAll metódus kiválasztja a Memo, vagy más komponens egész tartamát. A SelLength és a SelStart metódusok a kiválasztott szöveg hosszával és kezdeti pozíciójával térnek vissza. • Készítsük el a következő eseménykezelőt az Edit|Select All menü OnClick eseményéhez: procedure TEditForm.SelectAll(Sender: TObject); begin Memo1.SelectAll; end; Szöveg kivágása, másolása és beillesztése A Delphi-ben a CopyToClipboard metódus a Memo, vagy Edit komponensben kiválasztott szöveget a Clipboard-ra másolja; míg a CutToClipboard metódus a Clipboard-ra vágja; és a PasteFromClipboard metódus a Clipboard-ra helyezett szöveget beilleszti az adott helyre. A szövegszerkesztőnkben ezek a metódusok az Edit menü megfelelő elmeinek OnClick eseményekor hívódnak meg. • Készítsük el a OnClick esemény kezelőjét az Edit|Cut, Edit|Copy, és
Edit| Paste parancsokhoz: procedure TEditForm.CutToClipboard(Sender: TObject); begin Memo1.CutToClipboard; end; procedure TEditForm.CopyToClipboard(Sender: TObject); begin Memo1.CopyToClipboard; end; procedure TEditForm.PasteFromClipboard(Sender: TObject); begin Memo1.PasteFromClipboard; end; Szöveg törlése a Clipboard tartalmának változtatása nélkül Az Edit menü tartalmazza a Delete parancsot, amely törli a Memo kiválasztott szövegét anélkül, hogy a szöveget a Clipboard-ra másolná. Az Edit| Delete parancshoz tartozó eseménykezelő a Memo1 ClearSelection metódusát hívja. • Készítsük el a következő eseménykezelőt az Edit|Delete parancs OnClick eseményéhez: procedure TEditForm.Delete(Sender: TObject); begin Memo1.ClearSelection; end; • Mentsük el az alkalmazást majd teszteljük az eddig elkészített funkciókat. Menüelemek elhalványítása Gyakran előfordul, hogy a program aktuális állapota miatt nem engedélyezhetjük bizonyos menüpontok
kiválasztását, de nem szeretnénk ugyanakkor, ha azokat eltávolítanánk a menülistából. Például ha nincs kiválasztott szöveg, akkor a Cut, Copy, és Delete elemek az Edit menüben el kell, hogy halványodjanak. Az Enabled tulajdonság beállításával ezt a problémát egyszerűen megoldhatjuk (A Visible tulajdonsággal ellentétben az Enabled tulajdonság láthatóan hagyja az objektumot, de False beállítás esetén elhalványítja azt. Az alapértelmezett értéke az Enabled tulajdonságnak a True) Az alkalmazásunkban az UpdateMenus metódus fogja beállítani az Enabled tulajdonság értékét a Cut, Copy, és Delete menüelemek esetén attól függően, hogy van-e kiválasztott szöveg a Memo-ban. A Paste parancs Enabled tulajdonságát pedig a Clipboard tartalma alapján fogja állítani. Az UpdateMenus a HasSelection Boolean változót használja a Memo SelLength tulajdonságára reagálván. Ha a SelLength nem nulla, akkor HasSelection True; egyébként False.
• A kódszerkesztő (Code Editor) megnyitásával készítsük el a következő metódust az MDIEdit unitban. Ezt a metódust más eseménykezelők fogják hívni, tehát az objektum felügyelő (Object Inspector) nem tudja elkészíteni. procedure TEditForm.UpdateMenus; var HasSelection: Boolean; begin Paste1.Enabled := ClipboardHasFormat(CF TEXT); tiltása} HasSelection := Memo1.SelLength <> 0; ban} Cut1.Enabled := HasSelection; HasSelection end; Copy1.Enabled := HasSelection; Delete1.Enabled := HasSelection; {a Paste menü engedélyezése illetve {ha van kiválasztott szöveg a Memo{a menüelemek engedélyezése a beállításától függ} A Clipboard HasFormat metódusa Boolean értékkel tér vissza attól függően, hogy a Clipboard tartalamz-e valamilyen objektumot. Metódus deklarálása Ha most próbálnánk lefordítani a programot, akkor a Delphi “Method identifier expected” hibaüzenettel állna le, mivel az UpdateMenus nem az objektum felügyelő
(Object Inspector) segítségével volt generálva és nem került deklarálásra. • Adjuk a következő sort a TEditForm típus deklarációjának private részéhez (az MDIEdit unit interface részében): procedure UpdateMenus; Eljárás hívása eseménykezelőből Az Edit menü OnClick eseménykezelője az előbb elkészített (UpdateMenus) metódust hívja. A későbbiekben elkészítendő pop-up menü OnClick eseménykezelője is ezt a metódust fogja használni. • Készítsük el a következő eseménykezelőt az Edit menüelem OnClick eseményéhez: procedure TEditForm.SetEditItems(Sender: TObject); begin UpdateMenus; end; Pop-up menü használata A pop-up, vagy helyi menük alkalmazása igen elterjedt. A szövegszerkesztőnkben pop-up menü segítségével a Cut, Copy, és Paste parancsokat használhatjuk. Ezek a pop-up menüelemek ugyanazokat az eseménykezelőket használják, amelyet az Edit menü esetében már elkészítettünk. • Helyezzünk el egy PopupMenu
komponenst az EditForm-ra, és a menütervező (Menu Designer) segítségével készítsük el a Cut, Copy, és Paste menüelemeket. Az OnPopup esemény kezelése A pop-up menü komponens OnPopup eseménykezelőjének ugyanaz lesz a feladata, mint ami Edit menü esetében az OnClick eseménykezelőnek volt: az UpdateMenus eljárás segítségével a menük elérhetőségét szabályozza. Először az UpdateMenus eljárást módosítjuk, hogy pop-up menü Cut, Copy és Paste elemére is működjön. • Az UpdateMenus eljárást módosítsuk három sor hozzáadásával: procedure TEditForm.UpdateMenus; var HasSelection: Boolean; begin Paste1.Enabled := ClipboardHasFormat(CF TEXT); Paste2.Enabled := ClipboardHasFormat(CF TEXT); HasSelection := Memo1.SelLength <> 0; Cut1.Enabled := HasSelection; Cut2.Enabled := HasSelection; Copy1.Enabled := HasSelection; Copy2.Enabled := HasSelection; Delete1.Enabled := HasSelection; end; Most már a pop-up menü komponens OnPopup
eseményéhez tartozó eljárás és a SetEditItems eseménykezelő ugyanezt az eljárást hívhatja. • Készítsük el a SetPopUpItems-nek nevezett új eseménykezelőt, amely a PopUpMenu komponens OnPopup eseményéhez tartozik, és az UpdateMenus eljárást hívja. procedure TEditForm.SetPopUpItems(Sender: TObject); begin UpdateMenus; end; A pop-up menü form-hoz rendelése Ahhoz hogy a pop-up menü a jobb egérgomb lenyomására aktivizálódjék a Memo komponensben, a form PopupMenu tulajdonságát be kell állítani. A tulajdonság azt határozza meg, hogy melyik pop-up menüt aktivizálja. • Az objektum választó (Object selector) segítségével válasszuk ki az EditForm-ot és állítsuk be a PopupMenu tulajdonságát PopupMenu1-re. • Futtasuk és teszteljük a programot. A Windows általános dialógusainak használata A komponens paletta Dialogs lapján elhelyezkedő komponensek a Windows általános dialógusait teszik a Delphi alkalmazások számára is
elérhetővé. Ezek a dialógusok minden Windows-alapú alkalmazás konzisztens használatát biztosítják például olyan file műveletek esetében, mint a megnyitás, mentés, vagy nyomtatás. Mindegyik dialógus az Execute metódussal hívható Az Execute Boolean értékkel tér vissza: ha a felhasználó <OK>-t választott, akkor True az értéke; ha a <Cancel>-lel menekült a dialógusból, akkor False. A feladat e részében az alábbi témákkal foglalkozunk: 1. 2. 3. 4. 5. 6. Az objektum felügyelő (Object Inspector) közös dialógusablak opciói A file megnyitás OpenDialog komponense A mentés Save dialógus box-a Szöveges file mentése A Font dialógus használata Memo komponens fontkészletének módosítása Az objektum felügyelő (Object Inspector) közös dialógusablak opciói A Delphi dialógusablakai (a Printer Setup dialógus kivételével) tartalmaznak egy Options tulajdonságot. Az elérhető beállítások ebben a tulajdonságban
szabályozhatóak A file megnyitás OpenDialog komponense A szövegszerkesztőben a FrameForm File|Open menüelemének OnClick eseménye a Windows Open file dialógusablakát fogja betölteni. Az OpenDialog komponens tulajdonságágainak kezdeti beállításával szabályozhatjuk a dialógusablak megjelenését és használatát. OpenDialog komponens tulajdonságai Az OpenDialog komponens tulajdonságai a dialógusablak részeihez kapcsolódnak: • Helyezzünk egy OpenDialog komponenst a FrameForm-ra és nevezzük el OpenFileDialog-nak. File szűrők (filters) készítése A listázandó fájltípus (List Files Of Type) combo-box-ban azok a file típusok látszódnak, amelyből a felhasználó választhat. Csak az ilyen kiterjesztésű állományok jelennek meg a file lista box-ban Ezeket a kiterjesztéseket szűrőknek nevezzük (filters). Az Open dialógusablak tartalmazza a Filters tulajdonságot, amely egyszerű lehetőséget biztosít a file típus és kiterjesztés gyors
beállítására. A Filter editor elindításához vagy duplán kattintsunk az érték oszlopban, vagy a (.) gombon kattintsunk A szűrő elnevezését (pl “Text”) és a hozzátartozó file-név kiterjesztést (pl. “*.TXT”) adhatjuk meg az egyes sorokban • A következő táblázat alapján készítsünk szűrőt a szövegszerkesztő Open dialógusához: Filter név Text files (*.TXT) All files Filter *.TXT *.* Egy létező file megnyitása Az alkalmazásunkban, hasonlóan a korábbiakhoz, a FrameForm File| Open és az EditForm File|Open menüpontok esetében ugyanazt az eljárást fogjuk meghívni. Az EditForm File|Open eseménykezelője a FrameForm File|Open eseménykezelőjére fog mutatni. • Készítsük el a következő eseménykezelőt EditForm és a FrameForm File|Open OnClick eseményéhez: procedure TEditForm.Open1Click(Sender: TObject); begin FrameForm.OpenChild(Sender); end; procedure TFrameForm.OpenChild(Sender: TObject); var EditForm: TEditForm; begin if
OpenFileDialog.Execute then begin EditForm := TEditForm.Create(Self); EditForm.Open(OpenFileDialogFilename); hívja} EditForm.Visible := True; end; end; {Az EditForm Open metódusát File|Open eseménykezelője az Open File dialógusablakot futtatja. Ha a felhasználó kiválaszt egy file-t, akkor az Execute függvény True-val tér vissza , és a file neve mint paraméter átadódik az Open metódusnak. Az EditForm Open függvényét azonban el kell még készíteni Mivel a file nevét más helyeken is fel fogjuk használni (pl., mentés), ezért előbb deklaráljunk egy form-szintű változót az MDIEdit unitban. Form-szintű változó deklarálása A szövegszerkesztő alkalmazás forrás kódja az MDIEdit unitban deklarált Filename változót fogja használni. Ez a változó tárolja annak a file-nak a nevét, amelyet a gyermek ablakok tartalmaznak Az előzőekben az MDIEdit unit TEditForm deklarációjának private részében deklaráltuk az UpdateMenus eljárást. Most a
Filename mezőt adjuk ugyanehhez a részhez • Az MDIEdit unit típus deklarációjának private részéhez - a kötött private szó után közvetlenül adjuk a következő sort: Filename: string; Figyelem! A mező deklarációnak meg kell előznie minden metódus deklarációt a private részben. A file betöltése Készítsük el az MDIEdit unit Open metódusát. • Elsőként a TEditForm típus deklarációjának interface részéhez adjuk a következő sort: procedure Open(const AFilename: string); A file nevet konstansként (const) deklaráltuk, mivel az eljárás nem fogja megváltoztatni. • Készítsük el az Open metódus kódját az implementation részben: procedure TEditForm.Open(const AFilename: string); begin Filename := AFilename; Memo1.LinesLoadFromFile(FileName); {file betöltés } Memo1.SelStart := 0; {kurzor pozícionálás} Caption := ExtractFileName(FileName); {file név megjelenítése a form fejlécében} Memo1.Modified := False; {ha a Memo-ban változás
lesz automatikusan True lesz.} end; A Memo komponens SelStart tulajdonsága a kijelölt szöveg pozíciójával, vagy az aktuális pozícióval tér vissza, ha nem volt kijelölés. Annak érdekében, hogy a file betöltése után a kurzor pozíció ne az alapértelmezett file vége legyen, a kurzort előre állítottuk. Az ExtractFileName metódus a file teljes azonosításából (meghajtó és elérési út!) a file nevét és kiterjesztését adja vissza. A Memo Modified tulajdonságának False-ra állítása lehetőséget biztosít annak követésére, hogy történik e majd változtatás a Memo-ban és így a felhasználó által szerkeszthető szövegben. A Save dialógusablak használata Minden új file létrehozásakor, vagy meglévő állomány módosításakor lehetőséget kell biztosítani a mentésre. A FrameForm File|Save menüje a Save As dialógus box-ot fogja használni a mentéshez Ha a felhasználó még sosem mentett, akkor a dialógusablak jelenik meg a mentés
előtt, ha pedig már van neve az állománynak, akkor nem jelenik meg dialógusablak, hanem a file mentésre kerül és egy backup példány készül a korábbi állapotáról. A SaveDialog komponens tulajdonságai A Save As dialógusablakot file-ok mentésénél használjuk. A dialógusablak tulajdonságai megegyeznek az OpenDialog komponens tulajdonságaival. A Filter tulajdonság beállítása mellett az Options tulajdonság Read Only értékét fogjuk módosítani. • Helyezzünk egy SaveDialog komponenst az EditForm-ra és állítsuk be jellemzőit a következők szerint. Tulajdonság Filter Name Options Érték Text Files (*.TXT) | *.TXT | All Files (*.*) | .* SaveFileDialog [ofHideReadOnly, ofNoReadOnlyReturn] A text file mentése A text editor alkalmazásban a file mentés három eljárás használatával készül el: 1. Save1Click, amely a File|Save menü használatakor hívódik, függetlenül attól, hogy új, vagy már létező file-t ment a felhasználó, 2.
SaveAs1Click, amely a File|Save As menü aktivizálásakor hívódik, 3. CreateBackup, amely a Save1Click eljárásból hívódik és abba van beágyazva • Készítsük el a következő eseménykezelőt az EditForm File|Save As eseményéhez: procedure TEditForm.SaveAs1Click(Sender: TObject); begin SaveFileDialog.Filename := Filename; {a Filename változó aktuális értékét megjeleníti} if SaveFileDialog.Execute then begin Filename := SaveFileDialog.Filename; Caption := ExtractFileName(Filename); Save1Click(Sender); end; end; A következő lépésben a Save1Click metódust írjuk meg, amelyet a SaveAs1Click eljárás is hív. Backup file készítése A CreateBackup beágyazott eljárás a Visual Class Library három metódusát hívja: ChangeFileExt, DeleteFile, és RenameFile. A ChangeFileExt-nek két formális paramétere van, FileName és Extension (file név és kiterjesztés). Esetünkben az Extension string paraméter a BackupExt konstanssal lesz helyettesítve. •
Készítsük el a következő konstans deklarációt az MDIEdit unit implementation részében: const BackupExt = .BAK; • Készítsük el a következő eseménykezelőt az EditForm File|Save OnClick eseményéhez: procedure TEditForm.Save1Click(Sender: TObject); procedure CreateBackup(const Filename: string); var BackupFilename: string; begin BackupFilename := ChangeFileExt(Filename, BackupExt); DeleteFile(BackupFilename); RenameFile(Filename, BackupFilename); end; begin if Filename = then SaveAs1Click(Sender) else begin CreateBackup(Filename); Memo1.LinesSaveToFile(Filename); Memo1.Modified := False; end; end; A Font dialógusablak használata A text editor alkalmazásban a Character|Font menü megnyitja Font dialógusablakot, ahol a felhasználó kiválaszthat egy fonttípust. • Helyezzünk egy Font dialógusablak komponenst az EditForm-ra. A Font dialógusablak komponens tulajdonságai A Font dialógus komponens néhány jellemzőjének értelmezését a következő ábra
szemlélteti. A dialógusablak kiinduló értékeit tervezési időben a Font tulajdonság objektum felügyelőben (Object Inspector) történő beállításával valósíthatjuk meg, ha a (.) gombra klikkelünk A Memo komponens fontjának megváltoztatása Az alábbi eseménykezelő a Memo komponens aktuális értékeit állítja be a Font dialógusablakban és lehetőséget biztosít módosítás esetén az aktualizálásra. • Készítsük el a következő eseménykezelőt a Character|Font menü OnClick eseményéhez: procedure TEditForm.SetFont(Sender: Tobject); begin FontDialog1.Font := Memo1Font; if FontDialog1.Execute then Memo1.Font := FontDialog1Font; end; Szöveges file nyomtatása Az alkalmazásunkban nem fogjuk kihasználni a Delphi által biztosított összes nyomtatási lehetőséget. A kiválasztott szövegrész, illetve az egész dokumentum nyomtatását megvalósító rutinokat készítünk csak. A Printers unit-ban deklarált TPrinter objektum mint interface
szolgál a munkánk és a printer között. Az AssignPrn eljárás a szövegfile-t a Print Setup dialógusablakban kiválasztott aktuális, vagy alapértelmezett nyomtatóhoz irányítja. A Printer objektum használata A dokumentum kinyomtatása érdekében a Printer objektum tulajdonságait állítjuk be, majd az objektum metódusait hívjuk meg. Ezek a metódusok és tulajdonságok a Print és a Printer Setup általános dialógusokkal vannak kapcsolatban. A File|Print OnClick eseménykezelője a printer objektum alábbi lehetőségeit használják ki. Canvas A Canvas a kinyomtatandó dokumentum felületét reprezentálja, oly módon, hogy a szöveges file tartalmát a printer objektum Canvas tulajdonságához rendeljük és a Printer objektum azután a Canvas tulajdonságban megadottakat (a szövegfile-t) a nyomtatóra küldi. Fonts A Fonts tulajdonság az aktuális nyomtató által támogatott típusokat tartalmazza. Ha meg szeretnénk változtatni a printer betűtípusát,
akkor elég a Memo1 Font tulajdonságát a printer objektum Canvasának Font tulajdonságához rendelni. Például: PrinterCanvasFont := Memo1Font; A printer dialógusablakok használata A szövegszerkesztő alkalmazás File|Print parancsa megnyitja a Print dialógusablakot, ahol a felhasználó beállíthatja a nyomtatás paramétereit, vagy megnyitva a Printer Setup dialógusablakot megváltoztathatja a nyomtatót. A File menü Print Setup parancsa szintén a Printer Setup dialógust nyitja meg. • Helyezzünk egy Printer Setup dialógusablak-komponenst az EditForm-ra. A Print dialógus komponens tulajdonságai A Print dialógus komponens objektum felügyelőben (Object Inspector) elérhető tulajdonságai javarészt a Print dialógusablak következő jellemzőire vonatkoznak. A File | Print Setup OnClick esemény kezelése A File menü Print Setup OnClick eseménykezelője egyszerűen csak a Print Setup dialógusablakot hívja. • Készítsük el a következő eseménykezelőt
az EditForm File|Print Setup OnClick eseményéhez: procedure TEditForm.PrintSetUp1Click(Sender: TObject); begin PrinterSetupDialog1.Execute; end; A szöveges file nyomtatása A nyomtatás érdekében egy text-file változót rendelünk a printerhez az AssignPrn eljárás segítségével. A PrintText lokális változót a File|Print OnClick eseménykezelője (Print1Click) fogja deklarálni. Ezután minden Write, vagy Writeln utasítás, amely a file-t használja a nyomtató Canvas objektumára ír, felhasználva a Canvas Font és Pen position tulajdonságait. A Memo1 komponens sorait egyszerű for ciklus segítségével írhatjuk a nyomtatóra. Az AssignPrn metódus a Delphi Printers unit-jában van deklarálva, és ezért az MDIEdit uses részében a Printers rendszerunitot fel kell sorolni. • Az MDIEdit interface részéhez adjuk a Printers unitot. • Készítsük el a következő eseménykezelőt az EditForm File|Print OnClick eseményéhez: procedure
TEditForm.Print1Click(Sender: TObject); var Line: Integer; { A szöveg sorai } PrintText: System.Text; { A PrintText a System unit-ban definiált text típus } begin if PrintDialog1.Execute then begin AssignPrn(PrintText); { A PrintText printerhez rendelése } Rewrite(PrintText); { Létrehozza és megnyitja az output file-t } Printer.CanvasFont := Memo1Font; for Line := 0 to Memo1.LinesCount - 1 do Writeln(PrintText, Memo1.Lines[Line]); { A Memo kinyomtatása a printer objektum segítségével } CloseFile(PrintText); end; end; • Mentsük le és teszteljük az alkalmazást. Kilépés az alkalmazásból Az olyan alkalmazások esetében, amikor a felhasználó módosíthatja állományok tartalmát biztosítani kell, hogy a felhasználó ne veszíthesse el véletlenül a munkáját. A backup file készítésén kívül másik fontos biztonsági megoldás, ha a kilépéskor, - módosított file-ok esetén - lehetőséget biztosítunk mentésre is. Az ablak, illetve alkalmazás
bezárására használható Close menü a form OnCloseQuery eseménykezelő kódját futtatja, amely a CanClose Boolean paraméterrel tér vissza. Ha a CanClose True-val tér vissza, akkor a Close metódus a form OnClose eseménykezelőjét futatja. Az OnCloseQuery eseménykezelő kód készítése során kell biztosítani, hogy ha a szövegben valamilyen változás volt, akkor azt a bezárás előtt lekezelhessük. Az ablak bezárása A szövegszerkesztő alkalmazásban két menüelem hívja a Close metódust: a File|Close, és a File|Exit. A File|Close bezárja a gyermek ablakokat, a File|Exit bezárja a FrameForm-ot, amely egyben az alkalmazásból való kilépést is biztosítja. A menü kiválasztásán kívül az ALT+F4, a CTRL+F4, valamint a vezérlő menübox megfelelő használata is meghívja a Close eljárást. • Készítsük el a következő eseménykezelőt az EditForm File|Close OnClick eseményéhez: procedure TEditForm.Close1Click(Sender: TObject); begin Close; end;
• Ha a felhasználó nem a File|Close paranccsal zárja be az ablakot, akkor a következő eseménykezelőt kell elkészíteni: procedure TEditForm.FormClose(Sender: TObject; var Action: TCloseAction); begin Action := caFree; end; Ez az eljárás bezárja az ablakot és felszabadít minden allokált memóriát. A file-ban történő változások detektálása Ha a szövegen változtat a felhasználó, akkor a Memo1 Modified tulajdonságának értéke is megváltozik és így az ablak bezárásakor lekezelhető az esetleges adatvesztési probléma. A szövegszerkesztő alkalmazás globális konstanst használ a file nevének megjelenítésére abban a dialógusablakban, amely akkor látható, ha a felhasználó mentés nélkül szeretne kilépni a módosított szövegből. • Deklaráljuk a következő globális konstanst az MDIEdit unit implementation részében: const SWarningText = Save Changes to "%s"?; • Készítsük el a következő eseménykezelőt az EditForm
OnCloseQuery eseményéhez: procedure TEditForm.FormCloseQuery(Sender: TObject; var CanClose: Boolean); var DialogValue: Integer; {A felhasználói válasz } FName: string; {A file neve a mentéshez } begin if Memo1.Modified then begin FName := Caption; if Length(FName) = 0 then FName := Untitled; [mbYes, end; end; DialogValue := MessageDlg(Format(SWarningText, [FName]), mtConfirmation, mbNo, mbCancel], 0); case DialogValue of id Yes: Save1Click(Self); id Cancel: CanClose := False; end; Kilépés az alkalmazásból Mivel a FrameForm és az EditForm File menüje tartalmazza a File|Exit parancsot, így ugyanazt a megoldást alkalmazhatjuk az eseménykezelő elkészítésekor, mint amit a File|New és a File|Open OnClick eseményekor már megtettünk. • Készítsük el a következő eseménykezelőt az EditForm File|Exit OnClick eseményéhez: procedure TEditForm.Exit1Click(Sender: TObject); begin FrameForm.Exit1Click(Sender); end; • Majd készítsük el a következő
eseménykezelőt a FrameForm File|Exit OnClick eseményéhez: procedure TFrameForm.Exit1Click(Sender: TObject); begin Close; end; Delphi gyakorló feladatok Összeállította: Vámossy Zoltán Budapest, 1996. 4. Téma: Menüszerkesztés Megismerendő eszközök A menük egyszerű módot biztosítanak ahhoz, hogy logikusan csoportosított parancsokat használhassanak a felhasználók. A Delphi menü tervezője (Menu Designer) segítségével egyszerűen készíthetünk menüket, vagy felhasználhatunk meglévő mintákat. A menüelemeket többnyire begépeléssel hozhatjuk léte, de át is rendezhetjük azokat több módszerrel is. (Természetesen futási időben is módosíthatjuk menürendszerünket.) Ebben a feladatban a főmenü és a pop-up (helyi) menü készítését ismerhetjük meg az alábbi sorrendben: 1. 2. 3. 4. 5. A menü tervező (Menu Designer) megnyitása. Menük készítése. Menüelemek szerkesztése. Gyorsmenü és gyorsító billentyűk készítése.
Menüminták alkalmazása és menük sablonként való elmentése. A menü tervező (Menu Designer) megnyitása. A menü tervező használata érdekében elsőként vagy egy MainMenu, vagy egy PopupMenu komponenst kell a form-ra helyeznünk.A MainMenu komponens egy olyan menüsort hoz létre, amely az ablak fejlécéhez van mindig rögzítve. A PopupMenu pedig csak akkor jelenik meg a form-on, ha a felhasználó a jobb egérgombbal kattint azon. A Pop-up menüknek nincs menüsoruk A menü tervezőt az alábbi módszerek valamelyikével indíthatjuk el, miután kiválasztottuk valamely menükomponenst a form-on: Duplán klikkelünk a komponensen, vagy az objektum felügyelőben (Object Inspector) az Items tulajdonság (property) mellett duplán kattintunk az érték oszlopban, vagy egyszer a (.) gombon A megjelenő menü tervezőben az első elem lesz kiválasztva az objektum felügyelőben (Object Inspector) pedig a Caption property. Menü készítés Menü és menüelemek (items)
azonosítója A menü azonosítóját a Delphi automatikusan elkészíti, de módosíthatjuk azt a Pascal konvenciók szerint. A menüelemek azonosítóját (Name) illetve a megjelenő szöveg feliratot (Caption) a más komponenseknél már megszokott módon készíthetjük el. Menüelemek hozzáadása, beszúrása és törlése A menütervezőben válasszuk ki elsőként azt a helyet, ahova menüpontot hozzá szeretnénk adni. Ez új menünél az első elem automatikusan. Vagy gépeljük be az elem nevét, vagy az objektum felügyelőben (Object Inspector) adjuk meg az azonosítóját (Name) először, utána pedig a Caption tulajdonságot. Az <Enter> leütése után a következő lehetséges menühelyek lesznek kiemelt színűek. Az elkészített menüelemeket az egér húzásával esetleg más helyre mozgathatjuk. A menüelem beszúrása érdekében egérrel válasszuk ki azt a helyet ahová be szeretnénk szúrni és nyomjuk le az <Insert> billentyűt. A beszúrás
elé illetve balra történik Amennyiben törölni szeretnénk egy elemet, akkor a kiválasztás után a <Del>-t üssük le. A menühely tartó nem jelenik meg futási időben , így azt nem kell törölni. Elválasztó sorok, gyorsító kulcsok és gyorsítóbillentyűk készítése A menüben az elválasztó sorok használatával csoportosíthatjuk a menüpontokat. Az elválasztás a "-", mint Caption begépelésével történik. A gyorsító kulcsok használatakor a felhasználó az <Alt> és a menüelemben aláhúzott karakter leütésével a billentyűzetről választhatja ki a kívánt parancsot. A gyorsítóbillentyűk valamilyen speciális egyidejű kombinációt jelentenek, melynek hatására indul el a parancs anélkül, hogy a menürendszer megnyílna. A gyorsító kulcs elkészítéséhez a megfelelő karakter elé egy & karaktert kell gépelni, a gyorsbillentyűk elkészítéséhez pedig válasszuk ki az objektum felügyelőben ShortCut
property-t és a legördülő listából a megfelelő elemet, esetleg gépeljük be azt. Beágyazott almenü készítése Gyakran előforduló feladat, hogy valamely almenü kiválasztásakor, egy az elem mellett megjelenő drop-down almemü gördüljön le. Az ilyen menüelemeket egy pici jobbranyíl szokta jelezni A menüstruktúra ilyen jellegű megtervezése a struktúra szélességét csökkenti, mélységben pedig jobban tagolttá teszi azt. Az ilyen típusú almenü készítéséhez: 1. Válasszuk ki a menüelemet 2. A <CTRL> és a lenyomásával, vagy a gyorsmenü Create Submenu funkciójának választásával az almenü szerkeszthető lesz. 3. A szerkesztés a szokásos módon történik 4. Az előző szintre az <Esc> leütésével léphetünk A menütervező (Menu Designer) gyorsmenü lehetőségei A gyorsmenü lehetőséget nyújt a menükészítés során előforduló leggyakoribb feladatok hatékony megvalósításához. A gyorsmenü vagy a Menu
Designer ablakában történő jobb egérgomb lenyomásával, vagy az <Alt>+F10 billentyű kombinációval indítható. A gyorsmenü lehetőségei a következők: Menü parancs Hatás Insert Delete Create Submenu Select Menu Üres hely beszúrása le, vagy balra. A menüelem (és a hozzátartozó almenü) törlése. A kiválasztott menüitemhez almenünek nyit helyet. Ha egy form-on több menüt helyezzünk el, ekkor lehetőséget nyújt a választásra. A sablonként történő elmentés dialógusablakát nyitja meg, miután lehetőségünk lesz a menü újabb felhasználására. A sablonokat DMT kiterjesztésű állományokban tárolja a Delphi DELPHIBIN könyvtárban. A menüminták használatát biztosítja. A dialógusablak megnyitása után kitörölhetünk egy menüsablont. Az erőforrásokat kezelő dialógusablak segítségével egy .MNU kiterjesztésű fájlban eltárolt menüt helyezhetünk a form-ra. Save As Template Insert From Template Delete Templates Insert
From Resource Menüesemények lekezelése A menüszerkesztő segítségével csak a menüstruktúra határozható meg. Azonban minden menüelemhez tartozik egy OnClick esemény (event). A MainMenu komponens annyiban eltér a PopupMenu komponenstől, hogy ez utóbbinak un. OnPopup esménye van, amely a jobboldali egérgomb lenyomásakor aktivizálódik futás során. A menüsor elemein való klikkelés gyakran a megfelelő almenük karbantartását (kiválasztható, vagy sem, stb.) biztosító eseménykezelőt indít Az eseménykezelők készítésének módja megegyezik a már megismertekkel. Tehát vagy az OnClick esemény érték oszlopában duplán kattintva, vagy a menüelemre klikkelve megjelenik a kódszerkesztő az eljárásfejléccel. Menüelemek dinamikus kezelése Futás közben sokszor előfordulhat, hogy menüelemeket szeretnénk hozzávenni, vagy beszúrni az eddigiekhez. A menuitemek Add illetve Insert metódusával oldhatjuk meg ezt a problémát Alternatívát
jelenthet ha elrejtjük vagy megjelenítjük a menüelemet a Visible tulajdonságának állításával. Az Enabled property használatával a kiválaszthatóság lehetőségét szabályozhatjuk. MDI és OLE kliens alkalmazásokban a főmenünek képesnek kell lennie, hogy a gyermek ablakok megnyitásakor, vagy az OLE aktivizálásakor automatikusan kiegészüljön a menürendszer. Ezt gyakran menük ragasztásának (merging menus) nevezik. A megvalósítás egyik módja a form menü tulajdonságának módosítása: Form1.Menu := SecondMenu; A menüelemek hozzáragasztásának másik módja a GroupIndex tulajdonság használata. A GroupIndex meghatározza, hogy az illesztett menüelemek milyen sorrendben jelenjenek meg a menüsorban. Az index alapértéke 0. A következő szabályok igazak a GroupIndex használatakor: Az alacsonyabb értékek esetén a menü balrább jelenik meg, nagyobb értékek pedig jobbra. Ha ugyanazt a GroupIndex értéket adjuk az illesztendő menünek, akkor
helyettesíti az eredeti menüt. Ha pedig olyan értéket határozzunk meg, amilyen érték még nem szerepelt a GroupIndex értékek között, akkor beszúródik a menü. Delphi gyakorló feladatok Összeállította: Vámossy Zoltán Budapest, 1996. 6. Téma: Futás idejű grafika használata I Megismerendő eszközök Amikor a Delphi alkalmazásban grafikát készítünk, akkor az objektum canvas-ára (festővászon) rajzolunk és nem direkt az objektumra. A canvas az adott objektum tulajdonsága és maga is objektum, így rendelkezik tulajdonságokkal. A canvas négy legfontosabb tulajdonságága a következő: a toll (pen), mely vonalas rajzra szolgál, a festőecset (brush), melynek segítségével alakzatokat tölthetünk ki, a betűtípust (font) szöveg írására használható és a pixelek tömbje, amely a képet reprezentálja. Ebben a feladatban a toll, a festőecset és a pixel tömb alkalmazását ismerjük meg. Mivel a canvas-ok csak futás időben
érhetőek el, így kódot kell készítenünk, ha meg szeretnénk ismerni a Delphi következő grafikai elemeit: 1. 2. 3. 4. a pixel tömb használata vonalas rajz alakzatok rajzolása speciális részek rajzolása A pixel tömb használata Minden canvas rendelkezik egy Pixels-nek nevezett tulajdonsággal, amely a kép színes pontjainak tömbje. A pontok egyenként is színezhetőek, de a toll és a festőecset kényelmesebb módja lehet a képpontok csoportos használatának. A canvas pixel-ei egy kétdimenziós tömbben helyezkednek el Minden elemnek meghatározott színe van. Az egyes pixeleket olvashatjuk, vagy beállíthatjuk Pixel színének olvasása Egy adott pixel színének olvasásához a canvas Pixels tulajdonságának x-, y- koordinátájú elemét kell beolvasni. A canvas koordinátarendszerének origója a bal felső sarokban helyezkedik el. A következő, kiválasztó box-hoz tartozó eseménykezelő például a box betűszínét változtatja meg: procedure
TForm1.CheckBox1Click(Sender: TObject); begin CheckBox1.FontColor := CanvasPixels[10, 10]; end; Pixel színezése Az adott x-, y- koordinátájú pont színének beállításához szintén a Pixels tulajdonságot használjuk. Az alábbi eseménykezelő egy-egy pixel színét változtatja pirosra kattintás hatására. procedure TForm1.Button1Click(Sender: TObject); begin Canvas.Pixels[Random(ClientWidth), Random(ClientHeight)] := clRed; end; Delphi Vámossy, 1996 A toll használata A canvas Pen property-je vonalas rajz elkészítésére szolgál. A toll négy tulajdonsága állítható be: Color (szín), Width (szélesség), Style (stílus) és Mode (mód). Ezen tulajdonságok határozzák meg azt, hogy a toll miként fogja a vonalas rajzot elkészíteni. Az alapértelmezés szerinti toll fekete színű, egy pixel széles, tömör stílusú és a módja un. copy, amely azt jelenti, hogy felülír mindent, ami már a festővásznon (canvas) volt A szín (Color) tulajdonság
hasonlóan szabályozható futás időben, mint más objektum esetében. A szélesség (Width) egész érték lehet. A stílus (Style) pl tömör vonal, pont vonal, szaggatott vonal, stb lehet A mód tulajdonság (Mode) pedig azt állítja be miként kombinálódjon a toll színe azzal a színnel, amely a festővásznon már korábban elhelyezkedett. A toll mozgatása A toll aktuális rajzoló pozíciója, az a pont, amelyből kiindulva fogja a toll a következő vonalat húzni. Ezt a pontot a canvas PenPos tulajdonsága tárolja. Ez a tulajdonság csak a kirajzolandó vonalra van hatással, alakzat vagy szöveg adott pozícióban történő megjelenítéséhez nem használható, ott más paramétereket kell beállítani. A rajzolási pozíció beállítására a festővászon MoveTo metódusát használjuk. Például a rajzolási pozíció bal felső sarokba való mozgatásához a következő kódot kell megírnunk: Canvas.MoveTo(0, 0); Megjegyzés: A LineTo metódus történő
rajzolás az aktuális rajzolási pozíciót a megrajzolt vonal végére állítja. Az ecset használata A festővászon (canvas) Brush tulajdonsága határozza meg, hogy miként töltünk ki egy adott területet. A kitöltő eljárás nagy számú szomszédos pixel színét speciálisan változtatja meg. Az ecsetnek három tulajdonsága állítható be: Color (szín), Style (stílus), és a Bitmap, melyek meghatározzák az alakzat vagy a terület kitöltését. Alapértelmezésként az ecset színe fehér, tömör és nem mintázott a bitmap. A szín (Color) tulajdonság hasonlóan szabályozható futás időben, mint más objektum esetében. A Style tulajdonság azt határozza meg, hogy az ecset színe milyen kölcsönhatásban legyen a festővászon eredeti színeivel. A Bitmap segítségével pedig kitöltési mintát állíthatunk be Szakaszok és poligonok rajzolása Két fajta vonalas rajzot készíthetünk: szakaszokat, vagy poligonokat. Az egyenes szakasz kirajzolása
során két pontot kötünk össze, a poligon pedig egymáshoz kötött egyenes szakaszok olyan füzére, melynek a kezdő és végpontja ugyanaz. Szakaszok rajzolása Szakaszok festővásznon történő megjelenítésére a canvas LineTo metódusát használjuk. A LineTo egy egyenest húz az aktuális toll pozíciótól egy meghatározott pozícióba és a szakasz végpontjára változtatja meg az aktuális toll pozíciót. Például a következő eljárás átlós keresztet rajzol: procedure TForm1.FormPaint(Sender: TObject); begin with Canvas do begin MoveTo(0, 0); 2 Delphi end; Vámossy, 1996 end; LineTo(ClientWidth, ClientHeight); MoveTo(0, ClientHeight); LineTo(ClientWidth, 0); Az OnPaint esemény akkor történik, ha a Windows detektálja, hogy az adott form-ot újra kell rajzolni, például, ha egy másik, előtte elhelyezkedő ablakot bezárunk, mozgatunk. A FormPaint az alapértelmezett neve a Delphi által generált OnPaint eseményhez tartozó
eseménykezelőnek. Poligonok kirajzolása Egymáshoz kapcsolódó egyenes szakaszokat a canvas PolyLine metódusával rajzolhatunk. Az eljárásnak átadott paraméterek az egyes csúcspontok pozícióit tartalmazó tömb. A következő eljárás rombuszt rajzol: procedure TForm1.FormPaint(Sender: TObject); begin with Canvas do PolyLine([Point(0, 0), Point(50, 0), Point(75, 50), Point(25, 50), Point(0, 0)]); end; Megjegyzés: ez az eljárás a Delphi nyitott tömb lehetőségét is bemutatja. Tetszőleges számú tömbpontot átadhatunk paraméterként, ha a paramétereket szögletes zárójelbe helyezzük. Alakzatok rajzolása A canvas négy alakzattípust tud kirajzolni a metódusai segítségével. A canvas az alakzatok határát a toll segítségével húzza meg, a belsejüket pedig az ecsettel tölti ki. Az alakzat típusok a következők: 1. Téglalap és ellipszis 2. Lekerekített sarkú téglalap 3. Poligon által határolt terület Téglalap és ellipszis rajzolása
Téglalap, vagy ellipszis kirajzolásához a canvas Rectangle illetve Ellipse metódusát hívhatjuk. Az átadandó paraméterek a határoló téglalap koordinátái. A Rectangle metódus kirajzolja a határoló téglalapot, míg az Ellipse olyan ellipszist rajzol, mely érinti a határoló téglalapot. A példában egy form bal felső negyedét téglalappal festjük ki, majd ellipszist rajzolunk rá: procedure TForm1.FormPaint(Sender: TObject); begin Canvas.Rectangle(0, 0, ClientWidth div 2, ClientHeight div 2); Canvas.Ellipse(0, 0, ClientWidth div 2, ClientHeight div 2); end; 3 Delphi Vámossy, 1996 Lekerekített sarkú téglalap rajzolása Lekerekített sarkú téglalap rajzolása érdekében a canvas RoundRect metódusát alkalmazhatjuk. Az első négy paraméter a határoló téglalapot jelenti míg a további két paraméter a sarok lekerekítését határozza meg. A következő eljárás lekerekített sarkú téglalapot rajzol, ahol a körívek átmérője 10 pixel:
procedure TForm1.FormPaint(Sender: TObject); begin Canvas.RoundRect(0, 0, ClientWidth div 2, ClientHeight div 2, 10, 10); end; Poligon rajzolása Poligon rajzolása a canvas Polygon metódusával történik. A Polygon metódus a csúcspontok tömbparaméterét használja. A toll segítségével összeköti a pontokat (az utolsót az elsővel is), majd az ecset tulajdonságainak felhasználásával kitölti az alakzatot. Egy derékszögű háromszög megrajzolását szemlélteti a következő eljárás: procedure TForm1.FormPaint(Sender: TObject); begin Canvas.Polygon([Point(0, 0), Point(0, ClientHeight), Point(ClientWidth, ClientHeight)]); end; Speciális alakzatok rajzolása A canvas további alakzatok kirajzolását is biztosítja pl. ívek, szeletek, stb megjelenítését 4 Delphi gyakorló feladatok Összeállította: Vámossy Zoltán Budapest, 1996. 7. Téma: Futás idejű grafika használata II Megismerendő eszközök Ebben a feladatban olyan egyszerű grafikai
alkalmazást készítünk, melynek segítségével vonalas rajzokat, alakzatokat készíthetünk az egér bizonyos eseményeinek hatására. A programkészítés fő lépései a következők lesznek: 1. 2. 3. 4. 5. 6. 7. 8. Az egérhez kapcsolódó események kezelése Eszköztár készítése gyorsító gombokkal Toll és ecset beállítás Státuszsor készítése Bitmap-re történő rajzolás Grafika nyomtatása Munka grafikus állományokkal A vágólap grafikus tartalmának használata Az egérhez kapcsolódó események kezelése Négy olyan egérhez kapcsolódó esemény van, amelyekre az alkalmazásban reagálhatunk. A következő három önálló esemény: egérgomb lenyomása , felengedése és az egér mozgatása. A negyedik, az egérrel történő kattintás azonban egy kicsit eltér az előzőektől, mert az bizonyos esetekben speciális billentyű kombináció eredményeként is generálható (pl. Enter leütése modális dialógusablakban) Ebben a feladatban csak az
önálló egéreseményekkel foglalkozunk. Az alkalmazásban az egér által kiváltott események hatására alakzatokat fogunk rajzolni: az egérgomb lenyomására kezdjük, felengedésére befejezzük a rajzot. A fix kiindulópont és a felengedés pillanatáig változó végpont között folyamatosan új és új alakzatokat kell rajzolni, az előző állapotokat pedig törölni kell. Elsőként egy szakaszt próbálunk megjeleníteni a fenti technikával. Később pedig más alakzatokat is Delphi Vámossy, 1996 A Delphi önálló egéreseményei A Delphi három önálló egéreseményének: (OnMouseDown, OnMouseMove és OnMouseUp) öt-öt paramétere van. Ezek a következők: Paraméter Sender Button Shift X, Y Jelentés Az objektum, mely detektálta az eseményt. A lenyomott egérgomb: mbLeft, mbMiddle, vagy mbRight. Speciális billentyűk állapotát adja vissza az esemény pillanatában: Alt, Ctrl és Shift billentyűk. A pont koordináta, ahol az esemény történt.
A legtöbb esetben a koordináták értéke az elsődleges, de sokszor az egérgombokat is figyelni kell, hogy melyik generálta az eseményt. Az egérgomb lenyomására történő reakció Valahányszor a felhasználó lenyom egy egérgombot, akkor egy OnMouseDown esemény játszódik le. Ebben a feladatban a lenyomás hatására kezdjük majd el a rajzolást. • Azért, hogy vizsgálni tudjuk az eseménykezelőt, próbáljunk meg egy rövid szöveget kiírni a lenyomás helyszínén. Az X és Y paraméterek segítségével a TextOut metódust hívjuk meg a szöveg megjelenítésére: procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin Canvas.TextOut(X, Y, IntToStr(X)+, +IntToStr(Y)); end; • Teszteljük a kódot. • A megoldandó feladatban az egérgomb lenyomása csak a szakasz kiinduló pontját azonosítja. Ezért elsőként módosítsuk az eseménykezelőt: procedure TForm1.FormMouseDown(Sender: TObject; Button:
TMouseButton; Shift: TShiftState; X, Y: Integer); begin Canvas.MoveTo(X, Y); {alapértelmezett toll pozíció: PenPos} end; Az egérgomb felengedéséhez kapcsolódó eseménykezelő Az OnMouseUp esemény akkor történik, amikor felengedjük az egérgombot. • A feladatban egy szakaszt jelenítünk meg a felengedést lekezelő eljárásban: procedure TForm1.FormMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin Canvas.LineTo(X, Y); { szakaszt rajzol a PenPos-tól (X, Y) pozícióba} end; Futás során azonban csak akkor láthatjuk a szakaszokat, ha már felengedtük az egérgombot. Az egér mozgásának követése 2 Delphi Vámossy, 1996 Az OnMouseMove esemény akkor történik, amikor a felhasználó mozgatja az egeret. • Készítsük el a következő eseménykezelőt az egér OnMouseMove eseményéhez: procedure TForm1.FormMouseMove(Sender: TObject;Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin Canvas.LineTo(X,
Y); { szakasz kirajzolása az aktuális pozícióba } end; Ekkor azonban nem csak akkor készül rajz ha lenyomott az egérgomb, hanem az egér minden megmozdítása egyegy rövid szakaszt eredményez. Kézenfekvő, hogy el kell tárolni egy változóban azt, hogy lehetséges-e a rajzolás • A Drawing Boolean változót deklaráljuk a form public változói között. • Hasonlóan deklaráljuk az Origin-nak és a MovePt-nak nevezett pontokat is: type TForm1 = class(TForm) procedure FormMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); procedure FormMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); procedure FormMouseMove(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); public Drawing: Boolean; Origin, MovePt: TPoint; { pontok tárolására } end; • Módosítsuk az eseménykezelőket az alábbiak szerint, majd teszteljük a programot: procedure TForm1.FormMouseDown(Sender: TObject; Button:
TMouseButton; Shift: TShiftState; X, Y: Integer); begin Drawing := True; { a Drawing beállítása } Canvas.MoveTo(X, Y); end; procedure TForm1.FormMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin Canvas.LineTo(X, Y); Drawing := False; end; procedure TForm1.FormMouseMove(Sender: TObject;Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin if Drawing then Canvas.LineTo(X, Y); end; Habár most már csak az egérgomb lenyomása és felengedése között rajzolunk, az eredmény mégsem megfelelő, mert nem a kiinduló pontot köti össze a rajzunk az aktuális ponttal. Ennek az az oka, hogy a LineTo eseménykezelő folyamatosan módosítja az aktuális rajzpoziciót. Az Origin és a MovePt éppen ezért a kezdő és közbenső pontokat fogja azonosítani. • Állítsuk be az Origin változó értékét úgy, hogy a mouse-down esemény eltárolja a kívánt kezdőpontot és a mouse-up esemény innen kezdi majd a vonal húzását: 3
Delphi Vámossy, 1996 procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin Drawing := True; Canvas.MoveTo(X, Y); Origin := Point(X, Y); end; procedure TForm1.FormMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin Canvas.MoveTo(OriginX, OriginY); Canvas.LineTo(X, Y); Drawing := False; end; procedure TForm1.FormMouseMove(Sender: TObject;Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin if Drawing then Canvas.MoveTo(OriginX, OriginY); Canvas.LineTo(X, Y); end; A továbbiakban már csak az előzőleg kirajzolt szakaszt kell mindig törölnünk. Az előző szakasz végpontjának eltárolására használjuk a MovePt korábban már deklarált változót. • Állítsuk be a MovePt pontot a közbenső szakaszok végpontjának, így törölhetjük az előző szakaszt a MovePt és az Origin pontok ismeretében: procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer); begin Drawing := True; Canvas.MoveTo(X, Y); Origin := Point(X, Y); MovePt := Point(X, Y); { az előző pont tárolása } end; procedure TForm1.FormMouseMove(Sender: TObject;Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin if Drawing then begin Canvas.PenMode := pmNotXor; { az XOR módot használjuk a rajzra és a törlésre } Canvas.MoveTo(OriginX, OriginY); Canvas.LineTo(MovePtX, MovePtY); { a régi szakasz törlése } Canvas.MoveTo(OriginX, OriginY); { az új start pont } Canvas.LineTo(X, Y); { az új szakasz } end; MovePt := Point(X, Y); { az aktuális pozíció eltárolása } Canvas.PenMode := pmCopy; end; A toll módjának pmNotXor-ra állítása biztosítja a pixelek folyamatos törlését ha nem háttérszínűek voltak azok, illetve beállítását ellenkező esetben. A pmCopy-ra való visszaállítás eredményezi, hogy az egérgomb felengedése után a toll kirajzolja az utolsó szakaszt. 4 Delphi Vámossy, 1996 A
többi alakzatot is hasonló technikával kell majd kirajzolni. Ehhez azonban előbb lehetőséget kell biztosítani az alakzatok közötti választásra. Eszköztár használata Az eszköztár (tool bar) egy panel, amely rendszerint a form tetején a menüsor alatt helyezkedik el és vezérlő eszközöket, többnyire gyorsító gombokat tartalmaz. Az eszköztár elkészítése érdekében a következőket kell megoldani: 1. Helyezzünk egy Panel komponenst a form-ra 2. Állítsuk be a panel Align tulajdonságát alTop-ra Ennek a beállításnak a hatására a panel állandó magassága mellett a szélessége megegyezik folyamatosan a form kliensterületének a szélességével, ha átméretezzük az ablakot. 3. Helyezzünk el gyorsító gombokat és más vezérlő elemeket a panelra • A mintafeladat megoldásához készítsünk elő egy eszköztárat egy panel komponens használatával. Töröljük a Caption tulajdonságát. A későbbiekben fogjuk elhelyezni a gyorsító gombokat
és újabb eszköztárakat is létre fogunk hozni. Gyorsító gombok elhelyezése az eszköztáron Az eszköztárak készítéséhez a Delphi speciális gombokat (speed button) biztosít. A gyorsító gomboknak nem szokott felirata lenni, hanem csak egy kis grafika (glyph) jelenik meg rajtuk. A gyorsító gombnak háromféle funkciója lehet: 1. Szabályos nyomógombként funkcionálhat 2. Ki - és bekapcsolhatóak, ha rákattintunk 3. Rádiógombként is használhatóak Gyorsító gombok eszköztáron való alkalmazásakor négy feladatot kell megoldanunk: 1. 2. 3. 4. A gyorsító gombot az eszköztárra kell helyeznünk. Grafikát (glyph) kell hozzárendelnünk a gombhoz. A kezdeti feltételeket be kell állítanunk. Csoportosítani kell a gyorsító gombokat. • Helyezzünk hat gyorsító gombot az eszköztárra az alábbi ábra szerinti elrendezésben és változtassuk meg a nevüket, ahogy az jelezve van. • Az alapértelmezett magassága az eszköztárnak 41 pixel, a
gyorsító gombnak 25. Ha a gombok Top tulajdonságát 8-ra állítjuk, akkor éppen középen helyezkednek el függőleges irányban a panelen. Minden gyorsító gombon célszerű elhelyezni egy olyan grafikus ábrát, amely a gomb funkciójára utal. Ha egy képet rendelünk a gombhoz, akkor a gomb működése során jelzi, hogy a gomb benyomott-e vagy sem. Lehetőség van azonban arra, hogy különböző képeket rendeljünk a gomb különböző állapotaihoz. Általában tervezési időben rendelünk képet a gyorsító gombhoz, futási időben pedig a különböző képeket cserélhetjük. A kép (glyph) hozzárendelése a gyorsító gombhoz a következő módon történik tervezési időben: 1. Kiválasztjuk a gombot 5 Delphi Vámossy, 1996 2. Az objektum felügyelőben a Glyph tulajdonság érték oszlopában duplán kattintunk 3. A Delphi megnyitja a képszerkesztőt és a Load paranccsal tölthetünk be képet, amit majd az <OK> gombbal rendelhetjük a
gyorsító gombhoz. • Készítsünk és/vagy rendeljünk az ábrának megfelelő képeket a gyorsító gombokhoz. A gyorsító gombok kezdeti állapotának beállítása Ahhoz, hogy egy gyorsító gomb lenyomott állapotban jelenjék meg, állítsuk a Down tulajdonságát True-ra. • Mivel az elkészítendő alkalmazásban a vonal az alapértelmezett rajzolási alakzat, állítsuk a LineButton Down tulajdonságát True-ra. Gyorsító gombok csoportba sorolása A gyorsító gombok egy halmaza gyakran reprezentál egymást kölcsönösen kizáró választásokat. Ekkor a gombokat csoportba kell foglalni és ha a csoport valamelyik elemére kattintunk, kiválasztjuk azt, akkor a többi gomb kiemelt állapotban kell hogy megjelenjék. A csoportbasorolást a GroupIndex tulajdonság ugyanolyan értékre történő beállításával valósíthatjuk meg. • A rajzolási alakzatokat megjelenítő gombok kizáró választásokat testesítenek meg, ezért rendeljük a GroupIndex
tulajdonságukhoz az 1 értéket. Gyakran előforduló feladat, hogy olyan csoportban szereplő gombot kell készítenünk, mely más gomboktól függetlenül benyomható illetve kikapcsolható. Ezt a funkciót az AllowAllUp tulajdonság beállításával generálhatjuk. Ha ezt a tulajdonságot True-ra állítottuk, akkor minden a csoportban elhelyezkedő gombra is arra áll és lehetővé teszi azt, hogy mindig csak egy gomb legyen kiválasztott, vagy a kiválasztottságot meg tudjuk szüntetni. • Mind a tollhoz, mind az ecsethez tartozó gomb AllowAllUp property-jét állítsuk True-ra, majd rendeljünk a PenButton-hoz 2-es GroupIndex értéket, a BrushButton-hoz 3-t. Rajzolás különböző eszközökkel A grafikus programban folyamatosan tudnunk kell, hogy a felhasználó milyen rajzeszközt választott. Egy felsorolt típust deklarálunk erre a célra. • A form típus deklarációs részéhez adjuk a TDrawingTool típus deklarációját: type TDrawingTool = (dtLine,
dtRectangle, dtEllipse, dtRoundRect); TForm1 = class(TForm) { ez már adott } Megjegyzés: a Delphi konvenciói szerint a típusok deklarációját T-vel kezdjük, a hasonló konstansokat (pl. felsorolt típus elemei) pedig 2 karakteres előtaggal, (a dt jelentése: “drawing tool”). • A form deklarációjához rendeljük a DrawingTool változót, amely az aktuális rajzolási eszközt fogja jelenteni. public Drawing: Boolean; Origin, MovePt: TPoint; 6 Delphi end; Vámossy, 1996 DrawingTool: TDrawingTool; { az aktuális rajzeszköz } Mivel az objektumok mezői a zéró értékkel lesznek inicializálva, így a DrawingTool értéke indításkor dtLine lesz. • A rajzolási eszközök változtatásához készítsük el a következő eseménykezelőket, amelyek megváltoztatják a DrawingTool változó értékét annak megfelelően, hogy melyik gyorsító gombot nyomtuk meg. procedure TForm1.LineButtonClick(Sender: TObject); begin DrawingTool := dtLine; end; procedure
TForm1.RectangleButtonClick(Sender: TObject); begin DrawingTool := dtRectangle; end; procedure TForm1.EllipseButtonClick(Sender: TObject); begin DrawingTool := dtEllipse; end; procedure TForm1.RoundedRectButtonClick(Sender: TObject); begin DrawingTool := dtRoundRect; end; A rajzolási eszközök beállítása utáni lépés az lesz, hogy a legelsőként megírt vonalszakasz rajzolásához hasonló eseménykezelőket készítsünk különböző rajzeszközök esetében is. A rajzeszközök használata A megfelelő alakzat kirajzolásához módosíthatnánk az eseménykezelőket az alábbiak szerint: procedure TForm1.FormMouseUp(Sender: TObject); begin case DrawingTool of dtLine: begin Canvas.MoveTo(OriginX, OriginY); Canvas.LineTo(X, Y) end; dtRectangle: Canvas.Rectangle(OriginX, OriginY, X, Y); dtEllipse: Canvas.Ellipse(OriginX, OriginY, X, Y); dtRoundRect: Canvas.RoundRect(OriginX, OriginY, X, Y, (OriginX - X) div 2, (OriginY - Y) div 2); end; Drawing := False; end; procedure
TForm1.FormMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); begin if Drawing then begin 7 Delphi Vámossy, 1996 Canvas.PenMode := pmNotXor; case DrawingTool of dtLine: begin Canvas.MoveTo(OriginX, OriginY); Canvas.LineTo(MovePtX, MovePtY); Canvas.MoveTo(OriginX, OriginY); Canvas.LineTo(X, Y); end; dtRectangle: begin Canvas.Rectangle(OriginX, OriginY, MovePtX, MovePtY); Canvas.Rectangle(OriginX, OriginY, X, Y); end; dtEllipse: begin Canvas.Ellipse(OriginX, OriginY, X, Y); Canvas.Ellipse(OriginX, OriginY, X, Y); end; dtRoundRect: begin Canvas.RoundRect(OriginX, OriginY, X, Y, (OriginX - X) div 2, (Origin.Y - Y) div 2); Canvas.RoundRect(OriginX, OriginY, X, Y, (OriginX - X) div 2, (Origin.Y - Y) div 2); end; end; MovePt := Point(X, Y); end; end; Canvas.PenMode := pmCopy; Mivel azonban ismétlődő részek vannak a kódban, ezért deklaráljunk egy alakzatrajzoló eljárást és ezt hívjuk majd a fenti rutinok módosított változatában. • A form objektum
deklaráció public részéhez írjuk be a következő DrawShape eljárást: type TForm1 = class(TForm) . . . public { Public declarations} procedure DrawShape(TopLeft, BottomRight: TPoint; AMode: TPenMode); end; • Az implementation részben határozzuk meg a rutin működését: procedure TForm1.DrawShape(TopLeft, BottomRight: TPoint; AMode: TPenMode); begin with Canvas do begin Pen.Mode := AMode; case DrawingTool of dtLine: begin MoveTo(TopLeft.X, TopLeftY); LineTo(BottomRight.X, BottomRightY); end; 8 Delphi end; Vámossy, 1996 end; dtRectangle: Rectangle(TopLeft.X, TopLeftY, BottomRightX, BottomRightY); dtEllipse: Ellipse(TopLeft.X, TopLeftY, BottomRightX, BottomRightY); dtRoundRect: RoundRect(TopLeft.X, TopLeftY, BottomRightX, BottomRightY, (TopLeft.X - BottomRightX) div 2, (TopLeftY - BottomRightY) div 2); end; • Az eddigi eseménykezelőket pedig módosítsuk a DrawShape eljárás hívásával az alábbiak szerint: procedure TForm1.FormMouseUp(Sender: TObject;
Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin DrawShape(Origin, Point(X, Y), pmCopy); { a végső alakzat kirajzolása } Drawing := False; end; procedure TForm1.FormMouseMove(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin if Drawing then begin DrawShape(Origin, MovePt, pmNotXor); { az előző alakzat törlése } MovePt := Point(X, Y); { az aktuális pont tárolása } DrawShape(Origin, MovePt, pmNotXor); { az aktuális alakzat rajzolás } end; end; A toll és az ecset beállítása A program fejlesztésének alábbi szakaszában a rajzolási színek és stílusok beállítása érdekében az alábbi tevékenységeket végezzük el: 1. 2. 3. 4. 5. 6. Rejtett eszköztár elkészítése és annak be-, illetve kikapcsolása A toll stílusának megváltoztatása A toll színének módosítása A toll vastagságának állítása Az ecset stílusának módosítása Az ecset színének szabályozása Rejtett eszköztár elkészítése és
annak be-, illetve kikapcsolása Rejtett eszköztár készítéséhez a már megismert módszer szerint hozzunk létre egy eszköztárat (Ne felejtsük el a panel Align tulajdonságát alTop-ra állítani!) és állítsuk be Visible property-t False-ra. • Készítsünk egy PenBar és egy BrushBar nevű rejtett eszköztárakat, amint azt az alábbi ábra mutatja. A gyorsító gombokon kívül használjuk a következő komponenseket: ColorGrid, ScrollBar, és Label a PenBar esetében és ColorGrid a BrushBar estében 9 Delphi Vámossy, 1996 10 Delphi Vámossy, 1996 • A komponensek beállítása a következő legyen: Component SolidPen DashPen DotPen DashDotPen DashDotDotPen ClearPen PenColor PenWidth PenSize SolidBrush ClearBrush HorizontalBrush VerticalBrush FDiagonalBrush BDiagonalBrush CrossBrush DiagCrossBrush BrushColor Property Glyph Down Glyph Glyph Glyph Glyph Glyph BackgroundEnabled GridOrdering Height Top Width LargeChange Top FocusControl Caption Top
Glyph Down Glyph Glyph Glyph Glyph Glyph Glyph Glyph BackgroundEnabled GridOrdering Height Top Width Value SOLID.BMP True DASHED.BMP DOTTED.BMP DASHDOT.BMP DASHDOT2.BMP CLEAR.BMP False go8x2 30 5 144 10 12 PenWidth 1 13 FSOLID.BMP True FCLEAR.BMP FHORIZ.BMP FVERT.BMP FDIAG.BMP BDIAG.BMP CROSS.BMP DCROSS.BMP False go8x2 30 5 144 Az eszköztárak elrejtése Ha több eszköztárat alkalmazunk egy programban, akkor előfordul, hogy bizonyos eszköztárakat rendre el akarunk rejteni, ki akarjuk kapcsolni azokat. (Előfordul, hogy ezeken az eszköztárakon egy-egy bezárás gomb is szerepel.) • Ebben az alkalmazásban a fő eszköztár toll és ecset gombjának beállításával fogjuk az imént elkészített eszköztárakat ki-, illetve bekapcsolni: procedure TForm1.PenButtonClick(Sender: TObject); begin PenBar.Visible := PenButtonDown; end; procedure TForm1.BrushButtonClick(Sender: TObject); begin BrushBar.Visible := BrushButtonDown; end; A toll stílusának megváltoztatása 11
Delphi Vámossy, 1996 A toll stílusa meghatározza, hogy milyen vonalat rajzolhatunk: tömör vonal, szaggatott vonal, pont-vonal, stb. A feladatban egyetlen eseménykezelőt fogunk elkészíteni a lehetséges vonal beállításokhoz, és a Sender paraméter vizsgálatának függvényében rendeljük a megfelelő konstans értéket a toll stílusához. • Osszuk meg a következő eseménykezelőt a toll stílus gombjaihoz. Az eseménykezelő neve SetPenStyle legyen, amit természetesen az objektum felügyelő segítségével állítsunk be: procedure TForm1.SetPenStyle(Sender: TObject); begin with Canvas.Pen do begin if Sender = SolidPen then Style := psSolid else if Sender = DashPen then Style := psDash else if Sender = DotPen then Style := psDot else if Sender = DashDotPen then Style := psDashDot else if Sender = DashDotDotPen then Style := psDashDotDot else if Sender = ClearPen then Style := psClear; end; end; A toll színének módosítása A toll színének
megváltoztatásához a toll Color tulajdonságát kell beállítani. A felhasználó a ColorGrid használatával fogja beállítani a színeket. • Készítsük el a következő eseménykezelőt a ColorGrid-en való kattintáshoz: procedure TForm1.PenColorClick(Sender: TObject); begin Canvas.PenColor := PenColorForegroundColor; end; A toll vastagságának állítása A toll vastagságának állításához a toll Width tulajdonságát kel állítani. A gördítősáv használatával ez a feladat egyszerűen megoldható. • Kezeljük a gördítősáv (scroll bar) OnChange eseményét a következők szerint: procedure TForm1.PenWidthChange(Sender: TObject); begin Canvas.PenWidth := PenWidthPosition; PenSize.Caption := IntToStr(PenWidthPosition); end; { a szélesség beállítása } { és megjelenítése a címkén } Az ecset stílusának módosítása Az ecset stílusa azt határozza meg, hogy milyen mintákat használhatunk az alakzatok kitöltéséhez. Az előre definiált
konstansok segítségével speciális hatásokat érhetünk el: (bsSolid, bsClear, bsHorizontal, bsVertical, bsFDiagonal, bsBDiagonal, bsCross, bsDiagCross). • Válasszuk ki a nyolc ecset-stílus gombot és készítsük el a következő SetBrushStyle közös eseménykezelőt az OnClick kezelésre: 12 Delphi Vámossy, 1996 procedure TForm1.SetBrushStyle(Sender: TObject); begin with Canvas.Brush do begin if Sender = SolidBrush then Style := bsSolid else if Sender = ClearBrush then Style := bsClear else if Sender = HorizontalBrush then Style := bsHorizontal else if Sender = VerticalBrush then Style := bsVertical else if Sender = FDiagonalBrush then Style := bsFDiagonal else if Sender = BDiagonalBrush then Style := bsBDiagonal else if Sender = CrossBrush then Style := bsCross else if Sender = DiagCrossBrush then Style := bsDiagCross; end; end; Az ecset színének szabályozása Az ecset színe határozza meg az alakzat szinét. • Az ecset eszköztárán elhelyezkedő
ColorGrid komponenshez készítsük el a következő eseménykezelőt: procedure TForm1.BrushColorClick(Sender: TObject); begin Canvas.BrushColor := BrushColorForegroundColor; end; Státusz sor készítése A státusz sor az ablakok alján szokott megjelenni és rendszerint szövegek megjelenítésére alkalmazzák. Panel komponensek segítségével könnyen készíthetünk státusz sorokat. • Státusz sor készítése céljából adjunk egy panelt a form-ra, nevezzük StatusBar-nak és állítsuk be az Align tulajdonságát alBottom-ra. Töröljük a panel Caption mezejének tartalmát • Helyezzünk két további panelt (OriginPanel és CurrentPanel) a státusz sorra. Az egyiket igazítsuk balra (alLeft), a másikat pedig a megmaradt kliens területhez (alClient). Állítsuk be a kívánt 3-D effektusokat a BevelInner és BorderWidth tulajdonságokkal, majd módosítsuk az alábbi eseménykezelőket: procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton; Shift:
TShiftState; X, Y: Integer); begin Drawing := True; Canvas.MoveTo(X, Y); Origin := Point(X, Y); MovePt := Origin; OriginPanel.Caption := Format(Origin: (%d, %d), [X, Y]); end; procedure TForm1.FormMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); begin if Drawing then begin DrawShape(Origin, MovePt, pmNotXor); MovePt := Point(X, Y); DrawShape(Origin, Point(X, Y), pmNotXor); end; 13 Delphi end; Vámossy, 1996 CurrentPanel.Caption := Format(Current: (%d, %d), [X, Y]); Rajzolás a bimap-re Bár gyakran előfordul, hogy direkt a form-ra rajzolunk, ennél jóval általánosabb, hogy egy alkalmazásban valamilyen bitmap-re kell rajzolnunk. A bitmap-ek nagyon hatékony lehetőséget biztosítanak olyan funkciókhoz, mint másolás, nyomtatás, mentés, stb. A bitmap természetesen eltérő méretű lehet, mint a form: lehet nagyobb, vagy kisebb. Egy gördítő box-ot (scroll box) helyezve a form-ra, és ebbe helyezve egy image komponenst, szinte tetszőleges méretű
képet hatékonyan kezelhetünk, szükség esetén gördíthetünk. • Ebben az alkalmazásban az eszköztárak és a státusz sor közötti egész területet gördíthető részként fogjuk használni. Ezért helyezzünk egy scroll box komponenst a form-ra és állítsuk az Align tulajdonságát alClientre, biztosítván azt, hogy a kép kitöltse szükség esetén a form teljes munkaterületét Az image control egy olyan komponens, amely lehetővé teszi, hogy bitmap, vagy metafile képet tartalmazzon. A méretét vagy kézzel, vagy futás közben állíthatjuk be. • Helyezzünk egy image control-t a form-ra úgy, hogy az a scroll box-ban helyezkedjék el. Állítsuk be az image tulajdonságait a következők szerint: Tulajdonság Name AutoSize Left Top Érték Image True 0 0 A bitmap kezdeti méretének beállítása Amikor egy image komponenst helyezünk a form-ra az még nem tartalmaz képet. Csak a kép "tartóját" határozza meg. Az image control Picture
tulajdonságát állíthatjuk tervezési időben, ha az a célunk, hogy mindig ugyanazt a képet tartalmazza. Szabályozhatjuk azonban futási időben is, ha valamely háttértárolón elhelyezkedő képet kell megjeleníteni, vagy amennyiben rajzolni szeretnénk rá. Ekkor futási időben kell egy üres bitmap-et létrehoznunk • Az alkalmazás indításakor egy üres bitmap-nek kell megjelennie. Ezért a form OnCreate eseménykezelőjében hozzunk létre egy bitmap objektumot és az image Picture.Graphic tulajdonságához rendeljük azt hozzá: procedure TForm1.FormCreate(Sender: TObject); var Bitmap: TBitmap; { temporary változó a bitmap tárolására } begin Bitmap := TBitmap.Create; { A bitmap objektum létrehozása } Bitmap.Width := 200; Bitmap.Height := 200; { kezdeti méretek } Image.PictureGraphic := Bitmap; { a bitmap image controlhoz rendelése } end; A hozzárendeléssel az image komponens lesz a bitmap tulajdonosa és így nem kell majd nekünk felszabadítani a
futtatás végén. Ha most teszteljük az alkalmazást, akkor már egy a szükség szerint gőrdítősávokkal szabályozható rajzolási területünk van, a rajzolási tevékenységek azonban nem látszanak, mert az alkalmazás még a form-ra rajzol. 14 Delphi Vámossy, 1996 Rajzolás a bitmap-re Két dolgot kell megoldanunk annak érdekében, hogy a bitmap-re rajzoljunk a form helyett. Használjuk az image control canvas-át a form canvas-a helyett és az egér eseménykezelőit is az image control-hoz kell, hogy rendeljük. • Cseréljük le a “Canvas ” string minden előfordulását “Image.Canvas ”-ra majd az objektum felügyelőben az image control OnMouseDown eseményéhez rendeljük FormMouseDown eseménykezelőt. Hasonlóan járjunk el az OnMouseMove és az OnMouseUp események esetében is. Ha szeretnénk, akkor a form eseménykezelői közül eltávolíthatjuk a már feleslegessé vált fenti három eljárást. (Mivel a form sosem fogja megkapni az
eseményeket, így nem szükséges e módosítás). Menü készítése Az alkalmazás vezérléséhez készítsük el a következő főmenüt. • Helyezzünk egy MainMenu komponenst a form-ra az alábbi beállításokkal: &File &New &Open. &Save Save &as. &Print - <hyphen> E&xit &Edit Cu&t &Copy &Paste • A File|Exit parancshoz (OnClick) írjuk meg a következő eseménykezelőt: procedure TForm1.Exit1Click(Sender: TObject); begin Close; end; Amikor a menürendszert használjuk, akkor észrevehetjük, hogy bizonyos esetekben felesleges vonalak jelennek meg a rajzon miután a menüelemre kattintottunk. Ennek az az oka, hogy a Windows néha egy mouse-up üzenetet küld. • Módosítsuk az OnMouseUp eseménykezelőt, ellenőrizzük a Drawing változó beállítását rajzolás előtt: procedure TForm1.FormMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin if Drawing then begin DrawShape(Origin,
Point(X, Y), pmCopy); Drawing := False; end; end; Grafika nyomtatása Grafikus képek kinyomtatása egyszerű feladat Delphi-ben. A Printers unit-ot soroljuk fel a form uses-ai között E unitban vannak deklarálva a Printer objektum, amely rendelkezik canvas tulajdonsággal és a kinyomtatandó lapot reprezentálja. A grafikus kép kinyomtatása érdekében másoljuk a képet a Printer canvas-ára 15 Delphi Vámossy, 1996 • Ha a File menü Print elemére kattintunk, akkor a következő eljárás futtatásával nyomtathatjuk ki a képet: procedure TForm1.Print1Click(Sender: TObject); begin with Printer do begin BeginDoc; { nyomtatás kezdete } Canvas.Draw(0, 0, ImagePictureGraphic); { a kép kirajzolása } EndDoc; { nyomtatás befejezése } end; end; Grafikus állományok használata A feladat ezen részében az alábbiakat oldjuk meg: 1. Kép betöltése 2. Kép mentése 3. Kép helyettesítése • Helyezzünk egy-egy open-file, save-file dialog box-ot a form-ra. A
CurrentFile string típusú változót pedig a form public változói közé vegyük fel. Ebben a változóban tároljuk majd az aktuális kép nevét Kép betöltése Grafikus file betöltése érdekében használjuk az image control Picture objektumának LoadFromFile metódusát. • A File|Open menü OnClick eseményéhez készítsük el a következő eseménykezelőt: procedure TForm1.Open1Click(Sender: TObject); begin if OpenDialog1.Execute then begin CurrentFile := OpenDialog1.FileName; Image.PictureLoadFromFile(CurrentFile); end; end; Kép mentése A Delphi Picture objektuma különböző formátumokat biztosít, ha menteni akarunk. Mindehhez a SaveToFile metódust kell csak meghívnunk. Ezen eljárás paramétere a fájl neve Ha egy új képet szeretnénk menteni, vagy egy meglévőt más néven szeretnénk tárolni, akkor lehetőséget kell biztosítani, hogy a felhasználó beállíthassa az állomány nevét. • A File|Save és File|Save As menükhöz készítsük el az
alábbi kezelőket: procedure TForm1.Save1Click(Sender: TObject); begin if CurrentFile <> then Image.PictureSaveToFile(CurrentFile) else SaveAs1Click(Sender); end; 16 { mentse el ha már van neve } { nevezzük el } Delphi Vámossy, 1996 procedure TForm1.SaveAs1Click(Sender: TObject); begin if SaveDialog1.Execute then begin CurrentFile := SaveDialog1.FileName; Save1Click(Sender); end; end; { a file-név } Kép helyettesítése • Ha egy image control Picture objektumához egy új grafikát rendelünk, akkor a régi grafika helyettesítődik. A helyettesítés előtt biztosítani kell, hogy a felhasználó beállíthassa a kép alapvető méreteit, vagy valamilyen alapértelmezett méreteket használhat. Ehhez készítsük el az alábbi form-ot, a hozzátartozó unit-ot nevezzük BMPDlg-nak, a form-ot pedig NewBmpForm-nak. Az edit box-okat az ábrán látható nevekkel azonosítsuk • Adjuk a BMPDlg unit-ot a projektünkhöz és hivatkozzunk a főform uses
részben a BMPDlg unit-ra is. • Ezután írjuk meg a következő eseménykezelőt a File|New parancs OnClick eseményéhez: procedure TForm1.New1Click(Sender: TObject); var Bitmap: TBitmap; { temporary változó az új bitmap tárolására} begin with NewBMPForm do begin ActiveControl := WidthEdit; {fókusz állítás } WidthEdit.Text := IntToStr(ImagePictureGraphicWidth); HeightEdit.Text := IntToStr(ImagePictureGraphicHeight); if ShowModal <> idCancel then begin Bitmap := TBitmap.Create; Bitmap.Width := StrToInt(WidthEditText); Bitmap.Height := StrToInt(HeightEditText); Image.PictureGraphic := Bitmap; { a grafika helyettesítése az új bitmap-pel } CurrentFile := ; end; end; end; Megjegyzés: Ha egy új bitmap-et rendelünk a Graphic tulajdonsághoz, akkor automatikusan lebomlik a régi bitmap és az új tulajdonosa lesz a Picture objektum. A Clipboard használata grafika esetén A Windows Clipboard-ját használhatjuk alkalmazások közötti adatcserére grafikák esetében
is. A Delphi Clipboard objektuma egyszerű kezelési lehetőséget biztosít. 17 Delphi Vámossy, 1996 • A ClipBrd unit-ot soroljuk fel a uses részben. Grafika vágólapra helyezése A vágólapra másoláshoz rendeljük a képet a Clipboard objektum Assign metódusával a vágólaphoz. • Az alkalmazásban az Edit|Copy menün történő kattintásra reagáljunk a következő eljárással: 18 Delphi Vámossy, 1996 procedure TForm1.Copy1Click(Sender: TObject); begin Clipboard.Assign(ImagePicture); end; Grafika vágólapra vágása A kivágás hasonló a másoláshoz, de törölni kell a grafikát a forrásról, például a rajzolási terület fehérre festésével. • Az Edit|Cut menü OnClick eseményéhez rendeljük az alábbi eseménykezelőt: procedure TForm1.Cut1Click(Sender: TObject); var ARect: TRect; begin Copy1Click(Sender); with Image.Canvas do begin CopyMode := cmWhiteness; ARect := Rect(0, 0, Image.Width, ImageHeight); CopyRect(ARect,
Image.Canvas, ARect); CopyMode := cmSrcCopy; end; end; { a Clipboard-ra másolás } { minden fehér } { a bitmap területe } { sajátmagára másolja a bitmap-et } { az eredeti mód visszaállítása } Grafika beillesztése Ha a Windows vágólap bitmap grafikát tartalmaz, akkor beilleszthetjük azt bármely image objektumba. Elsőként hívjuk meg a Clipboard HasFormat metódusát, annak leellenőrzésére, hogy grafika van-e a vágólapon. A HasFormat Boolean értékű függvény és True-val tér vissza, ha a vágólap tartalma olyan formátumú, mint amit a paraméterben átadtunk a függvénynek. Ezután egyszerűen hozzárendelhetjük a vágólap tartalmát a bitmap-hez • A Clipboard tartalmát az Edit|Paste menün való kattintás hatására fogjuk beilleszteni: procedure TForm1.PasteButtonClick(Sender: TObject); var Bitmap: TBitmap; begin if Clipboard.HasFormat(CF BITMAP) then begin Bitmap := TBitmap.Create; try Bitmap.Assign(Clipboard); Image.CanvasDraw(0, 0, Bitmap);
finally Bitmap.Free; end; end; end; 19 { bitmap van-e a clipboard-on ) { a bitmap tárolásához .}