Home > Net >  Inputting data to JTextField by pressing JButton
Inputting data to JTextField by pressing JButton

Time:08-01

I wrote a program that creates a sudoku board according to the difficulty level chosen by the user. There's a basic GUI using JFrame and JPanel. The board itself is built using a 2D array of JTextFields to allow for editing by the user and I made a table of JButtons representing digits 1-9. I'm trying to make it so when I press a digit button while my cursor is on the relevant text field, it'll input that number to the field. I think there's a problem with how I defined the buttons but would love a hand. By the way, this is my first official stack overflow question so thanks in advance to all who help :)

    /*Java Program to solve Sudoku problem using Backtracking*/
import javax.swing.*;
import javax.swing.border.Border;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import java.awt.*;


public class Solver extends Board {

    Solver(int N, int K) {
        super(N, K);
    }

    private static void createWindow() {
        JFrame frame = new JFrame("Sudoku");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        createUI(frame);
        frame.setSize(250, 80);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    private static void createUI(final JFrame frame) {
        JPanel panel = new JPanel();
        LayoutManager layout = new FlowLayout();
        panel.setLayout(layout);

        JButton button = new JButton("Play");
        button.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                String result = (String) JOptionPane.showInputDialog(
                    frame,
                    "Difficulty Glossary:\n\n Hard - 50/81 blank spaces\n Medium - 35/81 blank spaces\n Easy - 20/81 blank spaces\n\nChoose your desired difficulty:\n\tHard: 1\n\tMedium: 2\n\tEasy: 3\nIf your input doesn't match one of these digits, the board generated will be on easy mode.",
                    "Difficulty Glossary",
                    JOptionPane.PLAIN_MESSAGE,
                    null,
                    null,
                    "3"
                );
                optionBoard();
                play(Integer.parseInt(result));
            }
        });

        panel.add(button);
        frame.getContentPane().add(panel, BorderLayout.CENTER);
    }
    public static void optionBoard(){

    }

    public static void play(int level) {
        int N = 9, K = 0;
        switch (level) {
            case 1:
                K = 50;
                break;
            case 2:
                K = 35;
                break;

            default:
                K = 20;
                break;
        }
        Solver sudoku = new Solver(N, K);
        sudoku.fillValues();
        createBoard(sudoku.puzzle);
    }

    public static void createBoard(int[][] puzzle) {
        final Border fieldBorder = BorderFactory.createLineBorder(Color.BLACK);

        final JPanel grid = new JPanel(new GridLayout(9, 9));
        for (int i = 0; i < 9; i  ) {
            for (int j = 0; j < 9; j  ) {
                final JTextField field = new JTextField(2);
                if (puzzle[i][j] != 0) {
                    field.setText(puzzle[i][j]   "");
                } else {
                    field.setText("");
                }
                field.setHorizontalAlignment(JTextField.CENTER); //Center text horizontally in the text field.
                field.setBorder(fieldBorder); //Add the colored border.
                grid.add(field);
            }
        }

        final JPanel digits = new JPanel(new GridLayout(3, 3));
        int num=1;
        for (int i = 1; i < 4; i  ) {
            for (int j = 1; j < 4; j  ) {
                final JButton digit = new JButton(num "");
                num  ;
                
                digits.add(digit);
            }
        }

        final JPanel centeredGrid = new JPanel(new GridBagLayout());
        centeredGrid.add(digits);
        centeredGrid.add(grid);
    
        final JFrame frame = new JFrame("Sudoku Board");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().add(centeredGrid);
        frame.setSize(400,400);
        frame.setVisible(true);

        JButton button = new JButton("Check");
        button.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                
            }
        });

       // centeredGrid.add(button);
    }


    // Driver code
    public static void main(String[] args) {
        createWindow();
    }
}

I've only provided the relevant GUI class since the mathematical logic part of building the board is solid and works fine. That's what the Board class is.

CodePudding user response:

It sounds like a great project. May I suggest you choose to go with either the JTextField, or JComboBox, to make it easier for you. If you want to use JTextField, you will need to use a parameter check to verify that a number between 1 and 9 was entered. Whereas a JComboBox provides the acceptable values. This way you aren't using one UI to edit another UI before processing the input.

