简体   繁体   English

Java:如何控制JPanel长宽比?

[英]Java: How to control JPanel aspect ratio?

I have a JPanel which I want to remain a square however I want it to size so that it fills the maximum amount of space possible in its parent JFrame but remains square ie it takes the shortest side of the JFrame as the square width. 我有一个JPanel,我想保留一个正方形,但是我希望它具有一定的大小,以便它填充其父JFrame中可能的最大空间,但仍保持正方形,即它将JFrame的最短边作为正方形宽度。

I've searched the net, checked all layout managers and none seem to have a simple solution to this very simple problem. 我已经搜索了网络,检查了所有的布局管理器,似乎没有一个简单的解决方案可以解决这个非常简单的问题。

在此处输入图片说明在此处输入图片说明

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

You may use a GridBagLayout and ComponentListener , 您可以使用GridBagLayoutComponentListener

For example: (inspired from: https://community.oracle.com/thread/1265752?start=0&tstart=0 ) 例如:(启发自: 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();
    }
}

Here's my take for a most reusable solution, which use the Swing Layout concept. 这是我采用的最有价值的解决方案,它使用了Swing Layout概念。 So that you can use it simply by copy/pasting this Layout class and set the layout on your Swing Containers. 这样您就可以简单地通过复制/粘贴此Layout类并在Swing容器上设置布局来使用它。 I was surprised not to find it already done on the net, so here it is ! 我很惊讶没有在网上找到它,所以就在这里! A main method is included, it creates a JFrame similar to the screenshots by Andrew Thompson 其中包含一个主要方法,它创建了一个与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);
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM