Gyakorlati alapok IV.
Végre ablakozunk! (AWT, Swing, JavaFX)
Játék: Wollen Sie arbeiten? (Akar Ön dolgozni?)
Amint láttuk az előző fejezetben (Frame középre igazítva), sikerült egy középre igazított frame-et alkotnunk:
Végeredmény (a monitor közepén / felbontástól függetlenül/):
Most nem teszünk mást, mint 1 kicsit eljátszunk ezzel a frame-mel, mellette persze 1-2 új dolgot is tanulunk.
Az alábbi játékkal egyszer régen találkoztam, német nyelven, innen az alkalmazás címe. A program feltette ezt az egyszerű kérdést és ha az OK gombra kattintottunk, akkor teleszórta a képernyőt ablakokkal, amelyeket egyenként kellett becsukni. Ezt a mókát programozzunk most le kis korlátok között, hiszen gombot (JButton) még nem rajzoltunk a frame-re, illetve eseménykezelésről (event handling) sem esett szó (ebben az esetben: egérkattintás).
Nem probléma ez, hiszen a jelen pillanatban ezen a szinten vagyunk, így alkalmazásunk még tökéletes átmenet lesz a konzolos és ablakos megvalósítás között. Ettől függetlenül benne célirányosan meg fognak jelenni a magasabb szintű objektumorientált alapelvek, főként a funkciók meghatározása és szétválasztása, valamint osztályokba való rendezése. A későbbiekben ezt a mókát leprogramozzuk teljes Swing-komponensekkel is.
Rögtön nézzük is meg ezen funkciókat:
-
Működtetés
-
Megjelenítés
-
Üzenetek
-
Bemeneti adat ellenőrzése (validálás)
-
A frame középre zárása
Működtetés
Benne a main() főprogrammal, illetve egyetlen osztály, a Window példányosításával.
Main.java
public
class Main {
public static void main(String[] args) {
Window window = new Window();
}
}
Megjelenítés
Az az igazság, hogy ez az osztály nemcsak megjelenítést tartalmaz, hanem az elején adatbekérést és kiértékelést is.
Talán az adatbekérést áthelyezhettem volna a validáló osztályba, ám innentől akkor már koncepcionális vitaalap, hogy a mindenkori validáló osztály tartalmazhat-e adatbekérést.
Illetve létre lehetett volna hozni még egy külön kiértékelő osztályt, de a kód viszonylagos egyszerűsége és olvashatósága végett erről végül lemondtam. A kód így is eléggé tagolt és funkcionális lett ahhoz képest, hogy egy egyszerű konzolos alkalmazás.
Az Window-osztályban észrevehetünk 2 új metódust is: getContentPane() és setBackground(Color).
getContentPane()
Amikor Swing-komponenseket használunk fel és azokat folyamatosan hozzáadjuk a frame-hez (ezt a mechanizmust majd később látjuk és kipróbáljuk), azaz fokozatosan felépítjük vizuális alkalmazásunkat, akkor a rendszernek a hozzáadott komponenseket nyilvánvalóan valahol el is kell tárolni. A tárolóegységet egységesen container névvel illetjük. Ennek több tárolórétege van (layer), az egyik ilyen a content pane, amelyet egyébként a Java futási környezet hoz létre (Java Runtime Environment). A getContentPane() metódus hívásával hozzáférhetünk ezen réteg tartalmához és módosíthatjuk azt vagy akár hozzáadhatunk újabb objektumot.
setBackground(Color)
A metódus segítségével a frame háttérszínét állíthatjuk be, akár többféle típusú színmegadással. Láthatjuk, hogy a frame-ek színét pirosra állítottuk (Color.RED) és egy kissé méretüket is megváltoztattuk (frame.setSize(200, 200)).
A frame-ek folyamatos kirajzolásáról egy hátultesztelő ciklus gondoskodik, amelyet a while(true) utasítással kiakasztottunk egyenesen a végtelenbe.
Window.java
import
java.awt.Color;
import java.awt.Dimension;
import java.util.Scanner;
import javax.swing.JFrame;
import javax.swing.WindowConstants;
class Window extends JFrame {
Window() {
Message message = new Message();
Validation validation = new
Validation();
Scanner scanner = new
Scanner(System.in);
String inputString = "";
boolean isValid = true;
message.messageWelcome();
inputString = scanner.nextLine();
isValid =
validation.isValidInputString(inputString);
while(!isValid) {
message.messageBadInput();
inputString =
scanner.nextLine();
isValid =
validation.isValidInputString(inputString);
}
do
try {
JFrame frame = new JFrame();
Center center = new Center();
frame.setSize(200, 200);
center.setCenter(frame);
frame.getContentPane().setBackground(Color.RED);
frame.setVisible(true);
Thread.sleep(500);
} catch
(Exception e) {
e.printStackTrace();
} while(true);
}
}
Üzenetek
Ez a funkció külön osztályt kapott és 3 db eljárást tartalmaz.
Message.java
public
class Message {
public void messageWelcome() {
System.out.println("Udvozlom! Akar On dolgozni (I vagy N)?");
}
public void messageBadInput() {
System.out.println("Rossz bemeneti adat, kerem ismetelje meg
(I vagy N)!");
}
public void messageExit() {
System.out.println("Viszlat!");
}
}
Bemeneti adat ellenőrzése (validálás)
Ez az osztály a címben említett funkciót ellenőrzi és ehhez 1 db metódust használ fel. Egyúttal a program egyetlen (hivatalos) kilépőpontja is itt van implementálva.
Validation.java
public
class Validation {
public boolean isValidInputString (String inputString) {
boolean isValid = false;
if(inputString.equals("I") || inputString.equals("i")) {
isValid = true;
return isValid;
}
else if(inputString.equals("N") || inputString.equals("n")) {
Message message = new Message();
message.messageExit();
System.exit(0);
}
return isValid;
}
}
A frame középre zárása
A Center osztályra továbbra is szükségünk van, mert a monitor középpontja jó vizuális kiindulópont, de nem lenne látványos minden frame-et ugyanarra a központi helyre kitenni. A megoldás, hogy a középpont körül véletlenszerűen pakolgassuk ki a generált frame-eket. Ehhez 1 kissé, véletlenszám-generálással módosítottuk a kódot:
int randomIntX = (int)(Math.random() * 500);
int randomIntY = (int)(Math.random() * 500);
int x = (int) center.getX() - (frame.getWidth() / 2) +
randomIntX;
int y = (int) center.getY() - (frame.getHeight() / 2) +
randomIntY;
Center.java
import java.awt.GraphicsEnvironment;
import java.awt.Point;
import javax.swing.JFrame;
public class Center {
void setCenter(JFrame frame) {
Point center =
GraphicsEnvironment.getLocalGraphicsEnvironment().getCenterPoint();
int randomIntX = (int)(Math.random() * 500);
int randomIntY = (int)(Math.random() * 500);
int x = (int) center.getX() - (frame.getWidth() / 2) +
randomIntX;
int y = (int) center.getY() - (frame.getHeight() / 2) +
randomIntY;
Point ablakCenter = new Point(x, y);
frame.setLocation(ablakCenter);
}
}
Nézzük meg a futtatható Java-kódot:
Main.java
public
class Main {
public static void main(String[] args) {
Window window = new Window();
}
}
Window.java
import
java.awt.Color;
import java.awt.Dimension;
import java.util.Scanner;
import javax.swing.JFrame;
import javax.swing.WindowConstants;
class Window extends JFrame {
Window() {
Message message = new Message();
Validation validation = new
Validation();
Scanner scanner = new
Scanner(System.in);
String inputString = "";
boolean isValid = true;
message.messageWelcome();
inputString = scanner.nextLine();
isValid =
validation.isValidInputString(inputString);
while(!isValid) {
message.messageBadInput();
inputString =
scanner.nextLine();
isValid =
validation.isValidInputString(inputString);
}
do
try {
JFrame frame = new JFrame();
Center center = new Center();
frame.setSize(200, 200);
center.setCenter(frame);
frame.getContentPane().setBackground(Color.RED);
frame.setVisible(true);
Thread.sleep(500);
} catch
(Exception e) {
e.printStackTrace();
} while(true);
}
}
Message.java
public
class Message {
public void messageWelcome() {
System.out.println("Udvozlom! Akar On dolgozni (I vagy N)?");
}
public void messageBadInput() {
System.out.println("Rossz bemeneti adat, kerem ismetelje meg
(I vagy N)!");
}
public void messageExit() {
System.out.println("Viszlat!");
}
}
Validation.java
public
class Validation {
public boolean isValidInputString (String inputString) {
boolean isValid = false;
if(inputString.equals("I") || inputString.equals("i")) {
isValid = true;
return isValid;
}
else if(inputString.equals("N") || inputString.equals("n")) {
Message message = new Message();
message.messageExit();
System.exit(0);
}
return isValid;
}
}
Center.java
import java.awt.GraphicsEnvironment;
import java.awt.Point;
import javax.swing.JFrame;
public class Center {
void setCenter(JFrame frame) {
Point center =
GraphicsEnvironment.getLocalGraphicsEnvironment().getCenterPoint();
int randomIntX = (int)(Math.random() * 500);
int randomIntY = (int)(Math.random() * 500);
int x = (int) center.getX() - (frame.getWidth() / 2) +
randomIntX;
int y = (int) center.getY() - (frame.getHeight() / 2) +
randomIntY;
Point ablakCenter = new Point(x, y);
frame.setLocation(ablakCenter);
}
}
Végeredmény:
Udvozlom!
Akar On dolgozni (I vagy N)?
h
Rossz bemeneti adat, kerem ismetelje meg (I vagy N)!
4
Rossz bemeneti adat, kerem ismetelje meg (I vagy N)!
ghgh
Rossz bemeneti adat, kerem ismetelje meg (I vagy N)!
i
A program vég nélkül fogja kipakolni a frame-eket a képernyőre, de ne ijedjünk meg, mert az egészet megállíthatjuk a futtatás STOP gombjával (és minden ablak egyszerre el fog tűnni):
Ehhez a totális marhasághoz talán még annyit adhatunk hozzá, hogy minden egyes ablakot más és más színben jelenítünk meg. Ehhez kihasználjuk azt a már említett lehetőséget, hogy a színeket más kódformátumban is megadhatjuk. Legyen ez most megvalósítva a klasszikusnak számító RGB-színkódokkal, amelyek értéke 0 és 255 között váltakozhat. Persze ezeket kevernünk is kell, ezért az egyik, jól bevált véletlenszámgeneráló függvényünkhez fordulunk (Véletlenül generáljunk már véletlenszámokat! című fejezet).
int randomR
= (int)(Math.random() * 255);
int randomG = (int)(Math.random() * 255);
int randomB = (int)(Math.random() * 255);
frame.getContentPane().setBackground(new Color(randomR, randomG, randomB));
Nézzük meg a futtatható Java-kódot:
Main.java
public
class Main {
public static void main(String[] args) {
Window window = new Window();
}
}
Window.java
import
java.awt.Color;
import java.awt.Dimension;
import java.util.Scanner;
import javax.swing.JFrame;
import javax.swing.WindowConstants;
class Window extends JFrame {
Window() {
Message message = new Message();
Validation validation = new
Validation();
Scanner scanner = new
Scanner(System.in);
String inputString = "";
boolean isValid = true;
message.messageWelcome();
inputString = scanner.nextLine();
isValid =
validation.isValidInputString(inputString);
while(!isValid) {
message.messageBadInput();
inputString =
scanner.nextLine();
isValid =
validation.isValidInputString(inputString);
}
do
try {
JFrame frame = new JFrame();
Center center = new Center();
frame.setSize(200, 200);
center.setCenter(frame);
int randomR = (int)(Math.random() * 255);
int randomG = (int)(Math.random() * 255);
int randomB = (int)(Math.random() * 255);
frame.getContentPane().setBackground(new Color(randomR, randomG, randomB));
frame.setVisible(true);
Thread.sleep(500);
} catch
(Exception e) {
e.printStackTrace();
} while(true);
}
}
Message.java
public
class Message {
public void messageWelcome() {
System.out.println("Udvozlom! Akar On dolgozni (I vagy N)?");
}
public void messageBadInput() {
System.out.println("Rossz bemeneti adat, kerem ismetelje meg
(I vagy N)!");
}
public void messageExit() {
System.out.println("Viszlat!");
}
}
Validation.java
public
class Validation {
public boolean isValidInputString (String inputString) {
boolean isValid = false;
if(inputString.equals("I") || inputString.equals("i")) {
isValid = true;
return isValid;
}
else if(inputString.equals("N") || inputString.equals("n")) {
Message message = new Message();
message.messageExit();
System.exit(0);
}
return isValid;
}
}
Center.java
import java.awt.GraphicsEnvironment;
import java.awt.Point;
import javax.swing.JFrame;
public class Center {
void setCenter(JFrame frame) {
Point center =
GraphicsEnvironment.getLocalGraphicsEnvironment().getCenterPoint();
int randomIntX = (int)(Math.random() * 500);
int randomIntY = (int)(Math.random() * 500);
int x = (int) center.getX() - (frame.getWidth() / 2) +
randomIntX;
int y = (int) center.getY() - (frame.getHeight() / 2) +
randomIntY;
Point ablakCenter = new Point(x, y);
frame.setLocation(ablakCenter);
}
}
Végeredmény:
Udvozlom!
Akar On dolgozni (I vagy N)?
k
Rossz bemeneti adat, kerem ismetelje meg (I vagy N)!
8
Rossz bemeneti adat, kerem ismetelje meg (I vagy N)!
oo
Rossz bemeneti adat, kerem ismetelje meg (I vagy N)!
i
A program megint csak vég nélkül kipakolja a frame-eket a képernyőre, amelynek futtatását megállíthatjuk a STOP gombbal (és minden ablak egyszerre el fog tűnni):