简体   繁体   中英

JAVA SWING: Unable to change text of JTextField

I am working on a program to generate and solve sudoku puzzles in java using a swing gui. I am having a problem where I use the .setText() method on a JTextField but the text is not updated.

Here is my code:

main class:

package sudoku;

public class SudokuSolver {

    public static void main(String[] args) {

        GUI gui = new GUI();
        gui.setVisible(true);

    }

}

GUI class:

package sudoku;

import java.awt.BorderLayout;
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import javax.swing.JButton;
import java.awt.Window.Type;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class GUI extends JFrame implements ActionListener {

    private JPanel contentPane;
    private Puzzle puzzle = new Puzzle();
    private Board board = new Board();
    private int[][] puzz = new int[9][9];

    // GUI Constructor
    public GUI() {

        // set up window
        setResizable(false);
        setTitle("Sudoku Solver");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setBounds(100, 100, 300, 300);
        contentPane = new JPanel();
        contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
        contentPane.setLayout(new BorderLayout(0, 0));
        setContentPane(contentPane);

        // set up button panel
        JPanel buttons = new JPanel();
        contentPane.add(buttons, BorderLayout.SOUTH);

        // set up generate button
        JButton genButton = new JButton("Generate");
        genButton.setMnemonic('g');
        buttons.add(genButton);
        genButton.addActionListener(this);

        // set up solve button
        JButton solveButton = new JButton("Solve");
        solveButton.setMnemonic('s');
        buttons.add(solveButton);
        solveButton.addActionListener(this);

        // set up board
        contentPane.add(board, BorderLayout.CENTER);
    }

    // Button listener
    public void actionPerformed(ActionEvent e) {

        String cmd = e.getActionCommand();

        if (cmd == "Generate") {
            // generate puzzle
            puzz = puzzle.generate();

        } else if (cmd == "Solve") {
            // solve puzzle
            puzz = puzzle.solve(puzz);

        }

        // display puzzle on the board
        board.fill(puzz);

    }

}

Board class:

package sudoku;

import java.awt.Color;
import java.awt.GridLayout;

import javax.swing.BorderFactory;
import javax.swing.JPanel;

public class Board extends JPanel {

    // 9x9 board sections
    private BoardSection nw = new BoardSection();
    private BoardSection n = new BoardSection();
    private BoardSection ne = new BoardSection();
    private BoardSection w = new BoardSection();
    private BoardSection c = new BoardSection();
    private BoardSection e = new BoardSection();
    private BoardSection sw = new BoardSection();
    private BoardSection s = new BoardSection();
    private BoardSection se = new BoardSection();

    // array of sections
    private BoardSection[] sections = { nw, n, ne, w, c, e, sw, s, se };

    // Board Constructor
    public Board() {

        // 3x3 grid layout
        setLayout(new GridLayout(3, 3));

        // border
        setBorder(BorderFactory.createLineBorder(Color.BLACK, 2));

        // add board sections to board
        for (int i = 0; i < sections.length; i++) {
            sections[i] = new BoardSection();
            add(sections[i]);
        }

    }

    // fill the board with data
    public void fill(int[][] data) {

        // create data sections
        String[][] nwData = new String[3][3];
        String[][] nData = new String[3][3];
        String[][] neData = new String[3][3];
        String[][] wData = new String[3][3];
        String[][] cData = new String[3][3];
        String[][] eData = new String[3][3];
        String[][] swData = new String[3][3];
        String[][] sData = new String[3][3];
        String[][] seData = new String[3][3];

        // break data into data sections
        nwData = createSection(data, 0, 0);
        nData = createSection(data, 3, 0);
        neData = createSection(data, 6, 0);
        wData = createSection(data, 0, 3);
        cData = createSection(data, 3, 3);
        eData = createSection(data, 6, 3);
        swData = createSection(data, 0, 6);
        sData = createSection(data, 3, 6);
        seData = createSection(data, 6, 6);

        // fill board section with data section
        nw.fillSection(nwData);
        n.fillSection(nData);
        ne.fillSection(neData);
        w.fillSection(wData);
        c.fillSection(cData);
        e.fillSection(eData);
        sw.fillSection(swData);
        s.fillSection(sData);
        se.fillSection(seData);

    }

    // split data into 3x3 section with 0,0 starting at x, y then convert to
    // string
    private String[][] createSection(int[][] data, int x, int y) {

        int[][] intSection = new int[3][3];
        String[][] strSection = new String[3][3];

        // break into section
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++) {
                intSection[i][j] = data[i + x][j + y];
            }
        }
        // convert section to string
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++) {

                strSection[i][j] = Integer.toString(intSection[i][j]);

            }

        }

        return strSection;
    }

}

BoardSection class:

package sudoku;

import java.awt.Color;
import java.awt.GridLayout;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.BorderFactory;

public class BoardSection extends JPanel {

    // each square
    private JTextField nw = new JTextField();
    private JTextField n = new JTextField();
    private JTextField ne = new JTextField();
    private JTextField w = new JTextField();
    private JTextField c = new JTextField();
    private JTextField e = new JTextField();
    private JTextField sw = new JTextField();
    private JTextField s = new JTextField();
    private JTextField se = new JTextField();

    // array of the squares
    private JTextField[] fields = new JTextField[] { nw, n, ne, w, c, e, sw, s,
            se };

