# GUI-Komponenten skalieren



## Colt45 (8. Nov 2011)

Moin, ich habe eine GUI mit geschachtelten JSplitPanes (alles ohne LayoutManager) und möchte nun die einzelnen Komponenten darin beim Programmstart in Abhängigkeit des ParentContainers skalieren. Leider funktioniert setPreferredSize in dem Zusammenhang nicht.
Die Abhängigkeiten hab ich mir folgendermaßen berechnet:


```
int screenX = (int) this.getSize().getWidth();
int screenY = (int) this.getSize().getWidth();
Dimension mapSize = new Dimension((int) (screenX*(2/3)), screenY);
Dimension unitSize = new Dimension((int) (screenX*(1/6)), (int) (screenY*(2/3)));
Dimension missionSize = new Dimension((int) (screenX*(1/6)), (int) (screenY*(2/3)));
Dimension logSize = new Dimension((int) (screenX*(1/3)), (int) (screenY*(1/3)));
```

aussehen soll das dann wie folgt:






Hier noch der komplette Code, vllt. kann mir jemand weiterhelfen bzgl. des Verhaltens von JSplitPanes/JScrollPanes. (UnitPanel, MissionPanel, etc sind lediglich von JPanel abgeleitete Klassen und enthalten eine JList)
Danke shconmal...


```
public class ROCFrame extends javax.swing.JFrame 
{
	private JSplitPane jSplitPane1;
	private JSplitPane jSplitPane2;
	private JScrollPane logScroller;
	private JScrollPane missionScroller;
	private UnitPanel unitPanel;
	private MapPanel mapPanel;
	private MissionPanel missionPanel;
	private LogPanel logPanel;
	private JScrollPane unitScroller;
	private JSplitPane jSplitPane3;


	public ROCFrame() {
		super();
		initGUI();
	}
	
	private void initGUI() 
	{
		int screenX = (int) this.getSize().getWidth();
		int screenY = (int) this.getSize().getWidth();
		Dimension mapSize = new Dimension((int) (screenX*(2/3)), screenY);
		Dimension unitSize = new Dimension((int) (screenX*(1/6)), (int) (screenY*(2/3)));
		Dimension missionSize = new Dimension((int) (screenX*(1/6)), (int) (screenY*(2/3)));
		Dimension logSize = new Dimension((int) (screenX*(1/3)), (int) (screenY*(1/3)));
		
		try 
		{
			setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
			{
				jSplitPane1 = new JSplitPane();
				getContentPane().add(jSplitPane1, BorderLayout.CENTER);
				{
					jSplitPane2 = new JSplitPane();
					jSplitPane1.add(jSplitPane2, JSplitPane.RIGHT);
					jSplitPane2.setOrientation(JSplitPane.VERTICAL_SPLIT);
//     				jSplitPane2.setPreferredSize(new java.awt.Dimension(280, 266));
					{
						jSplitPane3 = new JSplitPane();
						jSplitPane3.setResizeWeight(0.5);
						jSplitPane2.add(jSplitPane3, JSplitPane.TOP);
						{
							missionScroller = new JScrollPane();
							jSplitPane3.add(missionScroller, JSplitPane.LEFT);
							{
								missionPanel = new MissionPanel();
								missionScroller.setViewportView(missionPanel);
								missionPanel.setPreferredSize(missionSize);
							}
						}
						{
							unitScroller = new JScrollPane();
							jSplitPane3.add(unitScroller, JSplitPane.RIGHT);
							{
								unitPanel = new UnitPanel();
								unitScroller.setViewportView(unitPanel);
								unitPanel.setPreferredSize(unitSize);
							}
						}
					}
					{
						logScroller = new JScrollPane();
						jSplitPane2.add(logScroller, JSplitPane.BOTTOM);
						{
							logPanel = new LogPanel();
							logPanel.setPreferredSize(logSize);
							logScroller.setViewportView(logPanel);
						}
					}
				}
				{
					mapPanel = new MapPanel();
					mapPanel.setPreferredSize(mapSize);
					jSplitPane1.add(mapPanel, JSplitPane.LEFT);
				}
			}
			pack();
			setSize(400, 300);
		} catch (Exception e) {
		    //add your error handling code here
			e.printStackTrace();
		}
	}
	
	public static void main(String[] args) 
	{
		SwingUtilities.invokeLater(new Runnable() 
		{
			public void run() 
			{
				ROCFrame inst = new ROCFrame();
				inst.setLocationRelativeTo(null);
				inst.setVisible(true);
				inst.setExtendedState(MAXIMIZED_BOTH);
			}
		});
	}
}
```


