我有一个JPanel,我想要保持正方形但是我希望它的大小,以便它填充其父JFrame中可能的最大空间量但保持正方形,即它采用JFrame的最短边作为方形宽度
我已经搜索了网络,检查了所有布局管理器,似乎没有一个解决这个非常简单的问题的简单方法。
答案 0 :(得分:7)
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);
}
}
答案 1 :(得分:2)
您可以使用GridBagLayout
和ComponentListener
,
例如:(灵感来自: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();
}
}
答案 2 :(得分:0)
这是我对最可重用解决方案的看法,它使用了Swing Layout概念。因此,您只需复制/粘贴此Layout类并在Swing容器上设置布局即可使用它。 我很惊讶没有发现它已经在网上完成了,所以在这里!包含一个主要方法,它创建一个类似于屏幕截图的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);
}
}