JButtons внутри JPanels с помощью GridLayout JFrame

Java/Eclipse IDE здесь.

У меня есть один JFrame, который установлен в GridLayout размера NxN. N задается пользователем в командной строке в начале программы. JButtons в шаблоне NxN добавляются в окно в JPanels, устанавливаются в местоположении с помощью GridLayout (я думаю).

Каждому JButton нужен собственный JPanel для использования GridLayout? У меня создается впечатление, что вы можете настроить только один JPanel для всех кнопок и установить JPanel в GridLayout для JButtons. Я хочу добавить еще один JPanel слева от массива кнопок, чтобы отображать нажатия кнопок (JLabel) и кнопку reset внутри той же левой JPanel.

Вот (немного) моего кода, где N задан пользователем, система - это мой класс фоновых процессов, а ButtonEvent - класс ActionListener/actionPerformed:

JFrame window = new JFrame("");
GridLayout layout = new GridLayout(N,N);
window.setLayout(layout);

for (int row = 0; row < N; row++){
    for (int col = 0; col < N; col++){
        JPanel panel = new JPanel();
        JButton b = new JButton ("("+row+","+col+")");
        window.add(b).setLocation(row, col);
        panel.add(b);
        b.addActionListener(new ButtonEvent(b, system, row, col));
        window.add(panel);
    }
}

window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.pack();
window.setVisible(true);

И это то, что у меня (N = 4):

http://i.imgur.com/nbQoM.png

Вот (приблизительно) то, что я ищу (N = 4):

http://i.imgur.com/SiVWO.png

Все, что мне нужно/нужно, это две (или более) JPanels, которые настроены примерно так же, как и выше, и все планировщики макетов, которые я пробовал, не очень хорошо сочетаются с макетом GridLayout JFrame.

Приглашаются любые рекомендации относительно лучшего решения.

Спасибо!

Ответ 1

Вот пример этого кода:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class LayoutExample extends JFrame
{
    private static final String INITIAL_TEXT = "Nothing Pressed";
    private static final String ADDED_TEXT = " was Pressed";
    private JLabel positionLabel;
    private JButton resetButton;
    private static int gridSize = 4;

    public LayoutExample()
    {
        super("Layout Example");
    }

    private void createAndDisplayGUI()
    {       
        setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);

        JPanel contentPane = new JPanel();
        contentPane.setLayout(new FlowLayout(FlowLayout.LEFT, 20, 20));
        contentPane.setBorder(BorderFactory.createLineBorder(Color.DARK_GRAY, 2));

        JPanel leftPanel = new JPanel();
        leftPanel.setBorder(BorderFactory.createLineBorder(Color.DARK_GRAY, 2));
        leftPanel.setLayout(new BoxLayout(leftPanel, BoxLayout.Y_AXIS));    
        JPanel labelPanel = new JPanel();
        positionLabel = new JLabel(INITIAL_TEXT, JLabel.CENTER);
        JPanel buttonLeftPanel = new JPanel();
        resetButton = new JButton("Reset");
        resetButton.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent ae)
            {
                positionLabel.setText(INITIAL_TEXT);
            }
        });
        labelPanel.add(positionLabel);
        buttonLeftPanel.add(resetButton);
        leftPanel.add(labelPanel);
        leftPanel.add(buttonLeftPanel);

        contentPane.add(leftPanel);

        JPanel buttonPanel = new JPanel();
        buttonPanel.setLayout(new GridLayout(gridSize, gridSize, 10, 10));
        for (int i = 0; i < gridSize; i++)
        {
            for (int j = 0; j < gridSize; j++)
            {
                JButton button = new JButton("(" + i + ", " + j + ")");
                button.setActionCommand("(" + i + ", " + j + ")");
                button.addActionListener(new ActionListener()
                {
                    public void actionPerformed(ActionEvent ae)
                    {
                        JButton but = (JButton) ae.getSource();
                        positionLabel.setText(
                            but.getActionCommand() + ADDED_TEXT);                           
                    }
                });
                buttonPanel.add(button);
            }
        }
        contentPane.add(buttonPanel);

        setContentPane(contentPane);
        pack();
        setLocationByPlatform(true);
        setVisible(true);
    }

    public static void main(String[] args)
    {
        if (args.length > 0)
        {
            gridSize = Integer.parseInt(args[0]);
        }
        SwingUtilities.invokeLater(new Runnable()
        {
            public void run()
            {
                new LayoutExample().createAndDisplayGUI();
            }
        });
    }
}

ВЫХОД:

StartAfter Click

Ответ 2

Каждому JButton нужен собственный JPanel для использования GridLayout?

Нет. Добавить и setLayout на JFrame не делают то, что они видят. JFrame - это контейнеры верхнего уровня, и лучше организовать ваш контент в JPanels.

Вы должны организовать свои панели в этой форме:

----JPanel----------------------------|
| ---LeftPanel---  ---ButtonsPanel--- |
| |             |  |                | |
| |             |  |                | |
| |             |  | GridLayout(N,N)| |
| |             |  |                | |
| |             |  |                | |
| ---------------  ------------------ |
---------------------------------------

Затем добавьте JPanel в JFrame. Также поместите панели в отдельные классы:

class BPanel extends JPanel {
    public BPanel() {
        GridLayout layout = new GridLayout(N,N, hgap, vgap);
        setLayout(layout);
        for (int row = 0; row < N; row++){
            for (int col = 0; col < N; col++){
                JButton b = new JButton ("("+row+","+col+")");
                add(b).setLocation(row, col);
                b.addActionListener(new ButtonEvent(b, system, row, col));
            }
        }
    }
}
class LeftPanel extends JPanel {
....
}

class MainFrame extends JFrame {
    public MainFrame() {
        JPanel p = new JPanel();
        p.add(new LeftPanel());
        p.add(newButtonsPanel());
        add(p);
    }
}

Ответ 3

Одно из преимуществ предоставления каждой кнопке (или группе кнопок) собственной панели состоит в том, что вложенная панель может иметь разный макет. В этом примере каждый вложенный ButtonPanel имеет значение по умолчанию FlowLayout, поэтому размер кнопки остается неизменным по мере изменения размера контейнера-контейнера.