FlowLayout Live-Demo

Aus Byte-Welt Wiki

Autor: Gernot Segieth

Die FlowLayout-Live-Demo erleichtert spielerisch durch Erkunden und Verändern von Werten in der Benutzeroberfläche das Verständnis von FlowLayout.

Kopieren Sie sich die Quellcodes in einzelne Java-Dateien. Achten Sie auf die richtige Verteilung der Klassen in die im Code angegebenen Packages, oder kommentieren Sie die Package-Anweisung einfach aus, wenn Sie unsicher sind. Anschließend kompilieren Sie die Java-Dateien und starten die Hauptklasse.

FlowLayoutDemo.java - Die Hauptklasse

[Bearbeiten | Quelltext bearbeiten]
/*
 * FlowLayout-Live-Demo
 *
 * Copyright (c) 2019 Gernot Segieth - wiki.byte-welt.net
 * 
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following
 * conditions:
 * 
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 */
package flowlayout;

import flowlayout.event.AddAction;
import flowlayout.event.FlowOperations;
import flowlayout.event.HgapChangeAction;
import flowlayout.event.RemoveAction;
import flowlayout.event.SelectAction;
import flowlayout.event.VgapChangeAction;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.Toolkit;
import javax.swing.BorderFactory;
import javax.swing.ComboBoxModel;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSpinner;
import javax.swing.SpinnerNumberModel;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;

/**
 * Die FlowLayout-Live-Demo erleichtert spielerisch durch Erkunden und Verändern
 * von Werten in der Benutzeroberfläche das Verständnis von FlowLayout.
 *
 * @author Gernot Segieth, (c)2019
 * @see java.awt.FlowLayout
 */
public class FlowLayoutDemo implements FlowOperations {

    private JPanel flowPanel;
    private FlowLayout layout;
    private SpinnerNumberModel hgapModel; //JSpinner zur Eingabe horizontaler Abstände
    private SpinnerNumberModel vgapModel; //JSpinner zur Eingabe vertikaler Abstände
    private ComboBoxModel<Integer> alignArgumentModel;
    private int compCount; //zählt die Komponenten   

    public FlowLayoutDemo() {
        JFrame frame = new JFrame("FlowLayout (Live-Demo)");
        frame.add(createFlowPanel(), BorderLayout.CENTER);
        frame.add(createControlPanel(), BorderLayout.NORTH);
        frame.add(createSouthPanel(), BorderLayout.SOUTH);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        frame.setVisible(true);
    }

    @Override
    public void addComponent() {
        flowPanel.add(new JButton("JButton " + (++compCount)));
        flowPanel.validate();
        flowPanel.repaint();
    }

    @Override
    public void removeComponent() {
        if (compCount > 0) {
            flowPanel.remove(--compCount);
            flowPanel.validate();
            flowPanel.repaint();
        }
    }

    @Override
    public void changeAlignment() {
        int alignment = (Integer) alignArgumentModel.getSelectedItem();
        layout.setAlignment(alignment);
        update();
    }

    @Override
    public void changeHgap() {
        layout.setHgap((int) hgapModel.getNumber());
        update();
    }

    @Override
    public void changeVgap() {
        layout.setVgap((int) vgapModel.getNumber());
        update();
    }

    private JPanel createFlowPanel() {
        layout = new FlowLayout();
        flowPanel = new JPanel(layout) {
            @Override
            public Dimension getPreferredSize() {
                Dimension size = Toolkit.getDefaultToolkit().getScreenSize();
                return new Dimension(size.width * 40 / 100, size.height * 40 / 100);
            }
        };
        flowPanel.setBackground(Color.WHITE);
        return flowPanel;
    }

