web-dev-qa-db-ger.com

Dynamische Steuerung der automatischen Größenänderung von Komponenten in Java Swing

Erstellen einer neuen GUI in Java (1.8) Swing, ich suche nach einer Möglichkeit, das Größenänderungsverhalten aller meiner Komponenten zu überschreiben.

Lassen Sie mich Ihnen mit einigen bearbeiteten Fotos erklären:

1. Vollbild-GUI

Dies ist meine Vollbild-GUI mit 3 Panels und einer JToolBar. Das grüne muss ein feste Größe haben, die anderen wären skalierbar.

Derzeit habe ich nur 2 kleine GridLayout, um sie zu organisieren (eine vertikale und eine horizontale für grüne und cyanfarbene Panels).

FullScreen GUI

2. Kleine horizontale Größenänderung

Wenn ich beispielsweise die Framegröße von der rechten Seite her verkleinere, möchte ich, dass mein blauer und zyanfarbener Bereich verkleinert entsprechend der neuen Framegröße wird. Das grüne Feld muss jedoch fixiert sein. (Nicht der schwierigste Teil, denke ich.)

Resized once GUI

3. Minimale horizontale Größe

Dies ist der schwierigste Teil für mich. Sobald das Cyan (oder Blau) -Panel-Minimum eine minimale Größe hat, möchte ich, dass er das grüne Panel nach links "Push", auch wenn es vom Rahmen verschwindet.

Wenn Sie den Rahmen nach rechts ziehen, wird das grüne Feld natürlich wieder angezeigt.

Minimum size of the GUI

Wie kann ich das machen?

Ich dachte daran, JSplitPane oder einen bestimmten Listener zu verwenden, um das Größenänderungsverhalten manuell zu bestimmen, aber ich brauche ein paar Ratschläge.

Entschuldigung, wenn ein vorhandener Beitrag dies beantworten kann, habe ich keine Antwort gefunden, die das Problem für mich erklärt.

Danke im Voraus!


Wenn Sie mehr Beispiele wünschen, schauen Sie sich die "Evernote" -Software an, die auf dieselbe Weise funktioniert.

12
Kapcash

Durch das Festlegen der maximalen/minimalen/bevorzugten Größe des Green-Bereichs kann dieser Bereich unter der ersten Bedingung die gleiche Größe beibehalten. Um nach Größenänderungen zu suchen, können Sie eine ComponentListener für eine der anderen JPanels verwenden. Wenn die Größe unter eine bestimmte Breite fällt, ändern Sie die max/min/bevorzugte Größe des Green-Bedienfelds. 

Im Folgenden finden Sie ein zusammen gehacktes Beispiel dafür - es ändert die Größe des Green-Bedienfelds, wenn die Blue <600 ist und die Größenänderung eine gewichtete Größenänderung (30% der Gesamtbreite) ist. Um das wahre L & F und das, was Sie wünschen, zu erhalten, müssen Sie möglicherweise mit dem Layout/den Größen spielen. 

import Java.awt.BorderLayout;
import Java.awt.Color;
import Java.awt.Dimension;
import Java.awt.GridBagConstraints;
import Java.awt.GridBagLayout;
import Java.awt.GridLayout;
import Java.awt.Insets;
import Java.awt.Rectangle;
import Java.awt.event.ComponentAdapter;
import Java.awt.event.ComponentEvent;
import Java.awt.event.ComponentListener;

import javax.swing.Box;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JToolBar;
import javax.swing.SwingUtilities;


public class GridTest extends JPanel{

    private boolean changeAllowed = false;
    //keep reference to cyan for the height dimension
    final JPanel cyan = new JPanel();

    public GridTest(){
        cyan.setPreferredSize(new Dimension(600, 300));//provide sizing hint
    }

    private Dimension getCustomDimensions(){
        if ( changeAllowed ){
            return new Dimension((int)(super.getParent().getBounds().width * 0.3), cyan.getBounds().height);
        }else{
            return new Dimension(200, cyan.getBounds().height);
        }
    }
    @Override
    public Dimension getMaximumSize(){
        return getCustomDimensions();
    }
    @Override
    public Dimension getMinimumSize(){
        return getCustomDimensions();
    }
    @Override
    public Dimension getPreferredSize(){
        return getCustomDimensions();
    }

    public static void main(String[] args) throws Exception{
        SwingUtilities.invokeAndWait(new Runnable(){

            @Override
            public void run() {
                final int MINIMUM = 600;
                JFrame frame = new JFrame();
                frame.add(new JToolBar(), BorderLayout.NORTH);
                final JPanel blue = new JPanel();

                final GridTest green = new GridTest();
                green.setBackground(Color.green);
                green.setOpaque(true);

                green.cyan.setBackground(Color.cyan);
                green.cyan.setOpaque(true);
                blue.setOpaque(true);
                blue.setBackground(Color.blue);
                blue.setPreferredSize(new Dimension(900, 300));//hint at size
                blue.setMinimumSize(new Dimension(100, 200));//hint at size
                //Nest Box Layouts
                Box top = Box.createHorizontalBox();
                top.add(blue);
                Box bottom = Box.createHorizontalBox();
                bottom.add(green);
                bottom.add(green.cyan);
                Box vert = Box.createVerticalBox();
                vert.add(top);
                vert.add(bottom);
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(vert);
                //listen for resizes
                blue.addComponentListener(new ComponentAdapter(){

                    @Override
                    public void componentResized(ComponentEvent e) {
                        if ( blue.getBounds().width < MINIMUM ){//set flag
                            green.changeAllowed = true;
                        }else{
                            green.changeAllowed = false;
                        }
                    }
                });

                frame.pack();
                frame.setSize(800, 600);
                frame.setVisible(true);

            }

        });
    }
}
7
copeg

