0

我正在寻找一个 java 自定义布局管理器,它以类似于蜗牛的背线的方式排列几个数据(例如 jlabels)。

到目前为止,我一直在尝试使用我在互联网上找到的圆圈布局来定制它,但没有运气.. 有什么想法吗???

4

1 回答 1

2

您可以编写自己的布局。我从Spirals得到的螺旋公式。它是阿基米德,而蜗牛更像是费马螺旋,您可以更改calculatePoint()方法以返回不同的螺旋。

注意:这种布局效率有点低,因为它每次都重新计算所有组件的位置,而不是缓存它。

import java.awt.*;
import java.util.*;
import javax.swing.*;
import javax.swing.event.*;

public class SpiralLayout implements LayoutManager2 {

    private enum Size { MIN, MAX, PREF }

    private double radiusStep;
    private double angleStep;

    public SpiralLayout() {
        this(10, Math.toRadians(15.0));
    }

    public SpiralLayout(double radius, double stepSize) {
        this.radiusStep = radius;
        this.angleStep = stepSize;
    }

    public void setRadiusStep(double radiusStep) {
        this.radiusStep = radiusStep;
    }


    public void setAngleStep(double angleStep) {
        this.angleStep = angleStep;
    }

    @Override
    public void addLayoutComponent(String name, Component comp) {
        // calculated on the fly
    }

    @Override
    public void removeLayoutComponent(Component comp) {
        // calculated on the fly
    }

    @Override
    public Dimension preferredLayoutSize(Container parent) {
        return getSize(parent, Size.PREF);
    }

    private Dimension getSize(Container parent, Size size) {
        doLayoutContainer(parent, Short.MAX_VALUE, Short.MAX_VALUE, size);

        Point min = new Point(Integer.MAX_VALUE, Integer.MAX_VALUE);
        Point max = new Point(0, 0);
        for(Component component : parent.getComponents()) {
            Dimension preferredSize = getSize(component, size);
            min.x = Math.min(min.x, component.getX());
            min.y = Math.min(min.y, component.getY());
            max.x = Math.max(max.x, component.getX() + preferredSize.width);
            max.y = Math.max(max.y, component.getY() + preferredSize.height);
        }
        int center = Short.MAX_VALUE / 2;
        return new Dimension(
                Math.max(Math.abs(center - min.x), Math.abs(center - max.x) * 2),
                Math.max(Math.abs(center - min.y), Math.abs(center - max.y) * 2));
    }

    private Dimension getSize(Component component, Size size) {
        switch(size) {
        case MAX:
            return component.getMaximumSize();
        case MIN:
            return component.getMinimumSize();
        case PREF:
            return component.getPreferredSize();
        default:
            assert false : "Unknown size: " + size;
            return new Dimension();
        }
    }

    @Override
    public Dimension minimumLayoutSize(Container parent) {
        return getSize(parent, Size.MIN);
    }

    @Override
    public void layoutContainer(Container parent) {
        doLayoutContainer(parent,
                parent.getWidth(), parent.getHeight(), Size.PREF);
    }

    private List<Rectangle> doLayoutContainer(Container parent,
            int width, int height, Size size) {

        Point offset = new Point(width / 2, height / 2);
        List<Rectangle> componentBounds = new ArrayList<Rectangle>();
        double angle = 0;
        double radius = 1;
        for(Component component : parent.getComponents()) {
            Dimension preferredSize = getSize(component, size);
            Rectangle bounds;
            do {
                bounds = new Rectangle(
                        add(calculatePoint(angle, radius), offset),
                        preferredSize);
                angle += angleStep;
                radius += radiusStep;
            }
            while(overlaps(bounds, componentBounds));

            component.setBounds(bounds);
            componentBounds.add(bounds);
        }
        return componentBounds;
    }

    private Point calculatePoint(double angle, double radius) {
        double x = radius * Math.cos(angle);
        double y = radius * Math.sin(angle);
        return new Point((int) x, (int) y);
    }

    private boolean overlaps(Rectangle bounds, List<Rectangle> componentBounds) {
        for(Rectangle other : componentBounds) {
            if(other.intersects(bounds)) {
                return true;
            }
        }
        return false;
    }

    private Point add(Point a, Point b) {
        return new Point(a.x + b.x, a.y + b.y);
    }

    @Override
    public void addLayoutComponent(Component comp, Object constraints) {
        // calculated on the fly
    }

    @Override
    public Dimension maximumLayoutSize(Container parent) {
        return getSize(parent, Size.MAX);
    }

    @Override
    public float getLayoutAlignmentX(Container target) {
        return 0.5f;
    }

    @Override
    public float getLayoutAlignmentY(Container target) {
        return 0.5f;
    }

    @Override
    public void invalidateLayout(Container target) {
        // calculated on the fly
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                final SpiralLayout layout = new SpiralLayout();
                final JPanel panel = new JPanel(layout);

                final JSpinner angleSpinner = new JSpinner(new SpinnerNumberModel(Math.toDegrees(layout.angleStep), 1.0, 360.0, 5.0));
                angleSpinner.addChangeListener(new ChangeListener() {
                    @Override
                    public void stateChanged(ChangeEvent e) {
                        double angle = (Double) angleSpinner.getValue();
                        layout.setAngleStep(Math.toRadians(angle));
                        panel.revalidate();
                    }
                });
                final JSpinner radiusSpinner = new JSpinner(new SpinnerNumberModel((int)  layout.radiusStep, 1, 1000, 1));
                radiusSpinner.addChangeListener(new ChangeListener() {
                    @Override
                    public void stateChanged(ChangeEvent e) {
                        int radius = (Integer) radiusSpinner.getValue();
                        layout.setRadiusStep(radius);
                        panel.revalidate();
                    }
                });
                JPanel buttons = new JPanel();
                buttons.add(new JLabel("Radius step:"));
                buttons.add(radiusSpinner);
                buttons.add(new JLabel("Angle step"));
                buttons.add(angleSpinner);

                for(int i = 1; i <= 25; i++) {
                    panel.add(new JLabel("Label " + i));
                }
                JFrame frame = new JFrame("Test");
                frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
                frame.getContentPane().add(buttons, BorderLayout.PAGE_START);
                frame.getContentPane().add(panel);
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }
}
于 2012-09-17T11:52:40.473 回答