编辑:一个最简单,最简单和可检查的问题
恢复
我正在做一个拉丁方应用程序,它设置一个大小为s的正方形,你需要用一些限制来着色它,例如,在同一行或同一列中不是相同的颜色。
但我的麻烦不是问题本身,而是Swing。
我试图用Swing来做一些图形和更好的外观。
问题是,当我找到解决方案时,我想停下来观看它,然后继续寻找其他人(我将使用Thread.sleep())。
但我看着这个广场没有变色。只有完成方法后,才能自行更改。
主要问题
仅显示它找到的最后一个解决方案,并在完成Backtracking方法时显示。
当我单击resolve按钮时,有一个实现ActionListener接口的类,该接口具有actionPerformed方法,该方法调用主框架类的方法,该方法解析方形。所以问题是,如果我在找到解决方案时停止执行,GUI就不会改变,但在内部,当我检查属性(调试)时,单元格的颜色已更新,但不在GUI中。
我不知道为什么:(
更详细
我的想法是,制作一个带有两个面板的框架,一个在左边,一个在中间(可能在将来,放在右边的东西)。
为此,我使用BorderLayout。
所以左边的第一个面板,就像基本的配置菜单,用户可以设置方块的大小并运行它以获得解决方案。
为此,我有两个按钮,一个用于修改大小,另一个用于解决它。
所以我需要按钮的事件。大小不是给我问题,但解决是的。
所以我检查了,比如我为某些正方形着色并暂停执行(Scanner.nextLine()或Thread.sleep())没有在GUI中进行更改,但是当我调试时,正方形在属性中着色,所以我不太明白为什么是faling。
在哪里我认为是问题
所以我有一个按钮,点击时解决方块。我想,我真的不知道,但我怀疑,这样做会创建一个新的Thread或者其他东西,所以,不能更新GUI;只有完成后才能做到。
无论如何要改变这个?
class ResolveListener implements ActionListener
{
@Override
public void actionPerformed(ActionEvent e)
{
int size = Integer.parseInt(textField.getText());
latinSquareFrame.resolve(size);
}
}
一个简单的问题
我在评论中读到了一个与此类似的最小和简单的可检查问题。
所以我做了。这段代码与我的问题类似,有一个正方形,我和我想在点击按钮时给它上色。
问题是,如果我暂停它,它没有着色,只有在方法完成时才会着色,我不知道为什么。
我认为这与我以前面临的问题类似。
这是我能用于解决问题的最小代码。
package LatinSquare;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Scanner;
public class Test
{
public static void main(String[] args)
{
TestFrame testFrame = new TestFrame();
}
}
class TestFrame extends JFrame
{
public TestFrame()
{
this.setVisible(true);
this.setBounds(400,300,400,300);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setLayout(new BorderLayout());
TestJPanel testJPanel = new TestJPanel();
this.add(testJPanel,BorderLayout.CENTER);
TestContainerButtonJPanel testContainerButtonJPanel = new TestContainerButtonJPanel(testJPanel);
this.add(testContainerButtonJPanel, BorderLayout.SOUTH);
this.revalidate();
this.repaint();
}
}
class TestContainerButtonJPanel extends JPanel
{
private JButton resolve;
public TestJPanel testJPanel;
public TestContainerButtonJPanel(TestJPanel testJPanel)
{
this.testJPanel = testJPanel;
this.setVisible(true);
resolve = new JButton("RESOLVE");
ActionListener resolveListener = new ResolveListener();
resolve.addActionListener(resolveListener);
this.add(resolve);
}
class ResolveListener implements ActionListener
{
@Override
public void actionPerformed(ActionEvent e)
{
try {
TestContainerButtonJPanel.this.testJPanel.colourCells();
} catch (InterruptedException e1) {
e1.printStackTrace();
}
}
}
}
class TestJPanel extends JPanel
{
private JButton[][] board;
public TestJPanel()
{
this.board = new JButton[4][4];
this.setVisible(true);
this.setLayout(new GridLayout(4,4));
for(int i=0; i<4;i++)
{
for(int j=0; j<4;j++)
{
JButton cell = new JButton();
board[i][j] = cell;
board[i][j].setBackground(Color.WHITE);
this.add(cell);
}
}
}
public void colourCells() throws InterruptedException {
for(int i=0; i<4;i++)
{
for(int j=0;j<4;j++)
{
this.board[i][j].setBackground(Color.RED);
Thread.sleep(300);
}
}
}
}
好的,首先要做的事情:
Thread.sleep()
更新GUI,它会阻止EDTJFrame
,而是创建它的实例,请参阅:Extends JFrame vs. creating it inside the programsetVisible(...)
)。它可能会导致您的程序以错误的方式运行。Swing Timer
或Swing Worker
(问题评论中的链接)因此,考虑到所有这些因素,我决定创建一个遵循上述所有规则的新程序,并在该时间过后使单元格变为蓝色3秒或白色,并且还更新JButton
中的文本以及禁用防止多个计时器一次执行。
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class Test {
private JFrame frame;
private JPanel pane;
private JPanel cellsPane;
private MyCell[][] cells;
private JButton button;
private Timer timer;
private int counter = 3;
private boolean isFinished = false;
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> new Test().createAndShowGui());
}
private void createAndShowGui() {
frame = new JFrame(getClass().getSimpleName());
pane = new JPanel();
cellsPane = new JPanel();
pane.setLayout(new BoxLayout(pane, BoxLayout.PAGE_AXIS));
cellsPane.setLayout(new GridLayout(4, 4, 5, 5));
cells = new MyCell[4][4];
for (int i = 0; i < cells.length; i++) {
for (int j = 0; j < cells[i].length; j++) {
cells[i][j] = new MyCell(Color.WHITE);
cellsPane.add(cells[i][j]);
}
}
button = new JButton("Press me!");
timer = new Timer(1000, listener);
button.addActionListener(e -> {
button.setEnabled(false);
isFinished = false;
updateCellsColors();
timer.start();
});
pane.add(cellsPane);
pane.add(button);
frame.add(pane);
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
private void updateCellsColors() {
for (int i = 0; i < cells.length; i++) {
for (int j = 0; j < cells[i].length; j++) {
cells[i][j].setCellColor(isFinished ? Color.WHITE : Color.BLUE);
}
}
}
private ActionListener listener = new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (counter == 0) {
timer.stop();
counter = 3;
isFinished = true;
button.setEnabled(true);
updateCellsColors();
}
if (isFinished) {
button.setText("Press me!");
} else {
button.setText("You have " + counter + " seconds remaining");
}
counter--;
}
};
}
@SuppressWarnings("serial")
class MyCell extends JPanel {
private Color cellColor;
public Color getCellColor() {
return cellColor;
}
public void setCellColor(Color cellColor) {
this.cellColor = cellColor;
this.setBackground(cellColor);
}
public MyCell(Color cellColor) {
this.cellColor = cellColor;
this.setOpaque(true);
this.setBackground(cellColor);
}
@Override
public Dimension getPreferredSize() {
// TODO Auto-generated method stub
return new Dimension(30, 30);
}
}
你可以复制粘贴它并看到与我相同的结果:
需要另一个线程来修复它。
更改侦听器类,工作正常:
class ResolveListener implements ActionListener
{
@Override
public void actionPerformed(ActionEvent e)
{
new Thread(new Runnable()
{
@Override
public void run()
{
try {
TestContainerButtonJPanel.this.testJPanel.colourCells();
} catch (InterruptedException e1) {
e1.printStackTrace();
}
}
}).start();
}
}
}