JPanels auf gleicher Höhe (Y-Achse) in einem FlowLayout platzieren

Exolution

Mitglied
Guten Abend zusammen,

ich komme derzeit bei diesem doch recht "lächerlichem" Problem nicht weiter und möchte hiermit um eure Hilfe bitten.

Zum Problem:
Ich habe mehrere JPanels, alle von denen haben eine unterschiedliche Größe, da jedes JPanel eine unterschiedliche Anzahl an JLabels hat.
Wenn ich diese JPanels jetzt einem JPanel zuordne, welches als Layout den FlowLayout nutzt, dann reihen sich alle schön zentiert in der X-Achse ein, soweit so gut.
Da aber die JPanels alle eine unterschiedliche Größe besitzten, kommt es zum Problem:
Die kleineren JPanels zentrieren sich in der Y-Achse mittig zum größten JPanel im FlowLayout, jedoch möchte ich, dass die kleineren JPanels sich alle oben anordnen, genauso wie der größte JPanel.

Ich habe zwei Bild angehangen, einmal der IST-Zustand und der SOLL-Zustand.
Ich hätte gerne das die Labels trotz unterschiedlicher Größe auf gleicher Höhe sind (Siehe Bild 2), wie erziele ich das gewünschte Ergebnis?

MfG Exolution

Der Code:

Java:
public class Problem {

    public static void main(String[] args) {

        JFrame frame = new JFrame();
        frame.setSize(1300, 700);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setResizable(false);
        frame.getContentPane().setBackground(Color.RED);
        
            JPanel maincontent = new JPanel();
            maincontent.setBorder(BorderFactory.createEmptyBorder(25, 25, 25, 25));
            maincontent.setBackground(Color.GREEN);
            maincontent.setSize(1275, 675);
            maincontent.setLayout(new GridLayout());
        
                JPanel mainpanel = new JPanel();
                mainpanel.setLayout(new FlowLayout(FlowLayout.CENTER, 30, 0));
        
                JPanel content1 = new JPanel();
                content1.setLayout(new GridBagLayout());
                GridBagConstraints gbc = new GridBagConstraints();
                gbc.gridx = 0;
                gbc.anchor = gbc.NORTHWEST;
                for (int i = 0; i < 10; i++) {
                    gbc.gridy = i;
                    content1.add(new JLabel("Label: " + (i+1)), gbc);
                }
                
            mainpanel.add(content1);
        
                JPanel content2 = new JPanel();
                content2.setLayout(new GridBagLayout());
                GridBagConstraints gbc2 = new GridBagConstraints();
                gbc2.gridx = 0;
                gbc2.anchor = gbc2.NORTHWEST;
                for (int i = 0; i < 15; i++) {
                    gbc2.gridy = i;
                    content2.add(new JLabel("Label: " + (i+1)), gbc2);
                }
                
            mainpanel.add(content2);
        
        maincontent.add(mainpanel);
        
    frame.getContentPane().add(maincontent);
    frame.setVisible(true);

    }

}
 

Anhänge

  • Screenshot (272).png
    Screenshot (272).png
    20,6 KB · Aufrufe: 4
  • Screenshot (273).png
    Screenshot (273).png
    16,4 KB · Aufrufe: 9
Dein Code ein wenig umgebaut funktioniert. Statt FlowLayout mit GridBagLayout.
[CODE lang="java" title="StartProblem"]import java.awt.Color;
import javax.swing.JFrame;

public class StartProblem {
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setSize(1300, 700);
frame.add(new Problem(1275, 675));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(false);
frame.getContentPane().setBackground(Color.RED);
frame.pack();
frame.setVisible(true);
}
}[/CODE]

[CODE lang="java" title="Problem" highlight="17-26"]import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import javax.swing.BorderFactory;
import javax.swing.JPanel;

@SuppressWarnings("serial")
public class Problem extends JPanel {
public Problem(int width, int height) {
setPreferredSize(new Dimension(width, height));
setBorder(BorderFactory.createEmptyBorder(25, 25, 25, 25));
setBackground(Color.GREEN);
setLayout(new GridLayout());
JPanel mainpanel = new JPanel();
mainpanel.setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.anchor = GridBagConstraints.PAGE_START;
gbc.gridx = 0;
gbc.weighty = 1;
gbc.ipadx=20;
mainpanel.add(new LabelListPanel(10),gbc);
gbc.gridx = 1;
mainpanel.add(new LabelListPanel(15),gbc);
add(mainpanel);
}
}[/CODE]
[CODE lang="java" title="LabelListPanel vermeidet doppelten Code"]import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import javax.swing.JLabel;
import javax.swing.JPanel;

@SuppressWarnings("serial")
public class LabelListPanel extends JPanel {
public LabelListPanel(int num) {
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.anchor = GridBagConstraints.NORTHWEST;
for (int i = 0; i < num; i++) {
gbc.gridy = i;
add(new JLabel("Label: " + (i + 1)), gbc);
}
}
}[/CODE]
 
Danke für eure Antwort!

Leider benötige ich das FlowLayout, da das Fenster im eigentlichen Projekt resizeable ist und die Labels dann abgeschnitten sind, wenn das Fenster zu klein wird.

Wie realisiere ich das am besten?
 