So mache ich es und ich bin nicht sicher, ob dies der richtige Weg ist:

Setzen Sie zunächst das Layout auf null.

Erstellen Sie als Nächstes ein Ereignis in der Größe einer Komponente für Ihren Frame:

addComponentListener(new ComponentAdapter(){
            public void componentResized(ComponentEvent e){
            }
        });

Hier können Sie manuell Änderungen an den Komponenten vornehmen, wenn deren Größe geändert wird. Ich habe dies für ein paar meiner Programme getan, um einen Bildlaufbereich links und rechts des Rahmens immer auf der gleichen Breite zu halten und die Größe der anderen Größe zu ändern.

3
Forseth11

Mit einem GridBagLayout sollte dies problemlos möglich sein, vorausgesetzt, Sie haben geeignete Mindestgrößen für die Grün- und Cyan-Komponenten festgelegt:

setLayout(new GridBagLayout());
green.setMnimumSize(new Dimension(0, 0));
cyan.setMinimumSize(new Dimension(100, 100)); // whatever fits
add(blue, new GridBagConstraints(0, 0, 2, 1,
        1.0, 0.0,
        GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL,
        new Insets(0, 0, 0, 0), 0, 0);
add(green, new GridBagConstraints(0, 1, 1, 1,
        0.0, 0.0,
        GridBagConstraints.WEST, GridBagConstraints.NONE,
        new Insets(0, 0, 0, 0), 0, 0);
add(cyan, new GridBagConstraints(1, 1, 1, 1,
        1.0, 0.0,
        GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL,
        new Insets(0, 0, 0, 0), 0, 0);

Durch die Angabe einer Gewichtung x für die Cyan- und Blau-Komponente sowie die Einstellung von resize = HORIZONTAL wird die Größe des Containers angepasst.

3
Durandal

Sie können eine BoxLayout verwenden, um das grüne und das cyanfarbene Bedienfeld aufzunehmen. Eine BoxLayout berücksichtigt die minimalen und maximalen Größen einer Komponente. Für das grüne Feld setzen Sie dann die maximale Größe entsprechend der bevorzugten Größe und für das Cyan-Feld die minimale Größe, die der bevorzugten Größe entspricht:

import Java.awt.*;
import Java.util.*;
import javax.swing.*;

public class SSCCE extends JPanel
{
    public SSCCE()
    {
        JPanel blue = new JPanel();
        blue.setBackground( Color.BLUE );
        blue.setPreferredSize( new Dimension(500, 100) );

        Box box = Box.createHorizontalBox();

        JPanel green = new JPanel();
        green.setBackground( Color.GREEN );
        green.setPreferredSize( new Dimension(200, 100) );
        green.setMaximumSize( green.getPreferredSize() );
        box.add( green );

        JPanel cyan = new JPanel();
        cyan.setBackground( Color.CYAN );
        cyan.setPreferredSize( new Dimension(300, 100) );
        cyan.setMinimumSize( cyan.getPreferredSize() );
        box.add( cyan );

        setLayout( new BorderLayout() );
        add(blue, BorderLayout.NORTH);
        add(box, BorderLayout.CENTER);
    }

    private static void createAndShowGUI()
    {
        JFrame frame = new JFrame("SSCCE");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(new SSCCE());
        frame.setLocationByPlatform( true );
        frame.pack();
        frame.setVisible( true );
    }

    public static void main(String[] args)
    {
        EventQueue.invokeLater(new Runnable()
        {
            public void run()
            {
                createAndShowGUI();
            }
        });
    }
}

Natürlich ist es die richtige Lösung, die getMaximumSize()- bzw. getMinimumSize()-Methoden jedes Panels zu überschreiben, um nur die bevorzugte Größe des Panels zurückzugeben.

2
camickr

Die wichtige Reihenfolge ist folgende:

                frame.revalidate();
                frame.pack();
                frame.repaint();
  1. revalidate (): macht die Komponenten bis zur nächsten Wurzel ungültig, danach wird die Komponente Hierarchie ausgehend von der nächstgelegenen Validierungswurzel validiert.
  2. pack (): Legt fest, dass die Größe des Fensters der bevorzugten Größe und dem bevorzugten Layout seiner Unterkomponenten entspricht. Die resultierende Breite und Höhe des Fensters werden automatisch vergrößert.
  3. repaints (): Nach all diesen Neuberechnungen zeigt die Neulackierung die Komponenten.

Verwenden Sie diese Reihenfolge nach jeder Reihe von Änderungen, die Sie in Ihrem Code vorgenommen haben und die Ergebnisse auf dem Bildschirm angezeigt werden sollen.

Ich mag das Java.awt.GridBagLayout in Kombination mit dem Java.awt.GridBagConstraints und verwende dieses Layout für alle Container, die vom Inhaltsbereich aus gestartet werden.

Wenn Sie einen Container zu einem anderen Container hinzufügen, verwenden Sie für jedes Container ein Layout. Andernfalls schlägt die Berechnung fehl, weil das Layout in der Hierarchie fehlt.

0
michbau