Größe der Parent-Component dynamisch an children anpassen

blz

Bekanntes Mitglied
Hallo,
ich möchte gerne folgendes programmieren:

ein blaues JPanel soll untereinander zwei JTextAreas enthalten, in der oberen steht default-mäßig Hallo.
Die JTextAreas sollen linksbündig im Panel so positioniert sein, dass drumherum ein Rand von 10px ist.
Wenn man Text eingibt, sei es in die Breite, oder auch durch Enter eine weitere Zeile erzeugt, soll sich die Größe des beinhaltenden Panels automatisch anpassen.
(Das Panel kommt dann wiederum in einen JFrame.)

asdf.png

Ich bin relativ unerfahren in der Grafikprogrammierung.
Ich bin mir nicht sicher, welchen LayoutManager ich für das Panel benutzen sollte. GridLayout wäre plausibel, fällt aber doch dadurch raus, dass ich die 2 Textfelder nicht einfach oben positioniere sondern den Rand brauche.

Und wie teile ich der Parentcomponent mit, dass sich was getan hat? Ist es sinnvoll, an jede Textarea einen KeyListener zu heften und wenn sich was tut, dann die Größe des Textfelds abzufragen?
Was mich zur Frage führt, wie man das zu Beginn löst, denn da ist z. B. die Breite immer 0.

Vielen Dank für jede Hilfe!
 

mihe7

Top Contributor
Das, was Du vorhast, muss erst genauer spezifiziert werden. Hintergrund ist, dass das Fenster letztlich die maximale Größe vorgibt. D. h. die Fenstergröße definiert den zur Verfügung stehenden Platz und ausgehend davon werden die Komponenten im Fenster verteilt. Insofern stellt sich die Frage, welcher Platz denn genutzt werden soll, um die JTextArea zu vergrößern?
 

blz

Bekanntes Mitglied
OK, der frame hat eine fixe Größe und das panel darin wird nicht so groß werden wie der frame, soll heißen, sooo viel Text wird da nicht eingegeben werden.
Ich fände es sogar recht schön, wenn man nicht 'aus dem frame rausschreiben' könnte.

Im Fenster soll später allerdings noch eine Menuleiste sein und auch noch links eine menubar, auf der man dann ZB das Element mit den zwei textareas auswählen und um Fenster platzieren kann.
 

blz

Bekanntes Mitglied
OK der frame hat ne fixe Größe.
In das beschriebene Element wird wohl nie so viel Text eingegeben, dass das über den frame hinausgehen würde. Falls doch, fände ich eine automatische Begrenzung durch die frame Größe schön.
In den frame sollen später noch eine Menuleiste oben und eine menubar links hinkommen. Auf letzterer kann man dann ZB das beschriebene Element auswählen und mit der Maus im frame platzieren.
 

mihe7

Top Contributor
Java:
import java.awt.BorderLayout;
import javax.swing.*;

public class Test {

    public void run() {
        JTextArea area = new JTextArea();
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        frame.add(area, BorderLayout.NORTH);
        frame.setSize(800, 600);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> new Test().run());
    }
}
 

blz

Bekanntes Mitglied
Hallo, vielen Dank, aber das sieht bei mir so aus:
1585996171583.png
Die Area geht über die ganze Breite.
Sie sollte ja nur so breit sein wie ein Beispielwort, das drinsteht, zB Hallo.
Außerdem sollte sie ja noch auf einem farbigen Panel liegen, das man darunter sieht.
Kann man das noch einbauen?
 

blz

Bekanntes Mitglied
Ich bin nun so weit, dass das Prinzip anschaulich klar wird, aber es sind noch etliche Probleme drin:

Java:
import java.awt.Color;

import javax.swing.JPanel;

public class BackgroundPanel extends JPanel {
    
    public BackgroundPanel() {
        super();       
        setBackground(Color.BLUE);
    }
}

Java:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.geom.Point2D;

import javax.swing.BorderFactory;
import javax.swing.JPanel;
import javax.swing.JTextArea;

public class MyEditablePanel extends JPanel {
    
    private static final long serialVersionUID = 1L;

    JTextArea jta1;
    JTextArea jta2;
      
    public MyEditablePanel() {
        super();
    }
    
    public MyEditablePanel(Color c) {
        super();
        // The GridLayout class is a layout manager that lays out a container's components in a rectangular grid. (Raster)
        // The container is divided into equal-sized rectangles, and one component is placed in each rectangle.
        setLayout(new GridLayout(2, 1, 2, 2));
        setBackground(c);
              
        jta1 = new JTextArea(1, 0);
        jta1.setLocation(2, 2);
        jta1.setAlignmentX(0.5f);       
        add(jta1);             
        
        jta2 = new JTextArea("...");       
        add(jta2);
    }
}

Java:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.geom.Point2D;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;


public class MyEditableFrame extends JFrame {
    
    private JPanel contentPane;

    public MyEditableFrame() {
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setBounds(0, 0, 500, 500);
        setResizable(false);
        setLayout(null);
        
        contentPane = new JPanel();
        contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
        contentPane.setLayout(new BorderLayout());
        setContentPane(contentPane);
        
        MyEditablePanel panel0 = new MyEditablePanel(Color.PINK);
       
        BackgroundPanel bp = new BackgroundPanel();
        bp.setPreferredSize(new Dimension(50, 50));
        bp.add(panel0);
        panel0.setLocation(5, 5);
        
        contentPane.add(bp, BorderLayout.CENTER);
        
        setVisible(true);       
    }
    
    public static void main(String[] args) {
        MyEditableFrame mef = new MyEditableFrame();
    }
}

Probleme:
  1. Das GridLayout scheint keine gute Wahl zu sein: Denn wenn ich in der ersten Area Enter drücke, wird die zweite Zelle und damit auch die zweite Textarea genauso groß.
  2. Wie bekomme ich es hin, dass der Layoutmanager die Größe meiner Komponenten (hier des blauen Panels) nicht selbstständig entscheidet, sondern dass er es nur so groß macht, wie angegeben?
  3. Wie bekomme ich die Textareas auf dem blauen Panel so positioniert, dass sie links oben mit zwei Pixeln Abstand vom Rand starten?
 

