Java CardLayout JPanel moves up, when second JPane

2019-01-20 13:48发布

I am new to Java and mostly CardLayout. I want to simply switch "windows" represented by JPanels. I read somewhere that job for CardLayout. But my problem is, when add chatPanel to mainPanel (this is the CardLayout one), it shifts the content of connectPanel several pixels to the top, away from its centered position. Is I skip in my code createChatPanel(), its where it should be.

I have this code:

package App;

import java.awt.CardLayout;
import java.awt.Dimension;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.*;
import Validators.*;



public class GUI {

private JFrame mainFrame = null;
private JPanel mainPanel = null;
private CardLayout cl = new CardLayout();

public GUI(){


    try {
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
         } 
         catch (UnsupportedLookAndFeelException e) {
         }
         catch (ClassNotFoundException e) {
         }
         catch (InstantiationException e) {
         }
         catch (IllegalAccessException e) {
         }

    mainFrame = new JFrame("MainChat");
    mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    mainFrame.setSize(640,480);
    mainFrame.setLocationRelativeTo(null);
    mainFrame.setResizable(false);
    mainFrame.setLayout(new GridBagLayout());

    JMenuBar menuBar = new JMenuBar();

    JMenu menuFile = new JMenu("Soubor");
    JMenu menuHelp = new JMenu("Nápověda");

    menuBar.add(menuFile);
    menuBar.add(menuHelp);

    menuFile.add(new JMenuItem("Nové Připojení"));
    menuFile.add(new JSeparator());
    menuFile.add(new JMenuItem("Konec"));
    menuHelp.add(new JMenuItem("O programu"));
    mainFrame.setJMenuBar(menuBar);


    createMainPanel();
    createConnectPanel();
    createChatPanel();

    mainFrame.setVisible(true);
}

public void createMainPanel() {

    mainPanel = new JPanel(cl);
    mainFrame.add(mainPanel);

}

public void createConnectPanel() {

    JPanel connectPanel = new JPanel();
    mainPanel.add(connectPanel,"connectPanel");

    JTextField ip = new JTextField();
    ip.setDocument(new JTextFieldLimit(15));
    ip.setColumns(11);

    JLabel iplabel = new JLabel("IP:");
    connectPanel.add(iplabel);
    connectPanel.add(ip);

    JButton connect = new JButton("Connect");
    connect.addActionListener(new ActionListener() {

        @Override
        public void actionPerformed(ActionEvent e) {

            cl.show(mainPanel,"chatPanel");

        }
    });
    connectPanel.add(connect);

}

public void createChatPanel(){

    JPanel chatPanel = new JPanel();
    mainPanel.add(chatPanel,"chatPanel");

    JTextArea chatbox = new JTextArea();
    chatbox.setPreferredSize(new Dimension(200,200));
    chatPanel.add(chatbox);

}
}

Please, what I messed up? Thanks.

2条回答
Fickle 薄情
2楼-- · 2019-01-20 14:45

If you want a JPanel centered in another, place your connectPanel in another JPanel that acts as a dumb container, and have this container use GridBagLayout. Then if you add the connectPanel to the container without any GridBagConstraints, it will be added to the default position for GridBagLayout which is centered. You can then add this container JPanel to your mainPanel using the same constant that you would have used for your connectPanel.

I would tend to let the layouts determine the size of components and avoid using setSize and even setPreferredSize, and would definitely call pack() on my JFrame prior to setting it visible. You definitely don't want to set the size or preferredSize of your JTextField, but rather set its columns and rows and place it in a JScrollPane, and then add that JScrollPane to the view.

Edit:
Here's an example that shows placement of something like your connect panel at the top, middle and bottom of a small gui. Just press the "Next" button to see what I mean:

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

@SuppressWarnings("serial")
public class GUI2 extends JPanel {
    public static final String CONNECT_NORTH = "connect north";
    public static final String CONNECT_CENTER = "connect center";
    private static final String CONNECT_SOUTH = "connect south";
    private static final String CHAT_PANEL = "chat panel";
    private CardLayout cardlayout = new CardLayout();

    public GUI2() {
        setLayout(cardlayout);
        add(createConnectPanel(BorderLayout.NORTH), CONNECT_NORTH);
        add(createConnectPanel(BorderLayout.CENTER), CONNECT_CENTER);
        add(createConnectPanel(BorderLayout.SOUTH), CONNECT_SOUTH);
        add(createChatPanel(), CHAT_PANEL);
    }

    public void nextPanel() {
        cardlayout.next(this);
    }


    private JPanel createConnectPanel(String borderlayoutLocation) {
        JPanel innerPanel = new JPanel();
        innerPanel.add(new JLabel("IP:"));
        innerPanel.add(Box.createHorizontalStrut(5));
        innerPanel.add(new JTextField(11));
        innerPanel.add(Box.createHorizontalStrut(5));
        innerPanel.add(new JButton(new AbstractAction("Next") {

            @Override
            public void actionPerformed(ActionEvent arg0) {
                GUI2.this.nextPanel();
            }
        }));

        JPanel innerPanel2 = new JPanel(new GridBagLayout());
        innerPanel2.add(innerPanel);
        JPanel connectPanel = new JPanel(new BorderLayout());
        connectPanel.add(innerPanel2, borderlayoutLocation);
        return connectPanel;
    }

    private JPanel createChatPanel() {
        JPanel chatPanel = new JPanel(new BorderLayout(5, 5));
        chatPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
        chatPanel.add(new JScrollPane(new JTextArea(15, 30)), BorderLayout.CENTER);
        chatPanel.add(new JTextField(), BorderLayout.SOUTH);

        return chatPanel;
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                createGui();
            }
        });
    }

    private static void createGui() {
        JFrame frame = new JFrame("App");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().add(new GUI2());
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }
}
查看更多
甜甜的少女心
3楼-- · 2019-01-20 14:47

Since you are adding two JPanels to your main JPanel, these two panels both need to fit within the main panel.

If one of the inner panels is much larger than the other one, the main panel will adjust to fit the larger one.

E.g. commenting this line:

chatbox.setPreferredSize(new Dimension(200,200));

would cause your text field to stay put. This is because the chatbox would not cause the container to resize.

Also note that the main panel is not initially the same size as your main frame, since you have not set the size of the main panel.

If you would set the size of the connectPanel to the same size as your main frame, the connectPanel would not be automatically resized when adding the chatPanel (as a consequence of the mainPanel being resized)

So what you could do is add the middle line in:

JPanel connectPanel = new JPanel();
connectPanel.setSize(640, 480);
mainPanel.add(connectPanel, "connectPanel");

, which probably would solve your problem.

Although this would work, I definitely recommend using MIG Layout for all your GUI designing. It will save you plenty of time if you take an hour to learn it. It will also save you from having to set sizes manually (and thereby saving you from having to rewrite half your GUI code with every design change).

查看更多
登录 后发表回答