----------



## vanny (8. Nov 2011)

also da du in deinem Code nicht 
	
	
	
	





```
setLayout(null);
```
 stehen hast, benutzt dein JFrame sehr wohl einen LayoutManager (Default ist beim JFrame das BorderLayout).
Somit ignoriert er auch deine preferedSize (zumind. teilweise).
Wenn du also wirklich ohne LayoutManager arbeiten willst, dann benutze 
	
	
	
	





```
setBounds()
```
 auf deinen Komponenten um Position und Größe zu bestimmen.
Ich würde dir aber unterm Strich dringend vom NullLayout abraten tun //hihi

Gruß Vanny


----------



## Colt45 (9. Nov 2011)

Ja, mit NullLayout wollte ich auch nicht arbeiten, wegen der absoluten Werte, das hatte ich dann wohl nicht bedacht, dass ohne Angabe eines LayoutManagers automatisch null bzw. in dem Fall BorderLayout verwendet wird.
Hast du eine Idee, mit welchem LayoutManager ich das am besten lösen kann?
Ich dachte mir, vllt. dem JFrame ein Gridlayout(1,2) zu verpassen und dann den JSplitPanes jeweils auch ein Gridlayout mit der benötigten Anzahl an Spalten/Reihen zu geben. Die Frage ist halt, ob ein JSplitPane eine komplette Zelle füllt, oder ob die linke und rechte (bzw. obere und untere) Komponente jeweils eine Zelle füllen.


----------



## askk (9. Nov 2011)

Lad dir das TableLayout, super einfach zu bedienen und dein Layout ist damit wirklich leicht umzusetzen.

TableLayout


----------



## Gast2 (9. Nov 2011)

Jgoodies Forms Layout ist noch besser und einfacher. 

Dazu gibts auch nen tolles Tutorial.


----------



## askk (9. Nov 2011)

Das sollte ich mir dann vielleicht auch mal anschauen


----------



## vanny (9. Nov 2011)

Dein Layout lässt sich aber auch recht einfach mit den normalen Layouts lösen.

Die Map im CENTER des Frames, alles andere im EAST des Frames.
Dort dann wieder verschachteln, je nachdem, worauf du im Verhalten Wert legst.
Dann Benötigst du diese Startberechnung eigentlich gar nicht.

Kleiner Tipp: Ich leg mir erstmal immer einen Testframe an, mit Farbigen Panels um zu sehen, wie sich was verhält.

Gruß Vanny


----------



## Colt45 (9. Nov 2011)

JA das dachte ich mir auch, dass das mit den normalen LayoutManagern gehen muss, das Problem is nur, dass ich JSplitPanes verwende und sowas wie

```
jSplitPane.setLeftComponent(BorderLayout.CENTER)
```
funktioniert leider nicht.
Ich hab auch schon sowas hier probiert:

```
BorderLayout thisLayout = new BorderLayout();
			setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
			getContentPane().setLayout(thisLayout);
			{
				leftPanel = new JPanel();
				getContentPane().add(leftPanel, BorderLayout.CENTER);
				leftPanel.setBackground(Color.BLUE);
			}
			{
				rightPanel = new JPanel();
				getContentPane().add(rightPanel, BorderLayout.EAST);
				rightPanel.setBackground(Color.RED);
			}
			{
				splitPane = new JSplitPane();
				splitPane.setLeftComponent(leftPanel);
				splitPane.setRightComponent(rightPanel);
				add(splitPane);
				doLayout();				
			}
```

allerdings auch ohne den gewünschten Effekt.

JGoodiesForms und TableLayout hören sich interessant an, werd ich mir mal anschaun, aber für diesen simplen Zweck muss es doch eine simple Lösung geben...


