2012-09-16 2 views
0

나는 달팽이의 백 라인과 비슷한 방식으로 두 개의 데이터 (예 : jlabels)를 정렬하는 Java 사용자 정의 레이아웃 매니저를 찾고 있습니다.자바 달팽이 라인 레이아웃 매니저

지금까지 내가 인터넷에서 찾은 원 레이아웃에서 작동 시키려고했지만 행운이 없었습니다 .. 어떤 아이디어 ???

+0

레이블의 텍스트가 가로로 정렬되어 있습니까? 아니면 곡선을 따라 정렬되어 있습니까? 후자는 JLabel로하기가 어려울 것이지만 사용자 정의 페인팅으로는 더 쉽습니다. –

+0

기본적으로 레이아웃을 사용하여 노드를 배열하려고 시도하지만 먼저 데이터를 배열하는 방법을 알기 위해 일부 레이블이있는 JFrame에서이를 수행하려고하는 그래프입니다. 훨씬 더 간단합니다. – kafou

+0

"달팽이의 등선"DYM 나선형? * "어떤 아이디어?"* 고착 된 문제 수정? 열쇠를 보여주고 [무엇을 시도했는지] 보여줍니다 (http://www.whathaveyoutried.com/). –

답변

2

자신 만의 레이아웃을 작성할 수 있습니다. 나선형 수식은 Spirals에서 가져 왔습니다. 달팽이가 Fermat's spiral 일 때 아르키메데스 인 경우 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); 
      } 
     }); 
    } 
}