package elte.java2_utikalauz5.gui;
/**
Képernyőn mászkáló kukacszerű egyszerű animáció a megjelenítő metódusok
használatának szemléltetésére.
A kukac másodpercenként egyet mozog véletlenszerű irányba, és egérkattintással
tetszőleges új helyről is indítható. Amennyiben a kukac feje (piros) nem tud új
helyre lépni, vagy nem látszana a képernyőn, akkor új helyről fog indulni.
@link.forrásfájl {@docRoot}/../data/gui/src PaintTeszt.java
@since Java 2 Útikalauz programozóknak 5.0
*/
public class PaintTeszt extends java.awt.event.MouseAdapter implements Runnable,
java.awt.event.HierarchyListener {
/** A kukacot felépítő négyzetek oldalmérete képpontokban */
private static final int MÉRET = 10;
/** A kukacot felépítő négyzetek maximális száma */
private static final int MAXPONT = 20;
/** A kukac lépései közti várakozási idő ezredmásodpercben */
private static final long LÉPÉS = 1000;
/** A megjelenítésre használt grafikus komponens */
private java.awt.Component vászon;
/**
Konstruktor a megjelenítésre használt grafikus komponens megadásával.
@param vászon A megjelenítésre használt grafikus komponens
*/
public PaintTeszt( java.awt.Component vászon ) {
this.vászon = vászon;
vászon.addMouseListener(this); //egérkattintás figyelése a komponensen
vászon.setBackground(java.awt.Color.YELLOW); //saját színek beállítása
vászon.setForeground(java.awt.Color.BLUE);//a jobb nyomonkövethetőségért
vászon.addHierarchyListener( this );//animálás vezérlése a láthatósággal
}
/** A kukac pontjai */
private java.util.LinkedList pontok =
new java.util.LinkedList();
/**
Új pont hozzáadása a kukachoz.
Valóban új pont hozzáadásakor kéri a szükséges területek újrarajzolását is.
@param pont A hozzáadandó új pont
@return igaz, ha a megadott pont még nem volt része a kukacnak
*/
private boolean újpont(java.awt.Point pont) {
synchronized( pontok ) {
if (pontok.contains(pont)) return false; //már tartalmazott pont
pontok.add(pont); //új pont felvétele és megjelenítésének kérése
vászon.repaint(pont.x*MÉRET, pont.y*MÉRET, MÉRET, MÉRET);
if (pontok.size()>1) {
pont = pontok.get(pontok.size()-2);//előző fejpont újraszínezése
vászon.repaint(pont.x*MÉRET, pont.y*MÉRET, MÉRET, MÉRET);
for (int index = pontok.size()-MAXPONT; --index>=0; ) {
pont = pontok.get(index);//túlnyúló pontok törlésének kérése
vászon.repaint(pont.x*MÉRET, pont.y*MÉRET, MÉRET, MÉRET);
}
}
}
return true; //új pont felvételének jelzése
}
/**
Egérgomb megnyomása.
@param egéresemény Az aktuálisan lenyomott gombot reprezentáló esemény
*/
@Override
public void mousePressed(java.awt.event.MouseEvent egéresemény) {
java.awt.Point pont = egéresemény.getPoint();
pont.x /= MÉRET; //egérkoordináták átalakítása kukacpontokká
if (pont.x>=vászon.getWidth()/MÉRET) return; //ha nem látszik teljesen
pont.y /= MÉRET; //akkor nem fogadjuk el
if (pont.y>=vászon.getHeight()/MÉRET) return;
újpont(pont); //kattintási hely felvétele új kukacpontként
};
/** Kukacmozgatást végző programszál */
private Thread mozgató;
/** Kukacmozgatás indítása */
public synchronized void start() {
if (mozgató!=null) return; //ha már mozog, nincs mit tenni
System.out.println("Start: "+(vászon.isDoubleBuffered() ?//megjelenítési
"offscreen" : "normál")); //mód kiírása indítási üzenetként
mozgató = new Thread(this); //új programszál a mozgatáshoz
mozgató.start(); //programszál indítása
}
/** Kukacmozgatás leállítása */
public synchronized void stop() {
mozgató = null; //mozgató programszál felé jelezzük a megállást
}
/**
Animálás indítása és leállítása a vászon láthatóságának változásakor.
@param esemény a komponenshierarchia változási eseménye
*/
public void hierarchyChanged( java.awt.event.HierarchyEvent esemény ) {
if ((esemény.getChangeFlags() & java.awt.event.HierarchyEvent.
SHOWING_CHANGED)!=0) if (esemény.getComponent().isShowing()) start();
else stop();
}
/** Véletlenszámgenerátor a kukacmozgatáshoz */
private java.util.Random véletlen = new java.util.Random();
/** Kukacmozgatás egy lépésének elvégzése */
public void run() {
if (java.awt.EventQueue.isDispatchThread()) synchronized(pontok) {
java.awt.Point pont = null;
int maxx = vászon.getWidth()/MÉRET-1;//maximális látható koordináták
int maxy = vászon.getHeight()/MÉRET-1;
if (pontok.size()>0) { //folytatás keresése
pont = pontok.getLast();
if (pont.x<=maxx && pont.y<=maxy) {
java.util.Vector újpontok = //lehetséges
new java.util.Vector(8); //folytatások
if (pont.x>0) újpontok.add( //balra
new java.awt.Point(pont.x-1, pont.y));
if (pont.x0) újpontok.add( //fel
new java.awt.Point(pont.x, pont.y-1));
if (pont.y0) {//folytatás keresése/kiválasztása
pont = újpontok.elementAt(véletlen.nextInt(
újpontok.size()));
if (újpont(pont)) return; //megvan a folytatás
újpontok.remove(pont); //tovább kell keresni
}
}
} //nem sikerült folyamatos folytatást találni
if (maxx>=0 && maxy>=0) { //véletlenszerűen keresünk tovább
maxx++; maxy++;
int darab = MAXPONT; //próbálkozások számának maximalizálása
pont = new java.awt.Point();
do { //véletelen pont keresése
pont.x = véletlen.nextInt(maxx);
pont.y = véletlen.nextInt(maxy);
} while (pontok.contains(pont) && --darab>0);
if (újpont(pont)) { //új kezdés
System.out.println("új kezdés: "+pont);
return;
}
} //nem találtunk folytatást
System.err.println("Nem sikerült a folytatás...");
} else { //léptető programszál
while(true) try {
Thread.sleep(LÉPÉS); //lépések közti idő kivárása
synchronized(this) { //ha már nem kell tovább léptetni
if (Thread.currentThread() != mozgató) break;//akkor kilépés
}
java.awt.EventQueue.invokeLater(this); //léptetés elvégeztetése
} catch (Exception e) {
break;
}
}
}
/** Az utoljára kirajzolt állapot pontjainak végindexe (+1: darabszáma) */
private int maxindex;
/**
A kukac aktuális állapotának kirajzolása.
@param szöveg A kirajzolás oka (paint/update)
@param mind Igaz értéke esetén minden pont, hamis esetén csak az eddig meg
nem jelenített új pontok kirajzolása.
@param töröl Igaz esetén a kukac végén az elhagyott pontok törlése.
@param g A megjelenítéshez használt rajzolási környezet.
*/
public void pontoz( String szöveg, boolean mind, boolean töröl,
java.awt.Graphics g ) {
System.out.print(szöveg+": ");
if (mind) maxindex = 0; //minden pont esetén a kezdőindex nullázása
java.awt.Point pont = null;
java.awt.Rectangle négyzet = new java.awt.Rectangle();
java.awt.Rectangle vászon = new java.awt.Rectangle( //a látható terület
0, 0, this.vászon.getWidth(), this.vászon.getHeight());
java.awt.Shape vágás = g.getClip(); //a rajzolási környezet vágóterülete
int darab = 0;
synchronized( pontok ) {
int index = pontok.size()-MAXPONT;
if (index>0) { //elhagyott pontok törlése
maxindex-=index;
if (maxindex<0) maxindex=0;
while (--index>=0) {
pont = pontok.removeFirst(); //pontadatok törlése
if (töröl) { //pont megjelenítésének törlése
négyzet.setBounds(
pont.x*MÉRET, pont.y*MÉRET, MÉRET, MÉRET);
if (vászon.intersects(négyzet) && //amennyiben látható
(vágás == null || vágás.intersects(négyzet))) {
g.clearRect(négyzet.x, négyzet.y,//a terület törlése
négyzet.width, négyzet.height);
darab++;
}
}
}
if (darab>0) { //a törölt pontok számának megjelenítése
System.out.print(darab+" pont törölve, ");
darab = 0;
}
}
index=pontok.size();
g.setColor(java.awt.Color.RED); //a kezdőpontot kiemelő szín
while (index>0 && index >= maxindex) { //pontok megjelenítése
pont = pontok.get(--index);
négyzet.setBounds(pont.x*MÉRET, pont.y*MÉRET, MÉRET, MÉRET);
if (vászon.intersects(négyzet) && //amennyiben látható
(vágás == null || vágás.intersects(négyzet))) {
g.fillRect(négyzet.x, négyzet.y, //a pont megjelenítése
négyzet.width, négyzet.height);
darab++;
}
if (index==pontok.size()-1) //normál rajszín visszaállítása
g.setColor(this.vászon.getForeground());
}
maxindex=pontok.size(); //megjelenített pontok számának eltárolása
}
System.out.println(darab+" pont kirajzolva.");
}
}