2016-10-30 3 views
1

현재 내가 작업하고있는 프로젝트의 일부로, (암호화 알고리즘의 일부로) 비트의 순열을 시각화하는 데 사용할 수있는 구성 요소를 구현하고 있습니다. 저는 두 개의 "핀"행을 만들고 팁 사이에 선을 그어 연결하여 그들 사이에 일종의 웹을 만듭니다.BoxLayout을 사용하여 패널 사이의 간격을 0으로 설정 하시겠습니까?

이 중요한 부분은이 시각화를 다른 시각화 (예 : S-Boxes를 포함 할 수도 있음)의 일부분과 함께 사용하고 있다는 것입니다. 따라서 나는 시각화를 사용할 수 있어야합니다. 핀을 켜고 끕니다. 내 해결책은 JPanel을 사용하여 보이지 않게 할 수있는 머리말과 꼬리말 패널에 핀 행을 넣는 것입니다.

BoxLayout에 수직으로 레이아웃하고 있지만 머리글과 바닥 글 아래에 접착제를 추가하더라도 그 사이에 공백이 생깁니다.

Web without resizing.

을 내가 크기를 조정할 때, 그들은 함께 조금 온,하지만 여전히 한쪽에만 접촉 : 초기화 할 때

내 예는 다음과 같습니다

Web after resizing.

필자는 이것이 컴포넌트 공간과 레이아웃면에서 사용자 공간을 디바이스 공간으로 변환하는 일종의 어리석은 실수라고 추측하고 있지만, 필자의 삶 에선 찾을 수 없다. 나는 혼란을 드려 죄송하지만 이것은 내 코드입니다 :

import java.awt.BasicStroke; 
import java.awt.Dimension; 
import java.awt.FlowLayout; 
import java.awt.Graphics; 
import java.awt.Graphics2D; 
import java.awt.geom.Line2D; 
import java.awt.geom.Point2D; 
import java.awt.geom.Ellipse2D; 

import javax.swing.Box; 
import javax.swing.BoxLayout; 
import javax.swing.JFrame; 
import javax.swing.JPanel; 

public class PermutationWeb extends JPanel 
{ 
    private static enum EndPanelType 
    { 
     HEADER, FOOTER 
    } 

    private final JPanel header; 
    private final JPanel mainPanel; 
    private final JPanel footer; 

    private double widthFactor; 
    private double heightFactor; 
    private int  widthMax; 
    private int  heightMax; 
    private int[] indexMappings; 
    private Point2D.Double[] endpoints; 
    private Line2D.Double[] drawingLines; 

    public PermutationWeb(int indices, boolean endPanelsOn) 
    { 
     super(); 

     setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); 

     widthMax = (indices + 1)*2; 
     heightMax = (int)Math.round(widthMax*(3.0/17.0)); 
     widthFactor = 1; 
     heightFactor = 1; 

     endpoints = new Point2D.Double[indices * 2]; 
     drawingLines = new Line2D.Double[indices]; 

     for(int i=0; i<indices; i++) 
     { 
      endpoints[i]   = new Point2D.Double(i*2+2, 0); 
      endpoints[i+indices] = new Point2D.Double(i*2+2, heightMax); 
      drawingLines[i] = new Line2D.Double(); 
     } 

     header = new WebEndPanel(EndPanelType.HEADER); 
     mainPanel = new WebMainPanel(); 
     footer = new WebEndPanel(EndPanelType.FOOTER); 

     add(Box.createVerticalGlue()); 
     add(header); 
     add(mainPanel); 
     add(footer); 
     add(Box.createVerticalGlue()); 

