1

I'm trying to resize the JFrame on button click, the code works well (but i don't know if this is the best way to achieve this).

But the problem is: While resizing, the JFrame is slowly revalidated. The GIF can explain what exactly is happening:

GIF Picture of the problem

The piece of code is:

chatButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent arg0) {
                new Thread (new Runnable() {
                    public void run(){
                        int width = frame.getWidth();
                        int height = frame.getHeight();
                        int buttonWidth = chatButton.getWidth();
                        if (frame.getWidth() < 1150) {  
                            while (frame.getWidth() < 1150) {
                                width = frame.getWidth();
                                frame.setSize(width + 2 , height);
                                chatButton.setLocation(width - buttonWidth , 0);
                                frame.invalidate();
                                frame.validate();
                            }
                        } else {
                            while (frame.getWidth() > 897) {
                                width = frame.getWidth();
                                frame.setSize(width - 2 , height);
                                chatButton.setLocation(width - buttonWidth , 0);
                                frame.invalidate();
                                frame.validate();
                            }
                        }   
                    }
                }).start(); 
            }
        });

I've put it in a Runnable because it wasn't revalidating until the resize is over.

I've also tried repaint() and revalidate() but they didn't solve the problem at all.

What can I do?

Thanks in advance.

Samer Massad
  • 101
  • 1
  • 11
  • Personally, I'm not sure you'll find an completely satisfactory solution. The main reason is, as the window is resized, the contents isn't always updated immediately, the repaint manager may reduce the repeated calls for updates to a fewer actually updates, try resizing the window manually to see what I mean – MadProgrammer Feb 09 '16 at 13:30
  • `chatButton.setLocation(width - buttonWidth , 0);` this implies a null layout. Java GUIs have to work on different OS', screen size, screen resolution etc. using different PLAFs in different locales. As such, they are not conducive to pixel perfect layout. Instead use layout managers, or [combinations of them](http://stackoverflow.com/a/5630271/418556) along with layout padding and borders for [white space](http://stackoverflow.com/a/17874718/418556). **Further note: the looping part of it should be done with a Swing `Timer` so GUI updates are done on the EDT.** – Andrew Thompson Feb 09 '16 at 14:45
  • For better help sooner, post a [MCVE] or [Short, Self Contained, Correct Example](http://www.sscce.org/). – Andrew Thompson Feb 09 '16 at 14:46

1 Answers1

1

This happens because you adjusting the dimensions of swing components from a non-swing thread. This will cause the size of the window to be out of sync with the actual movement of the components. By making the inner code run on a timer tat activates every 50 milliseconds, you can get the smooth opening without the jitteriness.

timer = new Timer(50, new ActionListener() {
    public void actionPerformed(ActionEvent e) {
        int width = frame.getWidth();
        int height = frame.getHeight();
        int buttonWidth = chatButton.getWidth();
        if(frame.getWidth() < 1150) {
            width = frame.getWidth();
            frame.setSize(width + 2 , height);
            chatButton.setLocation(width - buttonWidth , 0);
            frame.invalidate();
            frame.validate();
         } else {
            ((Timer)e.getSource()).cancel()
         } 
     });
timer.setInitialDelay(0);
timer.start(); 

The above code is an example how to do this when opening the screen, you need to do the same logic for closing.

Ferrybig
  • 18,194
  • 6
  • 57
  • 79
  • thank you for your answer, but I'm sorry i couldn't find out where exactly to put the timer, should I put it inside the chatButton ActionListener? or somewhere else? – Samer Massad Feb 09 '16 at 13:08
  • Inside the actionlistener, after you checked if the window need to be increased in side, or decreased – Ferrybig Feb 09 '16 at 13:11
  • It keeps giving me the error: The constructor Timer(int, new ActionListener(){}) is undefined – Samer Massad Feb 09 '16 at 15:02
  • Did you import the correct timer? We are working with swing so you need javax.swing.Timer, it has a proper [Timer(int, new ActionListener(){})](https://docs.oracle.com/javase/8/docs/api/javax/swing/Timer.html#Timer-int-java.awt.event.ActionListener-) that you can use. – Ferrybig Feb 09 '16 at 15:04
  • well, u're right.. i checked my imports, and i remembered that i needed to import java.util.Timer to display a timer on the screen, so how can i import the both timers? – Samer Massad Feb 09 '16 at 15:17
  • http://stackoverflow.com/q/2079823/1542723 use the full name for the other, example `Timer normal; javax.swing.Timer swingTimer` or `java.util.Timer normal; Timer swingTimer` – Ferrybig Feb 09 '16 at 15:22
  • it kind of worked, except that i had this error: "The method cancel() is undefined for the type Timer" on this line "((javax.swing.Timer)e.getSource()).cancel();" – Samer Massad Feb 09 '16 at 16:51