Como posicionar melhor as GUIs Swing?

126

Em outro tópico , afirmei que gostava de centralizar minhas GUIs fazendo algo assim:

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

Mas Andrew Thompson tinha uma opinião diferente, para chamar

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

e mentes curiosas querem saber por quê?

Hovercraft cheio de enguias
fonte
A GUI deve começar no mesmo local em que terminou na última vez.
NomadMaker 22/03

Respostas:

167

A meu ver, uma GUI no meio da tela parece tão .. "splash-screen'ish". Eu continuo esperando eles desaparecerem e o verdadeiro GUI apareça!

Desde o Java 1.5, tivemos acesso Window.setLocationByPlatform(boolean). qual..

Define se essa janela deve aparecer no local padrão para o sistema de janelas nativo ou no local atual (retornado por getLocation) na próxima vez que a janela for tornada visível. Esse comportamento se assemelha a uma janela nativa mostrada sem definir programaticamente sua localização. A maioria dos sistemas de janelas em cascata abre janelas se seus locais não estiverem explicitamente definidos. A localização real é determinada quando a janela é exibida na tela.

Veja o efeito deste exemplo que coloca 3 GUIs nas posições padrão, conforme escolhido pelo sistema operacional - no Windows 7, Linux com Gnome e Mac OS X.

Janelas empilhadas no Windows 7 insira a descrição da imagem aqui Janelas empilhadas no Mac OS X

(3 lotes) 3 GUIs ordenadamente empilhadas. Isso representa 'o caminho da menor surpresa' para o usuário final, pois é assim que o sistema operacional pode posicionar três instâncias do editor de texto sem formatação padrão (ou qualquer outra coisa, nesse caso). Meus agradecimentos ao trashgod pelo Linux e Mac. imagens.

Aqui está o código simples usado:

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();
            }
        });
    }
}
Andrew Thompson
fonte
1
@AndrewThompson Por que seu contador é variável iie não apenas i? Isso segue alguma convenção ou é uma preferência pessoal (ou talvez algo completamente diferente)?
MirroredFate
1
@MirroredFate Umm .. Acho que vou travar na opção 3 lá, "algo completamente diferente". Era exatamente o que eu me acostumava quando programava pela primeira vez no Basic (sim, há muito tempo). Preguiça é o motivo do uso contínuo, 'se não estiver quebrado, não conserte'.
Andrew Thompson
1
@MirroredFate Você, por acaso, é fã do príncipe da Pérsia? Lamento colocar aqui. Eu apenas não poderia resistir
Anarach
11
@MirroredFate Aqui está o porquê eu uso em iivez de i. Quando participo de competições de programação, muitas vezes tenho que procurar o índice do loop para, digamos, +1ou a -1partir dele, corrigir um erro. Nesses casos, pesquisar iié muito mais fácil do que pesquisar i, independentemente de qual editor eu usei. Da mesma forma, eu uso jje kkpara os índices de loop aninhados. :)
musically_ut
5

Concordo totalmente que setLocationByPlatform(true)é a melhor maneira de especificar a posição de um novo JFrame, mas em uma configuração de monitor duplo, você pode entrar em problemas. No meu caso, o filho JFrame é gerado no monitor 'outro'. Exemplo: Eu tenho minha GUI principal na Tela 2, inicio um novo JFrame setLocationByPlatform(true)e ele abre na Tela 1. Portanto, aqui está uma solução mais completa, eu acho:

...
// 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);
Axel Podehl
fonte