Gui - Grundsätzliche Programmierung

  • Themenstarter Themenstarter Wes
  • Beginndatum Beginndatum
Status
Nicht offen für weitere Antworten.
W

Wes

Gast
Hab vor kurzem angefangen mich mit diesen Gui-Kram zu beschäftigen.
Kurz gesagt: Es ist grässlich, jedes Tutorial macht das anders und stellen fast nur die Grundlagen der Grundlagen dar oder springen sofort in den ( für mich ) Hardcore-Bereich.
Daher frage ich mal hier nach.
1. Wie schreibe ich guten Gui-Code. Mein Beispiel folgt - nehme gerne Vorschläge wegen Strukturierung und Variablen an, z.B. ob es besser wäre das Haupt-JFrame zu einer privaten Klassenvariable zu machen oder zu einer lokalen Variable des Konstruktors.
2. Warum wird meine Größenangabe zum Button nicht angenommen.
3.Wofür ist dieses pack() da? Wenn ich es mache sind die Größeneinstellungen des JFrame weg.

Code:
package grafik;
import javax.swing.*;
import java.awt.*;
public class Hauptbildschirm 
{
	//VARIABLEN----------------------------------------------------
	
	int bildschirmbreite,bildschirmhoehe;
	
	//KONSTRUKTOR--------------------------------------------------
	
	public Hauptbildschirm()
	{
		//JFrame
		JFrame brett = new JFrame("Go for");
		bildschirmbreite = Toolkit.getDefaultToolkit().getScreenSize().width;
		bildschirmhoehe = Toolkit.getDefaultToolkit().getScreenSize().height;
		brett.setSize(Math.round(this.bildschirmbreite/2),Math.round(this.bildschirmhoehe/2));
		brett.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		
		//Komponenten
		JButton test = new JButton("test");
			test.setLocation(10,10);
			test.setSize(100,200);
		
		brett.getContentPane().add(test);
		brett.setVisible(true);
	};
	
	//METHODEN-----------------------------------------------------
};

mfg Wes
 
1. Wie schreibe ich guten Gui-Code. Mein Beispiel folgt - nehme gerne Vorschläge wegen Strukturierung und Variablen an, z.B. ob es besser wäre das Haupt-JFrame zu einer privaten Klassenvariable zu machen oder zu einer lokalen Variable des Konstruktors.
An sich baut man eine Hauptfenster- Klasse, die von JFrame erbt und platziert alles andere auf dieser.

2. Warum wird meine Größenangabe zum Button nicht angenommen.
3.Wofür ist dieses pack() da? Wenn ich es mache sind die Größeneinstellungen des JFrame weg.

Beides hat mit dem LayoutManager zu tun. Dieser Manager hilft dir dabei, die Komponenten im Fenster zu platzieren. Es gibt für verschiedene Zwecke unterschiedliche Manager. Der einfachste ist das "FlowLayout", dass die Komponenten einfach setzt und eine neue Zeile anfängt, wenn das Fenster zu schmal wird.
Dann gibt es noch ein "GridLayout", dass deine Komponents wie in einer Tabelle anordnet usw. (Welche es noch gibt und wie sie funktionieren, wirst du dir wohl doch in irgendeinem Tutorial angucken müssen).
Mit JFrame.getContentPane().setLayoutManager(new WasAuchImmerLayout()) kannst du einstellen, welcher verwendet werden soll. Standardmäßig verwendet das JFrame ein FlowLayout.
Dein Button wird also sobald du ihn zum JFrame addest (Zeile 26) dem LayoutManager gezeigt, der sagt: "Oh, schön, stell es da hin" und überschreibt deine Einstellungen für Höhe und Breite sowie die Position. Deshalb sind die Einstellungen im Button weg.

Auch das pack() hat mit dem Manager zu tun. Hier fragt das Fenster den Manager, wie viel Platz die Komponenten den Brauchen und nimmt dann diese Größe an. Deshalb wird dein Fenster kleiner, wenn du pack() machst.

Auf Dauer solltest du lernen, die LayoutManager einzusetzen. Nur so kann deine Anwendung flexibel reagieren, falls sie plötzlich auf einem kleineren Bildschirm läuft. Komponenten mit absolut gesetzten Koordinaten verschwinden dabei gerne hinter den Bildschirmrändern. LayoutManager bringen alles irgendwie unter.
Für den Anfang, um zu begreifen, wie GUI funktioniert, kann es hilfreich sein, den LayoutManager abzuschalten. Das geht, indem du der oben genannten setLayoutManager- Methode null übergibst. Das ist allerdings nur eine Notlösung, für professionelle Programme ist das kaum geeignet.
 
