How to best position Swing GUIs?
Asked Answered
C

2

131

In another thread I stated that I liked to center my GUIs by doing something like this:

JFrame frame = new JFrame("Foo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new HexagonGrid());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);

But Andrew Thompson had a different opinion, to instead call

frame.pack();
frame.setLocationByPlatform(true);

and inquiring minds want to know why?

Christ answered 22/8, 2011 at 4:48 Comment(1)
The gui should start in the same place that it ended last time.Dandiprat
S
173

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 7 enter image description here Stacked 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();
            }
        });
    }
}
Schlueter answered 22/8, 2011 at 5:10 Comment(4)
@AndrewThompson Why is your counter variable ii rather than just i? Does that adhere to some convention or is it a personal preference (or maybe something entirely different)?Dickie
@Dickie Umm.. I think I'll lock in option 3 there, "something entirely different". It was just what I got used to when I first programmed in Basic (yes, a long time ago). Laziness it the reason for continued use, 'if it ain't broke, don't fix it'.Schlueter
@Dickie Are you by any chance prince of persia Fan? I am so sorry to put it here. I just couldnt resistIstic
@Dickie Here's why I use ii instead of i. When I take part in programming competitions, I often have to search for the loop index to, say, +1 or -1 from it to fix off by one errors. In those cases, searching for ii is much easier than searching for i, regardless of which editor I used. Similarly, I use jj and kk for the nested loop indexes. :)Conscientious
V
9

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);
Vicechairman answered 19/9, 2017 at 11:56 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.