【问题标题】:JAVA SWING: Unable to change text of JTextFieldJAVA SWING:无法更改 JTextField 的文本
【发布时间】:2013-06-05 00:07:13
【问题描述】:

我正在开发一个程序,以使用 swing gui 在 Java 中生成和解决数独难题。我在 JTextField 上使用 .setText() 方法但文本未更新时遇到问题。

这是我的代码:

主类:

package sudoku;

public class SudokuSolver {

    public static void main(String[] args) {

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

    }

}

GUI类:

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);

    }

}

板级:

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 类:

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++;

            }
        }
    }

}

我还有另一个名为 Puzzle 的类,其中有一个 generate() 和一个 solve() 方法,它们都返回 int[][]。我不相信其中的任何内容与问题有关,因此我将其省略。

问题在于这一行是 BoardSection 类:

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

我没有收到任何错误消息,但它没有更新文本。我尝试用“Z”替换 data[i][j] 以查看问题是否出在我传递的数据上,但它仍然不适用于仅使用一个简单的字符串。但是,我确实尝试将以下行放在 BoardSection 构造函数方法内部的 for 循环中,并且它确实显示了。

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

谁能解释为什么它在构造函数中起作用,但在调用 fillSection() 方法时不起作用?

【问题讨论】:

  • 我建议您在程序运行时启动调试器来查看代码中变量的值。

标签: java swing user-interface jtextfield


【解决方案1】:

您的意思是只填写第一个字段吗?您永远不会将 x 变量更新为 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]);
        }
    }
}

你可以试试……

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

或者实际相应地修改x参数...

更新...

您遇到的另一个问题是您隐藏了 data 变量已传递给您的 fillSection 方法...

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];
    //...
}

更新...

不知道这是否相关,但这仍然是一个问题......

你的String 比较是错误的...== 是检查两个对象是否共享相同的内存空间,String 永远不会是这样的(以这种方式)

if (cmd == "Generate") {

相反,您应该使用String#equals 来比较对象的内容...

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

这意味着puzz 永远不会被更新,所以当你将它传递给你的字段时,它可能是空白的......

更新...

还有一个问题;)

在您的 Board 课程中,您定义了 9 个板部分...

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};

但是在您的构造函数中,您正在重新安装它们(在sections 数组中)...

// 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]);
    }

}

这意味着BoardSections nw 等从未真正添加到屏幕上...

相反,您应该简单地删除这些部分并直接使用数组...

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);

    }

【讨论】:

  • 谢谢,我错过了。我添加了“x++;”在 setText() 之后。但是没有解决问题。
  • 也修复了阴影问题,谢谢。不确定我在想什么。虽然仍然没有解决问题。我用你的修复编辑了我的主要帖子。
  • 轰隆隆!最后一次更新是问题所在。现在一切正常。谢谢!
  • 提示一下,调试器是你的朋友 ;)-
【解决方案2】:

调用setText() 只会更新JTextField模型。换句话说,JTextField 存储了一个带有您发送的值的内部字符串。但是,视图(即屏幕上显示的内容)没有更新。这实际上是一件好事,因为绘画很慢。如果您在数独程序中每次调用 setText() 时都会更新 UI,那么它必须更新 81 次。

您可以通过在Component 的任何子类上调用invalidate() 来强制更新视图。在您的情况下,您可能应该在主要的JFrame 或包含所有JTextFields 的JPanel 上调用invalidate()。这将导致 GUI 刷新一次,而不是前面提到的 81 次。

附:如需更多信息,我建议您研究模型-视图-控制器设计模式。

【讨论】:

  • 首先,RepaintManager 将重绘请求合并到尽可能少的调用中,因此您可以随时调用repaintRepaintManager 将决定何时调用以及调用多少将要重新粉刷。其次,我不确定你的答案是否成立,即使在最简单的测试中,调用setText 也会(几乎)在屏幕上立即更新...invalidate 只处理组件的布局,它是一个它被绘制的副作用。
  • @MadProgrammer 啊!我对使用invalidate() 感到困惑……我想在回答此类问题之前我需要研究一下。
猜你喜欢
  • 2016-05-13
  • 2018-12-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-06-27
  • 2015-08-15
  • 2012-01-08
  • 1970-01-01
相关资源
最近更新 更多