【问题标题】:Java: How to control JPanel aspect ratio?Java:如何控制 JPanel 纵横比?
【发布时间】:2015-02-17 02:55:10
【问题描述】:

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

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

【问题讨论】:

  • 来自 ComponentListener 的事件被 Swing Timer 延迟,

标签: java swing jframe jpanel aspect-ratio


【解决方案1】:

您可以使用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();
    }
}

【讨论】:

  • 感谢这完美的作品。我所做的唯一修改是将容器 JPanel 的布局管理器替换为 FlowLayout 而不是 GridBagLayout 以减少闪烁,因为 FlowLayout 将其组件的大小仅基于其首选大小,这是您想要的,因为首选大小是在每次之后手动设置的调整大小。
【解决方案2】:

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);
    }
}

【讨论】:

    【解决方案3】:

    这是我对使用 Swing 布局概念的最可重用解决方案的看法。这样您就可以通过复制/粘贴此 Layout 类并在 Swing Containers 上设置布局来使用它。 我很惊讶没有发现它已经在网上完成了,所以就在这里!包含一个 main 方法,它通过以下方式创建一个类似于屏幕截图的 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);
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2016-01-13
      • 2012-08-11
      • 1970-01-01
      • 1970-01-01
      • 2016-10-13
      • 2023-04-07
      相关资源
      最近更新 更多