gpt4 book ai didi

java - 为什么这个线程代码不能在 GUI 中正常工作? [Java Swing] [线程]

转载 作者:行者123 更新时间:2023-12-02 10:36:40 24 4
gpt4 key购买 nike

我的项目使用Java Swing作为GUI。我正在制作汉诺塔游戏。我刚刚让 GUI 正常工作,但我的求解命令无法正常工作。

没有线程调用,它会立即按预期解决塔楼问题。我添加了几个 Thread.waits 期望它能够逐步解决这个问题,以便用户可以看到它是如何做的,但它会等待一段时间,然后立即解决整个难题。我在想可能不会重新绘制,但我不确定为什么。有谁知道这是怎么回事吗?

这是解决问题的代码:

public class Solver {

public Solver() {
// nothing
}


public void solve(
int numberBlocks,
int startPin,
int auxiliaryPin,
int endPin) {
if (numberBlocks == 1) {
movePin(startPin, endPin);
try {
Thread.sleep(200);
}
catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
else {
solve(numberBlocks - 1, startPin, endPin, auxiliaryPin);
movePin(startPin, endPin);
try {
Thread.sleep(200);
}
catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
solve(numberBlocks - 1, auxiliaryPin, startPin, endPin);
}
}


private void movePin(int startPin, int endPin) {
TowersOfHanoiGame.moveTopBlock(startPin, endPin);
}

下面是 GUI 中执行此操作的代码:我知道它写得很糟糕,这是我第一次使用 Java Swing 编写,我边学边学。如果有人对如何更好地构建这个有任何指示,我也很想听听。我将粘贴整个类,但重要的方法是 initListeners 和 moveTopBlock 以及它们调用的方法。

import java.awt.BorderLayout;
import java.awt.Button;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;

public class TowersOfHanoiGame {
private static JFrame mainWindow;
private static JPanel mainContentPanel;
private static JPanel content;

private static ArrayList<Block> pegOneBlocks = new ArrayList<Block>();
private static ArrayList<Block> pegTwoBlocks = new ArrayList<Block>();
private static ArrayList<Block> pegThreeBlocks = new ArrayList<Block>();
private Color[] randomColors = new Color[8];

private Dimension menuSize = new Dimension(100, 100);
private static final int DISCSTEXTSIZE = 20;
private static final int MOVESTEXTSIZE = 30;

private ActionListener downButtonListener;
private ActionListener upButtonListener;
private ActionListener solveButtonListener;

private JLabel discs;
private JLabel moves;

private int discsNumber = 3;
private int movesNumber = 0;

private Solver solver = new Solver();


public TowersOfHanoiGame() {
// do nothing
initRandomColors();
initBlocks(3);
}


/**
* Initialize and display the game
*/
public void display() {
initListeners();
initWindow();
mainWindow.setVisible(true);
}


private void initListeners() {
downButtonListener = new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
if (discsNumber > 3) {
discsNumber--;
updateLabels();
// clearContentFrame();
clearBlockArrays();
initBlocks(discsNumber);
reDrawContentFrame();
}

}
};
upButtonListener = new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
if (discsNumber < 8) {
discsNumber++;
updateLabels();
// clearContentFrame();
clearBlockArrays();
initBlocks(discsNumber);
reDrawContentFrame();
}
}
};

solveButtonListener = new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
solver.solve(discsNumber, 0, 1, 2);
}
};
}


private void updateLabels() {
discs.setText("DISCS: " + discsNumber);
moves.setText("MOVES: " + movesNumber);
}


/**
* Init the main window
*/
private void initWindow() {
mainWindow = new JFrame("Towers Of Hanoi");
initContentPanel();
mainWindow.setContentPane(mainContentPanel);
mainWindow.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mainWindow.setSize(1000, 1000);
mainWindow.setResizable(false);
mainWindow.getContentPane().setBackground(Color.WHITE);
}


/**
* Init the main content panel
*/
private void initContentPanel() {
mainContentPanel = new JPanel(new BorderLayout(50, 50));
JPanel menu = initMenuFrame();
content = initContentFrame();
mainContentPanel.add(menu, BorderLayout.PAGE_START);
mainContentPanel.add(content, BorderLayout.CENTER);
}


private static JPanel initContentFrame() {
JPanel ret = new JPanel(new BorderLayout());
JPanel pegs = new JPanel(new BorderLayout());
pegs.setBackground(Color.WHITE);
ret.setBackground(Color.WHITE);

Peg peg1 = new Peg(25, 500, 1.2);
Peg peg2 = new Peg(50, 500, 1.2);
Peg peg3 = new Peg(0, 500, 1.2);

peg1.addBlocks(pegOneBlocks);
peg2.addBlocks(pegTwoBlocks);
peg3.addBlocks(pegThreeBlocks);

pegs.add(peg1, BorderLayout.LINE_START);
pegs.add(peg2, BorderLayout.CENTER);
pegs.add(peg3, BorderLayout.LINE_END);

ret.add(pegs, BorderLayout.CENTER);
return ret;
}