mihe7

Top Contributor
Das ist das, was ich ursprünglich meinte: die Frage ist, wie der freie Platz verteilt werden soll.

Jede Komponente besitzt eine Mindest- und Maximalgröße, außerdem eine bevorzugte Größe. Der LayoutManager verteilt den zur Verfügung stehenden Platz (= freier Platz) im Fenster bzw. Container i. d. R. unter Berücksichtigung der bevorzugten Größe, ggf. auch unter Berücksichtigung der anderen Größen.

Java:
import java.awt.*;
import javax.swing.*;

public class Test {

    public void run() {
        JTextArea area = new JTextArea();
        area.setText("AA");

        GridBagLayout layout = new GridBagLayout();
        GridBagConstraints cc = new GridBagConstraints();
        JPanel panel = new JPanel(layout);
        panel.setBackground(Color.YELLOW);

        cc.anchor = GridBagConstraints.FIRST_LINE_START;
        cc.weightx = 1;
        cc.weighty = 1;
        panel.add(area, cc);
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        frame.add(panel);
        frame.setSize(800, 600);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> new Test().run());
    }
}
 

Blender3D

Top Contributor
Hallo,
ich möchte gerne folgendes programmieren:

ein blaues JPanel soll untereinander zwei JTextAreas enthalten, in der oberen steht default-mäßig Hallo.
Ich habe einmal ein relatives Layout benötigt. Damit ist gemeint, dass die Position und die Dimension der Komponenten in Prozenten relativ zur Dimension des Containers angegeben werden. Bei einem Resize des Containers kann dann automatisch angepasst werden. Es kommt dabei ein null Layout zum Einsatz damit jede Komponente punktgenau platziert werden kann. Vielleicht hilft dir das bei Deinem Problem weiter.
Java:
import java.awt.Color;
import java.awt.Component;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;

public class start {
    public static void main(String[] args) {
        final int WIDTH = 500;
        final int HEIGHT = 400;
        JFrame frame = new JFrame("Relatives Layout Resizeable");
        RelativeLayoutPanel layout = createLayout(WIDTH, HEIGHT);
        frame.addComponentListener(new ComponentAdapter() {
            @Override
            public void componentResized(ComponentEvent e) {
                layout.resize(frame.getWidth(), frame.getHeight());
            }
        });
        layout.addToContainer(frame.getContentPane());
        frame.pack();
        frame.setVisible(true);
    }

    private static RelativeLayoutPanel createLayout(int width, int height) {
        RelativeLayoutPanel panel = new RelativeLayoutPanel(500, 400);
        panel.setBackGround(Color.BLUE);
        LocationInfo[] info = { new LocationInfo(.02f, .02f, .451f, .05f), new LocationInfo(.5f, .02f, .451f, .05f),
                new LocationInfo(.02f, .09f, .451f, .7f), new LocationInfo(.5f, .09f, .451f, .3f) };
        Component[] component = { new MyLabel("Left Text"), new MyLabel("Right Text"), new JScrollPane(new JTextArea()),
                new JScrollPane(new JTextArea()) };
        panel.setBorder(BorderFactory.createLineBorder(Color.WHITE));

        for (int i = 0; i < info.length; i++)
            panel.add(new FlexibleLayoutComponent(component[i], info[i]));
        return panel;
    }
}
Java:
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.util.Vector;
import javax.swing.JPanel;
import javax.swing.border.Border;

/**
 * Allows to position Components using relative position and size.
 *
 * @see LocationInfo
 *
 */
public class RelativeLayoutPanel {
    private JPanel panel = new JPanel();
    private Vector<FlexibleLayoutComponent> components = new Vector<FlexibleLayoutComponent>();

    public RelativeLayoutPanel(int width, int height) {
        panel.setLayout(null);
        resize(width, height);
    }
    public Component addToContainer(Container container) {
        return container.add(panel);
    }
    public Component add(FlexibleLayoutComponent c) {
        if (components.contains(c))
            return null;
        components.add(c);
        Component tmp = c.addToContainer(panel);
        resize(panel.getPreferredSize());
        return tmp;
    }
    public void repaint() {
        panel.repaint();
    }
    public void remove(FlexibleLayoutComponent c) {
        if (!components.contains(c))
            return;
        components.remove(c);
        c.removeFromContainer(panel);
    }
    public void removeAll() {
        components.removeAllElements();
        panel.removeAll();
    }
    public void removeFromContainer(Container container) {
        container.remove(panel);
    }
    public void resize(Dimension dim) {
        resize(dim.width, dim.height);
    }
    public void resize(int width, int height) {
        panel.setPreferredSize(new Dimension(width, height));
        for (FlexibleLayoutComponent c : components)
            c.resize(width, height);
    }
    public void setBackGround(Color bg) {
        panel.setBackground(bg);
    }
    public void setBorder(Border b) {
        panel.setBorder(b);
    }
}
Java:
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;

public class FlexibleLayoutComponent {
    private LocationInfo info;
    private Component component;

    public FlexibleLayoutComponent(Component component, LocationInfo info) {
        this.component = component;
        this.info = info;
    }
    public Component addToContainer(Container contenpane) {
        return contenpane.add(component);
    }
    public void removeFromContainer(Container contenpane) {
        contenpane.remove(component);
    }
    /**
     * Call {@link #resize(int, int)} after setting new LocatinInfo.
     *
     * @param info
     */
    public void setLocationInfo(LocationInfo info) {
        this.info = info;
    }
    /**
     * Updates component's bounds relative to given dimension.
     *
     * @param dim
     *            Container's dimension.
     */
    public void resize(Dimension dim) {
        resize(dim.width, dim.height);
    }
    /**
     * @see #resize(Dimension)
     * @param width
     *            Container's width.
     * @param height
     *            Container's height.
     */
    public void resize(int width, int height) {
        component.setBounds(info.getX(width), info.getY(height), info.getWidth(width), info.getHeight(height));
    }
}
Java:
/**
 * Manages position and dimension info used by {@link RelativeLayoutPanel}
 */