CodePudding user response:

One way to do this could be to:

  • Put the JTextFields in an ArrayList<JTextField> so that you can get them later as you will likely need access to them during the game
  • Give the class a field, private JTextField selectedField = null;, set initially to null. This will point to the last JTextField that has been clicked (the last one to gain focus)
  • Give the JTextFields FocusListeners when created. If any field gains focus, set the selectedField to refer to it
  • In your number JButton's ActionListener, check that selectedField is not null
  • If not null, then set the button's actionCommand (its text) to be the selectedField's text.

Also, if you need more help, consider creating and posting a valid enter image description here

import java.awt.Color;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import java.util.ArrayList;
import java.util.List;
import javax.swing.*;

public class Solver2 extends JPanel {
    private static final float FONT_SIZE = 24f;
    private int gridEdgeSize = 9;
    private JTextField[][] fieldGrid = new JTextField[gridEdgeSize][gridEdgeSize];
    private List<JTextField> fieldList = new ArrayList<>();
    private JTextField selectedField = null;

    public Solver2() {
        JPanel gridPanel = new JPanel(new GridLayout(gridEdgeSize, gridEdgeSize, 2, 2));
        gridPanel.setBorder(BorderFactory.createLineBorder(Color.BLACK, 2));
        gridPanel.setBackground(Color.BLACK);

        for (int i = 0; i < gridEdgeSize; i  ) {
            for (int j = 0; j < gridEdgeSize; j  ) {
                JTextField textField = new JTextField(2);
                textField.setHorizontalAlignment(SwingConstants.CENTER);
                textField.setFont(textField.getFont().deriveFont(Font.BOLD, FONT_SIZE));
                textField.setBorder(null);
                textField.addFocusListener(new TextFieldFocusListener());
                gridPanel.add(textField);
                fieldList.add(textField);
            }
        }

        JPanel numberPanel = new JPanel(new GridLayout(0, 3));
        for (int i = 1; i < 10; i  ) {
            String text = String.valueOf(i);
            JButton button = new JButton(text);
            button.setFont(button.getFont().deriveFont(Font.BOLD, FONT_SIZE));
            button.addActionListener(e -> buttonListener(e));
            numberPanel.add(button);
        }

        setLayout(new GridLayout(1, 2));
        add(gridPanel);
        add(numberPanel);

    }
    
    private void buttonListener(ActionEvent e) {
        String text = e.getActionCommand();
        if (selectedField != null) {
            selectedField.setText(text);
        }
    }

    private class TextFieldFocusListener extends FocusAdapter {
        @Override
        public void focusGained(FocusEvent e) {
            selectedField = (JTextField) e.getComponent();
        }
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            Solver2 mainPanel = new Solver2();

            JFrame frame = new JFrame("GUI");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.add(mainPanel);
            frame.pack();
            frame.setLocationRelativeTo(null);
            frame.setVisible(true);
        });
    }

}

Side Note

If you want to restrict the JTextField from allowing keyboard or copy/paste entry, then one way could be to use a DocumentFilter added to each JTextField's Document.

You could give the class a private boolean field, say,

public class Solver2 extends JPanel {
    // .....
    private boolean blockTextInput = true;

and a private nested class that extends DocumentFilter. This class will prevent the document from allowing String inserts, removals or replacements as long as blockTextInput is true:

private class MyDocFilter extends DocumentFilter {
    @Override
    public void insertString(FilterBypass fb, int offset, String string, AttributeSet attr)
            throws BadLocationException {
        if (blockTextInput) {
            return;
        }
        super.insertString(fb, offset, string, attr);
    }
    
    @Override
    public void remove(FilterBypass fb, int offset, int length) throws BadLocationException {
        if (blockTextInput) {
            return;
        }
        super.remove(fb, offset, length);
    }
    
    @Override
    public void replace(FilterBypass fb, int offset, int length, String text, AttributeSet attrs)
            throws BadLocationException {
        if (blockTextInput) {
            return;
        }
        super.replace(fb, offset, length, text, attrs);
    }
}

then in the JTextField creation loop, set the filter:

for (int i = 0; i < gridEdgeSize; i  ) {
    for (int j = 0; j < gridEdgeSize; j  ) {
        JTextField textField = new JTextField(2);
        textField.setHorizontalAlignment(SwingConstants.CENTER);
        textField.setFont(textField.getFont().deriveFont(Font.BOLD, FONT_SIZE));
        textField.setBorder(null);
        textField.addFocusListener(new TextFieldFocusListener());
        
        // ***** here ****
        ((PlainDocument) textField.getDocument()).setDocumentFilter(new MyDocFilter());  
        
        gridPanel.add(textField);
        fieldList.add(textField);
    }
}

Then change the number JButton's ActionListeners to change blockTextInput before and after setting the JTextField's text:

private void buttonListener(ActionEvent e) {
    String text = e.getActionCommand();
    if (selectedField != null) {
        blockTextInput = false;
        selectedField.setText(text);
        blockTextInput = true;
    }
}

Done


The latest iteration of the program that uses a single FocusListener and a DocumentFilter:

import java.awt.Color;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.*;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.DocumentFilter;
import javax.swing.text.PlainDocument;

@SuppressWarnings("serial")
public class Solver2 extends JPanel {
    private static final float FONT_SIZE = 24f;
    private int gridEdgeSize = 9;
    private List<JTextField> fieldList = new ArrayList<>();
    private JTextField selectedField = null;
    private boolean blockTextInput = true;

    public Solver2() {
        JPanel gridPanel = new JPanel(new GridLayout(gridEdgeSize, gridEdgeSize, 2, 2));
        gridPanel.setBorder(BorderFactory.createLineBorder(Color.BLACK, 2));
        gridPanel.setBackground(Color.BLACK);

        FocusListener textFieldFocusListenr = new TextFieldFocusListener();
        for (int i = 0; i < gridEdgeSize; i  ) {
            for (int j = 0; j < gridEdgeSize; j  ) {
                JTextField textField = new JTextField(2);
                textField.setHorizontalAlignment(SwingConstants.CENTER);
                textField.setFont(textField.getFont().deriveFont(Font.BOLD, FONT_SIZE));
                textField.setBorder(null);
                textField.addFocusListener(textFieldFocusListenr);
                ((PlainDocument) textField.getDocument()).setDocumentFilter(new MyDocFilter());
                gridPanel.add(textField);
                fieldList.add(textField);
            }
        }

        JPanel numberPanel = new JPanel(new GridLayout(0, 3));
        for (int i = 1; i < 10; i  ) {
            String text = String.valueOf(i);
            JButton button = new JButton(text);
            button.setFont(button.getFont().deriveFont(Font.BOLD, FONT_SIZE));
            button.addActionListener(e -> buttonListener(e));
            numberPanel.add(button);
        }

        setLayout(new GridLayout(1, 2));
        add(gridPanel);
        add(numberPanel);

    }

    private void buttonListener(ActionEvent e) {
        String text = e.getActionCommand();

        if (selectedField != null) {
            blockTextInput = false;
            selectedField.setText(text);
            blockTextInput = true;
        }

    private class TextFieldFocusListener extends FocusAdapter {
        @Override
        public void focusGained(FocusEvent e) {
            selectedField = (JTextField) e.getComponent();
        }
    }

    private class MyDocFilter extends DocumentFilter {
        @Override
        public void insertString(FilterBypass fb, int offset, String string, AttributeSet attr)
                throws BadLocationException {
            if (blockTextInput) {
                return;
            }
            super.insertString(fb, offset, string, attr);
        }

        @Override
        public void remove(FilterBypass fb, int offset, int length) throws BadLocationException {
            if (blockTextInput) {
                return;
            }
            super.remove(fb, offset, length);
        }

        @Override
        public void replace(FilterBypass fb, int offset, int length, String text, AttributeSet attrs)
                throws BadLocationException {
            if (blockTextInput) {
                return;
            }
            super.replace(fb, offset, length, text, attrs);
        }
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            Solver2 mainPanel = new Solver2();

            JFrame frame = new JFrame("GUI");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.add(mainPanel);
            frame.pack();
            frame.setLocationRelativeTo(null);
            frame.setVisible(true);
        });
    }
}
  • Related