Duplabufferelés
Dobjunk fel a formunkra egy rajzvásznat (vagy nevezzük canvasnak, ha úgy tetszik), rajzoljunk rá valamit, majd töröljük le. Tegyük ezt meg újra és újra, sokszor egymás után. Ha csak kicsit változik a kép, és ezt elég sűrűn teszi, akkor úgy tűnik, minhta mozognának az alakzatok a vásznon. Innen már csak egy ötlet és kitartás kérdése, s már is egy egyszerű kis játék büszke szerzői lehetünk.
Az örömünk mégsem teljes, mert a kép furcsán villódzik. Érthető is ez, mert ha csak a másodperc tört részére, de akkor is letöröljük a képernyőt és ezalatt csak a nagy fehérség látszik, aztán megint a kép, amit mutatni szeretnénk. Idegesítő jelenség, de szerencsére a megoldást tálcán nyújtják felénk csak el kell fogadni.
Felveszünk a háttérben egy másik vásznat, ami rejtett a felhasználó előtt. Erre rajzolgatunk, s majd ha kész, akkor kirajzoljuk a látható vászonra is.
Ez így mind szép és jó, de az implementáció tartogat néhány buktatót. Szóval akkor lássuk is. JAVAban természetesen.
Két megoldást is találtam. Az első, ami a “józan paraszti ész” csapásirányát követi és ezáltal a nyelvi lehetőségeket nem annyira használja ki. Létrehozunk egy rejtett vásznat (Image), meg egy Graphics objektumot, amivel tudunk rá rajozlni. A paint() metódusban rajzolgatunk kedvünkre, de ezt a rejtett vászonra tesszük. S majd a legvégén az egész képet egyszerre rajzoljuk ki a látható Canvasra. (Ne felejtsük el letörölni rajzolás előtt a vásznat!)
Példakód:
public class myCanvas extends Canvas {
Image bufferImage;
Graphics bufferGraphics;
public void paint(Graphics g){
// letöröljük a vásznat
bufferGraphics.clearRect(0, 0, getWidth(), getHeight());
// itt rajzolgatunk, amit akarunk,
// de ezt a rejtett vászonra tegyük pl:
bufferGraphics.setColor(Color.RED);
bufferGraphics.drawRoundRect(200, 200, 150, 100, 10, 15);
...
// kirajzoljuk a rejtett vásznat
g.drawImage(bufferImage, 0, 0, null);
}
public void update(Graphics g){
// ez alapból letörli a Canvast,
// ezután pedig meghívja a paint metódust
// a letörlést mi végezzük
// különben is ez okozza a villódzást,
// ezért most ezt mellőzük
paint(g);
}
// elvégzi a rejtett és a látható vászon összerendelését.
// ezt csak akkor tehetjük meg, ha már látható a Canvas!!!
public void setDubleBuffer() {
bufferImage = createImage(getWidth(), getHeight());
bufferGraphics = bufferImage.getGraphics();
}
}
A másik lehetőség jobban kihasználja, hogy már mások is gondoltak erre a megoldásra, ezért jobban integrált nyelvi elemeket is adtak a kezünkbe.
Ebben az esetben nem piszkálunk bele a paint() metóduba, hanem ehelyett a az update() metódust módosítjuk. A duplabuffer kialakítását pedig a Canvas osztály void createBufferStrategy(int bufferlayers) metódusával végezzük, amit a setDubleBuffer metódusunkhoz hasonlóan csak a Canvas megjelenítése után futtathatunk.
Példakód (Canvas osztály update metódusának overloadingja):
public void update(Graphics g) {
BufferStrategy b = getBufferStrategy();
Graphics graph = b.getDrawGraphics();
graph.clearRect(0, 0, getWidth(), getHeight());
paint(graph);
graph.dispose();
b.show();
}
A formunkon a következő képpen alakítható ki a duplabuffer:
// mindenképpen láthatónak kell lennie a Canvasnak!!!
form.setVisible(true);
mycanvas.createBufferStrategy(2);
Bármelyik megoldást is választjuk, az eredmény ugyanaz. A megjelenítés nem villódzik, kényelmes a szemnek, és csupa jóság.
Megszenvedtem a wordpress szövegszerkesztőjével, szóval tessék megbecsülni. Meg is ijedtem, hogy ha ilyen szenvedés itt kódot beilleszteni és olvashatóra formázni, akkor virágzó kapcsolatom a wordpress-szel hamar derékba törik…