Fő tartalom
Programozás
A Button objektumtípus
Az objektum-orientált programozás használata az egyik legjobb módszer arra, ha szeretnénk újra-felhasználható, és hatékony kódot írni – főleg ha felhasználói felületet szeretnénk vezérelni, például gombokkal. Az objektum-orientált programozás használata során a programunk világában absztrakt objektumokat képzelünk el, melyek adott módon viselkednek, és ezen objektumok egy-egy konkrét példányát készítjük el egyéni paraméterekkel. Ha nem emlékszel, hogyan kell ezt csinálni JavaScriptben, itt át tudod ismételni.
Ahhoz, hogy OOP-t használj gombok létrehozásához, a
Button
objektumtípust kell definiálnunk, valamint ennek metódusait is, például a megrajzolását, illetve azt is, hogyan kezelje az egérkattintást. Szeretnénk egy ehhez hasonló kódot készíteni:var btn1 = new Button(...);
btn1.draw();
mouseClicked = function() {
if (btn1.isMouseInside()) {
println("Whoah, you clicked me!");
}
}
Hasonlítsuk ezt össze azzal a kóddal, amit az előző tananyagban írtunk:
var btn1 = {...};
drawButton(btn1);
mouseClicked = function() {
if (isMouseInside(btn1)) {
println("Whoah, you clicked me!");
}
}
Egészen hasonló, ugye? Egy nagy különbség van – minden függvény a
Button
objektumtípusra definiált, így tulajdonképpen a gombhoz tartoznak. Szorosabb kapcsolat van a tulajdonságok és a viselkedés között, így letisztultabb és máshol is könnyen újból használható kódot kapunk.A
Button
objektumtípus definiálásához a konstruktorral kell kezdenünk: ez egy olyan speciális függvény, mely konfigurációs paramétereket fogad, és beállítja az objektum egy példányának a kezdeti tulajdonságait.Első próbálkozásként íme egy konstruktor x, y, width (szélesség) és height (magasság) paraméterekkel:
var Button = function(x, y, width, height) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
};
var btn1 = new Button(100, 100, 150, 150);
Ez minden bizonnyal működik, de van egy másik megközelítés, amit szeretnék a figyelmedbe ajánlani. Ahelyett, hogy egyesével adnád meg a paramétereket, a konstruktor kaphat egy konfigurációs objektumot.
var Button = function(config) {
this.x = config.x;
this.y = config.y;
this.width = config.width;
this.height = config.height;
this.label = config.label;
};
A konfigurációs objektum előnye, hogy további paramétereket kezelhet a konstruktor (például lehet egy
label
, magyarul címke), és továbbra is könnyen érthető lesz, hogy melyik paraméter mire való, amikor a gombot elkészítjük:var btn1 = new Button({
x: 100, y: 100,
width: 150, height: 50,
label: "Please click!"});
De még ennél is tovább mehetünk! Mi lenne, ha minden gomb ugyanolyan széles és magas lenne? Csak akkor kellene megadnunk a szélességet és a magasságot, ha ettől eltérnénk. Lehet egy konstruktorunk, ami megvizsgálja, hogy a konfigurációs objektumban egyáltalán egy adott tulajdonság definiálva van-e, és beállíthat neki egy alapértelmezett értéket abban az esetben, ha nincs definiálva. Például így:
var Button = function(config) {
this.x = config.x || 0;
this.y = config.y || 0;
this.width = config.width || 150;
this.height = config.height || 50;
this.label = config.label || "Click";
};
Most már meghívhatjuk akár a tulajdonságok egy részhalmazával is, mert a többi tulajdonság értéke alapértelmezettre lesz állítva.
var btn1 = new Button({x: 100, y: 100, label: "Please click!"});
Ennyi munka egy konstruktorért? Hidd el nekem, megéri!
Most, hogy kellően kikerekítettük (vagy kigomboltuk?) a konstruktorunkat, definiáljuk a viselkedését: a
draw
metódust.Ugyanazt a kódot fogjuk használni, mint a drawButton
függvénynél, ám most a tulajdonságait a this
-től szerzi majd meg, hiszen magán az objektum prototípuson definiáljuk:Button.prototype.draw = function() {
fill(0, 234, 255);
rect(this.x, this.y, this.width, this.height, 5);
fill(0, 0, 0);
textSize(19);
textAlign(LEFT, TOP);
text(this.label, this.x+10, this.y+this.height/4);
};
Most, hogy már definiált, így hívhatjuk meg:
btn1.draw();
Íme egy program, ami a
Button
objektumot használva két gombot hoz létre – figyeld meg milyen egyszerű több gombot elkészíteni és kirajzolni:Viszont eddig átugrottuk a nehéz részt: a kattintások kezelését. Kezdhetjük azzal, hogy definiálunk egy függvényt a
Button
prototípuson, ami igaz értékkel tér vissza, ha a felhasználó az adott gomb befoglaló téglalapján belül kattint. Erre ismét egy korábbi függvényünket fogjuk használni, csak most a this
tulajdonságaival, egy átadott objektum helyett:Button.prototype.isMouseInside = function() {
return mouseX > this.x &&
mouseX < (this.x + this.width) &&
mouseY > this.y &&
mouseY < (this.y + this.height);
};
Már használhatjuk is ezt a
mouseClicked
függvényen belül:mouseClicked = function() {
if (btn1.isMouseInside()) {
println("You made the right choice!");
} else if (btn2.isMouseInside()) {
println("Yay, you picked me!");
}
};
Próbáld ki az alábbit, kattintgasd végig a gombokat:
Van itt azonban valami, ami nagyon bosszant azzal kapcsolatban, ahogyan a kattintások kezelését megoldottuk. Az objektum-orientált programozás lényege, hogy az objektum viselkedésével kapcsolatos dolgokat az objektumon belül kezeljük le, és a tulajdonságaik segítségével szabjuk testre a viselkedésüket. Viszont kilóg az, hogy a
mouseClicked
-en belül van egy println
, amit az objektumon kívül helyeztünk el, pedig annak a viselkedésével kapcsolatos:mouseClicked = function() {
if (btn1.isMouseInside()) {
println("You made the right choice!");
} else if (btn2.isMouseInside()) {
println("Yay, you picked me!");
}
};
A print utasításoknak inkább valahogyan a gombokhoz kellene kapcsolódniuk, a konstruktornak adva át ezeket. A mostani megoldást nézve, átadhatunk egy üzenetet a konstruktor konfigurációjában, és definiálhatunk egy
handleMouseClicked
függvényt, ami kiírja ezt:var Button = function(config) {
...
this.message = config.message || "Clicked!";
};
Button.prototype.handleMouseClick = function() {
if (this.isMouseInside()) {
println(this.message);
}
};
var btn1 = new Button({
x: 100,
y: 100,
label: "Please click!",
message: "You made the right choice!"
});
mouseClicked = function() {
btn1.handleMouseClick();
};
Ez már sokkal szebb, és mindent, ami a gomb egyedi viselkedésével kapcsolatos, a konstruktorban helyeztünk el. Viszont túlságosan egyszerű is. Mi lenne, ha szeretnénk egy üzenet kiírásán kívül mást is csinálni, például rajzolni pár alakzatot, vagy képernyőt váltani, amihez kellene még pár sornyi kód? Ebben az esetben nem csak egy sztringet szeretnénk átadni a konstruktornak – egy egész kód-csokrot szeretnénk adni neki! Hogyan is tudnánk kódot átadni?
... Hát egy függvénnyel! JavaScriptben átadhatunk függvényeket függvények paramétereként (ez nincs így minden nyelvben). Sok esetben ez nagyon hasznos, különösen akkor, ha egy felhasználói felületen egy vezérlőelemnek, például egy gombnak a viselkedését szeretnénk befolyásolni. Mondhatjuk a gombnak, hogy „hé, itt egy függvény valamennyi kóddal, és azt szeretnénk, ha meghívnád, amikor a felhasználó a gombra kattint.” Ezekre a függvényekre „callback” (magyarul visszahívó) függvényekként hivatkozunk, mert nem kerülnek azonnal meghívásra, hanem „vissza lesznek hívva” később, egy megfelelő időpontban.
Kezdhetjük azzal, hogy átadjuk az
onClick
paramétert, ami függvény:var btn1 = new Button({
x: 100,
y: 100,
label: "Please click!",
onClick: function() {
text("You made the right choice!", 100, 300);
}
});
Ezután meg kell mondanunk a konstruktornak, hogy állítsa be az
onClick
tulajdonságot annak megfelelően, amit átadtunk. Alapértelmezett esetben, ha nem adunk át onClick
-et, akkor készítünk egy ún. „no-op” – egy „nem csinál semmit” – függvényt. Ez csak azért van itt, hogy meghívjuk, és ne fussunk bele hibába:var Button = function(config) {
// ...
this.onClick = config.onClick || function() {};
};
Végül pedig vissza kell hívnunk a callback függvényt, amikor a felhasználó a gombra kattint. Ez igazából egész egyszerű – úgy hívjuk meg, hogy leírjuk a tulajdonság nevét üres zárójelekkel:
Button.prototype.handleMouseClick = function() {
if (this.isMouseInside()) {
this.onClick();
}
};
És kész is vagyunk – van egy
Button
objektumunk, amiből könnyen létrehozhatunk új gombokat, és minden gomb különbözőképpen nézhet ki, és különböző módon reagálhat a kattintás eseményre. Kattintgasd végig az alábbi példákat, és próbáld ki, mi történik, ha megváltoztatod a gombok paramétereit:Most, hogy már van egy sablonod, könnyen testre szabhatod a gombjaidat más módokon is, például különböző színekkel, vagy más eseményekre is reagálhatsz, például arra, ha az egeret a gomb fölé húzza a felhasználó. Próbáld ki a saját programjaidban!
Szeretnél részt venni a beszélgetésben?
Még nincs hozzászólás.