1

I hope you are having a good day.


NOTE: I have found the issue of this - High DPI Scaling. Since my computer was scaling everything to 250%, setMinimumSize wasn't working. Here is a bug report on it. Does anyone have a workaround that doesn't use addComponentListener (reasoning is below).


Today I was working on a Java Swing project when I tried to change the minimum size for the JFrame window. At first, I tried frame.setMinimumSize(new Dimension(500, 500));. The problem was (I think this has to do with my screen dimensions) that it did kind of work, but it would let me resize the window way less than 500, 500 (the window would stop resizing at about 100 pixels).

EDIT: Here is the code I used to test this:

import javax.swing.*;
import java.awt.*;

class Test {
    public static void main(String[] args) {
        JFrame frame = new JFrame("Test");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        frame.setMinimumSize(new Dimension(500, 500));

        frame.pack();
        frame.setSize(500, 500);
        frame.setVisible(true);
    }
}

Here is what happens to the frame when I resize it:

Using setMinimumSize()

After I googled it up, I found out you could do this neat little hack (this is just one of the many versions of the same code that showed up):

import javax.swing.*;
import java.awt.*;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;

class Test {
    public static void main(String[] args) {
        JFrame frame = new JFrame("Test");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        frame.setMinimumSize(new Dimension(500, 500));
        frame.addComponentListener(new ComponentAdapter() {
            public void componentResized(ComponentEvent evt) {
                Dimension size = frame.getSize();
                Dimension min = frame.getMinimumSize();
                frame.setSize((int) Math.max(min.getHeight(), size.getHeight()),
                        (int) Math.max(min.getWidth(), size.getWidth()));
            }
        });

        frame.pack();
        frame.setSize(500, 500);
        frame.setVisible(true);
    }
}

Here is what happens when I resize this:

Using addComponentListener()

The problem with this was that (even though it worked), it would glitch a lot when I tried to resize past the minimum size as it is not fast enough to change it back before the user resizes it.

After more googling, I found a bug report here. I tried out this code from the comments (yes, I did edit it to use Math.max):

import javax.swing.*;
import java.awt.*;

class Test {
    public static void main(String[] args) {
        JFrame frame = new JFrame("Test") {
            @Override
            public Dimension getPreferredSize()
            {
                Dimension pSize = super.getPreferredSize();
                Dimension mSize = getMinimumSize();
                int wid, ht;

                wid = Math.max(pSize.width, mSize.width);
                ht = Math.max(pSize.height, mSize.height);
                return new Dimension(wid, ht);
            }
        };

        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        frame.setMinimumSize(new Dimension(500, 500));

        frame.pack();
        frame.setSize(500, 500);
        frame.setVisible(true);
    }
}

This had no effect on the window (it behaved exactly like the first setMinimumSize trick).

EDIT 2: I also tried this (as @camickr suggested):

import javax.swing.*;
import java.awt.*;

class Test {
    public static void main(String[] args) {
        JFrame frame = new JFrame("Test");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        frame.setMinimumSize(new Dimension(500, 500));

        frame.setSize(750, 750);
        frame.setVisible(true);
    }
}

But it gave the same output as the first trick (setMinimumSize).

I also removed all setPreferredSize lines as there is no layout manager (more info here).

I am using Windows 10 and JDK v13.0.2 - here is the output from java -version:

java version "13.0.2" 2020-01-14
Java(TM) SE Runtime Environment (build 13.0.2+8)
Java HotSpot(TM) 64-Bit Server VM (build 13.0.2+8, mixed mode, sharing)

And the output from javac -version:

javac 13.0.2

EDIT 3: I have recently tried using JDK 11, but it gave the same results as JDK 13 (Looks like this is computer/platform-specific).

Does anyone know a way to fix this?

