Как лучше всего позиционировать Swing GUI?

126

В другом потоке я заявил, что мне нравится центрировать свои графические интерфейсы, делая что-то вроде этого:

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

Но Эндрю Томпсон придерживался другого мнения и вместо этого назвал

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

и пытливые умы хотят знать, почему?

Судно на воздушной подушке, полное угрей
источник
Графический интерфейс должен начинаться с того же места, где он заканчивался в прошлый раз.
NomadMaker

Ответы:

167

На мой взгляд, графический интерфейс в центре экрана выглядит таким ... "splash-screen'ish". Я все жду, когда они исчезнут и появится настоящий графический интерфейс!

Начиная с Java 1.5 у нас был доступ к Window.setLocationByPlatform(boolean). который..

Устанавливает, должно ли это окно отображаться в месте по умолчанию для собственной оконной системы или в текущем месте (возвращенном getLocation) в следующий раз, когда окно станет видимым. Это поведение похоже на обычное окно, показанное без программной установки его местоположения. В большинстве оконных систем окна каскадируются, если их расположение не задано явно. Фактическое местоположение определяется, когда окно отображается на экране.

Посмотрите на эффект этого примера, который помещает 3 графических интерфейса пользователя в позиции по умолчанию, выбранные ОС - в Windows 7, Linux с Gnome и Mac OS X.

Сложенные окна в Windows 7 введите описание изображения здесь Сложенные окна в Mac OS X

(3 партии) 3 аккуратно сложенных графических интерфейса. Это представляет собой «путь наименьшего удивления» для конечного пользователя, поскольку именно так ОС может размещать 3 экземпляра стандартного текстового редактора (или чего-либо еще, если на то пошло). Спасибо trashgod за Linux и Mac. изображений.

Вот используемый простой код:

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();
            }
        });
    }
}
Эндрю Томпсон
источник
1
@AndrewThompson Почему ваша переменная счетчика, iiа не просто i? Придерживается ли это какой-то условности или это личное предпочтение (или, может быть, что-то совершенно иное)?
MirroredFate
1
@MirroredFate Умм .. Я думаю, я включу вариант 3, "что-то совершенно другое". Это было то, к чему я привык, когда впервые программировал на Basic (да, очень давно). Лень - причина для продолжения использования, «если не сломалось, не чини».
Эндрю Томпсон
1
@MirroredFate Вы случайно не принц Персии Фан? Мне очень жаль помещать это здесь. Я просто не смог устоять
Анарач
11
@MirroredFate Вот почему я использую iiвместо i. Когда я участвую в соревнованиях по программированию, мне часто приходится искать индекс цикла, скажем, +1или -1от него, чтобы исправить одну ошибку. В таких случаях искать iiнамного проще, чем искать i, независимо от того, какой редактор я использовал. Точно так же я использую jjи kkдля индексов вложенного цикла. :)
musically_ut
5

Я полностью согласен, что setLocationByPlatform(true)это лучший способ указать новую позицию JFrame, но при настройке с двумя мониторами вы можете столкнуться с проблемами. В моем случае дочерний JFrame создается на «другом» мониторе. Пример: у меня есть основной графический интерфейс на экране 2, я запускаю новый JFrame с помощью, setLocationByPlatform(true)и он открывается на экране 1. Итак, я думаю, вот более полное решение:

...
// 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);
Аксель Подель
источник