2016-10-30 1 views
1

В настоящее время, как часть проекта, над которым я работаю, я реализую компонент, который можно использовать для визуализации перестановки битов (как часть криптографического алгоритма). Я делаю это, создавая две строки «штифтов» и соединяя их, рисуя линии между кончиками, создавая между ними какую-то сеть.Заставить пространство между панелями в 0 с помощью BoxLayout?

Важной частью этого является то, что я использую эту визуализацию как самостоятельно, так и часть других визуализаций (например, я могу включить S-боксы), и поэтому мне нужно иметь возможность поворачивать булавки включены и выключены. Моим решением было использовать JPanel s, чтобы поместить строки контактов в панель заголовка и нижнего колонтитула, которые можно сделать невидимыми.

Я размещаю их вертикально в 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 s может быть невидимым, но есть 0 пространство между ними и WebMainPanel когда показал (как если бы они были единым сущностью).

+1

Мне нужно было бы изучить код немного больше, но с первого взгляда, похоже, вы должны рассмотреть возможность рисования всего этого на * одиночной * панели. Вы все равно можете добиться всех желаемых эффектов и не зависеть от менеджера компоновки (что отлично подходит для «обычных графических интерфейсов», но, возможно, для хрупкой для пользовательской картины) – Marco13

+0

@ Marco13 Я бы выбрал более легкое решение для рисования всего сразу же, но этот проект требует различных конфигураций различных пользовательских фигур, которые раскрашиваются по запросу, как определено пользователями, поэтому, если бы я не столкнулся с этой проблемой, я бы с неизбежностью столкнулся с ней позже. –

ответ

2

A BoxLayout будет изменять размер компонента до его максимального размера, если доступно пространство.

Итак, сначала необходимо реализовать метод компонента getPreferredSize(), чтобы он мог быть упакован, как показано в его нормальном размере.

Затем, если у него есть способность расти (и ваша пользовательская окраска поддерживает это), вы переопределяете метод для возврата размера.

Поэтому картина должна основываться на фактическом размере панели, если вы хотите, чтобы она была смежной с другими панелями.

+0

Связанный пример показан [здесь] (http://stackoverflow.com/a/34443937/230513). – trashgod

+0

Я понял, что BoxLayout соблюдал максимальный размер, но ваш ответ заставил меня попробовать, что в конечном итоге решило мою проблему: я перегрузил getMaximumSize(), чтобы всегда иметь ширину MAX_VALUE и высоту, продиктованную тем, что я установил для высоты предпочтительного размера, затем ограничили эту предпочтительную высоту, используя отношение к фактической ширине. –