我正在寻找一个 java 自定义布局管理器,它以类似于蜗牛的背线的方式排列几个数据(例如 jlabels)。
到目前为止,我一直在尝试使用我在互联网上找到的圆圈布局来定制它,但没有运气.. 有什么想法吗???
我正在寻找一个 java 自定义布局管理器,它以类似于蜗牛的背线的方式排列几个数据(例如 jlabels)。
到目前为止,我一直在尝试使用我在互联网上找到的圆圈布局来定制它,但没有运气.. 有什么想法吗???
您可以编写自己的布局。我从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);
}
});
}
}