Why does my java gui "jump" when moving it the first time?
Asked Answered
G

2

1

I have a simple java gui (code below) which for some reason when displayed, will "jump" back to it's original position the first time I try to move or resize it. So basically I will have to move the gui twice to get it to move once because as soon as I release the mouse the first time it snaps back to where it originally came up.

import javax.swing.*;

public class JFrameTester {

  public static void main(String[] args) {

    JFrame f = new JFrame("A JFrame");
    f.setSize(250, 250);
    f.setLocation(300,200);
    f.getContentPane().add(new JTextArea(10, 40));    
    //f.pack();    
    f.setVisible(true);
    //f.validate();
  }

}

I am running on GNU Linux with java 1.6. I am exporting the display back to my Windows machine and wondering if it has something to do with the X11 forwarding because it does not show this behavior when I run the gui in Windows. However, when I run this gui on a Fedora Linux box (with java 1.7) it does not show this behavior at all - whether exporting the display or not.

Garmaise answered 15/11, 2012 at 21:28 Comment(4)
I would suspect the Xserver running on your Windows PC. Can you run the same app from the GNU/Linux Java 1.6 machine, and remotely display it on a different (non-windows) machine?Pagination
1) The GUI should be started and updated on the EDT. 2) Always call pack() in order to cause the GUI to be laid out and validated. 3) f.setSize(250, 250); in counter-productive. Set the size of the GUI according to the rows and columns needed for the text area.Foreyard
Also please check the text of tags carefully before applying them to a question. This has nothing to do with export as defined by SO.Foreyard
@dasrb I have tried from other machines and get the same behavior however they are all WindowsGarmaise
O
4

Several problems are apparent:

  • Construct and manipulate Swing GUI objects only on the event dispatch thread. Failing to do so creates a race condition that may be obscure until a different platform or network latency exposes it.

  • Use pack(), which "Causes this Window to be sized to fit the preferred size and layouts of its subcomponents." Failing to do so causes the invalid Container to be validated when moved or resized. When the prematurely visible components move to the defined positions, they appear to "jump."

  • Make setVisible() the last operation that affects the initial appearance.

The following example combines these suggestions:

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

public class JFrameTester {

    public static void main(String[] args) {

        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                JFrame f = new JFrame("A JFrame");
                f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                f.add(new JScrollPane(new JTextArea(10, 40)));
                f.pack();
                f.setLocationByPlatform(true);
                f.setVisible(true);
            }
        });
    }
}
Orpheus answered 16/11, 2012 at 6:56 Comment(2)
Tried this program and had high hopes, but still no luck :( Same behavior.Garmaise
You might edit your question to include the specific versions of Windows and X11; maybe somebody can reproduce the effect you describe.Orpheus
H
0

Problem elaboration

This problem arises when using an AWT or Swing app under the Cygwin X11 server. It only happens if you call setLocation or setLocationRelativeTo while constructing the window object. (But if you do not call setLocation, then the window appears in the top-left corner, which is inconvenient.)

The main symptom is: when a window or dialog box is first shown, and the user tries to move it by dragging the title bar, after the drag finishes, the window jumps back to its original position. After that, moving the window works normally.

Another curious symptom is: after attempting to drag once, and getting "rejected", the menu bar behaves differently, with each menu only remaining open while the mouse button is held down (like old X11 apps). Additionally there is an "offset" to the mouse's effect, with the highlighted menu item not being the one under the cursor, but a distance away related to the attempted drag distance. Moving the window a second time allows the menu to work normally, staying open after pressing and releasing the mouse button, and with no offset effect.

Solution

The solution I found is to programmatically adjust the window's position slightly just after it is first shown:

// Call this *before* 'setVisible(true)'.
f.addWindowListener(new java.awt.event.WindowAdapter() {
  @Override
  public void windowOpened(java.awt.event.WindowEvent e) {
    final java.awt.Window w = e.getWindow();

    javax.swing.Timer t = new javax.swing.Timer(100 /*ms*/,
      new java.awt.event.ActionListener() {
        @Override
        public void actionPerformed(java.awt.event.ActionEvent e) {
          // Slightly adjust the window position to work around a
          // bug where the window manager "rejects" the first
          // attempt to move the window.
          int y = w.getLocation().y;
          w.setLocation(w.getLocation().x, y+1);
        }
      });
    t.setRepeats(false);
    t.start();
  }
});

As noted, this must be called before setVisible(true), otherwise you might miss the windowOpened event. This is also important when using a JDialog because, in that case, setVisible(true) blocks until the dialog is closed.

Moving by 1 pixel is chosen to minimize disruption, since the adjustment is usually visible to the user. I say usually because sometimes (maybe 1 in 4 times) the adjustment does not happen, even though it successfully disarms the underlying bug. Moving by 0 pixels does not disarm the bug.

The timer is unfortunately necessary to avoid losing a race condition with the window manager. In my testing, without the timer, the window will still jump to its original position about 1 in 7 times when the user first moves it. With a 100 ms timer, I never observed it failing (after more than 100 tests), but 50 ms is not enough. This will depend on machine speed of course.

Versions: Java 1.8.0_92 on Linux and cygwin 3.4.7 on Windows 10.

Hermaherman answered 2/9, 2023 at 2:26 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.