Search code examples
javaswingjtextfield

How to make with JTextField and JButton a menu with name filling functions?


So i am trying to make a Panel where the player configures the names of the players in a local board game. I want them to be able to add players between 2 and 6 so by default i have made the panel show up 2 JTextField boxes for them to add names and under the second one there is a "+" button to add an extra player. But i dont know how to do that and how to perform such action, when the user presses the "+" button a new JTextField pops up for the player to add a new player name.

I am providing the code i am using for this particular panel but it is necessary i can provide the whole code for my window. Any help is appreciated and thanks in advance.

private void setLocalPanel() {

    GridBagConstraints c = new GridBagConstraints();
    
    // localButtonsPanel config
    localButtonsPanel = new JPanel(new GridLayout(0, 1, 0, 10));
    localButtonsPanel.setOpaque(false);
    
    // nameBox1 config
    nameBox1 = new JTextField("Player name");
    nameBox1.setBackground(new Color(255, 255, 255));
    nameBox1.setEditable(true);
    c.ipady = 10;
    localButtonsPanel.add(nameBox1, c);

    // nameBox2 config
    nameBox2 = new JTextField("Player name");
    nameBox2.setBackground(new Color(255, 255, 255));
    nameBox2.setEditable(true);
    localButtonsPanel.add(nameBox2, c);
    
    // + config
    extraBtn = new JButton("+");
    extraBtn.setForeground(new Color(255, 255, 255));
    extraBtn.setFont(new Font("Segoe Script", Font.BOLD,40));
    extraBtn.setOpaque(false);
    extraBtn.setContentAreaFilled(false);
    extraBtn.setBorderPainted(false);
    extraBtn.setFocusPainted(false);
    localButtonsPanel.add(extraBtn, new GridBagConstraints());
    
    c.gridy = 0;
    localPanel.add(localButtonsPanel, c);
    
    // startBtn config
    startBtn = new JButton("Start");
    startBtn.setForeground(new Color(255, 255, 255));
    startBtn.setFont(new Font("Segoe Script", Font.BOLD,40));
    startBtn.setOpaque(false);
    startBtn.setContentAreaFilled(false);
    startBtn.setBorderPainted(false);
    startBtn.setFocusPainted(false);
    c.gridy = 1;
    localPanel.add(startBtn, c);
    
    // localBackBtn config
    localBackBtn = new JButton("Back");
    localBackBtn.setForeground(new Color(255, 255, 255));
    localBackBtn.setFont(new Font("Segoe Script", Font.BOLD,40));
    localBackBtn.setOpaque(false);
    localBackBtn.setContentAreaFilled(false);
    localBackBtn.setBorderPainted(false);
    localBackBtn.setFocusPainted(false);
    c.gridy = 2;
    localPanel.add(localBackBtn, c);
    
    setLocalActions();
}
private void setLocalActions() {
    
    // startBtn config
    startBtn.addMouseListener(new MouseAdapter() {

        public void mouseEntered(MouseEvent e) {
            startBtn.setForeground(new Color(200, 210, 10));
            startBtn.setText("> Start <");
        }
        
        public void mouseExited(MouseEvent e) {
            startBtn.setForeground(new Color(255, 255, 255));
            startBtn.setText("Start");
        }
        
        public void mouseClicked(MouseEvent e) {
            // nameBox1.getText()
            // nameBox2.getText()
            localPanel.setVisible(false);
            gamePanel.setVisible(true);
        }
    });
    
    // localBackBtn config
    localBackBtn.addMouseListener(new MouseAdapter() {

        public void mouseEntered(MouseEvent e) {
            localBackBtn.setForeground(new Color(200, 210, 10));
            localBackBtn.setText("> Back <");
        }
        
        public void mouseExited(MouseEvent e) {
            localBackBtn.setForeground(new Color(255, 255, 255));
            localBackBtn.setText("Back");
        }
        
        public void mouseClicked(MouseEvent e) {
            localPanel.setVisible(false);
            playPanel.setVisible(true);
        }
    });
}

PS. the localPanel has a GridBagLayout.

enter image description here


