Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to best position Swing GUIs?

To my eye, a GUI in the middle of the screen looks so.. "splash-screen'ish". I keep waiting for them to disappear and the real GUI to appear!

Since Java 1.5 we've had access to Window.setLocationByPlatform(boolean). which..

Sets whether this Window should appear at the default location for the native windowing system or at the current location (returned by getLocation) the next time the Window is made visible. This behavior resembles a native window shown without programmatically setting its location. Most windowing systems cascade windows if their locations are not explicitly set. The actual location is determined once the window is shown on the screen.

Have a look at the effect of this example that puts 3 GUIs into the default positions as chosen by the OS - on Windows 7, Linux with Gnome & Mac OS X.

Stacked windows on Windows 7enter image description hereStacked windows on Mac OS X

(3 lots of) 3 GUIs neatly stacked. This represents 'the path of least surprise' for the end user, since it is how the OS might position 3 instances of the default plain-text editor (or anything else, for that matter). My thanks to trashgod for the Linux & Mac. images.

Here is the simple code used:

import javax.swing.*;

class WhereToPutTheGui {

    public static void initGui() {
        for (int ii=1; ii<4; ii++) {
            JFrame f = new JFrame("Frame " + ii);
            f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
            String s =
                "os.name: " + System.getProperty("os.name") +
                "\nos.version: " + System.getProperty("os.version");
            f.add(new JTextArea(s,3,28));  // suggest a size
            f.pack();
            // Let the OS handle the positioning!
            f.setLocationByPlatform(true);
            f.setVisible(true);
        }
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater( new Runnable() {
            public void run() {
                try {
                    UIManager.setLookAndFeel(
                        UIManager.getSystemLookAndFeelClassName());
                } catch (Exception useDefault) {}
                initGui();
            }
        });
    }
}

I totally agree that setLocationByPlatform(true) is the nicest way to specify a new JFrame's position but on a dual-monitor setup you can get into issues. In my case, the child JFrame is spawned on 'the other' monitor. Example: I have my main GUI on Screen 2, I start a new JFrame with setLocationByPlatform(true) and it opens on Screen 1. So here is a more complete solution, I think:

...
// Let the OS try to handle the positioning!
f.setLocationByPlatform(true);
if (!f.getBounds().intersects(MyApp.getMainFrame().getBounds())) {
    // non-cascading, but centered on the Main GUI
    f.setLocationRelativeTo(MyApp.getMainFrame()); 
}
f.setVisible(true);