Vielen Dank für die Antwort.
Inzwischen haben sich jedoch ein paar neue Fragen ergeben.

Aktueller Codestand:
Code:
package grafik;
import javax.swing.*;
import java.awt.*;
public class Hauptbildschirm 
{
	//VARIABLEN----------------------------------------------------
	
	JFrame haupt;
	
	//KONSTRUKTOR--------------------------------------------------
	
	public Hauptbildschirm(String pfad,int linien)
	{
		//JFrame
		haupt = new JFrame("Go for");
		haupt.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		
		//Komponenten
		JLabel brett = new JLabel(new ImageIcon(pfad + "\\Images\\brett_" + linien + ".png"));
		JButton test = new JButton("test");
		haupt.getContentPane().add(brett);
		haupt.add(test);
		
		haupt.pack();
		haupt.setVisible(true);
	};
	
	//METHODEN-----------------------------------------------------
};
1. Wo ist der Unterschied zwischen .getContentPane().add und einem einfachen .add()
2. Wenn ich das so ausführe wird nur der Button angezeigt, vertausche ich aber die Parameter der beiden add-Prozeduren so wird das Bild angezeigt.
 
Wes hat gesagt.:
1. Wo ist der Unterschied zwischen .getContentPane().add und einem einfachen .add()
2. Wenn ich das so ausführe wird nur der Button angezeigt, vertausche ich aber die Parameter der beiden add-Prozeduren so wird das Bild angezeigt.

Ein JFrame ist standardmässig schon mit Components gefüllt.
Unter anderem auch die ContentPane, in die du normalerweise deinen Inhalt packen solltest. (getContentpane().add())
machst du einfach JFrame.add(), wird der ContentPane-Inhalt davon überdeckt.
 
Wes hat gesagt.:
1. Wo ist der Unterschied zwischen .getContentPane().add und einem einfachen .add()
JFrame#add ist lediglich eine Abkürzung von JFrame#getContenPane().add,
beide Schreibweisen sind gleichwertig, erstere funktioniert aber erst seit Java 1.5.

Wes hat gesagt.:
2. Wenn ich das so ausführe wird nur der Button angezeigt,
vertausche ich aber die Parameter der beiden add-Prozeduren so wird das Bild angezeigt.
Standardmäßig verwendet das JFrame ein BorderLayout (nicht FlowLayout, wie Campino irrtümlich schrieb).
BorderLayout hat 5 Bereiche: CENTER und einen an jeder Seite. Wenn man im add(..) keinen Bereich angibt,
ist CENTER gemeint. Im CENTER kann aber nur eine einzige Komponente sein.
Darum ist von deinen beiden add(..) Aufrufen immer nur der letzte wirksam.
Siehe auch: Using Layout Managers
 
Danke für die Antworten.
Diese Layouts sind zwar ganz nett, aber ich bekomme meine Idee mit keiner der vorhandenen hin.
Das hier ist die Vorstellung:


Jedoch scheinen mir ( auch nach bissl rumtesten ) alle Layouts untauglich dafür.
 
Du kannst Layouts verschachteln

Also in deinem Bsp:

"Links" wäre dein Center vom BorderLayout (West bleibt leer und wird quasi ignoriert)
"Rechts" wäre dein East vom BorderLayout, in das du ein JPanel addest.
Dieses JPanel wiederrum kannst du ebenfalls einen LayoutManager verpassen.
Wieder Borderlayout, North, Center, South usw.

Oder du benutzt GridBagLayout, welches grade am Anfang doch sehr schwer verdaulich ist 😉

Generell solltest du dir halt erstmal das Sun-Tutorial anschauen, welches oben schon verlinkt wurde.
 
Code:
BorderLayout
|
|__CENTER
|  |
|  |__[Bild]
|
|__EAST
   |
   |__BorderLayout
      |
      |__NORTH
      |  |
      |  |__GridLayout
      |     |
      |     |__[Label 1]
      |     |
      |     |__[Label 2]
      |     |
      |     |__[Label 3]
      |     |
      |     |__[Label 4]
      |     |
      |     |__[Label 5]
      |     |
      |     |__[Label 6]
      |
      |__SOUTH
         |
         |__GridLayout
            |
            |__[Button 3]
            |
            |__[Button 2]
            |
            |__[Button 1]
So würde ich das umsetzen.

Ark
 
Das ganze könnte z.B. so aussehen

Code:
package de;

