Gyakorlati alapok IV.

Végre ablakozunk! (AWT, Swing, JavaFX)

 

2 db frame

 

Programozási ujjgyakorlatként gyorsan implementáljuk azt a megoldást, amelyik nem 1, hanem 2 db frame-t nyit meg. A már meglévő kódokból kompilálva ezt viszonylag könnyű megtennünk, ám már kissé nehezebb, ha a következő elvárásokat szeretnénk szem előtt tartani:

 

1.

Bár megtehetnénk, de nincs sok értelme a Window osztályt kétszer példányosítani...

 

Window window1 = new Window();

Window window2 = new Window();

 

...ezért legyen minden frame külön osztályban, így jelezvén a funkcionális szétválasztás mélyebb értelmét:

 

WindowLeft windowLeft = new WindowLeft();
WindowRight windowRight = new WindowRight();

 

2.

Futtatás során a 2 frame tökéletes fedésben egymásra fog kerülni, ez azonban enyhén szólva nem egészen elegáns megoldás. A Center osztály kis módosításával az igazítás megoldható:

 

void setCenter(JFrame frame, int offset) {
    Point center = GraphicsEnvironment.getLocalGraphicsEnvironment().getCenterPoint();
    int x = (int) center.getX() - (frame.getWidth() / 2 + offset);
    int y = (int) center.getY() - (frame.getHeight() / 2);
    Point ablakCenter = new Point(x, y);
    frame.setLocation(ablakCenter);

}

 

Ám az igazítás mértéke, azaz hogy a frame a centrumhoz képest a koordináta X tengelyen mennyire tolódik el (int offsetX) mégiscsak a Window osztályok belügye, amelyet private hozzáférés módosítóval kell magánnak minősítenünk, például:

 

private int offsetXWinLeft = 200;

 

Ezután viszont már kötelező ezen belső adatokra getter-setter függvényeket létrehozni, például:

 

public int getOffsetXWinLeft() {
    return offsetXWinLeft;
}

public void setOffsetXWinLeft(int offsetXWinLeft) {
    this.offsetXWinLeft = offsetXWinLeft;
}

 

3.

Megkülönböztetésül legyen a frame-ek színe zöld és piros.

 

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) {
    WindowLeft windowLeft = new WindowLeft();
    WindowRight windowRight = new WindowRight();

    }
}

 

WindowLeft.java

 

import java.awt.Color;
import javax.swing.JFrame;

public class WindowLeft extends JFrame {

private int offsetXWinLeft = 200;

public int getOffsetXWinLeft() {
    return offsetXWinLeft;
}

public void setOffsetXWinLeft(int offsetXWinLeft) {
    this.offsetXWinLeft = offsetXWinLeft;
}

WindowLeft() {
    JFrame frame = new JFrame();
    Center center = new Center();
    frame.setSize(400, 300);
    frame.setTitle("PJP - Penzes Java Programming");
    center.setCenter(frame, getOffsetXWinLeft());
    frame.getContentPane().setBackground(Color.GREEN);
    frame.setVisible(true);
    }
}

 

WindowRight.java

 

import java.awt.Color;
import javax.swing.JFrame;

public class WindowRight extends JFrame {

private int offsetXWinRight = -200;

public int getOffsetXWinRight() {
    return offsetXWinRight;
}

public void setOffsetXWinRight(int offsetXWinRight) {
    this.offsetXWinRight = offsetXWinRight;
}

WindowRight() {
    JFrame frame = new JFrame();
    Center center = new Center();
    frame.setSize(400, 300);
    frame.setTitle("PJP - Penzes Java Programming");
    center.setCenter(frame, getOffsetXWinRight());
    frame.getContentPane().setBackground(Color.RED);
    frame.setVisible(true);
    }
}

 

Center.java

 

import java.awt.GraphicsEnvironment;
import java.awt.Point;
import javax.swing.JFrame;