    // Board Section Constructor
    public BoardSection() {
        // 3x3 grid layout
        setLayout(new GridLayout(3, 3));

        // border
        setBorder(BorderFactory.createLineBorder(Color.BLACK, 1));

        // add all fields to the board section
        for (int i = 0; i < fields.length; i++) {
            fields[i] = new JTextField(1);
            fields[i].setHorizontalAlignment(JTextField.CENTER);
            fields[i].setEditable(false);
            add(fields[i]);
        }

    }

    // Display the data on the board
    public void fillSection(String[][] data) {

        int x = 0;
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++) {
                fields[x].setText(data[i][j]);
                x++;

            }
        }
    }

}

I also have another class called Puzzle where there is a generate() and a solve() method that both return int[][]. I don't believe anything in it is relevant to the problem so I'm omitting it for space.

The problem is with this line is the BoardSection class:

fields[x].setText(data[i][j]);

I am not getting any error messages, however it is not updating the text. I tried replacing data[i][j] with "Z" to see if the problem was the data I was passing but it still doesn't work with just a simple string. I did however try putting the following line in the for loop that is inside the BoardSection constructor method and it DID display.

fields[i].setText("0");

Can anyone explain why it works in the constructor but not when the fillSection() method is called?

Do you mean to only ever fill the first field? You never update the x variable to anything other the 0 ?

public void fillSection(String[][] data) {
    data = new String[3][3];
    int x = 0; // This never changes?
    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 3; j++) {
            fields[x].setText(data[i][j]);
        }
    }
}

You could try...

fields[i * j].setText(data[i][j]);

Or actually modify the x parameter accordingly...

Updated...

The other problem you're having is your shadowing the data variable been passed to your fillSection method...

public void fillSection(String[][] data) {
    // Oh look, I've overridden every thing
    // you just gave with my own copy of the data!!
    data = new String[3][3];
    //...
}

Updated...

Don't know if this is related or not, but it's still a problem...

You're String comparison is wrong... == is check to see if the two objects share the same memory space, which is never going to be true for String (in this manner)

if (cmd == "Generate") {

Instead, you should be using String#equals to compare the contents of the objects...

if ("Generate".equals(cmd)) {

This would mean that the puzz is never been updated, so when you pass it to your fields, it is probably blank...

Updated...

Yet another issue ;)

In your Board class, you are defining 9 board sections...

private BoardSection nw = new BoardSection();
private BoardSection n = new BoardSection();
private BoardSection ne = new BoardSection();
private BoardSection w = new BoardSection();
private BoardSection c = new BoardSection();
private BoardSection e = new BoardSection();
private BoardSection sw = new BoardSection();
private BoardSection s = new BoardSection();
private BoardSection se = new BoardSection();
// array of sections
private BoardSection[] sections = {nw, n, ne, w, c, e, sw, s, se};

But in you constructor, you are re-inistalition them (within in the sections array)...

// Board Constructor
public Board() {

    //...//

    // add board sections to board
    for (int i = 0; i < sections.length; i++) {
        // Look ma, new Board!!
        sections[i] = new BoardSection();
        add(sections[i]);
    }

}

This means that the BoardSection s nw , etc are never actually added to the screen...

Instead, you should simply drop those sections and use the array directly...

public class Board extends JPanel {

    // array of sections
    private BoardSection[] sections;

    // Board Constructor
    public Board() {

        //...//

        // add board sections to board
        sections = new BoardSection[9];
        for (int i = 0; i < sections.length; i++) {
            sections[i] = new BoardSection();
            add(sections[i]);
        }

    }

    // fill the board with data
    public void fill(int[][] data) {

        // create data sections
        String[][] nwData = new String[3][3];
        String[][] nData = new String[3][3];
        String[][] neData = new String[3][3];
        String[][] wData = new String[3][3];
        String[][] cData = new String[3][3];
        String[][] eData = new String[3][3];
        String[][] swData = new String[3][3];
        String[][] sData = new String[3][3];
        String[][] seData = new String[3][3];

        // break data into data sections
        nwData = createSection(data, 0, 0);
        nData = createSection(data, 3, 0);
        neData = createSection(data, 6, 0);
        wData = createSection(data, 0, 3);
        cData = createSection(data, 3, 3);
        eData = createSection(data, 6, 3);
        swData = createSection(data, 0, 6);
        sData = createSection(data, 3, 6);
        seData = createSection(data, 6, 6);

        // fill board section with data section
        sections[0].fillSection(nwData);
        sections[1].fillSection(nData);
        sections[2].fillSection(neData);
        sections[3].fillSection(wData);
        sections[4].fillSection(cData);
        sections[5].fillSection(eData);
        sections[6].fillSection(swData);
        sections[7].fillSection(sData);
        sections[8].fillSection(seData);

    }

Calling setText() only updates the model for the JTextField . In other words, the JTextField stores an internal String with the value which you sent it. However, the view (ie what is shown on your screen) is not updated. This is actually a good thing because painting is quite slow. If the UI was updated every time you call setText() in your Sudoku program, it would have to update 81 times.

You can force the view to update by calling invalidate() on any subclass of Component . In your situation, you probably should call invalidate() on the main JFrame or the JPanel that contains all of your JTextField s. This will cause the GUI to refresh once, rather than the 81 times mentioned before.

PS For more information, I suggest you research the Model-View-Controller design pattern.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM