Forum: PC-Programmierung Java BoxLayout - Größenverhältnis behalten


von javalie (Gast)


Lesenswert?

Hi Leute,

ich versuche mich gerade an Java mit Visual Studio Code. Geht auch ganz 
gut. Ich möchte gerne eine Oberfläche gestalten, die 3 Panels 
nebeneinander hat, und die Breite der 3 Panels soll immer im Verhältnis 
1 : 3 : 1 sein (Später kommen da Konponenten rein, in der Mitte ein 
großes Bild und rechts und links verschiedene Werkzeuge)

Das funktioniert auch mit diesem Code, aber nur, bis ich Komponenten in 
die Panels einfüge - dann ändern die Panels aus unerfindlichen Gründen 
ihre Breite - warum? Also wenn man die Zeile mit dem JLabel unten 
auskommentiert, passt alles. Sollte man dieses Breitenverhältnis anders 
(wie?) herbeiführen?

Code:
1
import javax.swing.*;
2
import java.awt.*;
3
4
public class AlngTest {
5
    public static void main(String[] args) throws Exception {
6
7
        // Creating and fill a panel and 3 inside with width-ratio 1:3:1
8
        JPanel panel_ml = new JPanel();
9
        JPanel panel_mm = new JPanel();
10
        JPanel panel_mr = new JPanel();
11
        panel_ml.setBackground(Color.BLUE);
12
        panel_mm.setBackground(Color.YELLOW);
13
        panel_mr.setBackground(Color.RED);
14
        panel_ml.setPreferredSize(new Dimension(2000, 0));
15
        panel_mm.setPreferredSize(new Dimension(6000, 0));
16
        panel_mr.setPreferredSize(new Dimension(2000, 0));
17
18
        JPanel panel_m = new JPanel();
19
        panel_m.setLayout(new BoxLayout(panel_m, BoxLayout.LINE_AXIS));
20
        panel_m.add(panel_ml);
21
        panel_m.add(panel_mm);
22
        panel_m.add(panel_mr);
23
24
        JFrame frame = new JFrame("Test");
25
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
26
        frame.setSize(800, 600);
27
        frame.getContentPane().add(BorderLayout.CENTER, panel_m);
28
29
        // see and get the original dimensions
30
        frame.setVisible(true);
31
        System.out.println(panel_mr.getWidth());
32
33
        panel_mr.add(new JLabel("Why this?"));
34
35
        // update / show again to see the change
36
        frame.setVisible(true);
37
        System.out.println(panel_mr.getWidth());
38
39
    }
40
}

von Schleimfasten (Gast)


Lesenswert?

javalie schrieb:
> Das funktioniert auch mit diesem Code, aber nur, bis ich Komponenten in
> die Panels einfüge - dann ändern die Panels aus unerfindlichen Gründen
> ihre Breite - warum?
Der Layoutmanager der per Default eingestellt ist, pfuscht dir hier 
dazwischen. pack() haste vergessen.

Die PreferredSize ist nicht verbindlich und hier auch völlig überflüssig 
wenn du das Fenster resizesed ist das Verhältnis sowieso dahin.

Wenn man es richtig macht:
Entweder du schreibts dir einen eigenen Layoutmanager oder reagierst auf 
das Resizeevent des Fensters und positionierst die Panel entspr. neu, 
was praktisch auf das selbe hinausläuft: du musst das selber 'sizen'.

von Schleimfasten (Gast)


Lesenswert?

Hier wird GridBagLayout empfohlen, damit kann man die Breiten gewichten, 
dann entfällt das manuelle nachjustieren bei einem Fensterresize.

https://stackoverflow.com/questions/12267311/java-swing-borderlayout-resize-difficulties

von javalie (Gast)


Lesenswert?

Schleimfasten schrieb:

> Die PreferredSize ist nicht verbindlich und hier auch völlig überflüssig
> wenn du das Fenster resizesed ist das Verhältnis sowieso dahin.

Also bei mir funktioniert das (wenn man die zeile mit dem JLabel 
auskommentiert) - bei Dir nicht?

Schleimfasten schrieb:
> pack() haste vergessen.

Was macht das (besser?)

Schleimfasten schrieb:
> reagierst auf
> das Resizeevent des Fensters und positionierst die Panel entspr. neu

Na ich dachte halt es geht eleganter. Und mir ist auch nicht klar, warum 
das rechte Panel mit dem Label größer wird - denn es ist ja genug Platz 
da?

von javalie (Gast)


Lesenswert?

Schleimfasten schrieb:
> Hier wird GridBagLayout empfohlen

Ah danke, das werde ich testen, sieht sehr passend aus!

von Schleimfasten (Gast)


Lesenswert?

javalie schrieb:
> Also bei mir funktioniert das (wenn man die zeile mit dem JLabel
> auskommentiert) - bei Dir nicht?
Das rechte Panel ist grösser. Dass Elemente nach dem Start nicht ganz
in Position sind kann vorkommen, deshalb ruft man pack am Ende auf wenn 
man alles in die ContentPane geworfen hat.

> Schleimfasten schrieb:
>> pack() haste vergessen.
> Was macht das (besser?)
Es ordnet die Componenten neu an wie man es eingestellt hat, 
(preferredSize, ...), bzw. versucht es, je nachdem wie gross das Fenster 
ist und die Werte eingestellt sind. Das geht dann eben manchmal schief. 
Nach dem Start ruft man deshalb nochmal pack auf, das ordnet die Element 
nochmal explizit an.

Bei mir ist nach einfügen von pack() alles korrekt, nach Verändern der 
Grösse des Fensters stimmt es aber nicht mehr.

>> reagierst auf
>> das Resizeevent des Fensters und positionierst die Panel entspr. neu
>
> Na ich dachte halt es geht eleganter. Und mir ist auch nicht klar, warum
> das rechte Panel mit dem Label größer wird - denn es ist ja genug Platz
> da?

Oh man jetzt weiss ich woran es liegt: an deinem Text. Wenn das Fenster 
zu schmal wird wird der rechte Panel soweit skaliert damit das JPanel 
sichtbar ist.

Hier kannst du prüfen wie die Breite immer ist, ohne das Jpanel mit dem 
Text,
ist immer gleich gross:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class ATest {

    public static void main(String[] args) throws Exception {

        // Creating and fill a panel and 3 inside with width-ratio 1:3:1
        JPanel panel_ml = new JPanel();
        JPanel panel_mm = new JPanel();
        JPanel panel_mr = new JPanel();

        panel_ml.setBackground(Color.BLUE);
        panel_mm.setBackground(Color.YELLOW);
        panel_mr.setBackground(Color.RED);

        panel_ml.setPreferredSize(new Dimension(100, 100));
        panel_mm.setPreferredSize(new Dimension(600, 100));
        panel_mr.setPreferredSize(new Dimension(100, 100));

        JPanel panel_m = new JPanel();

        panel_m.setLayout(new BoxLayout(panel_m, BoxLayout.LINE_AXIS));
        //panel_m.setLayout(new BoxLayout(panel_m));

        panel_m.add(panel_ml);

        panel_m.add(panel_mm);

        panel_m.add(panel_mr);

        JFrame frame = new JFrame("Test");

        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        frame.setSize(800, 600);

        frame.getContentPane().add(BorderLayout.CENTER, panel_m);

        // see and get the original dimensions
        frame.setVisible(true);

        System.out.println(panel_mr.getWidth());

        //panel_mr.add(new JLabel(this?"));


        frame.getRootPane().addComponentListener(new ComponentAdapter() 
{
            public void componentResized(ComponentEvent e) {
                // This is only called when the user releases the mouse 
button.
                System.out.println("links  dim:" + panel_ml.getSize());
                System.out.println("mitte  dim:" + panel_mm.getSize());
                System.out.println("rechts dim:" + panel_mr.getSize());
                System.out.println();

            }
        });

        // update / show again to see the change
        frame.pack();
        frame.setVisible(true);
        System.out.println(panel_mr.getWidth());

        System.out.println(panel_mr.getWidth());

    }
}

Da musst du evt. noch mit prefferedSize für das JPanel experimentieren
oder evt. nochmal in das rechte panel einen Layoutmanger reinpacken.

Wenn das alles komplexer wird, würde ich netbeans nehmen das hat einen 
guten Swing GUI
Editor wo du das alles zusammenklicken kannst. Dort nimmt man dann auch 
SpringLayout,
da siehst du dann grafisch wie was ausgerichtet wird anhand der 
"Federn".
Das ist sonst pain in the ass das alles von Hand zu codieren.

von javalie (Gast)


Lesenswert?

Ich habe mir jetzt ein Beispiel aus Gridbaglayouts zusammengestellt. Das 
funktioniert schon eher so, wie eich es gerne hätte, allerdings nur, 
wenn man das Fenster größer zieht, und noch schlechter, wenn man die 
volle Höhe verwenden will? (Siehe unten). Ich möchte die Layouts gerne 
verstehen, aber sie verhalten sich seltsam, oder mir fehlt noch ein 
Stück Wissen.

Also Quelltext siehe unten: Wenn ich den starte und das Fenster größer 
ziehe, sieht es ok aus, aber nicht, wenn ich es über einen gewissen 
Punkt hinaus wieder verkleinere, und nciht am Anfang.. was fehlt? Ist 
das bei Euch auch so?
1
import java.awt.BorderLayout;
2
import java.awt.Color;
3
import java.awt.Dimension;
4
import java.awt.EventQueue;
5
import java.awt.GridBagConstraints;
6
import java.awt.GridBagLayout;
7
import java.awt.event.ComponentAdapter;
8
import java.awt.event.ComponentEvent;
9
import javax.swing.BorderFactory;
10
import javax.swing.JFrame;
11
import javax.swing.JLabel;
12
import javax.swing.JPanel;
13
14
public class Example2 {
15
16
    private int fw = 800;
17
    private int fh = 600;
18
19
    public Example2() {
20
21
        JPanel parentPanel = new JPanel(new GridBagLayout());
22
        parentPanel.setBorder(BorderFactory.createLineBorder(Color.BLACK));
23
24
        GridBagConstraints gbc = new GridBagConstraints();
25
        gbc.fill = GridBagConstraints.BOTH;
26
        gbc.weighty = 1;
27
        gbc.weightx = 1;
28
        gbc.gridheight = 1;
29
        gbc.gridy = 0;
30
31
        gbc.gridx = 0;
32
        JPanel p1 = createChildPanel(1);
33
        parentPanel.add(p1, gbc);
34
        gbc.gridx = 1;
35
        JPanel p2 = createChildPanel(2);
36
        parentPanel.add(p2, gbc);
37
        gbc.gridx = 2;
38
        JPanel p3 = createChildPanel(3);
39
        parentPanel.add(p3, gbc);
40
41
        JFrame frame = new JFrame();
42
        frame.addComponentListener(new ComponentAdapter() {
43
            @Override
44
            public void componentResized(ComponentEvent e) {
45
                fw = (int) e.getComponent().getSize().getWidth();
46
                fh = (int) e.getComponent().getSize().getHeight();
47
                System.out.println("fw=" + fw);
48
            }
49
        });
50
51
        frame.getContentPane().setLayout(new GridBagLayout());
52
        frame.getContentPane().add(parentPanel);
53
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
54
        frame.setSize(fw, fh);
55
        frame.setVisible(true);
56
    }
57
58
    private JPanel createChildPanel(int number) {
59
        JPanel panel = new JPanel(new BorderLayout()) {
60
            @Override
61
            public Dimension getPreferredSize() {
62
                int w = fw / 5;
63
                int h = fh;
64
                System.out.println("w=" + w);
65
                if(number==2){return new Dimension(w*3, w);} else {return new Dimension(w, w);}
66
            }
67
        };
68
69
        JPanel addPanel = new JPanel();
70
        addPanel.setBorder(BorderFactory.createMatteBorder(1, 0, 1, 0, Color.LIGHT_GRAY));
71
72
        JLabel label = new JLabel(String.valueOf(number));
73
        label.setHorizontalAlignment(JLabel.CENTER);
74
75
        panel.setBorder(BorderFactory.createLineBorder(Color.GRAY));
76
        panel.add(label, BorderLayout.NORTH);
77
        panel.add(addPanel);
78
        return panel;
79
    }
80
81
    public static void main(String[] args) {
82
        EventQueue.invokeLater(new Runnable() {
83
            @Override
84
            public void run() {
85
                new Example2();
86
            }
87
        });
88
    }
89
90
}

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.