Question:
I need to constrain a certain aspect ratio of a JFrame so that the arrangement of what I want to display in it doesn't get distorted, but I wouldn't want to have to block resizing with setRezisable()
. The minimum aspect ratio I'm testing is 350×500 (7:10 ratio), but I'd like to keep this aspect ratio whenever the screen is resized.
I made an example to see how it looks:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class KeepAspectRatioTest extends JFrame {
private static final long serialVersionUID = 1L;
private static final int WIDTH = 350;
private static final int HEIGHT = 500;
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
KeepAspectRatioTest screen = new KeepAspectRatioTest();
screen.setVisible(true);
});
}
public KeepAspectRatioTest() {
initUI();
}
private void initUI() {
setDefaultCloseOperation(EXIT_ON_CLOSE);
setPreferredSize(new Dimension(WIDTH, HEIGHT));
setTitle("Keep Aspect Ratio");
JPanel board = new JPanel();
board.setBorder(BorderFactory.createMatteBorder(1, 1, 1, 1, Color.black));
JPanel sidePanel = new JPanel();
sidePanel.setBorder(BorderFactory.createMatteBorder(1, 1, 1, 1, Color.red));
sidePanel.setLayout(new BoxLayout(sidePanel, BoxLayout.Y_AXIS));
sidePanel.setPreferredSize(new Dimension(WIDTH/6, HEIGHT));
add(board, BorderLayout.CENTER);
add(sidePanel, BorderLayout.EAST);
pack();
setLocationRelativeTo(null);
}
}
How do I keep the screen aspect ratio after being resized?
PS: I believe I need to use a ComponentListener
, I just don't know how to control it with this listener, even more so because, by allowing resizing, it is also enabled for the screen to be maximized.
Answer:
You can use componentResized
from componentListener
to perform the calculation according to the ratio . Remember that the ratio is 10:7 or approximately 1.42 to be horizontal or 7:10 = 0.7 to be vertical. Works for conteiners
and painels
. Ex:
public class AspectRatio {
static final double RATIO = 0.7;
public static void main(String[] args) {
final JPanel innerPanel = new JPanel();
innerPanel.setBackground(Color.BLUE);
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, 800);
frame.setVisible(true);
}
private static void resizePreview(JPanel innerPanel, JPanel container) {
int width = container.getWidth();
int height = container.getHeight();
float currentAspectRatio = (float) width / height;
if (currentAspectRatio > RATIO) {
width = (int) (height * RATIO);
} else {
height = (int) (width / RATIO);
}
innerPanel.setPreferredSize(new Dimension(width, height));
container.revalidate();
}
}
If you want to keep the look of the Jframe
itself, you need to override the JFrame
's paint()
method, but it will only work if it's resized by the corners. It is worth remembering that it is not a good approximation, since the user should have full control over the window resizing, what should keep the appearance is the content inside it:
public class AspectRatio {
static final double RATIO = 1.42;
static JFrame frame;
public static void main(String[] args) {
final JPanel innerPanel = new JPanel();
innerPanel.setBackground(Color.BLUE);
final JPanel container = new JPanel(new GridBagLayout());
container.add(innerPanel);
frame = new JFrame("AspectRatio") {
public void paint(Graphics g) {
super.paint(g);
resizePreview(frame);
};
};
frame.getContentPane().add(container);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(300, 600);
frame.setVisible(true);
}
private static void resizePreview(JFrame jFrame) {
int width = jFrame.getWidth();
int height = jFrame.getHeight();
float currentAspectRatio = (float) width / height;
if (currentAspectRatio > RATIO) {
width = (int) (height * RATIO);
} else {
height = (int) (width / RATIO);
}
jFrame.setSize(new Dimension(width, height));
jFrame.revalidate();
jFrame.repaint();
}
}
Hope this helps!