    private JPanel createControlPanel() {
        JButton addButton = new JButton(new AddAction(this));
        JButton removeButton = new JButton(new RemoveAction(this));

        alignArgumentModel = createComboBoxModel();
        JComboBox<Integer> alignBox = new JComboBox<>(alignArgumentModel);
        alignBox.setEditable(false);
        alignBox.setRenderer(new AlignmentComboBoxRenderer());
        alignBox.addActionListener(new SelectAction(this));

        hgapModel = new SpinnerNumberModel(layout.getHgap(), 0, 50, 1);
        JSpinner hgapSpinner = new JSpinner(hgapModel);
        hgapSpinner.addChangeListener(new HgapChangeAction(this));

        vgapModel = new SpinnerNumberModel(layout.getVgap(), 0, 50, 1);
        JSpinner vgapSpinner = new JSpinner(vgapModel);
        vgapSpinner.addChangeListener(new VgapChangeAction(this));

        JPanel panel = new JPanel(new GridBagLayout());
        panel.setBorder(BorderFactory.createEmptyBorder(10, 0, 10, 0));
        GridBagConstraints gbc = new GridBagConstraints();

        int space = 20;
        gbc.gridx = 0;
        gbc.gridy = 0;

        gbc.gridx++;
        panel.add(new JLabel("<html>setAlignment(<strong>FlowLayout.</strong></html> "), gbc);

        gbc.gridx++;
        panel.add(alignBox, gbc);

        gbc.insets = new Insets(0, 0, 0, space);
        gbc.gridx++;
        panel.add(new JLabel(" );"), gbc);

        gbc.insets = new Insets(0, 0, 0, 0);
        gbc.gridx++;
        panel.add(new JLabel("setHgap( "), gbc);

        gbc.gridx++;
        panel.add(hgapSpinner, gbc);

        gbc.insets = new Insets(0, 0, 0, space);
        gbc.gridx++;
        panel.add(new JLabel(" );"), gbc);

        gbc.insets = new Insets(0, 0, 0, 0);
        gbc.gridx++;
        panel.add(new JLabel("setVgap( "), gbc);

        gbc.gridx++;
        panel.add(vgapSpinner, gbc);

        gbc.insets = new Insets(0, 0, 0, space);
        gbc.gridx++;
        panel.add(new JLabel(" );"), gbc);

        panel.add(addButton);
        panel.add(removeButton);

        return panel;
    }

    private JPanel createSouthPanel() {
        JLabel label = new JLabel("<html>&copy;2019 Gernot Segieth, Byte-Welt-Wiki (https://wiki.byte-welt.net)</html>");
        label.setForeground(label.getBackground().darker());
        label.setFont(label.getFont().deriveFont(10f));
        JPanel panel = new JPanel();
        panel.add(label);
        return panel;
    }

    private ComboBoxModel<Integer> createComboBoxModel() {
        Integer[] items = new Integer[]{
            FlowLayout.CENTER,
            FlowLayout.LEADING,
            FlowLayout.LEFT,
            FlowLayout.RIGHT,
            FlowLayout.TRAILING
        };
        alignArgumentModel = new DefaultComboBoxModel<>(items);
        alignArgumentModel.setSelectedItem(layout.getAlignment());
        return alignArgumentModel;
    }

    private void update() {
        SwingUtilities.invokeLater(() -> {
            flowPanel.updateUI();
        });
    }

    public static void main(String[] args) {
        JFrame.setDefaultLookAndFeelDecorated(true);
        UIManager.put("swing.boldMetal", false);
        SwingUtilities.invokeLater(() -> {
            new FlowLayoutDemo();
        });
    }

}

Klassen aus dem Event-Package

[Bearbeiten | Quelltext bearbeiten]

Interface FlowOperations - die Funktionen der Demo

[Bearbeiten | Quelltext bearbeiten]
package flowlayout.event;

/**
 *
 * @author Gernot Segieth
 */
public interface FlowOperations {

    public void addComponent();

    public void removeComponent();

    public void changeAlignment();

    public void changeHgap();

    public void changeVgap();

}

AddAction - Hinzufügen neuer Komponenten

[Bearbeiten | Quelltext bearbeiten]
package flowlayout.event;

import gridlayout.icons.MoreIcon;
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;

/**
 *
 * @author Gernot Segieth
 */
public class AddAction extends AbstractAction {

    private final FlowOperations fo;

    public AddAction(FlowOperations fo) {
        super("", new MoreIcon());
        this.fo = fo;
    }

    @Override
    public void actionPerformed(ActionEvent ae) {
        fo.addComponent();
    }

}

RemoveAction - Entfernen von Komponenten

[Bearbeiten | Quelltext bearbeiten]
package flowlayout.event;

import gridlayout.icons.LessIcon;
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;

/**
 *
 * @author Gernot Segieth
 */
public class RemoveAction extends AbstractAction {

    private final FlowOperations fo;

    public RemoveAction(FlowOperations fo) {
        super("", new LessIcon());
        this.fo = fo;
    }

    @Override
    public void actionPerformed(ActionEvent ae) {
        fo.removeComponent();
    }

}

SelectAction - Auswahl in der JComboBox behandeln

[Bearbeiten | Quelltext bearbeiten]
package flowlayout.event;

import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;

/**
 *
 * @author Gernot Segieth
 */
public class SelectAction extends AbstractAction {

    private final FlowOperations fo;

    public SelectAction(FlowOperations fo) {
        this.fo = fo;
    }

