Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

setDefaultLookAndFeelDecorated affects JFrame resize behaviour

This is my code:

import java.awt.Dimension;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;


public class Test{


public static void main(String[] args){

    SwingUtilities.invokeLater(new Runnable(){

        @Override
        public void run() {

            JFrame.setDefaultLookAndFeelDecorated(true);

            JFrame frame = new JFrame();
            JPanel jp = new JPanel();

            jp.setMinimumSize(new Dimension(200, 200));
            jp.setPreferredSize(new Dimension(200, 200));

            //frame.getContentPane().setMinimumSize(new Dimension(200, 200));
            //frame.getContentPane().setPreferredSize(new Dimension(200, 200));

            frame.getContentPane().add(jp);

            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.pack();
            frame.setVisible(true);
        }
    });
}
}

It behaves exactly the way I want. User can resize the JFrame but it'll always be large enough to hold 200px x 200px JPanel. But when I remove:

JFrame.setDefaultLookAndFeelDecorated(true);

user can resize JFrame to any size.

Why does default look and feel decoration affect resizing? How can i make it work without setDefaultLookAndFeelDecorated(true)? I know I can set frames minimum size manually (JFrame#setMinimumSize(new Dimension dim)) and I will if there is no smarter solution.

I'm using jdk 1.7 on Windows 7.

like image 393
Sumik Avatar asked Sep 30 '12 17:09

Sumik


2 Answers

This use to be a bug, the page speaks of work arounds like:

  • override setSize() and check if the new size is less than the desired
  • inside paint(Graphics g) of JFrame check height and width and "re-create" frame to new minimum size

however a person claims it to be fixed as the original example issued for the bug proposal omitted the call to setMinimumSize(...), this is needed because JFrame does not enforce minimum size

Here is the snippet which shows that persons' code:

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

public class JavaApplication118 {

    private final Dimension m_dim = new Dimension(200, 150);

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                new JavaApplication118().createAndShowUI();
            }
        });
    }

    private void createAndShowUI() {

        // JFrame.setDefaultLookAndFeelDecorated(true);

        final JFrame frame = new JFrame("Test") {

            @Override
            public Dimension getMinimumSize() {
                return m_dim;
            }

        };

        frame.setMinimumSize(m_dim);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        initComponents(frame);

        // frame.setResizable(false);
        frame.pack();
        frame.setVisible(true);
    }

    private void initComponents(JFrame frame) {
        JPanel jp = new JPanel();

        jp.setMinimumSize(new Dimension(200, 200));
        jp.setPreferredSize(new Dimension(400, 400));//for testing

        frame.getContentPane().add(jp);
    }
}

EDIT

The snippet overrode getMinimumSize() though this seems redundant after calling setMinimumSize(..), I kept it included as that's how I found the snippet (I did remove the overridden getPreferredSize() method of the JFrame which the snippet included).

like image 80
David Kroukamp Avatar answered Oct 22 '22 18:10

David Kroukamp


Why does default look and feel decoration affect resizing?

Because then the window sizing is under the complete control of the LAF while dragging: The mouseHandler installed by (f.i.) MetalRootPaneUI doesn't resize the window below the min returned by the LayoutManager. Without setting the frame's minimumSize, you can still decrease its size programatically.

The only way (unfortunately) to enforce a window's minimum size always is to manually set it. Unfortunate, as that implies keeping track of dynamic changes of that minimum and update it as appropriate.

A snippet to play with (un/comment the defaultDecoration and frame min setting)

JFrame.setDefaultLookAndFeelDecorated(true);
JPanel panel = new JPanel() {

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.setColor(Color.BLACK);
        Dimension m = getMinimumSize();
        // visualize the min
        g.drawRect(0, 0, m.width - 1, m.height -1);
    }

};
// BEWARE: for demonstration only, NEVER do in production code 
panel.setMinimumSize(new Dimension(400, 400));
panel.setPreferredSize(panel.getMinimumSize());
final JXFrame frame = new JXFrame("", true);
Action action = new AbstractAction("resize") {

    @Override
    public void actionPerformed(ActionEvent e) {
        frame.setSize(300, 300);
        LOG.info("succeeded? " + frame.getSize());
    }
};
panel.add(new JButton(action));
frame.add(panel);
frame.pack();
// set minimum is required to enforce the minimum
frame.setMinimumSize(frame.getMinimumSize());

Update

Looking at the Window source, turns out that you can have auto-magic dynamic respect of min size by overriding isMinimumSizeSet and returning true uncondinionally:

final JXFrame frame = new JXFrame("", true) {
    @Override
    public boolean isMinimumSizeSet() {
        return true;
    }
};
...
// no longer needed
// frame.setMinimumSize(frame.getMinimumSize());

not tested for side-effects, though

like image 27
kleopatra Avatar answered Oct 22 '22 18:10

kleopatra