Ordentlicher Code & Panel ab bestimmter Komponentenzahl scrollbar machen

CptK

Bekanntes Mitglied
Hallo zusammen, ich habe mich in letzter Zeit recht viel mit GUI-Programmierung beschäftigt, habe aber das Gefühl, dass mein Code nicht optimal ist. Ich habe jetzt zum Beispiel eine Klasse, abgeleitet von JPanel, die im Endeffekt eine Liste von Komponenten enthält. Das Ganze sieht so aus:
1614541174813.png
Darüber gibt es noch einen Button (der aber nicht zu der Klasse selbst gehört) mit dem man eine weitere Zeile hinzufügt. Der Mülleimer ist denke ich klar.

Jetzt wo das erwartete Ergebnis hoffentlich klar ist der Code:
Java:
public class LabelCombinationInput extends JPanel {

    private static final long serialVersionUID = 4125516955764108160L;

    private List<LabelCombinationInputField> labelCombinationInputFields;

    private GridBagLayout layout;
    private GridBagConstraints gbc;

    private JDialog parent;

    private JPanel container;
    private GridBagLayout containerLayout;


    public LabelCombinationInput(JDialog parent) {
        this.parent = parent;

        labelCombinationInputFields = new ArrayList<>();
        LabelCombinationInputField defaultComb = new LabelCombinationInputField(this);
        defaultComb.setDefault("default");
        labelCombinationInputFields.add(defaultComb);

        layout = new GridBagLayout();
        setLayout(layout);

        container = new JPanel();
        containerLayout = new GridBagLayout();
        container.setLayout(containerLayout);

        // Load default
        for (LabelCombinationInputField input : labelCombinationInputFields) {
            gbc = makegbc(0, container.getComponentCount(), 1, 1, GridBagConstraints.CENTER, new Insets(10, 0, 0, 0),
                    10, 0, GridBagConstraints.HORIZONTAL);
            containerLayout.addLayoutComponent(input, gbc);
            container.add(input);
        }

        gbc = makegbc(0, getComponentCount(), 1, 1, GridBagConstraints.PAGE_START, new Insets(10, 0, 0, 0), 10, 0,
                GridBagConstraints.HORIZONTAL);
        layout.addLayoutComponent(container, gbc);

        add(container);

        setVisible(true);
    }

    public void addLabelCombinationInputField() {
        LabelCombinationInputField newInput = new LabelCombinationInputField(this);
        labelCombinationInputFields.add(newInput);
        gbc = makegbc(0, container.getComponentCount(), 1, 1, GridBagConstraints.CENTER, new Insets(10, 0, 0, 0), 10, 0,
                GridBagConstraints.HORIZONTAL);
        containerLayout.addLayoutComponent(newInput, gbc);
        container.add(newInput);

        parent.pack();
        container.revalidate();
        validate();
    }

    public void removeLabelCombinationInputField(LabelCombinationInputField field) {
        try {
            containerLayout.removeLayoutComponent(field);
            container.remove(field);
            validate();
            parent.pack();
        } catch (Exception e) {
            throw new NullPointerException("Cannot remove Component.");
        }
    }

}

mit der makegbc-Methode habe ich schon ein bisschen was ausgelagert, bin mir aber sicher, dass man den Code, vor allem die beiden Methoden "addLabelCombinationInputField" und "removeLabelCombinationInputField" noch optimieren kann, nur wie ist mir nicht bewusst. Außerdem würde ich diese Liste gerne scrollbar machen, sobald sie mehr als 6 Elemente beinhaltet, sodass das Fenster nicht immer größer wird.

Ich würde mich freuen, wenn ich da ein paar Hinweise bekommen könnte.
 
