Как да програмирам този GUI в Java Swing

В момента разработвам малка помощна програма със следния GUI:

Примерен GUI

В момента имам контейнер (JPanel) с оформлението BorderLayout, което държи всичко на място. Имам още 2 JPanels, поставени съответно на BorderLayout.NORTH и BorderLayout.SOUTH, всеки с GridLayout (2 колони по 1 ред). Масата е върху основния контейнер, поставен в ЦЕНТЪРА му.

Смятате ли, че това е най-добрият подход? Трудно ми е да се справя с разстоянието между компонентите и границите на рамката.

В момента имам този код:

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.GridLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JSeparator;
import javax.swing.JTable;
import javax.swing.SwingUtilities;

public class GUI extends JFrame {

    private JButton loadFileBtn = new JButton("Load File");
    private JButton generateReportBtn = new JButton("Generate Report");
    private JButton exitBtn = new JButton("Exit");
    private JLabel fileNameLbl = new JLabel("File Name Here");
    private JMenuBar menuBar = new JMenuBar();
    private JMenu fileMI = new JMenu("File");
    private JMenuItem openFileMenu = new JMenuItem("Open File");
    private JSeparator separator = new JSeparator();
    private JMenuItem exitMenu = new JMenuItem("Exit");
    private JMenu reportMI = new JMenu("Report");
    private JMenuItem generateReportMenu = new JMenuItem("Generate Report");
    private JMenu helpMI = new JMenu("Help");
    private JMenuItem aboutMenu = new JMenuItem("About");
    private JTable table = new JTable(5, 2);
    private JPanel mainPanel = new JPanel(new BorderLayout(10, 10));
    private JPanel panel1 = new JPanel(new BorderLayout());
    private JPanel panel2 = new JPanel(new GridLayout(1, 2));
    private JPanel panel3 = new JPanel(new GridLayout(1, 2));

    public GUI() {

        super("Sample GUI");

        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setSize(new Dimension(300, 300));
        setResizable(false);

        setLayout(new BorderLayout(10, 10));

        fileMI.add(openFileMenu);
        fileMI.add(separator);
        fileMI.add(exitMenu);

        reportMI.add(generateReportMenu);

        helpMI.add(aboutMenu);

        menuBar.add(fileMI);
        menuBar.add(reportMI);
        menuBar.add(helpMI);

        setJMenuBar(menuBar);

        panel1.add(table, BorderLayout.CENTER);

        panel2.add(fileNameLbl);
        panel2.add(loadFileBtn);

        panel3.add(generateReportBtn);
        panel3.add(exitBtn);

        mainPanel.add(panel2, BorderLayout.NORTH);
        mainPanel.add(panel1, BorderLayout.CENTER);
        mainPanel.add(panel3, BorderLayout.SOUTH);

        add(mainPanel);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                GUI app = new GUI();
                app.setVisible(true);
            }
        });
    }
}

Какъв според вас би бил най-добрият подход за това?

Всяка помощ ще бъде оценена. Благодаря.


АКТУАЛИЗАЦИЯ:

В момента имам следния GUI

въведете описание на изображението тук

Искам компонентите да се раздалечават равномерно от границите, както в макета.


person DaveQuinn    schedule 12.03.2013    source източник
comment
Какъв точно ти е проблема? Кое пространство бихте искали да представите и създава проблеми? Винаги можете да използвате BorderFactory.createEmptyBorder(int, int, int, int)   -  person Guillaume Polet    schedule 12.03.2013
comment
@Guillaume Polet не съм сигурен, моля, не атакувайте, искате ли да използвате EmptyBorder за избягване на setPreferredSize или да използвате EmptyBorder за избягване на SpringLayout с GridBagLayout във формата NestedLayout, MigLayout или ...   -  person mKorbel    schedule 12.03.2013
comment
@mKorbel Празните граници са много лесно (и понякога елегантно) решение за правилно позициониране на компоненти в техния контейнер, без да се налага да превключвате към друг LayoutManager. Ако OP се чувства добре с тези LayoutManager, празните граници може да са добро решение на действителните му проблеми.   -  person Guillaume Polet    schedule 12.03.2013


Отговори (4)


2 неща, които можете да използвате, за да направите това:

  1. Използвайте BorderFactory.createEmptyBorder(int, int, int, int)
  2. Използвайте конструктора с 4 аргумента на GridLayout

Има други LayoutManager, които могат да осигурят същата функционалност (като GridBagLayout или използване на вложени BorderLayout), но ако се чувствате добре с текущите LayoutManager, няма наложителна необходимост да ги променяте. Начинът, по който сте постъпили, също е приемлив.

въведете описание на изображението тук

Може да помислите да опаковате таблицата в JScrollPane, за да я направите по-хубава, със заглавки и ленти за превъртане, ако някога са необходими.

Малък примерен код:

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.GridLayout;

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JSeparator;
import javax.swing.JTable;
import javax.swing.SwingUtilities;

public class GUI extends JFrame {

    private JButton loadFileBtn = new JButton("Load File");
    private JButton generateReportBtn = new JButton("Generate Report");
    private JButton exitBtn = new JButton("Exit");
    private JLabel fileNameLbl = new JLabel("File Name Here");
    private JMenuBar menuBar = new JMenuBar();
    private JMenu fileMI = new JMenu("File");
    private JMenuItem openFileMenu = new JMenuItem("Open File");
    private JSeparator separator = new JSeparator();
    private JMenuItem exitMenu = new JMenuItem("Exit");
    private JMenu reportMI = new JMenu("Report");
    private JMenuItem generateReportMenu = new JMenuItem("Generate Report");
    private JMenu helpMI = new JMenu("Help");
    private JMenuItem aboutMenu = new JMenuItem("About");
    private JTable table = new JTable(5, 2);
    private JPanel mainPanel = new JPanel(new BorderLayout(10, 10));
    private JPanel panel1 = new JPanel(new BorderLayout());
    private JPanel panel2 = new JPanel(new GridLayout(1, 2, 10, 10));
    private JPanel panel3 = new JPanel(new GridLayout(1, 2, 10, 10));