public class LocationInfo {
    final public float percentageX;
    final public float percentageY;
    final public float percentageWidth;
    final public float percentageHeight;
    /**
     *
     * @param x
     *            Relative x-coordinate.
     * @param y
     *            Relative y-coordinate.
     * @param percentageWidth
     *            Relative width.
     * @param percentageHeight
     *            Relative height.
     * @see RelativeLayoutPanel
     */
    public LocationInfo(float percentageX, float percentageY, float percentageWidth, float percentageHeight)
            throws IllegalArgumentException {
        if (!isInRange(percentageX) || !isInRange(percentageY) || !isInRange(percentageWidth)
                || !isInRange(percentageHeight))
            throw new IllegalArgumentException("LocationInfo parmeters have to be within range [0-1]!");
        this.percentageX = percentageX;
        this.percentageY = percentageY;
        this.percentageWidth = percentageWidth;
        this.percentageHeight = percentageHeight;
    }
    private boolean isInRange(float value) {
        return value >= 0 && value <= 1;
    }
    public int getHeight(int height) {
        return (int) (height * percentageHeight);
    }
    public int getWidth(int width) {
        return (int) (width * percentageWidth);
    }
    public int getX(int width) {
        return (int) (width * percentageX);
    }
    public int getY(int height) {
        return (int) (height * percentageY);
    }
}

Java:
import java.awt.Color;
import java.awt.Font;
import javax.swing.BorderFactory;
import javax.swing.JLabel;
import javax.swing.SwingConstants;
import javax.swing.border.BevelBorder;

@SuppressWarnings("serial")
public class MyLabel extends JLabel {
    public MyLabel(String text) {
        super(text, SwingConstants.CENTER);
        setVerticalAlignment(JLabel.BOTTOM);
        setBorder(BorderFactory.createBevelBorder(BevelBorder.RAISED));
        setBackground(Color.DARK_GRAY);
        setForeground(Color.WHITE);
        setOpaque(true);
    }

    /**
     * Override to adapt font's size to new height.
     *
     * @param x
     * @param y
     * @param width
     * @param height
     */
    @Override
    public void setBounds(int x, int y, int width, int height) {
        super.setBounds(x, y, width, height);
        setFont(new Font(getName(), Font.BOLD, (int) (height * .8)));
    }
}

Für dich interessant ist die Klasse start und MyLabel. Die anderen kannst Du einfach mit Copy Paste verwenden.
 

blz

Bekanntes Mitglied
Hallo,
vielen Dank für die Antworten. Ich bin mir nicht sicher, ob das, was ich möchte, richtig verstanden wurde:
Wenn ich in die zwei untereinanderliegenden Textareas tippe, verändert sich deren Breite und evtl. auch Höhe.
Ich möchte dann, dass der Container, das Panel, das die beiden Areas enthält, auch entsprechend mitwächst bzw. kleiner wird.
Ich habe mal auf Basis von mihes Klasse etwas programmiert, was das Ganze glaube ich ganz gut illustriert.

Ein großes Problem dabei ist momentan, dass ich das Panel zwischendurch immer erst auf eine große Größe setzen muss, damit man abfragen kann, wie groß das Textfeld denn nach Eingabe eines Zeichens nun ist. Erst dann kann man ausrechnen, wie groß das Panel eigentlich sein müsste und seine Größe wieder korrekt setzen.

Beim Enter-Drücken klappt es auch erst, wenn man danach ein Zeichen eingegeben hat ...

Man sieht aber, was ich will: Der gelbe Rand soll fix so breit wie vorgegeben die beiden Areas umschließen, diese sollen nur gerade so groß sein wie der enthaltene Text.

Java:
package package3;

import java.awt.*;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import javax.swing.*;

public class Test {

    int actMaxWidth;
    int actSumOfHeights;
    
    
    int paddLeftRight;
    int paddCell1Top;    
    int paddCell1Bottom;    
    int paddCell2Top;    
    int paddCell2Bottom;
    
    JTextArea area1;
    JTextArea area2;
    
    JPanel panel;
    
    public void run() {
        
        paddLeftRight = 15;            
        paddCell1Top = 15;        
        paddCell1Bottom = 5;        
        paddCell2Top = 5;        
        paddCell2Bottom = 15;        
        
        area1 = new JTextArea();
        area1.setText("Hallo!");
        area1.addKeyListener(new KeyAdapter() {                
            @Override
            public void keyTyped(KeyEvent e) {
                panelSizeAdaption();
                System.out.println("Key pressed");
            }        
        });

        area2 = new JTextArea();
        area2.setText("B");
        
        GridBagLayout layout = new GridBagLayout();
        GridBagConstraints cc = new GridBagConstraints();
        panel = new JPanel(layout);
        panel.setBackground(Color.YELLOW);
        panel.setSize(new Dimension(250, 250));

        // Place the component in the corner of its display area where the first line of text on a page would normally begin for the current ComponentOrientation.
        cc.anchor = GridBagConstraints.FIRST_LINE_START;
        cc.gridx = 0;
        cc.gridy = 0;
        cc.weightx = 1;
        cc.weighty = 1;
        cc.fill = GridBagConstraints.NONE;
        // padding (Abstand zw. Zellrand und Element): top, left, bottom, right
        cc.insets = new Insets(paddCell1Top, paddLeftRight, paddCell1Bottom, paddLeftRight);

        panel.add(area1, cc);
        System.out.println(area1.getHeight());

        cc.insets.set(paddCell2Top, paddLeftRight, paddCell2Bottom, paddLeftRight);
        cc.gridy = 1;
        panel.add(area2, cc);        
        
        JFrame frame = new JFrame();
        frame.setLayout(null);
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        frame.add(panel);
        frame.setSize(800, 600);
        System.out.println(area1.getHeight());
        System.out.println(area1.getHeight());

        frame.setVisible(true);
        

        panelSizeAdaption();
    }
    
