VisualC2008_24_04.qxd
3/2/2009
10:18 AM
Page 81
4. ÓRA Események A lecke tartalmából: • • • • • • •
Az eseményvezérelt programozás Események kiváltása Az önhívó események elkerülése Az objektumok eseményeinek elérése Eseményparaméterek használata Eseménykezelõk létrehozása Az eseménynevek frissen tartása
A Visual C# beépített tervezõeszközeivel könnyû tetszetõs felületet készíteni egy alkalmazáshoz: gyönyörû ablakokat állíthatunk elõ, amelyeken gombok vannak, amelyekre kattinthatunk, szövegmezõk, amelyekbe információt írhatunk be, képmezõk, amelyek képeket jelenítenek meg, és még sok más kreatív és vonzó elemmel állhatunk elõ, amellyel a felhasználók kapcsolatba léphetnek. Egy Visual C#-program fejlesztésének azonban mindez csak a kezdete – a felület megtervezésén kívül fel kell vérteznünk azzal a képességgel is a programunkat, hogy mind a felhasználó, mind a Windows tevékenységére válaszolva mûveleteket tudjon végrehajtani. Ezt események segítségével érjük el.
VisualC2008_24_04.qxd
3/2/2009
10:18 AM
Page 82
82 I. rész • A Visual C# 2008 környezet
A 3. órán az objektumokról és azok tagjairól, a tulajdonságokról és a tagfüggvényekrõl tanultunk. Ezen az órán az objektumok eseményei és az eseményvezérelt programozás kerülnek terítékre, és megtanuljuk, hogyan tehetjük az események segítségével az alkalmazásainkat válaszképessé.
Az eseményvezérelt programozás A hagyományos programozási nyelveken (amelyekre gyakran eljárásközpontú nyelvekként hivatkoznak) írt programok maguk szabják meg, hogy melyik kódrész végrehajtására mikor kerül sor. Amikor elindítunk egy ilyen programot, elõször a program elsõ kódsora fut le, majd a kód végrehajtása teljes mértékben elõre meghatározott módon folytatódik. A kód ugyan idõnként ágakra válhat szét, vagy ciklusokat indíthat, de a végrehajtás menetét teljesen a program határozza meg. Ez gyakran azzal jár, hogy az ilyen program csak korlátozottan képes a felhasználó mûveleteire válaszolni, például elvárhatja, hogy a képernyõn megjelenõ vezérlõkbe adott sorrendben írjunk be szöveget. Ez szöges ellentétben áll a Windows-programok viselkedésével, amelyekben a felhasználó a felület különbözõ elemeivel léphet kapcsolatba – gyakran teljesen tetszõleges sorrendben. A Visual C# az eseményvezérelt programozási modellre épül. Az eseményvezérelt alkalmazásokat nem kötik gúzsba az eljárásközpontú programok korlátai, mert az eljárásközpontú nyelvek felülrõl lefelé haladó megközelítése helyett a kód logikailag összetartozó részeit eseményekben fogják össze. Az események bekövetkeztének nincs elõre megszabott sorrendje; az eseményvezérelt programokban a felhasználó adott események interaktív elindításával – például egy gombra kattintással – gyakran teljesen maga szabhatja meg, hogy melyik kódrész hajtódjon végre. Az eseményeket a hozzájuk tartozó kóddal együtt eseménykezelõknek vagy eseményeljárásoknak hívjuk.
Események kiváltása A 3. órán megtanultuk, hogy a tagfüggvények nem mások, mint az objektumok függvényei. Bizonyos értelemben az események is egyfajta különleges tagfüggvények, amelyekkel egy objektum az állapotváltozásait jelezheti az ügyfelek (az objektumot használó kódok) számára. A Visual C# 2008 leírása valójában igen gyakran tagfüggvényekként hivatkozik az eseményekre (ami a kezdõ programozókat kétségkívül összezavarhatja). Az események tehát olyan tagfüggvények, amelyeknek a meghívása különleges módon történik – általában egy mûveleten keresztül, amelyet a felhasználó egy ablakon végrehajt, vagy maga a Windows által –, nem pedig egy kódutasítással. Az eseményeknek számos típusa létezik, és az elindításuk (kiváltásuk) is sokféleképpen történhet. Már láttuk, hogyan válthatja ki a felhasználó egy gomb eseményét azzal, hogy a gombra kattint. Az események kiváltására azonban nem csak a felhasználói mûveletek alkalmasak; esemény az alábbi négy módon indítható el:
VisualC2008_24_04.qxd
3/2/2009
10:18 AM
Page 83
4. óra • Események 83
• A felhasználó valamilyen mûveletet hajt végre a programban. Ha egy gombra kattint, akkor például a gomb Click eseményét váltja ki. • Szükség szerint az objektumok is kiválthatják a saját eseményeiket. A Timer (Idõzítõ) vezérlõ például szabályos idõközönként elindíthatja a saját Timer eseményét. • Az operációs rendszer (a felhasználó által futtatott Windows-változattól függetlenül) szintén kiválthat eseményeket. • Meghívással a programozó is elindíthat eseményeket, ugyanúgy, ahogy egy Visual C# kódban egy tagfüggvényt hív meg.
Felhasználói mûveletek által kiváltott események Az eseményeket egy programban a leggyakrabban a felhasználói mûveletek váltják ki. Minden ablak és szinte minden vezérlõ, amelyet egy ablakra helyezhetünk, az objektum típusára jellemzõ eseményhalmazzal rendelkezik. A Button (Gomb) vezérlõnek például számos eseménye van, köztük a Click (Kattintás) esemény, amellyel a korábbi órákon már találkoztunk. Amikor a felhasználó egy gombra kattint, a gomb Click eseménye indul el, és végrehajtódik a Click eseményben található kód. A TextBox (Szövegmezõ) vezérlõ, amely lehetõvé teszi, hogy a felhasználó adatokat vigyen be a billentyûzet segítségével, szintén rendelkezik eseményekkel. A TextBox egyes eseménytípusai megegyeznek a Button vezérlõével, például ennek a vezérlõnek is van Click eseménye, de a TextBox-hoz olyan események is tartoznak, amelyeket a Button vezérlõ nem támogat; ilyen például a MultilineChanged esemény, amelyre akkor kerül sor, amikor a szövegmezõ Multiline (Többsoros) tulajdonsága megváltozik. Mivel a felhasználó nem írhat szöveget egy Button vezérlõbe, a gomboknak nincs Multiline tulajdonságuk, így MultilineChanged eseményük sem. Minden objektum, amely támogatja az eseményeket, egyedi eseményhalmazzal bír. Minden eseménytípusnak megvan a saját viselkedése, ezért lényeges, hogy értsük az eseményeket, amelyeket használunk. A TextChanged esemény viselkedését például a kezdõ fejlesztõk nem biztos, hogy magától értetõdõnek találják, mert ez az esemény minden alkalommal elindul, amikor a szövegmezõ tartalma megváltozik. Képzeljük el, mi történne, ha beírnánk a következõ szöveget egy általunk létrehozott projekt egy üres szövegmezõjébe: Ozric Tentacles!
Könnyen azt hihetnénk, hogy a TextChanged esemény csak akkor indul el, amikor véglegesítjük a beírtakat, például elhagyjuk a szövegmezõt, vagy lenyomjuk az ENTER-t, de ez az esemény nem így mûködik. Ehelyett tizenhatszor kerül sor a TextChanged esemény bekövetkezésére, miközben beírjuk a fenti szöveget, mivel a szövegmezõ minden alkalommal megváltozik, amikor beírunk egy új karaktert. Még egyszer hangsú-
4
VisualC2008_24_04.qxd
3/2/2009
10:18 AM
Page 84
84 I. rész • A Visual C# 2008 környezet
lyozzuk: fontos, hogy ismerjük az általunk használt események finomságait és pontos viselkedését, mert ha anélkül vesszük igénybe õket, hogy teljes mértékben tisztában lennénk a mûködésükkel, a programunk szokatlan (ez általában nemkívánatost jelent) eredményeket adhat. Azt, hogy miként válthatunk ki eseményeket (amelyek csupán egyfajta eljárások) Visual C# kód segítségével, a 10. órán tárgyaljuk részletesen.
Objektum által kiváltott események Néha elõfordul, hogy egy objektum maga indítja el a saját eseményeit. Ennek legközönségesebb példája a Timer vezérlõ Tick eseménye. A Timer a szokványos fájlmegnyitó párbeszédablakhoz hasonlóan nem látható vezérlõ, tehát nem jelenik meg egyetlen ablakon sem a program futása közben, csak tervezéskor látható a nem vizuális vezérlõk számára fenntartott helyen. A Timer vezérlõ egyetlen célja, hogy az Interval (Idõköz) tulajdonságában megadott idõközönként elindítsa a Tick eseményét. A Timer vezérlõ Interval tulajdonságának beállításával a Tick esemény elindulásának idõközét szabályozzuk (ezredmásodperces lépésekben). A Tick esemény kiváltása után a Timer vezérlõ visszaállítja önmagát, és amint a beállított idõköz ismét letelt, újra elindítja a Tick eseményt. Ezt mindaddig ismétli, amíg az idõközt meg nem változtatjuk, a Timer vezérlõt ki nem kapcsoljuk, vagy el nem távolítjuk azt az ablakot, amelyiken a Timer vezérlõt elhelyeztük. Az idõzítõket a leggyakrabban arra használjuk, hogy egy órát hozzunk létre egy ablakon. Az idõt megjeleníthetjük egy szövegcímkében, és szabályos idõközönként frissíthetjük, ha elhelyezzük az aktuális idõt megjelenítõ kódot a Timer eseményben. A 8. órán majd írunk is egy programot, amely a Timer vezérlõt használja.
Az operációs rendszer által kiváltott események Az események elindításának harmadik módja, hogy az eseményt maga a Windows váltja ki. Ezeknek az eseményeknek gyakran a létezésérõl sem tudunk. Amikor egy ablakot például részben vagy teljes egészében eltakar egy másik ablak, a programnak értesülnie kell róla, amikor a felül levõ ablakot átméretezik vagy áthelyezik, hogy újrarajzolhassa a rejtett ablak területét. A Windows és a Visual C# ennek érdekében együttmûködik: amikor az elfedõ ablakot áthelyezik vagy átméretezik, a Windows az ablak újrarajzolására utasítja a Visual C#-ot, amelyet az meg is tesz, ezen kívül pedig kiváltja az ablak Paint eseményét. A Paint eseményben elhelyezett kóddal egyéni megjelenítést is meghatározhatunk az ablak számára, például alakzatokat rajzolhatunk rá egy Graphics objektummal. Az egyéni rajzolókódunk így minden alkalommal végrehajtódik, amikor az ablak újrarajzolja önmagát.
VisualC2008_24_04.qxd
3/2/2009
10:18 AM
Page 85
4. óra • Események 85
Az önhívó események elkerülése Ügyelnünk kell rá, hogy soha ne írjunk olyan kódot, amelyben egy esemény vég nélkül meghívhatja önmagát. Az ilyen eseményeket önhívó (rekurzív) eseményeknek hívják. Szemléltetésképpen lássunk egy olyan helyzetet, ami önhívó eseményt okozhat! Gondoljunk a TextBox vezérlõ korábban ismertetett TextChanged eseményére: ez az esemény minden alkalommal bekövetkezik, amikor a szövegmezõben található szöveg megváltozik. Ha olyan kódot helyezünk el a TextChanged eseményben, amely megváltoztatja a szövegmezõ szövegét, az esemény ismét el fog indulni, ami végül végtelen ciklust eredményez. Az önhívó események csak akkor szakadnak meg, amikor a Windows StackOverflow kivételt ad vissza (lásd a 4.1. ábrát), ami azt jelzi, hogy a Windows már nem rendelkezik elég erõforrással ahhoz, hogy folytassa az önhívást.
4
4.1. ábra Ha StackOverflow kivételt kapunk, egy önhívó esemény lehet a bûnös
Önhívó viselkedést nem csak egy esemény okozhat egy ciklusban. Például ha egy „A” esemény elindít egy „B” eseményt, amely viszont ismét az „A” eseményt váltja ki, a két esemény együttesen eredményez végtelen ciklust. Önhívó viselkedést ezenkívül események láncolata is elõidézhet, nem csak egy vagy két esemény. Az önhívó eljárásoknak is lehet haszna, például amikor összetett matematikai függvényeket írunk. Önhívó eseményeket gyakran használnak például faktoriálisszámításra. Mindazonáltal ha szándékosan hozunk létre önhívó eseményt, gondoskodnunk kell róla, hogy az önhívás ne ismétlõdhessen vég nélkül.
VisualC2008_24_04.qxd
3/2/2009
10:18 AM
Page 86
86 I. rész • A Visual C# 2008 környezet
Az objektumok eseményeinek elérése Az objektumok eseményeinek elérése egyszerû, és ha követtük a könyv eddigi példáit, több objektumnak már használtuk is az alapértelmezett eseményét. Ha el szeretnénk érni egy objektum eseményeit, kattintsunk duplán az objektumra az ablaktervezõ nézetben. Most egy olyan projektet fogunk megalkotni, amely segít, hogy ráérezzünk az események mûködésére. Indítsuk el a Visual C# 2008-at, hozzunk létre egy új Windows Application projektet View Events néven, majd kövessük az alábbi lépéseket: 1. Kattintsunk az egér jobb gombjával a Form1.cs fájlnévre a Solution Explorerben,
válasszuk a Rename (Átnevezés) parancsot, és módosítsuk az ablak nevét ViewEventsForm.cs-re. Ha a program rákérdez, hogy szeretnénk-e frissíteni
az összes hivatkozást a kódban, ezúttal is feleljünk igennel (Yes). 2. Kattintsunk egyszer az ablakra, hogy megjelenítsük a tulajdonságait, majd változtassuk a Text tulajdonság értékét View Events Example-re. 3. Az eszközkészlet segítségével adjunk egy képmezõt az ablakhoz, és változtassuk a nevét picTest-re.
Már tudjuk, hogy egy vezérlõ alapértelmezett eseményéhez úgy férhetünk hozzá, ha duplán kattintunk a vezérlõre az ablaktervezõben. A vezérlõk azonban gyakran események tucatjaival rendelkeznek. Az események listáját a Properties ablak Events (Események) gombjára kattintva érhetjük el. (Az Events gomb az, amelyiken egy villám rajza látható.) 4. Kattintsunk most az Events gombra a Properties ablakban, hogy megtekintsük a PictureBox vezérlõ által támogatott események listáját (lásd a 4.2. ábrát).
4.2. ábra Az egyes vezérlõk által támogatott eseményeket a Properties ablakban érhetjük el
VisualC2008_24_04.qxd
3/2/2009
10:18 AM
Page 87
4. óra • Események 87
5. Görgessünk lefelé a listában a MouseDown eseményig, és kattintsunk rá duplán.
Ezzel megnyitjuk a kódszerkesztõt, amely készen áll rá, hogy beírjuk a MouseDown esemény kódját (lásd a 4.3. ábrát).
4 4.3. ábra Amikor elõször jelöljük ki egy objektum valamelyik eseményét, a Visual C# egy üres eseményeljárást hoz létre
Jelenleg a picTest objektum MouseDown eseményét látjuk. A kurzor a MouseDown eseményeljárás belsejében tartózkodik, várva, hogy beírjuk a kívánt kódot. A kurzor felett látható kód az eseményt bevezetõ utasítás, más néven eseménydeklaráció. Az eseménydeklaráció olyan utasítás, amely az adott esemény szerkezetét határozza meg. Figyeljük meg, hogy az eseménydeklaráció az objektum nevébõl, egy aláhúzásjelbõl (_) és az esemény nevébõl áll, az esemény nevét pedig egy zárójelpár követi. A zárójelek között álló elemek az eseményparaméterek, amelyekrõl hamarosan szót ejtünk. Az eseményeljárások bevezetésének ez a szabványos szerkezete. Amikor duplán kattintunk egy eseményre az Events listában, a Visual C# egy új eseményeljárást hoz létre az adott esemény számára. A teljes eseménydeklaráció és az esemény szerkezete így fest: private void picTest_MouseDown(object sender, MouseEventArgs e) { }
A kapcsos zárójelek az eljárás kezdetét és végét jelölik; az eljárás teljes kódjának e két kapcsos zárójel között kell állnia. Ügyeljünk rá, hogy ne töröljük sem a nyitó, sem a záró zárójelet!
VisualC2008_24_04.qxd
3/2/2009
10:18 AM
Page 88
88 I. rész • A Visual C# 2008 környezet
Eseményparaméterek használata Ahogy korábban említettük, az eseménydeklarációk zárójelein belül álló elemeket eseményparamétereknek hívjuk. Az eseményparaméterek olyan változók, amelyeket a Visual C# hoz létre, és amelyekhez szintén a Visual C# rendel értéket. Ezeket a változókat az eseményre vonatkozó lényeges adatok kiolvasására és idõnként beállítására használjuk. Az adat lehet szöveg, szám, objektum – szinte bármi. Ha egy eseményeljárásnak több paramétere is van, azokat mindig vesszõk választják el egymástól. Amint fentebb láthattuk, a MouseDown (Egérgomb lenyomása) esemény két paraméterrel rendelkezik. Amikor az eseményeljárást elindítják, a Visual C# önmûködõen létrehozza az eseményparamétereket, és az eljárás adott végrehajtásának idejére értéket rendel hozzájuk. Amikor az eseményeljárás legközelebb lefut, a paraméterek értéke módosul. A paraméterek értékeit arra használjuk, hogy a kódunkban döntéseket hozzunk vagy mûveleteket hajtsunk végre. Az ablakok MouseDown eseményének a paraméterei tehát a következõk: object sender
és MouseEventArgs e
A paraméterek elsõ eleme a paraméterben tárolt adat típusát jelzi, míg a második az adatot tároló változó nevét. A MouseDown elsõ paramétere, a Sender (Küldõ), egy általános objektumot tartalmaz. Az objektumparaméterek bármilyen típusú objektumok lehetnek, amelyeket a Visual C# támogat. Még nem muszáj ismernünk az adattípusokat; elég annyival tisztában lennünk, hogy a különbözõ paraméterváltozók különbözõ típusú információkat hordozhatnak. Egyesekben szöveget, másokban számokat találunk, megint mások pedig (igen gyakran) egy objektumot tárolnak. A Sender paraméter mindig egy hivatkozást tartalmaz, amely arra a vezérlõre mutat, amelyik kiváltotta az eseményt. A MouseDown esemény e paramétere ezzel szemben az a hely, ahol a tényleges mûvelet végbemegy. Az e paraméter szintén egy objektumot tárol, de ennek az objektumnak a típusa MouseEventArgs, és olyan tulajdonságai vannak, amelyek a MouseDown eseményhez kapcsolódnak. Ha látni szeretnénk ezeket a tulajdonságokat, írjuk be a következõ kódot, de a pont karakter beírása után ne nyomjunk le semmilyen billentyût: e.
Amint beírjuk a pontot, egy lenyíló lista jelenik meg, amely az e objektum tagjait (tulajdonságait és tagfüggvényeit) mutatja (lásd a 4.4. ábrát). Az e objektum segítségével számos dolgot megállapíthatunk a MouseDown esemény bekövetkezésének körülményeirõl. Az érdekesebb információkat a 4.1. táblázat sorolja fel.
VisualC2008_24_04.qxd
3/2/2009
10:18 AM
Page 89
4. óra • Események 89
4.1. táblázat A MouseEventArgs szokványos tagjai Tulajdonság Leírás Clicks Azt adja vissza, hogy a felhasználó hányszor kattintott az egér gombjával. Button Azt adja vissza, hogy melyik egérgombot nyomták le (left, middle és right, vagyis bal, középsõ vagy jobb). X Azt a vízszintes koordinátát adja vissza, ahol az egérmutató tartózkodott, amikor a felhasználó kattintott. Y Azt a függõleges koordinátát adja vissza, ahol az egérmutató tartózkodott, amikor a felhasználó kattintott. Minden alkalommal, amikor egy esemény bekövetkezik, a Visual C# olyan értéket ad a paramétereknek, amelyek mindig az esemény adott bekövetkezésének körülményeit tükrözik.
4.4. ábra Az IntelliSense lenyíló listái szükségtelenné teszik, hogy objektumok százait jegyezzük meg
Minden eseményhez sajátos paraméterek tartoznak. A TextChanged esemény például más paramétereket ad vissza, mint a MouseDown. Eseményekkel nagyon gyakran fogunk dolgozni, úgyhogy gyorsan megtanuljuk majd az egyes eseménytípusok paramétereit. Azt, hogy a saját függvényeinkhez és eljárásainkhoz hogyan hozhatunk létre paramétereket, a 10. órán tanuljuk.
4
VisualC2008_24_04.qxd
3/2/2009
10:18 AM
Page 90
90 I. rész • A Visual C# 2008 környezet
Eseménykezelõ törlése Egy eseménykezelõ törlése nem csak annyiból áll, hogy töröljük az eseményeljárást. Amikor új eseménykezelõt adunk egy osztályhoz, a Visual C# automatikusan létrehozza számunkra az eseményeljárást, és a kurzort annak belsejébe helyezi, hogy beírhassuk a kívánt kódot. A Visual C# ugyanakkor a „színfalak mögött” ennél kicsit többet is tesz, mert az eseményeljárást a vezérlõhöz kell kapcsolnia. Ezt úgy éri el, hogy az osztály rejtett kódjában elhelyez egy kódutasítást. Ezzel az utasítással általában nem kell törõdnünk, de amikor törlünk egy eseményeljárást, a Visual C# a rejtett kódot nem törli automatikusan, ezért a fordítás meghiúsul. A hibát úgy küszöbölhetjük ki a legegyszerûbben, hogy futtatjuk a projektet, és amikor a Visual C# szembetalálkozik a hibával, megmutatja a problémát okozó utasítást, amelyet így már törölhetünk. Próbáljuk is ki most: 1. Töröljük az alább látható teljes MouseDown eljáráskódot (ehhez a kapcsos záróje-
leken belül álló kód mellett magukat a kapcsos zárójeleket is törölnünk kell): private void picTest_MouseDown(object sender, MouseEventArgs e) { e. }
2. Futtassuk a projektet az F5 billentyû lenyomásával. Egy üzenet fogunk kapni,
miszerint fordítási hiba lépett fel. Kattintsunk a No (Nem) gombra, hogy visszatérjünk a kódszerkesztõhöz.
4.5. ábra A Visual C# az Error List ablakban megmutatja a fordítási (a kódunkban található) hibákat
VisualC2008_24_04.qxd
3/2/2009
10:18 AM
Page 91
4. óra • Események 91
3. Megjelenik az Error List (Hibalista) ablak, amely részletezi az imént bekövetkezett
hibát (lásd a 4.5. ábrát). Kattintsunk duplán a hibára, és a Visual C# a problémát okozó utasításra ugrik, amely így fest (terjedelmi okok miatt két sorra tördelve): this.picTest.MouseDown += new System.Windows.Forms.MouseEventHandler(this.picTest_MouseDown);
4. Vegyük észre, hogy az eljárások bal felsõ sarokban található lenyíló listája az InitializeComponent() elemet mutatja. Ez az ablak egyik eseménye (amint
láthatjuk, baloldalt, az objektumok lenyíló listájának mezõjében az ablak neve áll). Ne változtassunk meg semmit ebben az eljárásban, hacsak nem tudjuk pontosan, mit csinálunk! Mi most egy hivatkozást szeretnénk törölni, amely egy már nem létezõ eseményeljárásra mutat, ezért töröljük a teljes utasítást. A kódunkat most már le lehet fordítani és futtatni. Amikor törlünk egy eseményeljárást, mindig törölnünk kell az eljárást az objektumához kapcsoló utasítást, mielõtt futtathatnánk a kódot. Most, hogy már tudjuk, hogyan kell törölni egy eseménykezelõt, lássuk a leggyorsabb és legkönnyebb módszert: tekintsük meg az objektumot tervezõnézetben, és kattintsunk a Properties ablak Events gombjára, hogy lássuk az objektum eseményeit. Ezt követõen jelöljük ki az esemény nevét a Properties ablakban, és nyomjuk le a DELETE billentyût. Ez meghagyja az esemény kódját az osztályban, amíg nem töröljük, de használaton kívül helyezi.
Egy eseményeket használó példaprojekt felépítése Most a MouseMove (Egérmozgatás) esemény használatát fogjuk megtanulni a Picture Viewer projektünk 3. órabeli állapotának módosításán keresztül. El fogjuk érni, hogy amikor a felhasználó a kép felett mozgatja az egeret, a mutató X és Y koordinátái megjelenjenek az ablakon. Az egérmutató helyzetét az e paraméter segítségével fogjuk kiolvasni.
A felhasználói felület elkészítése Kiindulópontként használjuk a Picture Viewer projektet abban a formában, amelyben a 3. óra végén hagytuk. Ha nem készítettük el a projektet, a szerzõ webhelyérõl is letölthetjük. Az ablakon két szövegcímkére lesz szükségünk: egyre az X, egyre pedig az Y koordinátához. A szövegcímkék (Label vezérlõ) statikus szöveg megjelenítésére valók, tehát a felhasználók nem írhatnak beléjük szöveget. Kövessük az alábbi lépéseket:
4
VisualC2008_24_04.qxd
3/2/2009
10:18 AM
Page 92
92 I. rész • A Visual C# 2008 környezet
1. Kattintsunk duplán a ViewerForm.cs elemre a Solution Explorerben, hogy
megnyissuk az ablakot a tervezõnézetben. 2. Adjunk egy Label vezérlõt az ablakhoz, duplán kattintva a Label eszközre
az eszközkészletben, és állítsuk be a tulajdonságait a következõk szerint: Tulajdonság
Érték
Name Location Text
lblX 300, 110 X:
3. Az eszközkészlet segítségével adjunk még egy szövegcímkét az ablakhoz. Ennek
tulajdonságértékei legyenek a következõk: Tulajdonság
Érték
Name Location Text
lblY 300, 125 Y:
Az ablakunknak most úgy kell kinéznie, mint a 4.6. ábrán. Célszerû gyakran menteni a munkánkat, ezért most mentsük is a projektet az eszköztár Save All (Mindent ment) gombjára kattintva.
4.6. ábra A Label vezérlõkben statikus szöveget jeleníthetünk meg a felhasználók számára
Eseménykezelõk létrehozása Példaprogramunk felülete ezzel készen is van – most jön az izgalmas rész. Létrehozzuk azokat az eseményeljárásokat, amelyek lehetõvé teszik a programnak, hogy csináljon is valamit. Az elsõ esemény, amellyel kezdenünk kell valamit, a MouseMove. A kód elkészítéséhez kövessük a következõ lépéseket:
VisualC2008_24_04.qxd
3/2/2009
10:18 AM
Page 93
4. óra • Események 93
1. Kattintsunk az ablakra helyezett képmezõre, hogy kijelöljük, majd kattintsunk
a Properties ablak Events gombjára (arra, amelyiken egy villám látható), hogy lássuk a képmezõ által támogatott események listáját. 2. Görgessünk lefelé a listában, amíg meg nem találjuk a MouseMove eseményt, és kattintsunk rá duplán, hogy létrehozzunk egy új MouseMove eseménykezelõt (lásd a 4.7. ábrát). 3. Írjuk be az alábbi kódot a MouseMove eseményeljárásba: lblX.Text = "X: " + e.X.ToString(); lblY.Text = "Y: " + e.Y.ToString();
4
4.7. ábra Minden alkalommal, amikor kijelölünk egy új eseményt, a Visual C# egy üres eseményeljárást hoz létre, amennyiben korábban nem hoztunk létre egyet a vezérlõ számára
Ez a kód meglehetõsen egyszerû, és lehet, hogy már értjük is. Ha még mindig nem lenne világos, hamarosan az lesz. Vegyük az elsõ sort (vagyis az elsõ utasítást): az lblX.Text az egyenlõségjel bal oldalán áll, tehát a Text a szövegcímke egy tulajdonsága, amelynek valamilyen értéket adunk. Az "X: " szöveg egy literális érték, amelyet a Label vezérlõ Text tulajdonságába helyezünk. Erre azért van szükség, mert amikor beállítjuk a Text tulajdonságot, teljesen felülírjuk annak jelenlegi értékét. A Properties ablakban az X: értéket adtuk a tulajdonságnak, ezért a tulajdonság beállításakor ezt is meg kell adnunk. A beállításnak persze csak akkor vesszük hasznát, ha az X pillanatnyi értékét is kiírjuk, amelyet az e objektum X tulajdonsága tartalmaz. Az "X: " literális értéket összefûzzük az e.X-ben tárolt értékkel; a két karakterlánc összefûzésére a + jel szolgál. Figyeljük meg az X tulajdonság ToString() tagfüggvényének használatát: erre azért van szükség, mert a Visual C# csak szöveget (karakterláncot) tud összefûzni, az X és az Y tulajdonság azonban számokat tárol. A ToString() függvény a számok karakterlánccá alakítására szolgál.
VisualC2008_24_04.qxd
3/2/2009
10:18 AM
Page 94
94 I. rész • A Visual C# 2008 környezet
A második utasítás ugyanezt végzi el, csak éppen az Y értékkel. Az objektumokban az a szép, hogy nem kell velük kapcsolatban minden részletet megjegyeznünk. Nem kell például memorizálnunk minden gombtípus visszatérési értékeit. (Egyébként is, ki akarna emlékezni olyasmikre, hogy e.X, e.Y vagy e.Button?) Csak annyit kell tudnunk, hogy az eseménnyel kapcsolatos információkat az e paraméter hordozza. Ha beírjuk az e betût, majd egy pontot, megjelenik az IntelliSense lenyíló listája, és megmutatja az e tagjait. Ne ijedjünk meg a könyv során felbukkanó objektumhivatkozásoktól! Fogadjuk el, hogy lehetetlen valamennyit megjegyezni, és nincs is rá szükség. A fontosakat meg fogjuk tanulni, ha pedig elakadnánk, a Súgóhoz is fordulhatunk. Ezenkívül ha egy adott esetben ismerjük a szülõobjektumot (a példánkban ez az e), könnyen meghatározhatjuk a hozzá tartozó objektumokat és tagokat az IntelliSense lenyíló listáinak segítségével. Kattintsunk most az eszköztár Save All gombjára a munkánk mentéséhez (nyilván nem szeretnénk elveszíteni), majd az F5 billentyû lenyomásával futtassuk a projektet, és mozgassuk az egeret a képmezõ felett. Láthatjuk, hogy az általunk létrehozott két szövegcímkében megjelennek az egérmutató koordinátái (a képmezõhöz viszonyítva; lásd a 4.8. ábrát).
4.8. ábra A MouseMove esemény segítségével könnyen nyomon követhetjük a mutató mozgását a vezérlõk felett
Most mozgassuk az egérmutatót a képmezõ területén kívülre. Figyeljük meg, hogy a címkék azt az utolsó koordinátát mutatják, amelyen a mutató a képmezõ felett tartózkodott, a MouseMove esemény ugyanis csak akkor indul el, ha az egeret az eseményhez kapcsolt vezérlõ (esetünkben tehát a képmezõ) felett mozgatjuk. Az immár értelmetlen számokat viszont nem hagyhatjuk ott, nem igaz?
VisualC2008_24_04.qxd
3/2/2009
10:18 AM
Page 95
4. óra • Események 95
A PictureBox-nak történetesen van egy másik eseménye, amellyel kiküszöbölhetjük ezt a problémát: a MouseLeave. Különös módon MouseLeave eseményre akkor kerül sor, ha az egérmutató elhagyja egy vezérlõ területét (végül is, ki lehetett találni). Ahhoz, hogy töröljük a koordinátákat, amikor a mutató elhagyja a képmezõt, kövessük az alábbi lépéseket: 1. Állítsuk le a projektet, ha még mindig futna, a Picture Viewer ablak bezárásával. 2. Kattintsunk a ViewerForm.cs[Design] fülre, hogy visszatérjünk az ablaktervezõhöz. 3. Kattintsunk a képmezõre (ha még nem lenne kijelölve), hogy megtekintsük az eseményeit. Keressük meg a MouseMove eseményt az események listájában, és
kattintsunk rá duplán, hogy létrehozzunk egy új eseményeljárást. 4. Írjuk be az alábbi kódot a MouseLeave eseménybe: lblX.Text = " "; lblY.Text = " ";
Futtassuk újra a projektet az F5 billentyû lenyomásával, és vigyük az egérmutatót a képmezõ fölé, majd húzzuk el onnan – megfigyelhetjük, hogy a koordináták eltûnnek. Mozgassuk újra a mutatót a képmezõ fölé, és ismét megjelennek – tökéletes! Ha kigyönyörködtük magunkat, állítsuk le a futó projektet. Már csak egy tennivalónk maradt. Észrevettük, hogy amikor elindítjuk a programot, a címkékben az X: és Y: szöveg látható? Nem lenne jobb, ha ezek sem jelennének meg addig, amíg a felhasználó a képmezõ fölé nem viszi az egeret? Megtehetnénk, hogy a szövegcímkék Text tulajdonságait üresen hagyjuk a Properties ablakban, de ha így teszünk, a tervezõben nem fogjuk látni a címkéket az ablakon, és véletlenül eltakarhatjuk õket más vezérlõkkel. Jobb megoldás, ha akkor adunk nekik kezdõértéket, amikor az ablak betöltõdik. Ezt a következõ mûveletek elvégzésével érhetjük el: 1. Kattintsunk ismét a ViewerForm.cs[Design] fülre, hogy visszatérjünk az ablakter-
vezõhöz. 2. Kattintsunk az ablakra, hogy kijelöljük és megtekinthessük az eseményeit. 3. Az ablak eseménylistájában keressük meg a Load (Betöltés) eseményt, és kattintsunk rá duplán egy új eseménykezelõ létrehozásához. A Load esemény automatikusan bekövetkezik, amikor az ablak betöltõdik, ami tökéletes alkalom a Label vezérlõk elõkészítéséhez. 4. Írjuk be az alábbi két kódutasítást: lblX.Text = " "; lblY.Text = " ";
Ennyi az egész. Az F5 billentyû lenyomásával futtassuk a projektet, és próbáljuk ki a program mûködését. Amikor a program ablaka betöltõdik, a koordinátacímkéknek üresnek kell lenniük (vagyis láthatatlanok lesznek), de amikor az egeret a képmezõ fölé visszük, megjelennek, ha pedig elhagyjuk a képmezõ területét, ismét eltûnnek. Ugye hogy mennyi mindent el lehet érni egy kis kóddal és a megfelelõ eseményekkel?
4
VisualC2008_24_04.qxd
3/2/2009
10:18 AM
Page 96
96 I. rész • A Visual C# 2008 környezet
Összefoglalás Ezen az órán az eseményvezérelt programozásról tanultunk: megtudtuk, mik azok az események, hogyan lehet elindítani õket, és hogyan kerülhetjük el az önhívó eseményeket. Ezenkívül láttuk, hogyan érhetjük el egy objektum eseményeit, és hogyan használhatjuk az eseményparamétereket. Programjaink kódjának nagy része valamilyen esemény hatására fog lefutni, és gyakran elõfordul majd az is, hogy egy vezérlõ több eseményéhez is kódot kell írnunk. Ha megértettük, hogyan mûködnek az események, és tisztában vagyunk vele, hogy milyen események és eseményparaméterek állnak a rendelkezésünkre, képesek leszünk olyan összetett Visual C#-programokat írni, amelyek számos felhasználói és rendszermûveletre válaszolni tudnak.
Kérdezz-felelek K: Lehet egyéni eseményeket létrehozni egy objektumhoz? V: Igen, létrehozhatunk egyéni eseményeket a saját objektumainkhoz (az egyéni
objektumokról a 16. órán tanulunk) és a meglevõ objektumokhoz is. Az egyéni események létrehozása azonban túlmutat könyvünk keretein. K: A felülettel nem rendelkezõ objektumok is támogathatnak eseményeket? V: Igen, de ha egy ilyen objektum eseményeit szeretnénk használni, az objektumváltozót különleges módon kell beállítanunk, különben az események nem lesznek hozzáférhetõk. A mûvelet nem egyszerû, ezért az ismertetése meghaladja ennek a könyvnek a kereteit.
Ismétlés Ez a rész az anyaggal kapcsolatos kérdések felvetésében, valamint a tanultak áttekintésében segít, és hozzájárul ahhoz, hogy az elméleti tudásunkat gyakorlatban is kamatoztathassuk.
Ismétlõ kérdések Nevezzünk meg három dolgot, ami eseményt válthat ki! Igaz vagy hamis? „Minden objektum ugyanazt az eseményhalmazt támogatja.” Mi a gombok alapértelmezett eseménytípusa? Hogy hívják azt, amikor egy eseményhez olyan kódot írunk, amely ugyanazt az eseményt váltja ki, és így láncreakciószerûen újra és újra elindítja az eseményt? 5. Mi a legegyszerûbb módja annak, hogy elérjük egy vezérlõ alapértelmezett eseménykezelõjét? 1. 2. 3. 4.
VisualC2008_24_04.qxd
3/2/2009
10:18 AM
Page 97
4. óra • Események 97
6. Minden vezérlõesemény egy hivatkozást ad át az eseményt kiváltó vezérlõnek.
Mi a neve annak a paraméternek, amelyik ezt a hivatkozást tartalmazza?
Válaszok 1. 2. 3. 4. 5. 6.
Felhasználói mûvelet, rendszerbemenet, egyéb kód. Hamis. A Click, vagyis a kattintás. Önhívás. Kattintsunk duplán a vezérlõre az ablaktervezõben. Sender, vagyis küldõ.
Gyakorlatok 1. Az eddig megszerzett tudásunkra alapozva hozzunk létre egy új projektet,
amelynek az ablaka tervezéskor szürke, de futtatáskor kék színnel jelenik meg. 2. Hozzunk létre egy projektet, amelyben egy ablak és egy szövegmezõ található. Írjunk olyan kódot a TextChanged eseményhez, amely önhívást eredményez,
ha a felhasználó szöveget ír be. (Tipp: fûzzünk egy karaktert a felhasználó által beírt karakterlánc végéhez egy az alábbihoz hasonló utasítással: txtMyTextBox.Text = txtMyTextBox.Text + "a";
A pluszjel arra utasítja a Visual C#-ot, hogy egy a betût fûzzön a szövegmezõ tartalmához. Figyeljük meg, hogy végül StackOverFlow hibaüzenetet kapunk – ami sohasem jó jel.)
4
VisualC2008_24_04.qxd
3/2/2009
10:18 AM
Page 98