GUI-Komponenten skalieren

Colt45

Aktives Mitglied
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:

Java:
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:
290r8lv.png


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...

Java:
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);
			}
		});
	}
}
 
also da du in deinem Code nicht
Code:
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
Code:
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
 
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.
 
Jgoodies Forms Layout ist noch besser und einfacher.

Dazu gibts auch nen tolles Tutorial.
 
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
 
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
Java:
jSplitPane.setLeftComponent(BorderLayout.CENTER)
funktioniert leider nicht.
Ich hab auch schon sowas hier probiert:
Java:
	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...
 
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:

Java:
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.
 
Zuletzt bearbeitet von einem Moderator:
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?
 
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
 

Zurück
Oben