JScrollPane ist die Komponente dafuer.
Ich habe das jetzt wie folgt versucht:
Java:
JScrollPane pane = new JScrollPane(container, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
pane.setBorder(null);
add(pane);
Dadurch, dass nach jedem einfügen eines Elements die Methode pack() aufgerufen wird, um das Layout umzusetzen, wird irgendwann, wenn kein Platz mehr ist, einfach das Fenster vergrößert. Ich habe versucht, das mit pane.setPreferredSize(new Dimension(400, 200)); zu lösen, Problem hier: wenn, wie am Anfang nur ein Element in dem ScrollPane ist, wird das so hässlich in der MItte angezeigt. Was ich gerne hätte ist, dass sich diese Scrollpane bis zu einer Anzahl von beispielsweise 6 Elementen vergrößert und wenn diese Grenze überschritten wird, das scrollen greift. Leider weiß ich nicht, wie ich sowas umsetzen kann.
Wenn ich versuche eine maximale Größe hinzuzufügen pane.setMaximumSize(new Dimension(400, 200)); dann wird das einfach ignoriert, vermutlich wegen dem pack().
 
Es ist moeglich dass das Layout das Problem ist, weil es die Komponenten einfach auf ihre bervorzugte Groesze wachsen laesst. Ich weisz dass, zum Beispiel, bei einem BorderLayout im Center das Problem nicht ist.
 
@UnknownInnocent, Du meinst sowas in der Richtung?
Java:
import java.awt.*;
import javax.swing.*;

public class Test {

    int counter;

    public void run() {
        JPanel content = new JPanel(new GridBagLayout());
        JPanel inner = new JPanel(new GridBagLayout());
        GridBagConstraints gbc = new GridBagConstraints();
        gbc.weighty=1;
        gbc.weightx=1;
        gbc.anchor=GridBagConstraints.PAGE_START;
        content.add(inner, gbc);

        gbc.anchor=GridBagConstraints.CENTER;

        JButton addRow = new JButton("+");
        addRow.addActionListener(e -> {            
            JLabel label = new JLabel("" + counter);
            gbc.gridx = 0;
            gbc.gridy = counter;
            inner.add(label, gbc);
            inner.revalidate();
            counter++;
        });

        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        frame.add(addRow, BorderLayout.NORTH);
        frame.add(new JScrollPane(content));
        frame.setSize(300, 100);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> new Test().run());
    }
}
 
@UnknownInnocent, Du meinst sowas in der Richtung?
Java:
import java.awt.*;
import javax.swing.*;

public class Test {

    int counter;

    public void run() {
        JPanel content = new JPanel(new GridBagLayout());
        JPanel inner = new JPanel(new GridBagLayout());
        GridBagConstraints gbc = new GridBagConstraints();
        gbc.weighty=1;
        gbc.weightx=1;
        gbc.anchor=GridBagConstraints.PAGE_START;
        content.add(inner, gbc);

        gbc.anchor=GridBagConstraints.CENTER;

        JButton addRow = new JButton("+");
        addRow.addActionListener(e -> {           
            JLabel label = new JLabel("" + counter);
            gbc.gridx = 0;
            gbc.gridy = counter;
            inner.add(label, gbc);
            inner.revalidate();
            counter++;
        });

        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        frame.add(addRow, BorderLayout.NORTH);
        frame.add(new JScrollPane(content));
        frame.setSize(300, 100);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> new Test().run());
    }
}
Genau, so was in der Art nur kriege ich das halt nicht auf meine Bedürfnisse angepasst
 
Wenn ich aber auf das Jdialog Fenster nicht pack() aufrufe, nachdem ich eine neue Komponente hinzugefügt habe bekomm ich folgendes Ergebnis:
1615043244921.png
das ja eigentlich so aussehen sollte (bis auf die hier fehlende Scrollbar):
1615043172303.png
 
Doch, das soll ja so sein: JDialog -> JScrollPane -> äußeres Panel -> inneres Panel.

Beim Öffnen des Dialogfensters sollte dieses durch die JScrollPane eine gewisse Größe bekommen. Das revalidate() auf dem inneren Panel sorgt dafür, dass das Layout der Container bis zum validation root (das dürfte der Viewport sein) hinauf neu validiert wird, um die neuen Komponenten und deren Auswirkungen zu berücksichtigen.

Pack den Code mal in ein kompilierbares und ausführbares Minimalbeispiel (das ohne das Mülltonnen-Icon auskommt), dann können wir das Problem besser nachvollziehen.
 

Zurück
Oben