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