package elte.java2_utikalauz5.gui;
/**
Méretarányokkal megadott komponensek elrendezési stratégiája.
A komponenseket az igazítási pontjuk figyelembe vételével csoportba (sor/oszlop)
rendezi, míg az be nem tellik, majd új csoportot kezd.
A kipróbálásakor paraméterként a csoportok konténerszélekhez történő igazítását is megadhatjuk (középre}, a csoport elejéhez vagy végéhez).
@link.forrásfájl {@docRoot}/../data/gui/src TesztLayout.java
@since Java 2 Útikalauz programozóknak 1.3
*/
class TesztLayout implements java.awt.LayoutManager2 {
/** Függőleges elrendezés előírása */
private boolean függőleges;
/**
Csoporton belüli igazítás. Negatív érték a csoport elejére, 0 középre,
pozitív pedig a csoport végére igazít.
*/
private int csoportigazítás;
/**
Vízszintes irányban komponensek közti helykihagyás.
A konténer bal és jobb széle mentén fele ekkor térköz lesz kihagyva.
*/
private int vhelykihagyás;
/**
Függőleges irányban komponensek közti helykihagyás.
A konténer alsó és felső széle mentén fele ekkor térköz lesz kihagyva.
*/
private int fhelykihagyás;
/**
Konstruktor az elrendezés irányultságával, igazításával és térközértékeivel.
@param függőleges az elrendezés függőleges(igaz) / vízszintes(hamis) iránya
@param igazítás Csoporton belüli igazítás. Negatív érték a csoport elejére,
0 középre, pozitív pedig a csoport végére igazít.
@param vhely Vízszintes irányban komponensek közti helykihagyás.
A konténer bal és jobb széle mentén fele ekkor térköz lesz kihagyva.
@param fhely Függőleges irányban komponensek közti helykihagyás.
A konténer alsó és felső széle mentén fele ekkor térköz lesz kihagyva.
*/
public TesztLayout(boolean függőleges, int igazítás, int vhely, int fhely) {
this.függőleges = függőleges;
csoportigazítás = igazítás;
vhelykihagyás = vhely;
fhelykihagyás = fhely;
}
/**
Az elrendezési stratégia leírásának lekérdezése.
@return Az elrendezési stratégia leírása az aktuális jellemzőinek értékével.
*/
@Override
public String toString() {
return getClass().getName()+"["+(függőleges?"vertikális":"horizontális")
+", vhely="+vhelykihagyás+", fhely="+fhelykihagyás+", csoportigazítás="+
(csoportigazítás<0?"elejé":(csoportigazítás>0?"végé":"közép"))+"re]";
}
/***************************************************************************
Pakolási jellemző a {@code TesztLayout} elrendezési stratégiához.
A komponensek méretét a konténer méretarányaként adja meg.
*/
public static class Constraints {
/** Komponens szélességi aránya */
private float xarány;
/** Komponens magassági aránya */
private float yarány;
/**
Konstruktor az arányszámokkal.
@param pXarány szélességi arány
@param pYarány magassági arány
*/
public Constraints( float pXarány, float pYarány ) {
setXarány( pXarány ); //arányok beállítása
setYarány( pXarány );
}
/**
Szélességi arány beállítása.
@param pXarány szélességi arány [0-1]
@throws IllegalArgumentException ha érvénytelen a paraméter
*/
public void setXarány( float pXarány ) {
if (pXarány<0 || pXarány>1) throw new IllegalArgumentException(
"Érvénytelen Xarány:"+pXarány); //paraméter ellenőrzése
xarány = pXarány;
}
/**
Szélességi arány lekérdezése.
@return szélességi arány
*/
public float getXarány() {
return xarány;
}
/**
Magassági arány beállítása.
@param pYarány magassági arány [0-1]
@throws IllegalArgumentException ha érvénytelen a paraméter
*/
public void setYarány( float pYarány ) {
if ((pYarány<0 || pYarány>1)) throw new IllegalArgumentException(
"Érvénytelen Yarány:"+pYarány); //paraméter ellenőrzése
yarány = pYarány;
}
/**
Magassági arány lekérdezése.
@return magassági arány
*/
public float getYarány() {
return yarány;
}
}//*************************************************************************
/** A komponensekhez rendelt elrendezési jellemzők tárolója */
private java.util.HashMap jellemzők =
new java.util.HashMap(7);
/**
Komponens hozzáadása szöveges paraméterrel.
@param para szöveges paraméter
@param pKomponens a felvevendő komponens
*/
public void addLayoutComponent(String para, java.awt.Component pKomponens) {
addLayoutComponent( pKomponens, para );
}
/**
Komponens hozzáadása {@code Constraints} elrendezési jellemzővel.
@param pKomponens a felvevendő komponens
@param pJellemző elrendezési jellemző
@throws IllegalArgumentException ha az elrendezési jellemző nem megfelelő
*/
public void addLayoutComponent( java.awt.Component pKomponens,
Object pJellemző) {
if (!(pJellemző instanceof Constraints)) //csak a megfelelő elrendezési
throw new IllegalArgumentException( //jellemző megengedett
"Hibás elrendezési jellemző:"+pJellemző+", komponens:"+pKomponens);
jellemzők.put( pKomponens, (Constraints)pJellemző );
}
/**
Komponens elrendezési jellemzőjének lekérdezése.
@param pKomponens a felvevendő komponens
@return a komponenshez rendelt elrendezési jellemző
@throws IllegalArgumentException a komponenshez nincs elrendezési jellemző
*/
public Constraints getConstraints( java.awt.Component pKomponens ) {
Constraints jellemző = jellemzők.get( pKomponens );
if (jellemző == null) throw new IllegalArgumentException(
"Constraints nincs megadva: "+pKomponens);
return jellemző;
}
/**
Komponens törlése az elrendezési stratégiából.
@param pKomponens a törlendő komponens
*/
public void removeLayoutComponent( java.awt.Component pKomponens ) {
jellemzők.remove( pKomponens );
}
/**
Megadja az elrendezési stratégia vízszintes igazítási pontját.
@param pKonténer az elrendezendő konténer
@return az igazítás mindig középre történik
*/
public float getLayoutAlignmentX( java.awt.Container pKonténer ) {
return java.awt.Component.CENTER_ALIGNMENT;
}
/**
Megadja az elrendezési stratégia függőleges igazítási pontját.
@param pKonténer az elrendezendő konténer
@return az igazítás mindig középre történik
*/
public float getLayoutAlignmentY( java.awt.Container pKonténer ) {
return java.awt.Component.CENTER_ALIGNMENT;
}
/********************Segédinterfész a méretkiszámításhoz.******************/
private interface MeretSzamolo {
/**
Visszaadja adott stratégia esetén a komponens kívánt méretét.
@param pKomponens a lekérdezett komponens
@return a komponens kívánt mérete
*/
public java.awt.Dimension méret( java.awt.Component pKomponens );
}//*************************************************************************
/** Segédobjektum a minimális méretekkel történő elrendezéshez */
private static final MeretSzamolo MINIMUM = new MeretSzamolo() {
/**
Visszaadja a komponens minimális méretét.
@param pKomponens a lekérdezett komponens
@return a komponens minimális mérete
*/
public java.awt.Dimension méret( java.awt.Component pKomponens ) {
return pKomponens.getMinimumSize();
}
};
/** Segédobjektum az optimális méretekkel történő elrendezéshez */
private static final MeretSzamolo PREFERRED = new MeretSzamolo() {
/**
Visszaadja a komponens optimális méretét.
@param pKomponens a lekérdezett komponens
@return a komponens optimális mérete
*/
public java.awt.Dimension méret( java.awt.Component pKomponens ) {
return pKomponens.getPreferredSize();
}
};
/** Segédobjektum a maximális méretekkel történő elrendezéshez */
private static final MeretSzamolo MAXIMUM = new MeretSzamolo() {
/**
Visszaadja a komponens maximális méretét.
@param pKomponens a lekérdezett komponens
@return a komponens maximális mérete
*/
public java.awt.Dimension méret( java.awt.Component pKomponens ) {
return pKomponens.getMaximumSize();
}
};
/**
Minimális elrendezési méret kiszámítása.
@param pKonténer az elrendezendő konténer
@return a konténer minimális mérete
*/
public java.awt.Dimension minimumLayoutSize( java.awt.Container pKonténer ){
return méret( pKonténer, MINIMUM );
}
/**
Optimális elrendezési méret kiszámítása.
@param pKonténer az elrendezendő konténer
@return a konténer optimális mérete
*/
public java.awt.Dimension preferredLayoutSize(java.awt.Container pKonténer){
return méret( pKonténer, PREFERRED );
}
/**
Maximális elrendezési méret kiszámítása.
@param pKonténer az elrendezendő konténer
@return a konténer maximális mérete
*/
public java.awt.Dimension maximumLayoutSize( java.awt.Container pKonténer ){
return méret( pKonténer, MAXIMUM );
}
/**
Elrendezés szerinti méret kiszámítása. Az arányok alapján kiszámítunk egy
konténerméretet, amiben minden komponens legalább minimálisan belefér.
@param pKonténer az elrendezendő konténer
@param pMeretSzamolo a felhasználandó méretet visszaadó segédobjektum
@return az elrendezett konténer mérete
*/
private java.awt.Dimension méret( java.awt.Container pKonténer,
MeretSzamolo pMeretSzamolo ) {
java.awt.Dimension viszonyítás = viszonyításiMéret( pKonténer );
java.awt.Dimension méret = elrendezés( //méretszámolás szimulálással
pKonténer, viszonyítás==null? 0 : viszonyítás.width,
viszonyítás==null? 0 : viszonyítás.height, 0, 0, pMeretSzamolo);
java.awt.Insets keretvastagság = pKonténer.getInsets(); //belső keret
méret.width += keretvastagság.left+keretvastagság.right; //vastagságának
méret.height += keretvastagság.top + keretvastagság.bottom; //hozzáadása
méret.width += vhelykihagyás; //szélek menti térközkihagyások
méret.height += fhelykihagyás;
if (pKonténer.isMinimumSizeSet()) { //minimális méret figyelembe vétele
java.awt.Dimension minimum = pKonténer.getMinimumSize();
méret.width = Math.max(méret.width, minimum.width);
méret.height = Math.max(méret.height, minimum.height);
}
if (pKonténer.isMaximumSizeSet()) { //maximális méret figyelembe vétele
java.awt.Dimension maximum = pKonténer.getMaximumSize();
méret.width = Math.min(méret.width, maximum.width);
méret.height = Math.min(méret.height, maximum.height);
}
return méret;
}
/**
Konténerelemek arányos méretezéséhez felhasznált viszonyítási méret megadása
@param pKonténer az elrendezendő konténer
@return az arányos méretezéshez felhasználandó összméret, vagy {@code null},
ha a teljes konténerméretet kell alapul venni.
*/
protected java.awt.Dimension viszonyításiMéret(java.awt.Container pKonténer){
return null;
}
/**
Konténerelemek elrendezése.
@param pKonténer az elrendezendő konténer
*/
public void layoutContainer(java.awt.Container pKonténer) {
java.awt.Dimension méret = new java.awt.Dimension(pKonténer.getWidth(),
pKonténer.getHeight());
java.awt.Insets keretvastagság = pKonténer.getInsets(); //keretvastagság
méret.width -= keretvastagság.left+keretvastagság.right + vhelykihagyás;
méret.height-= keretvastagság.top+keretvastagság.bottom + fhelykihagyás;
int startx = keretvastagság.left+vhelykihagyás/2;//konténer kezdő pontja
int starty = keretvastagság.top + fhelykihagyás/2;
elrendezés(pKonténer, méret.width, méret.height, startx, starty, null);
}
/**
Elrendezési stratégia megvalósítása.
@param pKonténer az elrendezendő konténer
@param pÖsszSzélesség az elrendezéshez felhasználandó szélesség
@param pÖsszMagasság az elrendezéshez felhasználandó magasság
@param pStartX az elrendezéshez felhasználandó vízszintes kezdőpozíció
@param pStartY az elrendezéshez felhasználandó függőleges kezdőpozíció
@param pMeretSzamolo a felhasználandó méretvisszaadó segédobjektum.
Megadásával az elrendezés csak szimulálva lesz.
@return Szimuláció esetén a konténer kiszámított mérete.
*/
private java.awt.Dimension elrendezés(java.awt.Container pKonténer,
int pÖsszSzélesség, int pÖsszMagasság, int pStartX, int pStartY,
MeretSzamolo pMeretSzamolo ) {
synchronized (pKonténer.getTreeLock()) { //szinkronizáció a konténerre
java.awt.Dimension viszonyítás = viszonyításiMéret( pKonténer );
int kezdőindex = 0; //első látható komponens indexe
int végindex = pKonténer.getComponentCount()-1; //és az utolsóé
while (végindex >= 0 &&
!pKonténer.getComponent(végindex).isVisible()) végindex--;
while (kezdőindex < végindex &&
!pKonténer.getComponent(kezdőindex).isVisible()) kezdőindex++;
java.awt.ComponentOrientation irány = //elrendezési irány
pKonténer.getComponentOrientation();
boolean sorba = irány.isHorizontal() && !függőleges;
boolean balróljobbra = irány.isLeftToRight();
java.awt.Component komponens = null; //aktuális komponens
int x = 0, y = 0; //aktuális helyzet
int szélesség = 0, magasság = 0; //komponens mérete
int igazítás=0, igazítás2=0; //aktuális elő- és utóigazítás
int maradék = 0; //a csoportban még megmaradt hely
boolean újrakezd = true; //kezdő értékek kérése
int elsőindex = kezdőindex;
for (int i = kezdőindex; i <= végindex; i++) {
if (újrakezd) { //kezdő értékek beállítása
x = pStartX + (balróljobbra ? 0 : pÖsszSzélesség);
y = pStartY;
igazítás = igazítás2 = 0;
maradék = sorba ? pÖsszSzélesség : pÖsszMagasság;
i = elsőindex = kezdőindex;
újrakezd = false;
}
komponens = pKonténer.getComponent(i);
if (!komponens.isVisible()) continue; //csak látható komponensek
Constraints jellemző = getConstraints( komponens );
float xarány = jellemző.getXarány();
float yarány = jellemző.getYarány();
java.awt.Dimension méret = null; //komponens minimális mérete
if (pMeretSzamolo!=null) {//szimulációkor teljes méretellenőrzés
méret = pMeretSzamolo.méret(komponens); //méret lekérése
if (xarány > 0) { //arány alapján a kívánt teljes szélesség
szélesség = (int)Math.ceil(méret.width/xarány);
if (szélesség > pÖsszSzélesség) { //ellenőrzése
pÖsszSzélesség = szélesség; //új szélesség esetén
újrakezd = true; //a szimuláció újraindítása
}
}
if (yarány > 0) { //arány alapján a kívánt teljes magasság
magasság = (int)Math.ceil(méret.height/yarány);
if (magasság > pÖsszMagasság) { //ellenőrzése
pÖsszMagasság = magasság; //új magasság esetén
újrakezd = true; //a szimuláció újraindítása
}
}
if (újrakezd) continue;//szimulációs elrendezés újraindítása
if (pMeretSzamolo!=MINIMUM) méret=null; //minimum megtartása
} //minimumméret
if (méret==null) méret=komponens.getMinimumSize(); //lekérdezése
szélesség=Math.max(Math.round((viszonyítás==null?pÖsszSzélesség:
viszonyítás.width)*xarány), méret.width);//arányos szélesség
magasság=Math.max(Math.round((viszonyítás==null ? pÖsszMagasság:
viszonyítás.height)*yarány),méret.height);//arányos magasság
int igazításipont = Math.round( sorba ? magasság * komponens.
getAlignmentY() : szélesség * komponens.getAlignmentX() );
if (maradék<(sorba?szélesség:magasság)&&i>elsőindex) { //csoport
if (pMeretSzamolo==null) //igazítása csak ha nem szimuláció
igazít(pKonténer, elsőindex, i-1, igazítás, igazítás2,
sorba, balróljobbra, maradék);
komponens = pKonténer.getComponent(i);
elsőindex = i; //új csoport kezdése
if (sorba) { //sorléptetés
x = pStartX + (balróljobbra ? 0 : pÖsszSzélesség);
y += igazítás+igazítás2+fhelykihagyás;
igazítás2 = magasság-igazításipont;
maradék = pÖsszSzélesség;
} else { //oszlopléptetés
if (balróljobbra) x += igazítás+igazítás2+vhelykihagyás;
else x -= igazítás+igazítás2+vhelykihagyás;
y = pStartY;
igazítás2 = szélesség-igazításipont;
maradék = pÖsszMagasság;
}
igazítás = igazításipont;
} else { //csoport folytatása
igazítás = Math.max(igazítás, igazításipont);
igazítás2 = Math.max(igazítás2,
(sorba ? magasság : szélesség)-igazításipont);
}
maradék-=sorba ? szélesség+vhelykihagyás:magasság+fhelykihagyás;
if (pMeretSzamolo!=null) continue; //szimuláció már mehet tovább
if (sorba) { //komponens soron belüli elhelyezése
if (balróljobbra) {
komponens.setBounds(x,y-igazításipont,szélesség,magasság);
x += szélesség+vhelykihagyás;
} else {
x -= szélesség+vhelykihagyás;
komponens.setBounds(x+vhelykihagyás, y-igazításipont,
szélesség, magasság);
}
} else { //komponens oszlopon belüli elhelyezése
komponens.setBounds(x-igazításipont, y, szélesség,magasság);
y += magasság+fhelykihagyás;
}
}
if (pMeretSzamolo!=null){//szimulációval kiszámolt méret visszaadása
igazítás += igazítás2;
if (sorba) pÖsszMagasság = Math.max( //utolsó sor
y+igazítás-pStartY, pÖsszMagasság );
else { //utolsó oszlop
if (!balróljobbra) x = pÖsszSzélesség - x;
pÖsszSzélesség=Math.max(pÖsszSzélesség, x+igazítás-pStartX);
}
return new java.awt.Dimension(pÖsszSzélesség, pÖsszMagasság);
}
igazít(pKonténer, elsőindex, végindex, igazítás, igazítás2,
sorba, balróljobbra, maradék); //maradékigazítás
}
return null;
}
/**
Egy csoportba tartozó konténerelemek igazítása a csoporton belül.
@param konténer az elemeket tartalmazó konténer
@param kezdőindex a csoport kezdő elemének indexe
@param végindex a csoport záró elemének indexe
@param igazítás igazítási pont feletti maximum méret
@param igazítás2 igazítási pont alatti maximum méret
@param sorba a csoport egy sor (igaz) vagy oszlop (hamis)
@param balróljobbra komponensek sorrendiségi irányultsága
@param maradék a csoport számára kiosztandó maradék terület mérete
*/
private void igazít(java.awt.Container konténer,int kezdőindex,int végindex,
int igazítás,int igazítás2,boolean sorba,boolean balróljobbra,int maradék){
maradék+=sorba ? vhelykihagyás : fhelykihagyás; //csoportigazítás
if (csoportigazítás<0) maradék = 0; //kiszámítása a maradék területre
else if (csoportigazítás==0) maradék /= 2;
int dx = sorba ? (balróljobbra ? maradék : -maradék) :
(balróljobbra ? igazítás : -igazítás2);
int dy = sorba ? igazítás : maradék;
for (int i=kezdőindex; i <= végindex; i++) { //igazítás csoporton belül
java.awt.Component komponens = konténer.getComponent(i);
if (komponens.isVisible())
komponens.setLocation(komponens.getX()+dx, komponens.getY()+dy);
}
}
/**
Megjelenítés érvénytelenítése.
@param pKonténer az elrendezett konténer
*/
public void invalidateLayout(java.awt.Container pKonténer) {}
}