How to maintain the screen ratio after being resized by the user?

Asked

Viewed 1,031 times

4

I need to restrict a certain proportion of a Jframe so that the layout of what I want to display on it isn’t distorted, but I wouldn’t want to have to block resizing with setRezisable(). The minimum ratio testing you is 350x500 (7:10 ratio), but I would like to keep this ratio whenever the screen has changed size.

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 maintain the screen ratio after resizing?

P.S.: I believe you need to use a ComponentListener, I just don’t know how to control it with this Resizer, especially since, by allowing resizing, it is also enabled that the screen is maximized.

  • 3

    What is the reason for the negative? Can I no longer have a question on the site? Negative just doesn’t help me realize how much my doubt "does not demonstrate research effort, is not clear or is not useful".

  • 2

    Man, I’ve tried to solve your problem in a lot of ways, both elegant and gambit, and I haven’t been able to yet. I am surprised that such a thing does not seem to have a simple solution. When/if it achieves this, put an answer.

  • @Victorstafusa I saw some answers in Soen, but none of them can actually solve it, it seems. In one of them, it is suggested to rewrite the window resize class at hand to restrict this.

  • I also reviewed Soen and tried to tinker with internal details of java.awt.Window and I couldn’t.

1 answer

0

You can use the componentResized of componentListener to perform the calculation in accordance with ratio. Remember that the ratio is 10:7 or approximately 1.42 to stay horizontal or 7:10 = 0.7 to stay 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 looking Jframe itself, you need to override the method paint() of JFrame, but it will work only if it is resized by the corners. It is worth remembering that it is not a good approximation, since the user should have total control over the resizing of the window, what should keep the aspect is the content within 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();
    }
}

I hope I’ve helped!

  • Right, I put the two for other users not to confuse, since most use horizontal 10:7 but in the example is 7:10. Maximization also calls the componentResized, then no problem.

  • Works for the JFrame also, just change the setPreferredSize for setSize. I’ll add on the answer.

  • I was able to remove the flickering using the method paint() jframe. I will update the answer.

  • Have you tried resizing the corners?

  • The most obvious middle ground is to leave the window (JFrame) released along with a JScrollPane for the OS and user, and only maintain the content ratio. Thus the resolution is not unique and does not allow the user to change anyway. But you just might not want it that way. So the closest I got was by paint() ofJFrame. Maybe someone will come up with a better way.

  • I appreciate the attempt, but the first solution by the componentResized ends up working better than Paint(), which only resizes in 4 directions and ends up "mocking" more when trying.

Show 1 more comment

Browser other questions tagged

You are not signed in. Login or sign up in order to post.