วิธีการจัดตำแหน่ง Swing GUI ให้ดีที่สุด?


126

ในอีกหัวข้อหนึ่งฉันระบุว่าฉันชอบที่จะวาง GUI ของฉันไว้ตรงกลางโดยทำสิ่งนี้:

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

ในสายตาของฉัน GUI ที่อยู่ตรงกลางของหน้าจอดูเหมือน .. "splash-screen'ish" ฉันรอให้พวกเขาหายไปและGUI ที่แท้จริงจะปรากฏ!

ตั้งแต่ Java 1.5 เราสามารถเข้าถึงWindow.setLocationByPlatform(boolean)ไฟล์. ที่..

ตั้งค่าว่าหน้าต่างนี้ควรปรากฏที่ตำแหน่งเริ่มต้นสำหรับระบบหน้าต่างดั้งเดิมหรือที่ตำแหน่งปัจจุบัน (ส่งคืนโดย getLocation) ในครั้งถัดไปที่หน้าต่างจะปรากฏขึ้น ลักษณะการทำงานนี้คล้ายกับหน้าต่างดั้งเดิมที่แสดงโดยไม่ได้ตั้งค่าตำแหน่งที่ตั้งของโปรแกรม ระบบหน้าต่างส่วนใหญ่เรียงซ้อนหน้าต่างหากไม่ได้ตั้งค่าตำแหน่งไว้อย่างชัดเจน ตำแหน่งจริงจะถูกกำหนดเมื่อหน้าต่างแสดงบนหน้าจอ

ดูเอฟเฟกต์ของตัวอย่างนี้ที่ทำให้ 3 GUI อยู่ในตำแหน่งเริ่มต้นตามที่ OS เลือก - บน Windows 7, Linux พร้อม Gnome & Mac OS X

หน้าต่างแบบซ้อนบน Windows 7 ใส่คำอธิบายภาพที่นี่ หน้าต่างแบบเรียงซ้อนบน Mac OS X

(3 ล็อต) 3 GUI ที่ซ้อนกันอย่างเรียบร้อย สิ่งนี้แสดงถึง 'เส้นทางแห่งความประหลาดใจน้อยที่สุด' สำหรับผู้ใช้เนื่องจากเป็นวิธีที่ระบบปฏิบัติการอาจวางตำแหน่ง 3 อินสแตนซ์ของโปรแกรมแก้ไขข้อความธรรมดาเริ่มต้น (หรืออย่างอื่นสำหรับเรื่องนั้น) ขอขอบคุณถังขยะสำหรับ 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 ไว้ตรงนั้น "บางอย่างที่แตกต่างไปอย่างสิ้นเชิง" มันเป็นเพียงสิ่งที่ฉันคุ้นเคยเมื่อฉันเขียนโปรแกรมในขั้นพื้นฐานเป็นครั้งแรก (ใช่นานมาแล้ว) ความเกียจคร้านเป็นสาเหตุของการใช้งานต่อไป 'ถ้ายังไม่พังอย่าซ่อม'
Andrew Thompson

1
@MirroredFate คุณเป็นเจ้าชายแห่งเปอร์เซียแฟนโดยบังเอิญหรือไม่? ฉันเสียใจมากที่ต้องใส่ไว้ที่นี่ ฉันไม่สามารถต้านทาน
Anarach

11
@MirroredFate นี่คือเหตุผลที่ผมใช้แทนii iเมื่อฉันเข้าร่วมการแข่งขันการเขียนโปรแกรมฉันมักจะต้องค้นหาดัชนีลูปเพื่อพูด+1หรือ-1จากดัชนีนี้เพื่อแก้ไขข้อผิดพลาดเพียงข้อเดียว ในกรณีดังกล่าวการค้นหาiiนั้นง่ายกว่าการค้นหาiมากไม่ว่าฉันจะใช้ตัวแก้ไขใดก็ตาม ในทำนองเดียวกันฉันใช้jjและkkสำหรับดัชนีวงซ้อน :)
musically_ut

5

ฉันยอมรับโดยสิ้นเชิงว่าsetLocationByPlatform(true)เป็นวิธีที่ดีที่สุดในการระบุตำแหน่งของ JFrame ใหม่ แต่ในการตั้งค่าจอภาพสองจอคุณจะพบปัญหาได้ ในกรณีของฉัน JFrame ลูกถูกสร้างบนจอภาพ 'อีกข้างหนึ่ง' ตัวอย่าง: ฉันมี GUI หลักของฉันบนหน้าจอ 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);
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.