public class Center {
 

void setCenter(JFrame frame, int offset) {
    Point center = GraphicsEnvironment.getLocalGraphicsEnvironment().getCenterPoint();
    int x = (int) center.getX() - (frame.getWidth() / 2 + offset);
    int y = (int) center.getY() - (frame.getHeight() / 2);
    Point ablakCenter = new Point(x, y);
    frame.setLocation(ablakCenter);

}

 

Végeredmény (a monitor közepén / felbontástól függetlenül/):

 

www.informatika-programozas.hu - 2 db frame

 

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

 

Mindeközben a tapasztaltabbak azt is látják, hogy nyilvánvalóan még ez sem elég a 2 frame egyidejű zavartalan működéséhez, hiszen azonos szálon futnak. Mivel (elméletileg) a frame-ek külön funkciók kereteiként szolgálnak, azokat mindenképpen külön szálakra (thread) kell tennünk, ráadásként pedig a futtatást a Swing belső EDT-mechanizmusára kell bíznunk (Event Dispatch Thread).

 

www.informatika-programozas.hu - További információk!

A legtöbb Swing-metódus nem "szálbiztos (thread safe)", ami azt jelenti, hogy több szál egyidejű működése esetén metódushíváskor ütközések és egyéb hibajelenségek léphetnek fel. Ennek kiküszöbölésére az EDT-mechanizmus megpróbál egy biztonságos, futtató szálkörnyezetet biztosítani.

 

Az EDT a SwingUtilities osztály importjával és annak invokeLater metódusával aktiválható; mindezt a Main osztályban állítjuk be.

 

Mivel a Java-nyelvben a többszörös öröklődés tiltott (tehát amikor egyszerre több osztályból származtatnánk), ezért külön szálak létrehozásához a Runnable interfészhez kell fordulnunk (Szálmenedzsment Runnable interfésszel című fejezet). Mindegyik Window osztály kap egy külön szálat (implements Runnable), amelyeknek lesz egy kötelezően kidolgozandó run() metódusa: ebbe kell tennünk a konkrét szálkódot.

 

Nézzük meg az ilyen programelemekkel módosított, futtatható Java-kódot:

 

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

 

 

 

 

 

 

 

 

Main.java

 

import javax.swing.SwingUtilities;

public class Main {

public static void main(String[] args) {
    SwingUtilities.invokeLater(windowLeft);
    SwingUtilities.invokeLater(windowRight);
    }
}

 

WindowLeft.java

 

import java.awt.Color;
import javax.swing.JFrame;

public class WindowLeft extends JFrame implements Runnable {

private int offsetXWinLeft = 200;

public int getOffsetXWinLeft() {
    return offsetXWinLeft;
}

public void setOffsetXWinLeft(int offsetXWinLeft) {
    this.offsetXWinLeft = offsetXWinLeft;
}

@Override
    public void run() {
    {
        JFrame frame = new JFrame();
        Center center = new Center();
        frame.setSize(400, 300);
        frame.setTitle("PJP - Penzes Java Programming");
        center.setCenter(frame, getOffsetXWinLeft());
        frame.getContentPane().setBackground(Color.GREEN);
        frame.setVisible(true);
        }
    }
}

 

WindowRight.java

 

import java.awt.Color;
import javax.swing.JFrame;

public class WindowRight extends JFrame implements Runnable{

private int offsetXWinRight = -200;

public int getOffsetXWinRight() {
    return offsetXWinRight;
}

public void setOffsetXWinRight(int offsetXWinRight) {
    this.offsetXWinRight = offsetXWinRight;
}

@Override
    public void run() {
        {
        JFrame frame = new JFrame();
        Center center = new Center();
        frame.setSize(400, 300);
        frame.setTitle("PJP - Penzes Java Programming");
        center.setCenter(frame, getOffsetXWinRight());
        frame.getContentPane().setBackground(Color.RED);
        frame.setVisible(true);
        }
    }
}

 

Center.java

 

import java.awt.GraphicsEnvironment;
import java.awt.Point;
import javax.swing.JFrame;

public class Center {
 

void setCenter(JFrame frame, int offset) {
    Point center = GraphicsEnvironment.getLocalGraphicsEnvironment().getCenterPoint();
    int x = (int) center.getX() - (frame.getWidth() / 2 + offset);
    int y = (int) center.getY() - (frame.getHeight() / 2);
    Point ablakCenter = new Point(x, y);
    frame.setLocation(ablakCenter);

}

 

Végeredmény (a monitor közepén / felbontástól függetlenül/):

 

www.informatika-programozas.hu - 2 db frame