Java:如何控制JPanel长宽比?

我有一个JPanel,我希望它保持正方形但是我希望它的大小,以便它填充其父JFrame中可能的最大空间量但保持方形,即它采用JFrame的最短边作为方形宽度。

我搜索了网络,检查了所有布局管理器,似乎没有一个简单的解决方案来解决这个非常简单的问题。

您可以使用GridBagLayoutComponentListener

例如:(灵感来自: https : //community.oracle.com/thread/1265752?start = 0&tstart = 0 )

 public class AspectRatio { public static void main(String[] args) { final JPanel innerPanel = new JPanel(); innerPanel.setBackground(Color.YELLOW); final JPanel container = new JPanel(new GridBagLayout()); container.add(innerPanel); container.addComponentListener(new ComponentAdapter() { @Override public void componentResized(ComponentEvent e) { resizePreview(innerPanel, container); } }); final JFrame frame = new JFrame("AspectRatio"); frame.getContentPane().add(container); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setSize(600, 600); frame.setVisible(true); } private static void resizePreview(JPanel innerPanel, JPanel container) { int w = container.getWidth(); int h = container.getHeight(); int size = Math.min(w, h); innerPanel.setPreferredSize(new Dimension(size, size)); container.revalidate(); } } 

在此处输入图像描述在此处输入图像描述

 import java.awt.*; import javax.swing.*; import javax.swing.border.EmptyBorder; public class YouAreSoSquare { private static JPanel createPanel() { // GBL is important for the next step.. JPanel gui = new JPanel(new GridBagLayout()); JPanel squareComponent = new JPanel() { private static final long serialVersionUID = 1L; @Override public Dimension getPreferredSize() { // Relies on being the only component // in a layout that will center it without // expanding it to fill all the space. Dimension d = this.getParent().getSize(); int newSize = d.width > d.height ? d.height : d.width; newSize = newSize == 0 ? 100 : newSize; return new Dimension(newSize, newSize); } }; squareComponent.setBackground(Color.RED); gui.add(squareComponent); return gui; } public static void main(String[] args) { Runnable r = new Runnable() { @Override public void run() { try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } catch (Exception useDefault) { } JFrame mainFrame = new JFrame("..So Square"); mainFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); mainFrame.setLocationByPlatform(true); mainFrame.add(createPanel()); mainFrame.pack(); mainFrame.setMinimumSize(mainFrame.getSize()); mainFrame.setVisible(true); } }; SwingUtilities.invokeLater(r); } } 

这是我对最可重用解决方案的看法,该解决方案使用Swing Layout概念。 因此,只需复制/粘贴此Layout类并在Swing容器上设置布局即可使用它。 我很惊讶没有发现它已经在网上完成了,所以在这里! 包含一个主要方法,它创建一个类似于Andrew Thompson截图的JFrame

 import java.awt.Color; import java.awt.Component; import java.awt.Container; import java.awt.Dimension; import java.awt.Insets; import java.awt.LayoutManager; import javax.swing.JFrame; import javax.swing.JPanel; //@Slf4j /** * A Swing Layout that will shrink or enlarge keep the content of a container while keeping * it's aspect ratio. The caveat is that only a single component is supported or an exception * will be thrown. * This is the component's {@link Component#getPreferredSize()} method that must return the * correct ratio. The preferredSize will not be preserved but the ratio will. * * @author @francoismarot * @see https://gist.github.com/fmarot/f04346d0e989baef1f56ffd83bbf764d */ public class SingleComponentAspectRatioKeeperLayout implements LayoutManager { /** Will be used for calculus in case no real component is in the parent */ private static Component fakeComponent = new JPanel(); public SingleComponentAspectRatioKeeperLayout() { fakeComponent.setPreferredSize(new Dimension(0, 0)); } @Override public void addLayoutComponent(String arg0, Component arg1) { } @Override public void layoutContainer(Container parent) { Component component = getSingleComponent(parent); Insets insets = parent.getInsets(); int maxWidth = parent.getWidth() - (insets.left + insets.right); int maxHeight = parent.getHeight() - (insets.top + insets.bottom); Dimension prefferedSize = component.getPreferredSize(); Dimension targetDim = getScaledDimension(prefferedSize, new Dimension(maxWidth, maxHeight)); double targetWidth = targetDim.getWidth(); double targetHeight = targetDim.getHeight(); double hgap = (maxWidth - targetWidth) / 2; double vgap = (maxHeight - targetHeight) / 2; // Set the single component's size and position. component.setBounds((int) hgap, (int) vgap, (int) targetWidth, (int) targetHeight); } private Component getSingleComponent(Container parent) { int parentComponentCount = parent.getComponentCount(); if (parentComponentCount > 1) { throw new IllegalArgumentException(this.getClass().getSimpleName() + " can not handle more than one component"); } Component comp = (parentComponentCount == 1) ? parent.getComponent(0) : fakeComponent; return comp; } private Dimension getScaledDimension(Dimension imageSize, Dimension boundary) { double widthRatio = boundary.getWidth() / imageSize.getWidth(); double heightRatio = boundary.getHeight() / imageSize.getHeight(); double ratio = Math.min(widthRatio, heightRatio); return new Dimension((int) (imageSize.width * ratio), (int) (imageSize.height * ratio)); } @Override public Dimension minimumLayoutSize(Container parent) { return preferredLayoutSize(parent); } @Override public Dimension preferredLayoutSize(Container parent) { return getSingleComponent(parent).getPreferredSize(); } @Override public void removeLayoutComponent(Component parent) { } public static void main(String[] args) { JFrame frame = new JFrame(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); JPanel panel = new JPanel(); // the panel we want to keep it's aspect ratio panel.setPreferredSize(new Dimension(300, 600)); panel.setBackground(Color.ORANGE); JPanel wrapperPanel = new JPanel(new SingleComponentAspectRatioKeeperLayout()); wrapperPanel.add(panel); frame.getContentPane().add(wrapperPanel); frame.setSize(450, 450); frame.setVisible(true); } }