     setEndPanelsOn(endPanelsOn); 
    } 

    public Point2D getEndpoint(int index) 
    { 
     return endpoints[index]; 
    } 

    public void updateMappings(int[] mappings) 
    { 
     this.indexMappings = mappings; 

     for(int i=0; i<indexMappings.length; i++) 
     { 
      drawingLines[i].setLine(endpoints[i], endpoints[indexMappings.length + indexMappings[i]]); 
     } 

     //paint(); 
    } 

    public void setEndPanelsOn(boolean endPanelsOn) 
    { 
     header.setVisible(endPanelsOn); 
     footer.setVisible(endPanelsOn); 
    } 

    @Override 
    public Dimension getMaximumSize() 
    { 
     int height = mainPanel.getHeight(); 
     if(header.isVisible()) 
     { 
      height += (header.getHeight() * 2); 
     } 

     int width = mainPanel.getWidth(); 

     return new Dimension(width, height); 
    } 

    @Override 
    public Dimension getPreferredSize() 
    { 
     return getMaximumSize(); 
    } 

    public static void main(String[] args) 
    { 
     JFrame jf = new JFrame(); 
     jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     jf.setSize(800, 600); 

     int[] mappings = {0,4,8,12,1,5,9,13,2,6,10,14,3,7,11,15}; 

     PermutationWeb webTest = new PermutationWeb(16, true); 
     jf.add(webTest); 
     jf.setVisible(true); 
     webTest.setVisible(true); 

     webTest.updateMappings(mappings); 

     System.out.printf("Header: [%s]\nMainPanel: [%s]\nFooter: [%s]\n", 
       webTest.header.getSize().toString(), 
       webTest.mainPanel.getSize().toString(), 
       webTest.footer.getSize().toString()); 
    } 


    private class WebMainPanel extends WebSubPanel 
    { 
     private static final double HEIGHT_RATIO = 0.25; 

     @Override 
     public void paintComponent(Graphics g) 
     { 
      Graphics2D g2 = (Graphics2D)g; 
      super.paintComponent(g2); 

      scaleTo(getSize()); 
      g2.scale(widthFactor, widthFactor); 
      g2.setStroke(new BasicStroke((float)(2.0/widthFactor))); 

      for(Line2D line: drawingLines) 
      { 
       g2.draw(line); 
      } 
     } 

     @Override 
     public Dimension getMaximumSize() 
     { 
      return new Dimension(MAX_WIDTH_PX, (int)(MAX_WIDTH_PX*HEIGHT_RATIO)); 
     } 
    } 

    private class WebEndPanel extends WebSubPanel 
    { 
     private static final double HEIGHT_RATIO = 0.125; 
     private static final double PIN_RADIUS = 0.5; 

     private final EndPanelType endType; 
     private Line2D.Double[] edgeLines; 
     private Ellipse2D.Double[] pinHeads; 

     public WebEndPanel(EndPanelType endType) 
     { 
      super(); 
      this.endType = endType; 
      this.edgeLines = new Line2D.Double[endpoints.length/2]; 
      this.pinHeads = new Ellipse2D.Double[endpoints.length/2]; 

      for(int i=0; i<edgeLines.length; i++) 
      { 
       Point2D pointA; 
       Point2D pointB; 


       if(EndPanelType.HEADER.equals(this.endType)) 
       { 
        pointA = new Point2D.Double(i*2+2, 4); 
        pointB = new Point2D.Double(i*2+2, 2); 

        pinHeads[i] = new Ellipse2D.Double(
          pointB.getX()-PIN_RADIUS, 
          pointB.getY()-PIN_RADIUS*2, 
          PIN_RADIUS*2, 
          PIN_RADIUS*2); 
       } 
       else // FOOTER 
       { 
        pointA = new Point2D.Double(i*2+2, 0); 
        pointB = new Point2D.Double(i*2+2, 2); 

        pinHeads[i] = new Ellipse2D.Double(
          pointB.getX()-PIN_RADIUS, 
          3-PIN_RADIUS*2, 
          PIN_RADIUS*2, 
          PIN_RADIUS*2); 
       } 

       edgeLines[i] = new Line2D.Double(pointA, pointB); 
      } 
     } 

     @Override 
     public Dimension getMaximumSize() 
     { 
      return new Dimension(MAX_WIDTH_PX, (int)(MAX_WIDTH_PX*HEIGHT_RATIO)); 
     } 

     @Override 
     public void paintComponent(Graphics g) 
     { 
      Graphics2D g2 = (Graphics2D)g; 
      super.paintComponent(g2); 

      scaleTo(getSize()); 
      g2.scale(widthFactor, widthFactor); 
      g2.setStroke(new BasicStroke((float)(2.0/widthFactor))); 

      for(Line2D line: edgeLines) 
      { 
       g2.draw(line); 
      } 

      for(Ellipse2D pin: pinHeads) 
      { 
       g2.draw(pin); 
      } 
     } 
    } 

    private abstract class WebSubPanel extends JPanel 
    { 
     protected static final int MAX_WIDTH_PX = 800; 

     public WebSubPanel() 
     { 
      super(); 
      setBorder(null); 
      setLayout(new FlowLayout(FlowLayout.CENTER, 0, 0)); 
     } 

     public void scaleTo(Dimension d) 
     { 
      widthFactor = d.getWidth()/(double)widthMax; 
      heightFactor = d.getHeight()/(double)heightMax; 
     } 

     @Override 
     public Dimension getPreferredSize() 
     { 
      return getMaximumSize(); 
     }   
    } 
} 

여기 궁극적 인 목표는 머리글과 바닥 글 WebEndPanel의 보이지 않는 될 수있는 크기 조정 웹이지만, 그들과 WebMainPanel 사이 0 공간이 표시 될 때 (마치 하나의 실체처럼).

+1

코드를 좀 더 살펴보아야하지만 처음부터이 모든 것을 * 단일 패널로 그리는 것이 좋습니다. 원하는 모든 효과를 얻을 수 있으며 레이아웃 관리자에 의존하지 않아도됩니다. ("일반 GUI"는 괜찮지 만 사용자 정의 그림의 경우 약할 수도 있습니다.) – Marco13

+0

@ Marco13 나는 모든 것을 그리기위한보다 쉬운 해결책을 선택할 것입니다. 한 번에,하지만이 프로젝트는 사용자가 정의한대로 주문형 도장의 다른 구성을 요구합니다. 따라서이 문제에 직면하지 않으면 필연적으로 필연적으로 직면하게됩니다. –

답변

2

BoxLayout은 공간을 사용할 수있는 경우 최대 크기까지 구성 요소의 크기를 조정합니다.

먼저 구성 요소의 getPreferredSize() 메소드를 구현해야 정상적인 크기로 표시되도록 패킹 할 수 있습니다.

성장 능력이있는 경우 (그리고 사용자 지정 그림에서이 기능을 지원하는 경우) getMaximumSize() 메서드를 재정 의하여 크기를 반환합니다.

그래서 다른 패널과 인접하도록하려면 그림을 패널의 실제 크기를 기반으로해야합니다.

+0

관련 예제가 여기에 표시됩니다. (http://stackoverflow.com/a/34443937/230513). – trashgod

+0

BoxLayout이 최대 크기를 존중한다는 것을 이해했으나 궁극적으로 내 문제를 해결할 수있는 방법을 찾았습니다. getMaximumSize()는 항상 MAX_VALUE의 너비를 가지며 원하는 크기의 높이로 설정 한 높이에 따라 높이가 결정됩니다. 그런 다음 실제 폭에 대한 비율을 사용하여 원하는 높이를 제한했습니다. –

관련 문제