1

I have added a button to a frame and controlling it's text and/or minimum size with timer.

I noticed, that button does grow sometimes, and sometimes does not.

If in null layout, then it ignores both text and minimum width changing.

If in FlowLayout layout, then it grows if text changing, but ignores minimum width changing.

How make it grow in latter case? If minimum width changes, then why doesn't layout manager reshapes button? How to force it to reshape?

Note: code below is SSCCE, i.e. it is for investigation purposes.

public class Try_ButtonAutoresize_01 {

    private static final Logger log = LoggerFactory.getLogger(Try_ButtonAutoresize_01.class);

    private static final String text = "Very Long Text For Appear On Button ";
    private static int position = 7;

    public static void main(String[] args) {

        final JButton button = new JButton(text.substring(0, position));
        button.setBounds(10, 10, 100, 50);

        JFrame frame = new JFrame();
        //frame.setLayout(null);
        frame.setLayout(new FlowLayout(FlowLayout.LEFT));
        frame.add(button);

        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLocation(100,100);
        frame.setSize(640, 480);
        frame.setVisible(true);

        new Timer(1000, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {


                /*
                button.setText(button.getText() + text.charAt(position));

                position++;
                if( position >= text.length() ) {
                    position=0;
                }
                */


                button.setMinimumSize(new Dimension((int)button.getMinimumSize().getWidth()+10, (int)button.getMinimumSize().getHeight()));

                log.info("Minimum width is now = {}", button.getMinimumSize().getWidth());
            }
        }).start();

    }

}

UPDATE

It does not work with preferred size too. Invalidation also does not help.

public class Try_ButtonAutoresize_01 {

    private static final Logger log = LoggerFactory.getLogger(Try_ButtonAutoresize_01.class);

    private static final String text = "Very Long Text For Appear On Button ";
    private static int position = 7;

    public static void main(String[] args) {

        final JButton button = new JButton(text.substring(0, position));
        button.setBounds(10, 10, 100, 50);

        final JFrame frame = new JFrame();
        //frame.setLayout(null);
        frame.setLayout(new FlowLayout(FlowLayout.LEFT));
        frame.add(button);

        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLocation(100,100);
        frame.setSize(640, 480);
        frame.setVisible(true);

        new Timer(1000, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {


                /*
                button.setText(button.getText() + text.charAt(position));

                position++;
                if( position >= text.length() ) {
                    position=0;
                }
                */


                //button.setMinimumSize(new Dimension((int)button.getMinimumSize().getWidth()+10, (int)button.getMinimumSize().getHeight()));
                button.setPreferredSize(new Dimension((int)button.getPreferredSize().getWidth()+10, (int)button.getPreferredSize().getHeight()));

                //frame.invalidate();
                //button.invalidate();

                log.info("Minimum width is now = {}", button.getMinimumSize().getWidth());
                log.info("Preferred width is now = {}", button.getPreferredSize().getWidth());
            }
        }).start();

    }

}

UPDATE 2

The answer reuires 2 conditions:

1) use setPreferredSize() as @Sage suggested, and

2) call revalidate() (what I saw in setText() source code).

The final working code follows:

public class Try_ButtonAutoresize_02 {

    private static final Logger log = LoggerFactory.getLogger(Try_ButtonAutoresize_02.class);

    public static void main(String[] args) {

        final JButton button = new JButton("short");

        final JFrame frame = new JFrame();
        frame.setLayout(new FlowLayout(FlowLayout.LEFT));
        frame.add(button);

        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLocation(100,100);
        frame.setSize(640, 480);
        frame.setVisible(true);

        new Timer(1000, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {


                //button.setMinimumSize(new Dimension((int)button.getMinimumSize().getWidth()+10, (int)button.getMinimumSize().getHeight()));
                button.setPreferredSize(new Dimension((int)button.getPreferredSize().getWidth()+10, (int)button.getPreferredSize().getHeight()));

                button.revalidate();

                log.info("Preferred width is now = {}", button.getPreferredSize().getWidth());


            }
        }).start();

    }

}
Suzan Cioc
  • 29,281
  • 63
  • 213
  • 385
  • [don't use setXXSize, ever](http://stackoverflow.com/a/7229519/203657) Instead, override the getter/s as suggested by @Sage – kleopatra Dec 03 '13 at 14:04

1 Answers1

3
  1. Don't go with first approach: null layout(AbsoluteLayout) even if someone threaten you to life death.
  2. Second approach with FlowLayout: It is a LayoutManager as you might already know. However, this layout manager respects preferred size of a component. So giving size hints by setting bounds:setBounds(x, y, width, height) won't have effect. Use button.setPreferredSize(Dimension) to have a quick result. But again you should actually extend the class and override the getPreferredSize(Dimension) and other getXXXSize(Dimension) method to adjust with the content size.

     JButton button = new JButton("Press Me"){
        @Override
        public Dimension getPreferredSize() {
            Dimension size = new Dimension();
            size.width = ???; // give some thinking about it
            size.height = ???; // give some thinking about it
            return size;
        }
    
     };
    
  3. As @mKobel has pointed out below, which i have forgotten to address: do not set size to JFrame. It reduce the chance for layout managers to layout properly. Call JFrame.pack() before JFrame.setVisible(true) instead.

Have a look in this tutorial page for details:

  1. How to use FlowLayout
  2. Solving Common Layout Problems
Sage
  • 15,290
  • 3
  • 33
  • 38
  • @Suzan Cioc set(Xxx)Size, setBounds to protect, reduce the LayoutManager to determine proper size, remove everything about and to call JFrame.pack() before JFrame.setVisible() instead – mKorbel Dec 02 '13 at 20:33
  • @Suzan Cioc button.getMinimumSize() can returns its size in two cases 1. is already visible, 2. JFrame.pack() is called, (3. NullLayout with/based on coordinates came from parents Insets) – mKorbel Dec 02 '13 at 20:35
  • It does not work with preferred size too. I don't see the reason to override `getPreferredSize()` since query shows it is updated. – Suzan Cioc Dec 02 '13 at 21:20
  • I am not seeing any `setPreferredSize` code in your update. And remove setBounds from the code as it will not have any effect. Remove `JFrame.setSize(Dimension)` too as `mKobel` has suggested above. Thanks – Sage Dec 02 '13 at 21:26
  • @Sage `setPreferredSize` line is 9th counting from bottom. `setSize` is there namely because it has no effect: no need to comment it out. – Suzan Cioc Dec 03 '13 at 12:00