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 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) {} }