メインでメソッドsolve()
への呼び出しが1つしかないSwingクラスをコーディングしました。このメソッドはwhileループを実装し、ほとんどのラウンドで別のメソッドを使用します。このメソッドはpaint()と呼ばれ、参照が2次元配列に格納されている9x9 GridLayoutの内部のJPanelの値を1つだけ変更します。Swingクラスのmainメソッドからのすべての呼び出しでスリープまたは待機する時間
パネルが変更される前に、タイマーはpaint()
である必要があります.2秒が経過します。これは最初に呼び出されますが、2秒後にループのすべてのラウンドが待機せずに実行されます。目標は、パネルが変更される前に2秒経過するのを見ることです。私は、javaxタイマーを使用してみました。 Thread.sleep()は明らかにSwingクラスでは機能しません。
import javax.swing.*;
import javax.swing.Timer;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.*;
import java.util.Stack;
public class SudokuApp {
private JFrame frame;
int i = 9;
int j = 9;
JPanel[][] board = new JPanel[i][j];
JButton nextButton = new JButton("Resolver");
Box[][] sudoku = new Box[9][9];
Box newCurrent = new Box();
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
SudokuApp window = new SudokuApp();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public SudokuApp() {
initialize();
}
private void initialize() {
frame = new JFrame();
frame.setTitle("Sudoku Solver");
frame.setBounds(100, 100, 510, 555);
frame.setLocationRelativeTo(null);
frame.setResizable(false);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
JPanel panel = new JPanel();
frame.getContentPane().add(panel, BorderLayout.CENTER);
panel.setLayout(new GridLayout(i, j));
//Initiate board
for (int m = 0; m < i; m++) {
for (int n = 0; n < j; n++) {
board[m][n] = new JPanel();
JTextField textField = new JTextField(1);
textField.setFont(new Font("Lucida Grande", Font.BOLD, 25));
board[m][n].add(textField);
panel.add(board[m][n]);
}
}
Box last = new Box();
for (int m = 0; m < this.i; m++) {
for (int n = 0; n < this.j; n++) {
sudoku[m][n] = new Box(m, n);
if (m != 0 || n != 0) sudoku[m][n].back = last;
last = sudoku[m][n];
}
}
//Solve button action listener
nextButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) {
if (validBoard()) {
nextButton.setEnabled(false);
solve();
}
else JOptionPane.showMessageDialog(null, "Condiciones iniciales inválidas.");
} });
frame.getContentPane().add(nextButton, BorderLayout.SOUTH);
}
private boolean validBoard() {
for (int m = 0; m < i; m++) {
for (int n = 0; n < j; n++) {
JTextField current = (JTextField) board[m][n].getComponent(0);
String text = current.getText();
if (text.length() == 1 && !text.contains("0")) {
try {
int number = Integer.parseInt(text);
if (!add(number, m, n)) return false;
current.setEditable(false);
} catch (NumberFormatException e) {
return false;
}
} else {
current.setText("");
current.setEditable(false);
}
}
}
return true;
}
private void solve() {
int i = 0;
int j = 0;
int newI = i + 1;
while (i < 9) {
while (j < 9) {
Box current = sudoku[i][j];
if (current.number == 0) {
HashSet<Integer> possibles = new HashSet<>();
HashSet<Integer> takenNumbers = getTakenNumbers(i, j);
for (int k = 1; k <= 9; k++) if (!takenNumbers.contains(k)) possibles.add(k);
if (possibles.isEmpty()) {
current.number = 0;
erase(i, j);
tryOther(current.back);
i = newCurrent.i;
newI = i + 1;
j = newCurrent.j + 1;
} else {
for (Integer p : possibles) current.possibles.push(p);
current.number = (int) current.possibles.pop();
paint(current.number, i, j);
j++;
newI = i + 1;
}
} else {
j++;
newI = i + 1;
}
}
i = newI;
j = 0;
}
}
private void tryOther(Box box) {
if (box.possibles.empty()) {
if (box.back != null) {
if (!box.initial) {
box.number = 0;
erase(box.i, box.j);
}
tryOther(box.back);
}
else newCurrent = null;
} else {
if (getTakenNumbers(box.i, box.j).contains(box.possibles.peek())) {
box.possibles.pop();
tryOther(box);
}
newCurrent = box;
box.number = (int) box.possibles.pop();
paint(box.number, box.i, box.j);
}
}
private boolean add(int a, int i, int j) {
if (getTakenNumbers(i, j).contains(a)) return false;
sudoku[i][j].number = a;
sudoku[i][j].initial = true;
return true;
}
private void paint(int a, int i, int j) {
JPanel panel = board[i][j];
JTextField jTextField = (JTextField) board[i][j].getComponent(0);
jTextField.setFont(new Font("Lucida Grande", Font.PLAIN, 25));
jTextField.setForeground(Color.gray);
ActionListener task = new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.out.println("T");
}
};
Timer timer = new Timer(3000 , task);
timer.setRepeats(false);
timer.start();
jTextField.setText("" + a);
panel.revalidate();
panel.repaint();
}
private void erase(int i, int j) {
JTextField jTextField = (JTextField) board[i][j].getComponent(0);
jTextField.setText("");
board[i][j].revalidate();
board[i][j].repaint();
}
private HashSet<Integer> getTakenNumbers(int i, int j) {
HashSet<Integer> takenNumbers = new HashSet<>();
for (int k = 0; k < 9; k++) if (sudoku[i][k].number != 0 && k != j) takenNumbers.add(sudoku[i][k].number);
for (int k = 0; k < 9; k++) if (sudoku[k][j].number != 0 && k != i) takenNumbers.add(sudoku[k][j].number);
int bigBoxRow = 0;
int bigBoxColumn = 0;
if (i <= 5 && i > 2) bigBoxRow = 3;
if (i <= 8 && i > 5) bigBoxRow = 6;
if (j <= 5 && j > 2) bigBoxColumn = 3;
if (j <= 8 && j > 5) bigBoxColumn = 6;
for (int k = bigBoxRow; k < bigBoxRow + 3; k++) for (int l = bigBoxColumn; l < bigBoxColumn + 3; l++) if (sudoku[k][l].number != 0 && k != i && l != j) takenNumbers.add(sudoku[k][l].number);
return takenNumbers;
}
}
import java.util.Stack;
public class Box {
public int number = 0;
public int i, j;
public Stack possibles = new Stack();
public Box back;
public boolean initial = false;
public Box(int i, int j) {
this.i = i;
this.j = j;
}
public Box() {}
}
' 「javax Timerを使用しようとしましたが、使用するアクションリスナーはありません。これは意味をなさないものです。 jTextFieldのテキストを設定するシンプルなActionListenerを作成できないのはなぜですか? –
あなたはそうです、私もそれをやったことがありますが、それはちょうど初めて待っています。更新されたコードを見てください。 – niklabaz
それはうまくいくはずです。そうでない場合は、[mcve]を作成して投稿し、コードをテストしてみましょう。 –