    @Override
    public void actionPerformed(ActionEvent ae) {
        fo.changeAlignment();
    }

}

HgapChangeAction - Horizontalen Abstand einstellen

[Bearbeiten | Quelltext bearbeiten]
package flowlayout.event;

import javax.swing.event.ChangeEvent;

/**
 *
 * @author Gernot Segieth
 */
public class HgapChangeAction extends AbstractChangeAction {

    private FlowOperations fo;

    public HgapChangeAction(FlowOperations fo) {
        this.fo = fo;
    }

    @Override
    public void stateChanged(ChangeEvent ce) {
        fo.changeHgap();
    }

}

VgapChangeAction - Vertikalen Abstand einstellen

[Bearbeiten | Quelltext bearbeiten]
package flowlayout.event;

import javax.swing.event.ChangeEvent;

/**
 *
 * @author Gernot Segieth
 */
public class VgapChangeAction extends AbstractChangeAction {

    private FlowOperations fo;

    public VgapChangeAction(FlowOperations fo) {
        this.fo = fo;
    }

    @Override
    public void stateChanged(ChangeEvent ce) {
        fo.changeVgap();
    }

}

Ein Renderer für die JComboBox

[Bearbeiten | Quelltext bearbeiten]
package flowlayout;

import java.awt.Component;
import java.awt.FlowLayout;
import javax.swing.DefaultListCellRenderer;
import javax.swing.JList;

/**
 *
 * @author Gernot Segieth
 */
public class AlignmentComboBoxRenderer extends DefaultListCellRenderer {

    @Override
    public Component getListCellRendererComponent(JList<?> list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
        super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
        if (value instanceof Integer) {
            Integer intValue = (Integer) value;
            switch (intValue) {
                case FlowLayout.LEADING:
                    this.setText("LEADING");
                    break;
                case FlowLayout.LEFT:
                    this.setText("LEFT");
                    break;
                case FlowLayout.RIGHT:
                    this.setText("RIGHT");
                    break;
                case FlowLayout.TRAILING:
                    this.setText("TRAILING");
                    break;
                default:
                    this.setText("CENTER");
            }
        }
        return this;

    }
}

Fehlen nur noch die Icons, die auch als Java-Klasse angelegt werden können.

Zunächst das Minus-Icon:

package flowlayout.icons;

import java.awt.BasicStroke;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.awt.geom.GeneralPath;
import java.awt.geom.Path2D;
import javax.swing.Icon;

public class LessIcon implements Icon {

    @Override
    public void paintIcon(Component c, Graphics gr, int x, int y) {
        Graphics2D g = (Graphics2D) gr;
        AffineTransform at = new AffineTransform();
        at.translate(x, y);
        at.scale(getIconWidth(), getIconHeight());
        Shape transformedShape = at.createTransformedShape(createShape());
        g.setStroke(new BasicStroke(2));
        g.draw(transformedShape);
        g.dispose();
    }

    @Override
    public int getIconWidth() {
        return 15;
    }

    @Override
    public int getIconHeight() {
        return getIconWidth();
    }

    private Shape createShape() {
        Path2D path = new GeneralPath();
        path.moveTo(0.1f, 0.5f);
        path.lineTo(0.9f, 0.5f);
        return path;
    }
}

Das Plus-Icon:

package flowlayout.icons;

import java.awt.BasicStroke;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.awt.geom.GeneralPath;
import java.awt.geom.Path2D;
import javax.swing.Icon;

public class MoreIcon implements Icon {

    @Override
    public void paintIcon(Component c, Graphics gr, int x, int y) {
        Graphics2D g = (Graphics2D) gr;
        AffineTransform at = new AffineTransform();
        at.translate(x, y);
        at.scale(getIconWidth(), getIconHeight());
        Shape transformedShape = at.createTransformedShape(createShape());
        g.setStroke(new BasicStroke(2));
        g.draw(transformedShape);
        g.dispose();
    }

    @Override
    public int getIconWidth() {
        return 15;
    }

    @Override
    public int getIconHeight() {
        return getIconWidth();
    }

    private Shape createShape() {
        Path2D path = new GeneralPath();
        path.moveTo(0.5f, 0.1f);
        path.lineTo(0.5f, 0.9f);
        path.moveTo(0.1f, 0.5f);
        path.lineTo(0.9f, 0.5f);
        return path;
    }
}


Das Thema wurde nicht ausreichend behandelt? Du hast Fragen dazu und brauchst weitere Informationen? Lass Dir von uns helfen!

  • Besuche unseren Chat

Wir helfen dir gerne!


Weiterführende Links

[Bearbeiten | Quelltext bearbeiten]