    private void panelSizeAdaption() {
         panel.setSize(new Dimension(250, 250));
        
        int width = getMaxWidth(); 
        boolean change = false;
            
        if (actMaxWidth != width) {
            actMaxWidth = width;
            change = true;
        }
            
        int heights = getSumOfHeights();
        
        if (actSumOfHeights != heights) {            
            actSumOfHeights = heights;
            change = true;
        }
        
        if (change) {                      
            panel.setSize(2 * paddLeftRight + actMaxWidth, paddCell1Top + paddCell1Bottom + paddCell2Top + paddCell2Bottom + actSumOfHeights);
            panel.repaint();
            change = false;
        }                
    }
    
    private int getSumOfHeights() {
        return area1.getHeight() + area2.getHeight();        
    }
    
    
    private int getMaxWidth() {
        int width = area1.getWidth();
        if (area2.getWidth() > width)
            width = area2.getWidth();
        return width;
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> new Test().run());
    }
}
 

mihe7

Top Contributor
Ich möchte dann, dass der Container, das Panel, das die beiden Areas enthält, auch entsprechend mitwächst bzw. kleiner wird.
Java:
import java.awt.*;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import javax.swing.*;

public class Test {

    int actMaxWidth;
    int actSumOfHeights;
    
    
    int paddLeftRight;
    int paddCell1Top;    
    int paddCell1Bottom;    
    int paddCell2Top;    
    int paddCell2Bottom;
    
    JTextArea area1;
    JTextArea area2;
    
    JPanel panel;
    
    public void run() {
        
        paddLeftRight = 15;            
        paddCell1Top = 15;        
        paddCell1Bottom = 5;        
        paddCell2Top = 5;        
        paddCell2Bottom = 15;        
        
        area1 = new JTextArea();
        area1.setText("Hallo!");
        area2 = new JTextArea();
        area2.setText("B");
        
        GridBagLayout layout = new GridBagLayout();
        GridBagConstraints cc = new GridBagConstraints();
        cc.fill = GridBagConstraints.NONE;       
        panel = new JPanel(layout);
        panel.setBackground(Color.YELLOW);

        cc.anchor = GridBagConstraints.FIRST_LINE_START;
        cc.gridx = 0;
        cc.gridy = 0;
        cc.weightx = 1;
        cc.weighty = 0;

        cc.insets = new Insets(paddCell1Top, paddLeftRight, paddCell1Bottom, paddLeftRight);
        panel.add(area1, cc);

        cc.insets.set(paddCell2Top, paddLeftRight, paddCell2Bottom, paddLeftRight);
        cc.gridy = 1;
        cc.weightx = 0;
        cc.weighty = 0;
        panel.add(area2, cc);       

        JPanel content = new JPanel(new GridBagLayout());
        cc = new GridBagConstraints();
        cc.anchor = GridBagConstraints.FIRST_LINE_START;
        cc.gridx = 0; 
        cc.gridy = 0;
        cc.weightx = 1;
        cc.weighty = 1;
        content.add(panel, cc);
            
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        frame.add(content);
        frame.setSize(800, 600);

        frame.setVisible(true);
    }
    
    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> new Test().run());
    }
}
 

blz

Bekanntes Mitglied
Hi,
vielen Dank, das funktioniert ja wunderbar :)

Was ich nicht ganz verstehe, ist die Funktion von weight:

Soweit ich das recherchiert habe, weist man Komponenten prozentual ein weight zu. Wenn sich dann die Größe der Parent-Komponente verändert, wird der zusätzliche/wenigere Platz entsprechend der angegebenen Prozentsätze auf die beinhalteten Komponenten verteilt.

Beobachtungen/Erste Frage:

  1. Für die Funktionalität meiner Anforderung scheine ich die weights nicht zu brauchen, wenn ich sie auskommentiere, funktioniert es genauso.
  2. Wenn ich die weights des Panels content auf 1 habe, ist das Panel links oben in der Ecke, bei den Werten Null ist es zentriert in der Frame-Mitte. Warum?
  3. Wenn ich die weights der Textareas modifiziere, kann ich keine Veränderungen beobachten.

Zweite Frage:
Warum brauche ich das zweite Panel? Wo ist der Unterschied, wenn ich dem Frame direkt das gelbe Panel hinzufüge?

Dritte Frage:
Obwohl der anchor vom Panel content auf "FIRST_LINE_START" gesetzt wurde, erscheint das Panel zentriert, wenn ich die weights auskommentiere.
Warum?
 

mihe7

Top Contributor
Soweit ich das recherchiert habe, weist man Komponenten prozentual ein weight zu. Wenn sich dann die Größe der Parent-Komponente verändert, wird der zusätzliche/wenigere Platz entsprechend der angegebenen Prozentsätze auf die beinhalteten Komponenten verteilt.
Fast. Der Platz wird anteilig auf die Spalten und Zeilen des Gitters verteilt. Gilt für alle Komponenten weightx == 0, dann kann zusätzlicher Platz keiner Spalte zugewiesen werden. Stattdessen wir der Platz zwischen dem Gitter und der Kante des Containers eingefügt, der die Komponenten enthält - und zwar auf beiden Seiten gleichmäßig. D. h. das Gitter wird horizontal zentriert. Analog gilt dies für weighty. Damit sind dürfte sowohl die erste als auch die dritte Frage beantwortet sein.

Auch die zweite Frage hängt damit zusammen. Das content-Panel sorgt einfach für Platz, in dem sich das gelbe panel "ausbreiten" kann. Würdest Du panel direkt zum JFrame hinzufügen, würde dessen BorderLayout dafür sorgen, dass das panel das gesamte Fenster ausfüllt. Es wäre also von vornherein so groß wie das Fenster (alles gelb). Um das zu verhindern, gibt es content.
 

blz