Ayush Garg
  • 2,234
  • 2
  • 12
  • 28
  • 2
    *I am using multiple JPanels to add elements instead of adding them directly onto the frame.* - when use code like frame.add(…) you are adding the components to the "content pane" of the frame. The content pane is a JPanel, so no it is not an issue. Using the `setMinimumSize(…)` works fine for me. Post your [mre] demonstrating the problem. That is all you need is a JFrame with a JPanel and invoke the setMinimumSize() method. Prove that is works in a simple case. – camickr Apr 17 '20 at 02:21
  • How's that? I added gifs and minimal reproducible examples – Ayush Garg Apr 17 '20 at 16:43
  • Your question is about setting the minimum size of a frame. Why are you adding a Component listener to the frame and playing with the size? Why are you invoking the setPreferredSize() method of the frame? If you want to test the functionality of a method then don't write any custom code? All you need to do is: 1) set the minimum size and 2) then set the size to some value greater than your minimum size. No need for the pack. Then are you able to shrink the frame below the minimum? I am not. I use JDK11 on Window 10. – camickr Apr 17 '20 at 17:03
  • @camickr - I took out the `setPreferredSize` line and the `frame.pack()` line, but it still reacts the same way as the first example. The window will still start at `500, 500` in width and height, but will only restrict the resizing to about `100` pixels. I am using JDK v13 on Windows 10. As for the Component listener, I was trying different methods (as I found these online) as they might have worked. For preferred size - I was using it in my actual code because I was using a layout manager there, but I'll change it to setSize. Also, according to... – Ayush Garg Apr 17 '20 at 18:31
  • ...[this](https://stackoverflow.com/questions/22982295/what-does-pack-do) StackOverflow question, `pack` is "preferable to `setSize`", which is why I'm using it. (Sorry for the long answer) – Ayush Garg Apr 17 '20 at 18:32
  • Also, I found out about the `setPreferredSize` used with Layout Managers [here](https://stackoverflow.com/questions/1783793/java-difference-between-the-setpreferredsize-and-setsize-methods-in-compone). – Ayush Garg Apr 17 '20 at 18:39
  • *I also tried this (as camickr suggested):* - well that is not exactly what I suggest. I suggested the size should be greater than the minimum size, so you can drag the frame a little smaller. *pack is "preferable to setSize", * - yes in a real program where you are adding real components to the frame. But this is NOT a real program. We are only trying to test the setMinimumSize() method. – camickr Apr 17 '20 at 19:19
  • 1
    *Does anyone know a reliable way to set the minimum size of a window?* - I already told you it works perfectly fine for my JDK and OS. If it doesn't work for you then it might be a platform issue. List your JDK and platform in your question. Post a proper [mre] that includes your import statements and a main() method so that people that use your platform can copy/paste/compile/test to see if they have the same results. – camickr Apr 17 '20 at 19:21
  • I have fixed everything you have asked me to. Making the size greater than the minimum size doesn't change anything, but I still changed the answer to add that. – Ayush Garg Apr 17 '20 at 19:50
  • Why aren't you using a LayoutManager? I've done a lot of Swing development in my time, and have not yet seen a good reason for not using one. – NomadMaker Apr 17 '20 at 20:03
  • @NomadMaker, I never found the need for one. I am just using tree different panels on top of each other to display everything. I just use `frame.add`, and it adds the panel below the previous one, just as I want it. I used the following code to do this (is this a Layout Manager?): `frame.getContentPane().setLayout(new BoxLayout(frame.getContentPane(), BoxLayout.Y_AXIS));` – Ayush Garg Apr 17 '20 at 20:54
  • Yes, BoxLayout is a LayoutManager. – NomadMaker Apr 17 '20 at 21:27
  • Ok, sure. Even with the Layout Manager, it wouldn't work (it would give the same results as the minimal reproducible example). – Ayush Garg Apr 17 '20 at 21:40
  • @NomadMaker, this question has nothing to do with layout managers. Keep your suggestions on topic. The question is about using the `setMinimumSize()` method of a frame. This method SHOULD prevent the frame frame being sized below a certain size "even if no components have been added to the frame*. I have already stated 3 times the code works fine for me. Once difference is that I am using JDK11, the OP is using JDK 13. Maybe this is the problem??? Does anybody else using JDK13 have the same problem??? – camickr Apr 17 '20 at 23:20
  • LayoutManagers deal with the minimum and maximum sizes. Most of the problems I've seen with size problems have been because of misuse of layout managers. – NomadMaker Apr 18 '20 at 00:04
  • I've also compiled and ran @Ayush Garg 's original code and it works fine, the window refusing to shrink. Window 10, jdk 11.0.6. – NomadMaker Apr 18 '20 at 00:08
  • @camickr, I think it might be for JDK v13. I will try to download JDK 11 and try the code with that - hopefully, it isn't a JDK issue!! – Ayush Garg Apr 18 '20 at 02:37
  • Okay - I just downloaded JDK 11, and it gave the same results as JDK 13. Looks like it is computer specific!! – Ayush Garg Apr 18 '20 at 02:52
  • @NomadMaker, I'm starting to think this has something to do with my screen dimensions. When I use `setMinimumSize`, it _does_ actually stop the window from resizing too far - just not the actual size. For example, if I don't set the minimum size, it will resize to about `50` pixels, but if I set it to say `500, 500`, then it will resize to a slightly larger value. Using 1000 makes it really close to 500, 500. – Ayush Garg Apr 18 '20 at 22:49
  • What are your screen dimensions? – NomadMaker Apr 18 '20 at 22:50
  • @NomadMaker, 3840 x 2160 in my settings. What are yours? I think I might have an idea... – Ayush Garg Apr 18 '20 at 22:53
  • 1920x1080. Laptop. – NomadMaker Apr 18 '20 at 22:55
  • @NomadMaker - I found out the issue! It turns out, in the settings panel, my scaling settings are set to 250% (because I have a huge screen resolution). This is causing Java to glitch and not properly scale the window. When I set it to 100%, it works perfectly fine. The problem - I can't scale to 100% because then everything is too small. Any suggestions? – Ayush Garg Apr 18 '20 at 23:00
  • I found a bug report on this [here](https://bugs.java.com/bugdatabase/view_bug.do?bug_id=JDK-8221452). Does anyone have a better workaround, though, as this one still uses `addComponentListener`? Or is this a lost cause for high DPI settings? – Ayush Garg Apr 18 '20 at 23:13

1 Answers1

0

I found a working solution for the minimum size with the ComponentAdapter, its pretty much the same as the code above but with a Robot that stops resizing the frame when minimum size is reached:

import java.awt.AWTException;
import java.awt.Dimension;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.InputEvent;
import javax.swing.JFrame;
import javax.swing.WindowConstants;

public class MinSizeFrameTest {

    public static void main(String[] args) {
        JFrame frame = new JFrame("MinSizeFrameTest");
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        frame.setMinimumSize(new Dimension(500, 500));
        frame.addComponentListener(new ComponentAdapter() {

            Robot robot;

            @Override
            public void componentResized(ComponentEvent e) {
                try {
                    if (robot == null)
                        robot = new Robot();
                    Rectangle bounds = frame.getBounds();
                    Dimension minSize = frame.getMinimumSize();
                    if (bounds.width < minSize.width || bounds.height < minSize.height) {
                        robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK);
                        int w = Math.max(minSize.width, bounds.width);
                        int h = Math.max(minSize.height, bounds.height);
                        frame.setBounds(new Rectangle(bounds.x, bounds.y, w, h));
                    }
                } catch (AWTException ex) {
                    ex.printStackTrace();
                }
            }
        });
        frame.setBounds(100, 100, 800, 600);
        frame.setVisible(true);
    }
}