----------



## vanny (10. Nov 2011)

Die erste Frage, dir ich mir da stelle ist: Wozu benötigst du die SplitPanes?
(Ich weiß wozu sie gut sind aber was bezweckst du in deinem speziellen Fall damit?)
Ich kann leider dem Screenshot nicht wirklich entnehmen, wie die Infos rechts geplant sind.

Generell denke ich aber, dass du, solange die Listen nicht zu pompös aufgezogen und befüllt werden müssen, auch ganz gut ohne die SplitPanes auskommen würdest (sollte aber auch mit Splitpanes gehen).

Was dein letztes Beispiel angeht fehlt entweder entscheidender Code, damit das Sinn macht oder du hast da noch nen Denkfehler drinn.

Wenn ich nicht gleich einfach einschlafe, bastel ich ma noch n Beispiel.

Gruß Vanny

So:


```
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.GridLayout;

import javax.swing.JFrame;
import javax.swing.JPanel;

public class DerFrame extends JFrame{
	
	private JPanel panCenter, panRight, subPanTop, subPan1, subPan2, subPan3;
	
	public DerFrame(){
		super("TestFrame");
		this.setDefaultCloseOperation(EXIT_ON_CLOSE);
		this.setSize(500, 500);
		this.setLocationRelativeTo(null);
		
		initWidgets();
		addWidgets();
		
		this.setVisible(true);
	}

	private void initWidgets() {
		panCenter = new JPanel();
			panCenter.setBackground(Color.YELLOW);
		panRight = new JPanel();
			panRight.setLayout(new BorderLayout(0, 0));
			panRight.setBackground(Color.PINK);
			
		subPanTop = new JPanel();
			subPanTop.setLayout(new GridLayout(1, 2));
			subPanTop.setBackground(Color.BLACK);
		
		subPan1 = new JPanel();
			subPan1.setBackground(Color.RED);
		subPan2 = new JPanel();
			subPan2.setBackground(Color.BLUE);
		subPan3 = new JPanel();
			subPan3.setBackground(Color.GREEN);
	}

	private void addWidgets() {
		subPanTop.add(subPan1);
		subPanTop.add(subPan2);
		
		panRight.add(BorderLayout.NORTH, subPanTop);
		panRight.add(subPan3);
		
		this.add(panCenter);
		this.add(BorderLayout.EAST, panRight);
	}

}
```

Wenn du jetzt Content-Komponenten in die subPanel 1-3 einfügst, haben die immer die benötigte Größe und der übrige Platz steht dem panCenter (also deiner Karte) zur Verfügung.

preferedSize sollte damit auch funktionieren  und auch die SplitPane lässt sich dort einfügen.

Natürlich gibt es je nachdem, was du erreichen möchtest noch andere Kombinations- / Verschachtelungsmöglichkeiten aber ich hoffe das Prinzip wird klar.


----------



## Colt45 (10. Nov 2011)

Die JSplitPanes brauch ich deswegen, dass der Benutzer sich seine einzelnen Panels nach Belieben zusammenschieben kann, da der Inhalt variabel ist von der Größe bzw. Breite.
Ich habs aber in der Zwischenzeit anders gelöst und zwar mit setResizeWeight(). Is vllt. nich der schönste Weg, aber das Ergebnis is zufriedenstellend und es sind keine absoluten Werte drin.
Trotzdem danke an alle...
Mal so ne Frage am Rande: Das is das erste Mal, dass ich ne größere Applikation schreib. Macht es denn Sinn, z.B. ne GUI-Controller-Klasse zu schreiben, die die ganzen Komponenten zusammenbaut und initialisiert anstatt die alle in der Frame-Klasse zu initialisieren?


----------



## vanny (10. Nov 2011)

Es macht zumind. Sinn, die Container, welche mehrere Standardkomponenten halten zu wrappen und dann nur noch diese in der nächst höheren Ebene zu initialisieren.

Ob man nun eine ControllerKlasse benötigt hängt wohl vom Projekt und vom Geschmack ab.

Gruß Vanny


----------