Bekanntes Mitglied
ok, danke für diese wirklich sehr schönen Erklärungen!
Fürs Verständnis (nur weightx-bezogen):
1586160874652.png
0. Mit "dann kann zusätzlicher Platz keiner Spalte zugewiesen werden" meinst du, "keiner Komponente"? Denn einer Spalte wird er ja letztlich schon zugewiesen?!
1. Ich gebe allen drei Buttons weightx = 0; dann darf keine Komponente breiter gemacht werden. Also bleibt nichts anderes übrig, als die blau markierten Abstände zu vergrößern?
2. Gäbe es nur die zweite Zeile des Layouts, dann läge der linke Button "eng" in der linken Spalte und es würde nur die rechte Spalte größer werden?
 
Zuletzt bearbeitet:

blz

Bekanntes Mitglied
Und:
Bzgl. Frage 2: Ich habe ausprobiert, dem frame ein GridBagLayout zu geben und dann das gelbe Panel direkt dem frame hinzuzufügen. Dann funktionierts auch. Kann mans so genauso machen oder hat es noch irgendwelche anderen Vorteile, das Panel zwischenzuschalten?
 

mihe7

Top Contributor
0. Richtig, es geht zunächst nicht um die Komponente, sondern um das Grid. Die Komponente betrifft dann die fill-Eigenschaft.
1. Nein, Du müsstest außenrum noch den Container zeichnen und dann wäre der Abstand des Containers zum Grid gemeint.
2. Nein, dann gäbe es keine zwei Spalten :)

Ich habe ausprobiert, dem frame ein GridBagLayout zu geben und dann das gelbe Panel direkt dem frame hinzuzufügen. Dann funktionierts auch. Kann mans so genauso machen oder hat es noch irgendwelche anderen Vorteile, das Panel zwischenzuschalten?
Das funktioniert natürlich, da das "content pane" des JFrame ja auch nur ein Container ist.
 

blz

Bekanntes Mitglied
Achso, da ist mein Denkfehler (oder zumindest einer davon) die ganze Zeit:
Das Grid, das Raster, also "die Tabelle", füllt nicht automatisch den ganzen Container aus?!!
Also hellblau ist der Container, gelb ist das Grid, das Raster und in grün der Abstand, der übrig bleibt:
1586176022977.png
Und man müsste es so darstellen, dass links und rechts der Buttons quasi kein Abstand innerhalb der einzelnen Zellen ist, wenn man davon aus geht, dass weightx == 0 gilt.
(So wie es jetzt abgebildet ist, wäre weightx beider Spalten vielleicht jeweils grob == 0,25, d. h. die Hälfte des gesamten Platzes wird innerhalb der "Tabelle" verteilt, die andere Hälfte außerhalb.)
 
Zuletzt bearbeitet:

mihe7

Top Contributor
Das Grid, das Raster, also "die Tabelle", füllt nicht automatisch den ganzen Container aus?!!
Richtig.
Und man müsste es so darstellen, dass links und rechts der Buttons quasi kein Abstand innerhalb der einzelnen Zellen ist, wenn man davon aus geht, dass weightx == 0 gilt.
Richtig.
So wie es jetzt abgebildet ist, wäre weightx beider Spalten vielleicht jeweils grob == 0,25, d. h. die Hälfte des gesamten Platzes wird innerhalb der "Tabelle" verteilt, die andere Hälfte außerhalb
Falsch :) Sobald irgendein weightx > 0 ist, füllt das Grid den Container in der Horizontalen aus. Welche Zahlen Du für weightx verwendest, spielt keine Rolle - es geht um Verhältnismäßigkeiten. Sprich: weightx einer Spalte / Summe der weightx aller Spalten, falls es ein weightx > 0 gibt.
 

blz

Bekanntes Mitglied
1. Ah ok, logisch. Das bedeutet, man kann nur dann ein Grid haben, das den Container nicht ausfüllt, wenn wirklich sämtliche weightx == 0 sind.
2. Dh der letzte abgebildete Fall ließe sich mit einem GridBagLayout so nicht realisieren. Man könnte höchstens ein vierspaltiges Grid nehmen, in die linke und rechte Spalte nichts reintun und diese dann mit einem passenden weightx (dann wohl jeweils 0,25 etwa) entsprechend breit machen.
3. Jetzt hab ich aber noch ein Problem: Es funktioniert eigentlich sehr gut, aber immer wenn ich Text eingebe, nachdem ich das Panel verschoben habe, springt es immer wieder zur ursprünglichen Position zurück.
 

blz

Bekanntes Mitglied
Und, Nachtrag: Ist auf dem äußeren Panel überhaupt auch zwingend das recht komplizierte GridBagLayout notwendig, oder ginge es auch mit einem anderen Layout (einfacher)?
 

mihe7

Top Contributor
1. genau
2. ja, wobei die Zahl, wie geschrieben, völlig egal ist. Du kannst auch 0, 1, 1 und 0 verwenden. Dann bleiben die beiden äußeren Spalten in ihrer Größe fix und die inneren bekommen zusätzlichen Platz zu gleichen Teilen.
3. Panel verschoben?!?
 

blz

Bekanntes Mitglied
zu 2: Was heißt, die anderen [äußeren] beiden bleiben in ihrer Größe fix. Wenn die ganze Spalte keinerlei Komponente enthalten, haben sie doch auch keine Breite, oder nicht?

zu 3: Hatte übersehen, dass ich das nicht eingangs geschrieben hatte. Ich möchte gerne mehrere dieser gelben Panels erzeugen und im Fenster mit der Maus herumschieben können. Mit bisher einem funktioniert das auch wunderbar, außer, dass, wenn ich es verschiebe und dann Text eingebe, es immer wieder zur Anfangsposition zurückspringt ...
edit: ich habe dem Panel einen MouseListener hinzugefügt und setze die Positon des Panels in MouseDragged(...) mittels panel.setLocation(...)
 
Zuletzt bearbeitet:

mihe7

Top Contributor
Was soll das heißen? Dass man ein null-Layout verwenden sollte?
Ja, wenn Du ein Panel frei verschieben willst, stört ein LayoutManager, dessen Aufgabe es ja ist, Position und Größe der Komponenten festzulegen.