private Color randomColor() {
int R = (int)(Math.random() * 256);
int G = (int)(Math.random() * 256);
int B = (int)(Math.random() * 256);
Color color = new Color(R, G, B); // random color, but can be bright or
// dull

// to get rainbow, pastel colors
Random random = new Random();
final float hue = random.nextFloat();
final float saturation = 0.9f;// 1.0 for brilliant, 0.0 for dull
final float luminance = 1.0f; // 1.0 for brighter, 0.0 for black
color = Color.getHSBColor(hue, saturation, luminance);
return color;
}


private void initRandomColors() {
for (int i = 0; i < 8; i++) {
randomColors[i] = randomColor();
}
}


private void initBlocks(int numBlocks) {
int startWidth = Block.LONGESTWIDTH;
for (int i = 0; i < numBlocks; i++) {
Block b = new Block((startWidth - (i * 15)), randomColors[i]);
pegOneBlocks.add(b);
}
}


private static void clearContentFrame() {
mainContentPanel.remove(content);
mainContentPanel.repaint();
}


private void clearBlockArrays() {
pegOneBlocks.clear();
pegTwoBlocks.clear();
pegThreeBlocks.clear();
}


public static void reDrawContentFrame() {
content = initContentFrame();
mainContentPanel.add(content, BorderLayout.CENTER);
mainContentPanel.repaint();
}


public static void moveTopBlock(int startPin, int destinationPin) {
Block b = null;
if (startPin == 0) {
b = pegOneBlocks.get(pegOneBlocks.size() - 1);
pegOneBlocks.remove(pegOneBlocks.size() - 1);
}
else if (startPin == 1) {
b = pegTwoBlocks.get(pegTwoBlocks.size() - 1);
pegTwoBlocks.remove(pegTwoBlocks.size() - 1);
}
else if (startPin == 2) {
b = pegThreeBlocks.get(pegThreeBlocks.size() - 1);
pegThreeBlocks.remove(pegThreeBlocks.size() - 1);
}

if (destinationPin == 0) {
pegOneBlocks.add(b);
}
else if (destinationPin == 1) {
pegTwoBlocks.add(b);
}
else if (destinationPin == 2) {
pegThreeBlocks.add(b);
}

reDrawContentFrame();
content.validate();
mainContentPanel.validate();
mainWindow.validate();
}


/**
* Build the menu panel
*
* @return menu panel
*/
private JPanel initMenuFrame() {
JPanel ret = new JPanel(new BorderLayout());
ret.setPreferredSize(menuSize);

// left
JPanel left = new JPanel(new FlowLayout());
left.setPreferredSize(menuSize);
JLabel label = new JLabel("DISCS: 3");
discs = label;
label.setFont(new Font("Serif", Font.BOLD, DISCSTEXTSIZE));
Button down = new Button("Decrease");
down.addActionListener(downButtonListener);
Button up = new Button("Increase");
up.addActionListener(upButtonListener);
left.add(label);
left.add(up);
left.add(down);

// mid
moves = new JLabel("MOVES: 0");
moves.setHorizontalAlignment(JLabel.CENTER);
moves.setFont(new Font("Serif", Font.BOLD, MOVESTEXTSIZE));

// right
JPanel right = new JPanel(new FlowLayout());
Button solve = new Button("Solve");
solve.addActionListener(solveButtonListener);
Button reset = new Button("Reset");
right.add(solve);
right.add(reset);

// sync
JPanel menu = new JPanel(new BorderLayout());
menu.add(left, BorderLayout.LINE_START);
menu.add(moves, BorderLayout.CENTER);
menu.add(right, BorderLayout.LINE_END);

ret.add(menu, BorderLayout.CENTER);
return ret;
}
}

最佳答案

solveButtonListener = new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
solver.solve(discsNumber, 0, 1, 2);
}
};

问题在于,为任何监听器调用的代码都是在事件调度线程 (EDT) 上执行的。 EDT 负责响应事件并重新绘制 GUI。 Thread.sleep() 方法导致 EDT hibernate ,因此 GUI 无法重新绘制自身,直到所有代码执行完毕。

您需要做的是在调用 solver.solve(...) 方法时启动一个单独的Thread

阅读 Swing 教程中关于 Concurrency 的部分了解更多信息。

请注意,上述使用单独线程的建议仍然不是正确的解决方案。 Swing 被设计为单线程,这意味着对 GUI 状态的所有更新以及 GUI 的重新绘制都应该在 EDT 上完成。因此,这意味着您还应该使用 SwingUtilities.invokeLater() 将代码添加到 EDT 中进行处理。我从未尝试在使用递归时这样做,所以我不确定执行此操作的最佳方法。

关于java - 为什么这个线程代码不能在 GUI 中正常工作? [Java Swing] [线程],我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53242086/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com