import java.awt.BorderLayout;
import java.awt.GridLayout;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class TestGUI extends JFrame {
	private JPanel bildPanel, navigationPanel, labelPanel, buttonPanel;

	public TestGUI() {
		getContentPane().setLayout(new BorderLayout());
		bildPanel = createBildPanel();
		navigationPanel = createNavigationPanel();
		labelPanel = createLabelPanel();
		buttonPanel = createButtonPanel();
		this.add(bildPanel, BorderLayout.CENTER);
		this.add(navigationPanel, BorderLayout.EAST);
		navigationPanel.add(labelPanel, BorderLayout.NORTH);
		navigationPanel.add(buttonPanel, BorderLayout.SOUTH);
		setSize(400, 300);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setVisible(true);

	}

	private JPanel createButtonPanel() {
		JPanel panel = new JPanel();
		panel.setLayout(new GridLayout(0, 1));
		for (int i = 0; i < 3; i++) {
			panel.add(new JButton("Button " + (i + 1)));
		}

		return panel;
	}

	private JPanel createLabelPanel() {
		JPanel panel = new JPanel();
		panel.setLayout(new GridLayout(0, 2));
		for (int i = 0; i < 6; i++) {
			panel.add(new JLabel("Label " + (i + 1)));
		}
		return panel;
	}

	private JPanel createNavigationPanel() {
		JPanel panel = new JPanel();
		panel.setLayout(new BorderLayout());

		return panel;
	}

	private JPanel createBildPanel() {
		// TODO Auto-generated method stub
		JPanel panel = new JPanel();
		panel.add(new JLabel("Bild"));
		return panel;
	}

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		SwingUtilities.invokeLater(new Runnable() {
			public void run() {
				new TestGUI();
			}

		});
	}

}
 
Ich stimmte args tree zu und würds so amchen

Code:
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.Toolkit;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;


public class BspGUI extends JFrame{
	
	private int breite, hoehe;
	
	private JPanel main, side;
	private JPanel sideHead, sideFoot;
	
	private JLabel Label1,Label2,Label3,Label4,Label5,Label6;
	private JButton Button1, Button2, Button3;
	
	public BspGUI(){
		//Fenstereinstellungen
		breite = (int)Math.round(Toolkit.getDefaultToolkit().getScreenSize().width / 2); 
		hoehe = (int)Math.round(Toolkit.getDefaultToolkit().getScreenSize().height / 2); 
		this.setPreferredSize(new Dimension(breite, hoehe));
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
		this.setLayout(new BorderLayout());
		
		//Pannels
		main = new JPanel();
		side = new JPanel();
		sideHead = new JPanel();
		sideFoot = new JPanel();
		
		side.setLayout(new BorderLayout());
		sideHead.setLayout(new GridLayout(6,1));
		sideFoot.setLayout(new GridLayout(3,1));
		
		//Labels
		Label1 = new JLabel("Label 1");
		Label2 = new JLabel("Label 2");
		Label3 = new JLabel("Label 3");
		Label4 = new JLabel("Label 4");
		Label5 = new JLabel("Label 5");
		Label6 = new JLabel("Label 6");
		
		//Buttons
		Button1 = new JButton("Button 1");
		Button2 = new JButton("Button 2");
		Button3 = new JButton("Button 3");
		
		//Alles zusammen manschen
		this.add(main, BorderLayout.CENTER);
		this.add(side, BorderLayout.EAST);
		
		side.add(sideHead,BorderLayout.NORTH);
		sideHead.add(Label1);
		sideHead.add(Label2);
		sideHead.add(Label3);
		sideHead.add(Label4);
		sideHead.add(Label5);
		sideHead.add(Label6);
		
		side.add(sideFoot,BorderLayout.SOUTH);
		sideFoot.add(Button1);
		sideFoot.add(Button2);
		sideFoot.add(Button3);
		
		//sonstiges
		this.pack();
		this.setVisible(true);
		
	}
	
	public static void main(String[] args) {
		new BspGUI();
	}
}

müsste eigentlich das sein was gesucht ist, habs aber nru hier rein geschrieben und nicht getestet.
 
Danke für die Antworten.
Eure Beispiele funktionieren gut, ich habe es vorher ein bisschen anders gemacht bei gleichem Ergebnis und werde daher doch vorerst bei meinem bleiben.

Ich glaube sowieso das ich das alles später nochmal umwerfen muss 😉
 
jops mach das
ich mach auch immer lieber alles selber als abzuschreiben
aber vergleichen und dann verbessern tu ich auch gerne ^^
 
Status
Nicht offen für weitere Antworten.

Neue Themen


Zurück
Oben