繁体   English   中英

Java:如何控制JPanel长宽比?

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

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

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

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

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

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

这是我采用的最有价值的解决方案,它使用了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);
    }
}

暂无
暂无

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

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