zu 2: Was heißt, die anderen [äußeren] beiden bleiben in ihrer Größe fix. Wenn die ganze Spalte keinerlei Komponente enthalten, haben sie doch auch keine Breite, oder nicht?
Ich meinte, wenn Du in den äußeren Spalten z. B. leere Panels (mit gegebener, bevorzugter Größe) einfügst.

Und, Nachtrag: Ist auf dem äußeren Panel überhaupt auch zwingend das recht komplizierte GridBagLayout notwendig, oder ginge es auch mit einem anderen Layout (einfacher)?
Das musst Du probieren, es könnte z. B. auch ein FlowLayout funktionieren.

zu 3: Hatte übersehen, dass ich das nicht eingangs geschrieben hatte. Ich möchte gerne mehrere dieser gelben Panels erzeugen und im Fenster mit der Maus herumschieben können.
Immer diese Nebensächlichkeiten... s. oben.
 

blz

Bekanntes Mitglied
Dann habe ich jetzt glaube ich größere Schwierigkeiten:

Momentan habe ich ein gelbes Panel mit GridBagLayout, das zwei Textareas enthält.
GridbagLayout deshalb, damit ich via Insets die Randbreite um die Textfelder herum setzen kann und ich die beiden Textareas schön untereinander anordnen kann.

Dann habe ich das blaue JPanel, auch mit GridBagLayout, damit das gelbe Panel darauf nicht maximal groß wird (wie es z. B. bei einem BorderLayout des blauen Panels der Fall wäre), sondern eben nur so groß wie nötig (durch weightx = 0).

Das blaue Panel setze ich schließlich in meinen JFrame.

1586301444529.png

Nun habe ich dem gelben Panel einen MouseListener hinzugefügt, damit ich es mit der Maus greifen und verschieben kann. Mit setLocation wird die neue Position gesetzt. Klappt so lange, bis sich die Größe des gelben Panels verändert. Dann springt es wieder an die ursprüngliche Position zurück.

Oben wurde geraten, man dürfe auf dem blauen Panel keinen LayoutManager verwenden, was einleuchtend klang.
Gleichzeitig ist der LayoutManager aber dafür verantwortlich, dass das gelbe Panel nur so groß wie nötig ist und nicht beliebig groß wird. Eine feste Größe kann ich auch nicht angeben, da die ja von den Textareas abhängt.

Wie könnte ich das lösen??
 

mihe7

Top Contributor
In dem Fall lohnt es sich, über einen eigenen LayoutManager nachzudenken:
Java:
import java.awt.*;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import javax.swing.*;

public class Test {

    int actMaxWidth;
    int actSumOfHeights;
    
    
    int paddLeftRight;
    int paddCell1Top;    
    int paddCell1Bottom;    
    int paddCell2Top;    
    int paddCell2Bottom;
    
    JTextArea area1;
    JTextArea area2;
    
    JPanel panel;

    LayoutManager freeLayout = new LayoutManager() {
        public void addLayoutComponent(String name, Component comp) {
        }

        public void removeLayoutComponent(Component comp) {
        }

        public Dimension minimumLayoutSize(Container parent)  {
            return null;
        }

        public Dimension preferredLayoutSize(Container parent)  {
            return null;
        }

        public void layoutContainer(Container parent) {
           for (Component c : parent.getComponents()) {
                 Rectangle bounds = c.getBounds();
                 Dimension pref = c.getPreferredSize();
                 c.setBounds(bounds.x, bounds.y, pref.width, pref.height);
            }
        }
    };
    
    public void run() {
        
        paddLeftRight = 15;            
        paddCell1Top = 15;        
        paddCell1Bottom = 5;        
        paddCell2Top = 5;        
        paddCell2Bottom = 15;        
        
        area1 = new JTextArea();
        area1.setText("Hallo!");
        area2 = new JTextArea();
        area2.setText("B");
        
        GridBagLayout layout = new GridBagLayout();
        GridBagConstraints cc = new GridBagConstraints();
        cc.fill = GridBagConstraints.NONE;       
        panel = new JPanel(layout);
        panel.setBackground(Color.YELLOW);

        cc.anchor = GridBagConstraints.FIRST_LINE_START;
        cc.gridx = 0;
        cc.gridy = 0;
        cc.weightx = 1;
        cc.weighty = 0;

        cc.insets = new Insets(paddCell1Top, paddLeftRight, paddCell1Bottom, paddLeftRight);
        panel.add(area1, cc);

        cc.insets.set(paddCell2Top, paddLeftRight, paddCell2Bottom, paddLeftRight);
        cc.gridy = 1;
        cc.weightx = 0;
        cc.weighty = 0;
        panel.add(area2, cc);       

        JPanel content = new JPanel(freeLayout);
        content.add(panel);
        panel.setBounds(50, 50, panel.getPreferredSize().width,
                          panel.getPreferredSize().height);
           
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        frame.add(content);
        frame.setSize(800, 600);

        frame.setVisible(true);
     }
    
    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> new Test().run());
    }
}
 

blz

Bekanntes Mitglied
ok ... saucool!
Ich muss das erste einmal verstehen/nachvollziehen, was der eigene LayoutManager da macht. Letztlich geht es ja "nur" um die Methode
layoutContainer: Für alle Elemente im ParentPanel werden x und y der linken oberen Ecke und die PreferredSize abgefragt und dann werden die x und y-Werte unverändert wieder gesetzt und als Breite und Höhe werden die Preferred-Werte gesetzt...
Also letztlich geht es wohl darum, als tatsächliche Größe die PreferredSize zu setzen.
Wieso löst das mein bisheriges Problem?

Eine Sache klappt noch nicht ganz: wenn ich zwei der yellowPanels erzeuge und sie im Fenster herumschiebe, dann bleibt manchmal eines vor/hinter dem anderen hängen, wenn man sie übereinander schiebt; manchmal klappts aber auch problemlos.
Könnte das etwas hiermit zu tun haben:
"Swing's painting architecture assumes the children of a JComponent do not overlap. If a JComponent's LayoutManager allows children to overlap, the JComponent must override isOptimizedDrawingEnabled to return false."
https://docs.oracle.com/javase/7/docs/api/java/awt/LayoutManager.html
 

mihe7

Top Contributor
Könnte das etwas hiermit zu tun haben:
Wäre denkbar. In jedem Fall sollte man sich daran halten.

die x und y-Werte unverändert wieder gesetzt und als Breite und Höhe werden die Preferred-Werte gesetzt...
Also letztlich geht es wohl darum, als tatsächliche Größe die PreferredSize zu setzen.
Wieso löst das mein bisheriges Problem?
Das Zurückspringen wird verhindert, gerade weil x- und y-Werte unverändert gesetzt werden, und dass sich das Panel in der Größe verändert wird erreicht, indem die preferred size gesetzt wird.

In der Regel funktioniert das Layout etwas anders: zu Beginn berechnet der LayoutManager die preferred size des Containers. Durch die Größe des Fensters (oder anderen Dingen) steht dann meist mehr oder weniger Platz zur Verfügung und der LayoutManager passt die Verteilung bzw. Größen der Komponenten entsprechend an.
 

blz

Bekanntes Mitglied
Hat sich erledigt: Das Layout passt perfekt, ich hatte einen Fehler in meinen MouseAdapter-Methoden.
Super!
Herzlichen Dank für die vielen Erklärungen, das hat mich alles ein großes Stück weiter gebracht!
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
L JDialog - Event wenn Parent größe ändert AWT, Swing, JavaFX & SWT 2
T Die Größe einer JTextArea an Ihren Parent JPanel anpassen. AWT, Swing, JavaFX & SWT 5
P JTextField wird nur sehr klein angezeigt und verändert die Größe nicht AWT, Swing, JavaFX & SWT 3
H JDialog in Größe ändern - Resize-Cursor bleibt betreten der Komponente AWT, Swing, JavaFX & SWT 1
H AWT Dialog Größe ändern - Schwarzer Inhalt beim groß ziehen AWT, Swing, JavaFX & SWT 1
Yonnig JavaFX Größe von WebView an Content anpassen AWT, Swing, JavaFX & SWT 3
J Swing Komponente wird unpassend angepasst in der Größe AWT, Swing, JavaFX & SWT 35
FrittenFritze Ein Problem mit der CSSBox, die Größe wird nicht angepasst AWT, Swing, JavaFX & SWT 5
D JavaFX Größe des Bild an ImageView anpassen AWT, Swing, JavaFX & SWT 3
B Dynamische ListView-Größe, die bei Fenstergrößenänderung sich anpasst AWT, Swing, JavaFX & SWT 19
R Swing JTextField - Schriftgröße je nach Länge und Größe ändern AWT, Swing, JavaFX & SWT 0
B veränderte Größe eines Panels im Vorhinein wissen? AWT, Swing, JavaFX & SWT 1
L JavaFX AnchorPane an die Größe der Scene oder Window binden? AWT, Swing, JavaFX & SWT 3
K JavaFX Component Größe an Inhalt anpassen AWT, Swing, JavaFX & SWT 11
S Java GUI durch variable Größe einer Map anpassen AWT, Swing, JavaFX & SWT 3
R Größe von Scene und stage an grid anpassen AWT, Swing, JavaFX & SWT 4
M Java FX größe der shapes anpassen AWT, Swing, JavaFX & SWT 0
L Swing JPanel Größe anpassen AWT, Swing, JavaFX & SWT 6
E Wie kann ich ein JLabel auf größe der schriftlänge setzten? AWT, Swing, JavaFX & SWT 2
C Swing JFrame ändert Größe AWT, Swing, JavaFX & SWT 0
G Swing JButton ändert (unerwünscht) Größe bei Ausführung AWT, Swing, JavaFX & SWT 4
L Swing Größe automatisch anpassen AWT, Swing, JavaFX & SWT 14
B AWT Panel größe im BorderLayout einstellen AWT, Swing, JavaFX & SWT 1
J Swing Pane im SplitPane automatische Größe aktivieren AWT, Swing, JavaFX & SWT 0
DaCrazyJavaExpert Swing Größe des JPanel ändern/wird nicht geändert. AWT, Swing, JavaFX & SWT 3
M Swing Mehrere Textfelder mit ScrollBars - Größe der Felder AWT, Swing, JavaFX & SWT 0
L JavaFX ListView Größe anpassen AWT, Swing, JavaFX & SWT 1
Neumi5694 Größe von Komboboxen neu berechnen AWT, Swing, JavaFX & SWT 3
L JavaFX List oder TableView Größe dynamisch anpassen? AWT, Swing, JavaFX & SWT 4
P Größe und Ausrichtung von Komponenten festlegen AWT, Swing, JavaFX & SWT 13
I CSS - backgroundImage - Größe automatisch an den Container anpassen AWT, Swing, JavaFX & SWT 1
C Größe des Mauszeigers ermitteln AWT, Swing, JavaFX & SWT 5
MaxG. JFrame Größe ändern AWT, Swing, JavaFX & SWT 16
P Jframe Bild einfügen, Hintergrund Farbe ändern, und Button schrift Größe ändern AWT, Swing, JavaFX & SWT 2
K GridBagLayout verändert die größe? AWT, Swing, JavaFX & SWT 1
D Swing Größe einer JComboBox im GridBagLayout aufgrund der maximalen Länge der enthaltenen Daten AWT, Swing, JavaFX & SWT 7
D JavaFX Alle Knöpfe auf die gleiche Größe AWT, Swing, JavaFX & SWT 14
G JFrame - manuell Größe verändern AWT, Swing, JavaFX & SWT 6
M LayoutManager GridBagLayout passt seine größe nicht an AWT, Swing, JavaFX & SWT 3
F Gui weicht von Designpreview ab (kein fensterrahmen, andere größe) AWT, Swing, JavaFX & SWT 13
A JPanel größe verändern AWT, Swing, JavaFX & SWT 4
M SWT ScrollPane Größe zu klein AWT, Swing, JavaFX & SWT 6
T Swing Größe einer Komponente in einem BoxLayout / FlowLayout festlegen AWT, Swing, JavaFX & SWT 7
H JTree in JScrollPane passt sich nicht an Größe von JPanel an AWT, Swing, JavaFX & SWT 2
L JButton - Größe anders als erwartet AWT, Swing, JavaFX & SWT 2
W GridBagLayout Größe geben AWT, Swing, JavaFX & SWT 1
S Swing JFrame hat nicht die Größe, die ich eingegeben habe AWT, Swing, JavaFX & SWT 3
S Größe der Komponenten, beim ändern der größe des Frames, mit ändern! AWT, Swing, JavaFX & SWT 2
S Größe und Farbe vom JButton festlegen AWT, Swing, JavaFX & SWT 2
D Swing Jlist Größe während der Laufzeit verändern. AWT, Swing, JavaFX & SWT 11
H AWT Fenster- und JLabel-Größe automatisch anpassen AWT, Swing, JavaFX & SWT 2
T Swing Größe des Randes AWT, Swing, JavaFX & SWT 2
C LayoutManager JFrame größe und ausrichtung + Position von Fensterelementen AWT, Swing, JavaFX & SWT 2
B Swing JTable mit Daten - Reihen-Größe anpassen AWT, Swing, JavaFX & SWT 0
D SWT Window passt Größe nicht an AWT, Swing, JavaFX & SWT 4
N JPanel größe wissen/festlegen vor dem Anzeigen AWT, Swing, JavaFX & SWT 3
U Größe eines Button im Menü ändern AWT, Swing, JavaFX & SWT 1
G JavaFX Größe der Parentknoten AWT, Swing, JavaFX & SWT 5
R JPanel-Größe verändert sich nicht. Warum? AWT, Swing, JavaFX & SWT 5
T Swing Aktuelle Größe eines Textes in einem Label darstellen AWT, Swing, JavaFX & SWT 3
A JPanel oder GridLayout Größe festsetzten AWT, Swing, JavaFX & SWT 4
F Swing JComboBox - Frage zur Größe AWT, Swing, JavaFX & SWT 11
X Swing Größe eines Fensters JFrame / Frame AWT, Swing, JavaFX & SWT 5
SimonRap Swing JFrame Größe zur Laufzeit ändern AWT, Swing, JavaFX & SWT 2
G 2D-Grafik Größe der JFrame Decorations herausfinden? AWT, Swing, JavaFX & SWT 4
O Swing Jpanel autom. auf JFrame Größe bringen AWT, Swing, JavaFX & SWT 6
M Swing JLabel mit fester größe nachträglich formatieren AWT, Swing, JavaFX & SWT 2
A JComponent Größe AWT, Swing, JavaFX & SWT 8
S Größe von Panel verändern welches auf anderem Panel sitzt AWT, Swing, JavaFX & SWT 10
B JTextArea Größe an Container anpassen AWT, Swing, JavaFX & SWT 2
S Swing TextPane größe beschränken AWT, Swing, JavaFX & SWT 2
R Ellipse2D ändert Größe AWT, Swing, JavaFX & SWT 3
H Swing JButton größe ändern AWT, Swing, JavaFX & SWT 5
G JScrollPane reagiert nicht auf Änderung der JPanel-Größe AWT, Swing, JavaFX & SWT 4
P JPanel Größe ändern AWT, Swing, JavaFX & SWT 22
I Größe eines rotierten Images AWT, Swing, JavaFX & SWT 3
C Button Größe einstellen klappt nicht (setBounds) AWT, Swing, JavaFX & SWT 8
S 2D-Grafik Canvas Problem(Größe) AWT, Swing, JavaFX & SWT 6
R Größe/Anordnung der Gui-Elemente automatisch? AWT, Swing, JavaFX & SWT 6
S Die größe eines JButton ändern AWT, Swing, JavaFX & SWT 7
U feste Größe für den Zeichenbereich eines JFrames AWT, Swing, JavaFX & SWT 4
L Graphics.drawImage() - Output-Größe entspricht nicht Parametern AWT, Swing, JavaFX & SWT 10
P Tatsächliche Größe für Applet AWT, Swing, JavaFX & SWT 3
C Swing GridBag-Probleme (Größe und Ausrichtung) AWT, Swing, JavaFX & SWT 3
K JFrame Größe ändern AWT, Swing, JavaFX & SWT 4
M jTable - Größe beim Erzeugen AWT, Swing, JavaFX & SWT 4
hdi Swing JFrame Größe ermitteln AWT, Swing, JavaFX & SWT 6
S Swing jFrame auf maximale Größe setzten AWT, Swing, JavaFX & SWT 7
Z größe der komponenten bestimmen AWT, Swing, JavaFX & SWT 16
X Alte Frame-Größe beim wiederholten Aufruf AWT, Swing, JavaFX & SWT 5
I Größe von JPanel ändern AWT, Swing, JavaFX & SWT 6
S SWT Shell durch Event in der Größe verändern AWT, Swing, JavaFX & SWT 7
L JFrame größe in einem ActionEvent ändern AWT, Swing, JavaFX & SWT 4
G LayoutManager BorderLayout WEST Bereich auf maximale Größe beschränken AWT, Swing, JavaFX & SWT 19
T Inhalt von einem Tab an JTabbedPane größe ausrichten? AWT, Swing, JavaFX & SWT 2
A Größe von Textfield bestimmen AWT, Swing, JavaFX & SWT 9
S Button Größe - Anfänger AWT, Swing, JavaFX & SWT 13
0 JPanel nicht an größe des JFrames anpassen AWT, Swing, JavaFX & SWT 3
S Swing Größe von JLabels verändern sich in einem Panel unterschiedlich AWT, Swing, JavaFX & SWT 6
B JPanel Größe regulieren AWT, Swing, JavaFX & SWT 4

Ähnliche Java Themen

Neue Themen


Oben