Java蜗牛线布局管理器
我正在寻找一个java自定义布局管理器,它以类似于snail的后端的方式排列一些数据(例如JLabel)Java蜗牛线布局管理器,java,swing,layout,layout-manager,cyclic,Java,Swing,Layout,Layout Manager,Cyclic,我正在寻找一个java自定义布局管理器,它以类似于snail的后端的方式排列一些数据(例如JLabel) 到目前为止,我已经尝试过在互联网上找到的圆形布局进行定制,但没有成功。。有什么想法吗?你可以自己写布局。螺旋公式我从。它是阿基米德式的,而蜗牛更像蜗牛,您可以更改calculatePoint()方法以返回不同的螺旋 注意:这个布局效率有点低,因为它每次都重新计算所有组件的位置,而不是缓存它 import java.awt.*; import java.util.*; import javax
到目前为止,我已经尝试过在互联网上找到的圆形布局进行定制,但没有成功。。有什么想法吗?你可以自己写布局。螺旋公式我从。它是阿基米德式的,而蜗牛更像蜗牛,您可以更改
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);
}
});
}
}
import java.awt.*;
导入java.util.*;
导入javax.swing.*;
导入javax.swing.event.*;
公共类SpiralLayout实现LayoutManager2{
私有枚举大小{MIN,MAX,PREF}
私有双半径步骤;
私人双阶梯;
公共空间布局(){
这(10,数学托拉迪安(15.0));
}
公共螺旋布局(双半径、双步长){
this.radiustep=半径;
此.angleStep=步长;
}
公共无效setRadiusStep(双radiusStep){
this.radiustep=radiustep;
}
公共无效setAngleStep(双angleStep){
this.angleStep=angleStep;
}
@凌驾
public void addLayoutComponent(字符串名称,组件组成){
//即时计算
}
@凌驾
公共void removeLayoutComponent(组件组件组件){
//即时计算
}
@凌驾
公共维度preferredLayoutSize(容器父级){
返回getSize(父级,Size.PREF);
}
私有维度getSize(容器父级,大小){
doLayoutContainer(父级,Short.MAX_值,Short.MAX_值,大小);
最小点=新点(Integer.MAX\u值,Integer.MAX\u值);
最大点=新点(0,0);
对于(组件:parent.getComponents()){
维度preferredSize=getSize(组件,大小);
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_值/2;
返回新维度(
数学最大值(数学绝对值(中心-最小值x)、数学绝对值(中心-最大值x)*2),
max(Math.abs(center-min.y)、Math.abs(center-max.y)*2);
}
私有维度getSize(组件、大小){
开关(尺寸){
最大情况:
返回组件。getMaximumSize();
案例最小值:
返回组件。getMinimumSize();
案例序言:
返回组件。getPreferredSize();
违约:
断言false:“未知大小:”+大小;
返回新维度();
}
}
@凌驾
公共维度minimumLayoutSize(容器父级){
返回getSize(父级,Size.MIN);
}
@凌驾
公共无效布局容器(容器父级){
doLayoutContainer(母公司、,
parent.getWidth()、parent.getHeight()、Size.PREF);
}
私有列表doLayoutContainer(容器父级,
整数宽度、整数高度、大小){
点偏移=新点(宽度/2,高度/2);
List componentBounds=新的ArrayList();
双角度=0;
双半径=1;
对于(组件:parent.getComponents()){
维度preferredSize=getSize(组件,大小);
矩形边界;
做{
边界=新矩形(
添加(计算点(角度、半径)、偏移),
首选尺寸);
角度+=角度步长;
半径+=半径步长;
}
while(重叠(边界、组件边界));
组件。立根(边界);
componentBounds.add(bounds);
}
返回组件边界;
}
专用点计算点(双角度、双半径){
双x=半径*数学cos(角度);
双y=半径*数学sin(角度);
返回新点((int)x,(int)y);
}
专用布尔重叠(矩形边界、列表组件边界){
用于(矩形其他:组件边界){
如果(其他相交(边界)){
返回true;
}
}
返回false;
}
专用点添加(点a、点b){
返回新点(a.x+b.x,a.y+b.y);
}
@凌驾
public void addLayoutComponent(组件组件、对象约束){
//即时计算
}
@凌驾
公共维度maximumLayoutSize(容器父级){
返回getSize(父级,Size.MAX);
}
@凌驾
公共浮点getLayoutAlignmentX(容器目标){
返回0.5f;
}
@凌驾
公共浮点GetLayoutAlignment(容器目标){
返回0.5f;
}
@凌驾
public void invalidateLayout(容器目标){
//即时计算
}
公共静态void main(字符串[]args){
invokeLater(新的Runnable(){
@凌驾
公开募捐{
最终螺旋布局=新的螺旋布局();
最终JPanel面板=新JPanel(布局);
最终JSpinner angleSpinner=新JSpinner(新SpinnerNumberModel(数学toDegrees(layout.angleStep),1.0360.0,5.0));
angleSpinner.addChangeListener(新的ChangeListener(){
@凌驾
公共无效状态已更改(更改事件e){
双角度=(双)角度微调器.getValue();
布局。setAngleStep(数学toRadians(角度));
panel.revalidate();
}
});
最终JSpinner radiusSpinner=新J