    public GUI() {

        super("Sample GUI");

        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setSize(new Dimension(300, 300));
        setResizable(false);

        setLayout(new BorderLayout(10, 10));

        fileMI.add(openFileMenu);
        fileMI.add(separator);
        fileMI.add(exitMenu);

        reportMI.add(generateReportMenu);

        helpMI.add(aboutMenu);

        menuBar.add(fileMI);
        menuBar.add(reportMI);
        menuBar.add(helpMI);

        setJMenuBar(menuBar);

        panel1.add(table, BorderLayout.CENTER);

        panel2.add(fileNameLbl);
        panel2.add(loadFileBtn);

        panel3.add(generateReportBtn);
        panel3.add(exitBtn);

        mainPanel.add(panel2, BorderLayout.NORTH);
        mainPanel.add(panel1, BorderLayout.CENTER);
        mainPanel.add(panel3, BorderLayout.SOUTH);
        mainPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
        add(mainPanel);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                GUI app = new GUI();
                app.setVisible(true);
            }
        });
    }
}
person Guillaume Polet    schedule 12.03.2013
comment
Точно това исках. Благодаря ти @Guillaume Polet. Опитах също GridBagLayout, но изглежда не мога да схвана концепцията. Някакви добри уроци бихте препоръчали? Този на уеб страницата на orcles не е толкова лесен за начинаещ. - person DaveQuinn; 12.03.2013
comment
хммм знаете ли, че Empty JPanels е добавен към зона W, E, S, N към JFrame, за да създаде тази празнина автоматично, няма причина да добавяте EmptyBorders за тази идея :-) - person mKorbel; 12.03.2013
comment
@mKorbel Предлагате ли по-скоро да добавите празен JPanel с принудителен предпочитан размер на запад, изток, север и юг от JFrame? - person Guillaume Polet; 12.03.2013
comment
Както @Gilbert Le Blanc предложи, използването на FlowLayout вместо GridLayout трябва да бъде много по-гъвкаво и да ми позволи да създам празнина между етикета и бутона, на север, и двата бутона, на юг. Какво е вашето мнение? - person DaveQuinn; 12.03.2013
comment
@PMMP Зависи какво се опитвате да постигнете. Ако искате да имате бутони с еднакъв размер, GridLayout е правилният начин. Ако сега предпочитате всеки бутон да има собствен размер и да бъде подравнен по някакъв начин, FlowLayout или BoxLayout са по-добри кандидати. Няма правилни или грешни LayoutManager, само подходящи за дадени нужди/желания. - person Guillaume Polet; 12.03.2013
comment
@Guillaume Polet тази празнина се създава автоматично в контейнер от най-високо ниво, BorderLayout, празен JPanel, не се изисква никакъв размер, направено от BorderLayout - person mKorbel; 12.03.2013
comment
@mKorbel Добре, сега разбирам какво имаш предвид. Ако добавя празни JPanels, hGap и vGap на BorderLayout ще влязат в действие и автоматично ще се появи празна рамка. Лично аз все още предпочитам явната празна граница, която е създадена точно за постигане на описания ефект. За цветове и вкусове винаги може да се спори... ;-) - person Guillaume Polet; 12.03.2013

В миналото открих, че използването на MigLayout решава всичките ми проблеми

person epoch    schedule 12.03.2013
comment
Да, MigLayout почти винаги е моят път. Доста лесен за научаване и наистина лесен за използване. - person wchargin; 12.03.2013
comment
Не знаех това. Благодаря, ще го проверя. - person DaveQuinn; 12.03.2013

Ето как бих подредил вашия GUI. Това е само един начин. Това не е единственият начин.

  • JTable влиза вътре в JScrollPane.

  • Button2 и Button3 влизат вътре в бутон JPanel с FlowLayout.

  • Label и Button1 влизат вътре в етикет JPanel с FlowLayout.

  • Файл, отчет и помощ са JMenuItems на JMenuBar.

  • Основният JPanel има BoxLayout с Y_AXIS ориентация.

  • Добавете етикета JPanel, JScrollPane и бутона JPanel към основния JPanel.

person Gilbert Le Blanc    schedule 12.03.2013
comment
Ще опитам @Gilbert Le Blanc. Благодаря за вашето мнение. Оценявам го. - person DaveQuinn; 12.03.2013

Най-добрият начин е да създадете GUI е да кодирате по начин, който вие и другите ще разберете. Разгледайте това Ръководство за мениджъри на оформление. Можете да използвате различни мениджъри на оформление за различни компоненти. Това ще ви помогне да зададете правилното разстояние.

Ако проблемът ви е само разстоянието около компонентите, задайте неговия Вмъквания.

person Jean Waghetti    schedule 12.03.2013
comment
Кои мениджъри на оформление препоръчвате за този дизайн? Това е мотивацията зад въпроса ми. - person DaveQuinn; 12.03.2013
comment
GridBagLayout е най-гъвкавият според мен. Но може би бих смесил някои мениджъри на оформление. Поставете панел отгоре и отдолу и маса в средата с BorderLayout. Панелите в долната част бих използвал FlowLayout, а панелът int отгоре може би FlowLayout или GridBagLayout. Или направете всичко с GridBagLayout (много много кодиране). - person Jean Waghetti; 12.03.2013