Solution

  • You need to add an ActionListener to a JButton and not a MouseListener. Refer to How to Use Buttons.

    When the + button is clicked, you want to add a new JTextField to the JPanel that contains the fields that allow the user to enter a player's name.

    Here is code, adapted from the code in your question, that adds a JTextField when the user clicks the + button. Notes about the code appear after it.

    import java.awt.BorderLayout;
    import java.awt.Color;
    import java.awt.Dimension;
    import java.awt.EventQueue;
    import java.awt.Font;
    import java.awt.GridBagConstraints;
    import java.awt.GridBagLayout;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.util.ArrayList;
    
    import javax.swing.JButton;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    import javax.swing.JTextField;
    import javax.swing.WindowConstants;
    
    public class PlayGame implements ActionListener, Runnable {
        private static final int  MAX_PLAYERS = 6;
        private static final String  BACK = "Back";
        private static final String  PLUS = "+";
        private static final String  START = "Start";
    
        private ArrayList<JTextField>  playerNameTextFields;
        private GridBagConstraints  gbc;
        private JFrame  frame;
        private JPanel  localButtonsPanel;
    
        public PlayGame() {
            playerNameTextFields = new ArrayList<>();
        }
    
        @Override // java.lang.Runnable
        public void run() {
            showGui();
        }
    
        @Override // java.awt.event.ActionListener
        public void actionPerformed(ActionEvent event) {
            String actionCommand = event.getActionCommand();
            switch (actionCommand) {
                case BACK:
                    // Add code to execute when user clicks 'Back' button.
                    break;
                case PLUS:
                    addPlayerNameTextField();
                    localButtonsPanel.revalidate();
                    localButtonsPanel.repaint();
                    if (playerNameTextFields.size() >= MAX_PLAYERS) {
                        ((JButton) event.getSource()).setEnabled(false);
                    }
                    break;
                case START:
                    // Add code to execute when user clicks 'Start' button.
                    break;
                default:
                    System.out.println("Not implemented: " + actionCommand);
            }
        }
    
        private void addPlayerNameTextField() {
            JTextField playerNameTextField = new JTextField(10);
            playerNameTextField.setName("player" + playerNameTextFields.size());
            playerNameTextFields.add(playerNameTextField);
            gbc.gridy++;
            localButtonsPanel.add(playerNameTextField, gbc);
        }
    
        private JPanel createLocalPanel() {
            JPanel localPanel = new JPanel(new GridBagLayout());
            localPanel.setOpaque(false);
            GridBagConstraints c = new GridBagConstraints();
            c.gridx = 0;
            c.gridy = 0;
            c.insets.top = 10;
            localButtonsPanel = new JPanel(new GridBagLayout());
            gbc = new GridBagConstraints();
            gbc.gridx = 0;
            gbc.gridy = -1;
            gbc.insets.top = 10;
            localButtonsPanel.setPreferredSize(new Dimension(120, 200));
            localButtonsPanel.setOpaque(false);
            addPlayerNameTextField();
            addPlayerNameTextField();
            localPanel.add(localButtonsPanel, c);
            c.gridy = 1;
            JButton extraBtn = new JButton(PLUS);
            extraBtn.setFont(new Font("Segoe Script", Font.BOLD,40));
            extraBtn.setForeground(Color.WHITE);
            extraBtn.setContentAreaFilled(false);
            extraBtn.setBorderPainted(false);
            extraBtn.setFocusPainted(false);
            extraBtn.addActionListener(this);
            extraBtn.setToolTipText("Add another player");
            localPanel.add(extraBtn, c);
            c.gridy = 2;
            JButton startBtn = new JButton(START);
            startBtn.setForeground(Color.WHITE);
            startBtn.setFont(new Font("Segoe Script", Font.BOLD,40));
            startBtn.setContentAreaFilled(false);
            startBtn.setBorderPainted(false);
            startBtn.setFocusPainted(false);
            startBtn.addActionListener(this);
            localPanel.add(startBtn, c);
            JButton localBackBtn = new JButton(BACK);
            localBackBtn.setForeground(Color.WHITE);
            localBackBtn.setFont(new Font("Segoe Script", Font.BOLD,40));
            localBackBtn.setContentAreaFilled(false);
            localBackBtn.setBorderPainted(false);
            localBackBtn.setFocusPainted(false);
            localBackBtn.addActionListener(this);
            c.gridy = 3;
            localPanel.add(localBackBtn, c);
            return localPanel;
        }
    
        private void showGui() {
            frame = new JFrame();
            frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
            frame.getContentPane().setBackground(Color.DARK_GRAY);
            frame.add(createLocalPanel(), BorderLayout.CENTER);
            frame.setSize(800, 600);
            frame.setLocationRelativeTo(null);
            frame.setVisible(true);
        }
    
        /**
         * Start here.
         */
        public static void main(String[] args) {
            EventQueue.invokeLater(new PlayGame());
        }
    }
    

    Note that when you call setContentAreaFilled(false) on a JButton, there is no need to also call setOpaque(false).

    Instead of new java.awt.Color(255, 255, 255) you can use the constant WHITE in class java.awt.Color.

    GridLayout and GridBagLayout are not the same. Refer to Laying Out Components Within a Container

    Rather than use a background image like you have done, I simply set the background color to dark gray.