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/):

 

www.informatika-programozas.hu - Frame

 

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).

 

www.informatika-programozas.hu - Ezt most meg kell tanulni!

 

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

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:

 

www.informatika-programozas.hu - Futtatható Java-kód!

 

 

 

 

 

 

 

 

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

 

www.informatika-programozas.hu - Frame

 

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):

 

www.informatika-programozas.hu - STOP gomb

 

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:

 

www.informatika-programozas.hu - Futtatható Java-kód!

 

 

 

 

 

 

 

 

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

 

www.informatika-programozas.hu - Frame

 

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):

 

www.informatika-programozas.hu - STOP gomb