18

I have a (somewhat philosophical) question relatively to Swing, or to GUI programming in general. Are there recognized best practices on where to locate the JFrame instances used in the application?

  1. Where should the first and main frame be located? Always at the center (setLocationRelativeTo(null))?
  2. Where should a child JFrame be located? Relatively to its parent JFrame, at the center of the screen, wherever we want?

I have always assumed there were some best practices, kind of a "GUI bible" about this, am I wrong and should I (gasp) arbitrarily decide what to do?

Robert Harvey
  • 178,213
  • 47
  • 333
  • 501
Scherrer Vincent
  • 244
  • 1
  • 3
  • 9
  • 2
    For part 1. See [How to best position Swing GUI's](http://stackoverflow.com/questions/7143287/how-to-best-position-swing-guis/) for part 2. I'd recommend having only 1 frame. The rest should probably be dialogs whose location is set relative to the position of the frame on `setVisible(true)`. – Andrew Thompson Oct 15 '11 at 12:00
  • 1) where do you want to be, anywhere, 2) for Child look for JDialog or JWindow, and could be placed where do you want or needed, 3) up to you – mKorbel Oct 15 '11 at 12:58

4 Answers4

25

Here is an example that incorporates the advice of:

  1. Hovercraft Full Of Eels - set location by platform.

  2. Aardvocate Akintayo Olu - serialize the location.

But goes on to add 2 tweaks:

  1. Serialize the width/height as well.
  2. If the frame is maximized at time of close, it is restored before getting the bounds. (I detest apps. that serialize options but do not take that into account. The user is sitting there clicking the 'Maximize / Restore' button & wondering why nothing is happening!)

The 4 points combined offer the best user experience!

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.Properties;
import java.io.*;

class RestoreMe {

    /** This will end up in the current directory
    A more sensible location is a sub-directory of user.home.
    (left as an exercise for the reader) */
    public static final String fileName = "options.prop";

    /** Store location & size of UI */
    public static void storeOptions(Frame f) throws Exception {
        File file = new File(fileName);
        Properties p = new Properties();
        // restore the frame from 'full screen' first!
        f.setExtendedState(Frame.NORMAL);
        Rectangle r = f.getBounds();
        int x = (int)r.getX();
        int y = (int)r.getY();
        int w = (int)r.getWidth();
        int h = (int)r.getHeight();

        p.setProperty("x", "" + x);
        p.setProperty("y", "" + y);
        p.setProperty("w", "" + w);
        p.setProperty("h", "" + h);

        BufferedWriter br = new BufferedWriter(new FileWriter(file));
        p.store(br, "Properties of the user frame");
    }

    /** Restore location & size of UI */
    public static void restoreOptions(Frame f) throws IOException {
        File file = new File(fileName);
        Properties p = new Properties();
        BufferedReader br = new BufferedReader(new FileReader(file));
        p.load(br);

        int x = Integer.parseInt(p.getProperty("x"));
        int y = Integer.parseInt(p.getProperty("y"));
        int w = Integer.parseInt(p.getProperty("w"));
        int h = Integer.parseInt(p.getProperty("h"));

        Rectangle r = new Rectangle(x,y,w,h);

        f.setBounds(r);
    }

    public static void main(String[] args) {
        final JFrame f = new JFrame("Good Location & Size");
        f.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
        f.addWindowListener( new WindowAdapter() {
            public void windowClosing(WindowEvent we) {
                try {
                    storeOptions(f);
                } catch(Exception e) {
                    e.printStackTrace();
                }
                System.exit(0);
            }
        });
        JTextArea ta = new JTextArea(20,50);
        f.add(ta);
        f.pack();

        File optionsFile = new File(fileName);
        if (optionsFile.exists()) {
            try {
                restoreOptions(f);
            } catch(IOException ioe) {
                ioe.printStackTrace();
            }
        } else {
            f.setLocationByPlatform(true);
        }
        f.setVisible(true);
    }
}
Community
  • 1
  • 1
Andrew Thompson
  • 168,117
  • 40
  • 217
  • 433
  • Wow that's a very elegant answer ! Thanks ! – Scherrer Vincent Oct 16 '11 at 09:19
  • I noticed that on system with funky visual graphical effect (e.g. Ubuntu or many other linux system), as the main Frame is not resized instantaneously, a Thread.sleep(1000) is needed right after the f.setExtendedState(Frame.NORMAL). Otherwise, the size and location will be screwed up. – dm76 Mar 02 '12 at 09:50
  • @dm76 Thanks for the info. It might be safer(1) to start a one shot Swing `Timer` set for the same delay, though that /may/ **would** clash with the shut-down process. 1) Pausing the EDT with a `Thread.sleep(n)` might itself cause the frame to remain the same size. – Andrew Thompson Mar 02 '12 at 10:10
  • @AndrewThompson, hmm good point, I didn't think of that! I'll give a shot – dm76 Mar 02 '12 at 18:59
  • 2
    Does the sleep indicate a need for the event loop to process to get the right values? If so, wouldn't we just be better off caching the height and width when normal and skipping the switch back to normal? – Jonathan Seng Mar 09 '13 at 04:29
9

I've usually let the platform decide by calling:

myJFrame.setLocationByPlatform(true);

This lets the window "appear at the default location for the native windowing system". For more on this: Window API

Hovercraft Full Of Eels
  • 283,665
  • 25
  • 256
  • 373
2

What I always do is start at the center of the screen for main frame, or at the center of a parent for child frames, I record this location. Then as users move the frames to wherever they want I record the new location and when next the app is started, I use the last location to place the frame.

Akintayo Olusegun
  • 917
  • 1
  • 10
  • 20
  • 1
    Don't like the first part of 'center', but storing location on exit/restoring location on start-up (with some tweaks) makes a lot of sense. – Andrew Thompson Oct 15 '11 at 13:33
1

Not sure if there's a best practice as it is very subjective.

Setting it at the center and allowing users to change it to the location they like seems to be the ideal one.

As regards to the child frame, depending on its size, in the center of the parent frame, or just something easy to use.

Mob
  • 10,958
  • 6
  • 41
  • 58