Leider benötige ich das FlowLayout, da das Fenster im eigentlichen Projekt resizeable ist und die Labels dann abgeschnitten sind
Wie willst du mittels FlowLayout bei einem zu kleinem Fenster verhindern, dass die Labels abgeschnitten werden?
Normalerweise arbeitet man da mit einer minimalen Größe die nicht unterschritten wird und ScrollPanes, um den Zugriff des Users auf alle Steuerelemente zu gewährleisten.
 
Wie willst du mittels FlowLayout bei einem zu kleinem Fenster verhindern, dass die Labels abgeschnitten werden?
Normalerweise arbeitet man da mit einer minimalen Größe die nicht unterschritten wird und ScrollPanes, um den Zugriff des Users auf alle Steuerelemente zu gewährleisten.
Genau, ich habe eine Mindestgröße des JFrames festgelegt und wenn es mehrere Panels werden, würde ich ScrollPane nutzen.

Wenn ich aber jetzt das Fenster verkleinere, schneidet das JFrame in Inhalt links und rechts ab, hätte ich ein FlowLayout würden alle weiteren JPanels sich untereinander anordnen, dann könnte man hier mittels JScrollPane den gesamten Inhalt anzeigen lassen.

Ich weiß nicht ob mein Text und Problem verständlich ist :/
 
Wie realisiere ich das am besten?
Mit einem passenden LayoutManager. Entweder suchst Du Dir einen fertigen oder Du schreibst Dir einen.

Du willst die Komponenten mit ihrer Preferred Size linksbündig nebeneinander setzen und umbrechen, wenn der Platz nicht reicht. Das ist nicht wirklich kompliziert, hier mal ein Ansatz:

Java:
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Insets;
import java.awt.LayoutManager;
import java.util.function.Function;

public class ReactiveLayout implements LayoutManager {

    private final int hGap;
    private final int vGap;

    public ReactiveLayout() {
        this.hGap = 0;
        this.vGap = 0;
    }

    public ReactiveLayout(int hGap, int vGap) {
        this.hGap = hGap;
        this.vGap = vGap;
    }

    @Override
    public Dimension minimumLayoutSize(Container parent) {
        return calculateLayoutSize(parent, c -> c.getMinimumSize());
    }

    @Override
    public Dimension preferredLayoutSize(Container parent) {
        return calculateLayoutSize(parent, c -> c.getPreferredSize());
    }

    private Dimension calculateLayoutSize(Container parent, Function<Component, Dimension> compSize) {
        int width = 0;
        int height = 0;

        for (Component c : parent.getComponents()) {
            if (c.isVisible()) {
                Dimension size = compSize.apply(c);
                width += size.width + (width > 0 ? hGap : 0);
                height = Math.max(height, size.height);
            }
        }

        Insets insets = parent.getInsets();
        width += insets.left + insets.right;
        height += insets.top + insets.bottom;

        return new Dimension(width, height);
    }

    @Override
    public void layoutContainer(Container parent) {
        Insets insets = parent.getInsets();
        int x = insets.left;
        int y = insets.top;
        int rowHeight = 0;
        Dimension parentSize = parent.getSize();
        int maxWidth = parentSize.width - insets.left - insets.right;

        for (Component c : parent.getComponents()) {
            if (c.isVisible()) {
                Dimension size = c.getPreferredSize();
                if (x + size.width > maxWidth) {
                    x = insets.left;
                    y += rowHeight + vGap;
                    rowHeight = 0;
                }
                c.setBounds(x, y, size.width, size.height);
                rowHeight = Math.max(rowHeight, size.height);
                x += size.width + hGap;
            }
        }
    }

    @Override
    public void addLayoutComponent(String name, Component comp) {}

    @Override
    public void removeLayoutComponent(Component comp) {}    
}
 
Vielleicht kommst du ja so zum Ziel?
Die Zeilen 7-9 und 20 sind der wichtige Teil daran, der Rest dient nur zum Aufbau des Beispiels
[CODE lang="java" title="Flowlayout" highlight="7,8,9,20"]public class FlowLayoutTopAlignment {

private static Component buildPanel(int nlabels) {
nlabels = Math.max(1, nlabels);
JPanel panel = new JPanel(new GridLayout(nlabels, 1)) {
@Override
public int getBaseline(int width, int height) {
return 0;
}
};

for (int i = 0; i < nlabels; i++) {
panel.add(new JLabel(String.format("Label %d", counter++)));
}
return panel;
}

public static void main(String[] args) {
FlowLayout fl = new FlowLayout();
fl.setAlignOnBaseline(true);
JPanel holder = new JPanel(fl);
holder.add(buildPanel(2));
holder.add(buildPanel(1));
holder.add(buildPanel(4));
holder.add(buildPanel(2));
holder.add(buildPanel(1));
holder.add(buildPanel(6));
holder.add(buildPanel(4));
holder.add(buildPanel(2));
JFrame frame = new JFrame("title");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setContentPane(holder);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
private static int counter = 1;
}
[/CODE]

Du bist aber nicht der erste mit diesem Problem, da haben sich schon massig Webdesigner den Kopf darüber zerbrochen. Mach dich per Google mal etwas schlau, ob es nicht schon vorgefertigte bessere Lösungen als diesen rudimentären Ansatz gibt. Einen externen Layoutmanager mit einzubinden, dürfte das kleinste aller möglichen Probleme sein.
 

Zurück
Oben