首先,对于这么长的篇幅,我深表歉意。
我正在尝试制作一个简单的轮盘游戏,它允许用户添加玩家、为这些玩家下注并旋转轮盘,它表示为一个简单的 JLabel,它会根据它通过的每个数字更新它的文本。
但是,我遇到了一个让我很头疼的错误:JLabel 只更新循环中last 元素的文本。
基本上,我的解决方案是这样工作的:
当用户按下标有“旋转”的按钮时(假定用户已添加到游戏中),我从名为 SpinWheelService
的类中调用一个方法,该类是一个 Observable 单例调用 notifyObservers()
方法:
public void actionPerformed(ActionEvent e) {
String cmd = e.getActionCommand();
String description = null;
if (ADD_PLAYER.equals(cmd)) {
addDialog();
} else if (PLACE_BET.equals(cmd)) {
betDialog();
} else if (SPIN.equals(cmd)) {
SpinWheelService.sws.setSpinWheelService();
} else if (DISPLAY.equals(cmd)) {
System.out.println("Display selected!");
}
}
这是我的 SpinWheelService
类:
package model;
import java.util.*;
public class SpinWheelService extends Observable {
public static SpinWheelService sws = new SpinWheelService();
public void setSpinWheelService() {
setChanged();
notifyObservers();
}
}
为 SpinWheelService
注册的唯一监听器是此类,其中 GameEngine 是我处理内部游戏逻辑的游戏引擎,WheelCallbackImpl 是更新 View 的类:
class SpinWheelObserver implements Observer {
GameEngine gameEngine;
ArrayList<SimplePlayer> players;
WheelCallbackImpl wheelCall;
int n;
public SpinWheelObserver(GameEngine engine, WheelCallbackImpl wheel, ArrayList<SimplePlayer> playerList) {
players = playerList;
gameEngine = engine;
wheelCall = wheel;
}
public void update(Observable sender, Object arg) {
// check if any players are present
if (players.size() == 0) {
System.out.println("Empty player array!");
return;
}
do {
gameEngine.spin(40, 1, 300, 30, wheelCall);
n = wheelCall.playback();
} while (n== 0);
}
}
这里的主要注意点是我的gameEngine.spin()
方法,它是这样的:
public class GameEngineImpl implements GameEngine {
private List<Player> playerList = new ArrayList<Player>();
// method handles the slowing down of the roulette wheel, printing numbers at an incremental delay
public void delay(int millis) {
try {
Thread.sleep(millis);
} catch (InterruptedException e) {
System.out.println("Sleep method failed.");
}
}
public void spin(int wheelSize, int initialDelay, int finalDelay,
int delayIncrement, WheelCallback callback) {
Random rand = new Random();
int curNo = rand.nextInt(wheelSize) + 1;
int finalNo = 0;
assert (curNo >= 1);
// while loop handles how long the wheel will spin for
while (initialDelay <= finalDelay) {
delay(initialDelay);
initialDelay += delayIncrement;
// handles rotating nature of the wheel, ensures that if it reaches wheel size, reverts to 1
if (curNo > wheelSize) {
curNo = 1;
callback.nextNumber(curNo, this);
curNo++;
}
assert (curNo <= wheelSize);
callback.nextNumber(curNo, this);
curNo++;
finalNo = curNo - 1;
}
calculateResult(finalNo);
callback.result(finalNo, this);
}
方法回调.nextNumber(curNo, this):
public void nextNumber(int nextNumber, GameEngine engine) {
String strNo = Integer.toString(nextNumber);
assert (nextNumber >= 1);
System.out.println(nextNumber);
wcWheel.setCounter(strNo);
}
其中,wcWheel 是我的 View 的单例实例,其中包含方法 setCounter():
public void setCounter(String value) {
label.setText(value);
}
很抱歉我的解释很复杂,但基本上可以归结为 setCounter()
确实被调用了,但似乎只调用了 setText()
最终数字的方法。所以我剩下的是一个空标签,在整个轮盘旋转完成之前不会显示数字。
我已经确定 setCounter()
在事件派发线程上运行,我怀疑这是一个并发问题,但我不知道如何更正它。
我已尝试包含所有相关代码,但如果我遗漏任何内容,请提及,我也会将其发布。
我已经无计可施了,所以如果有人愿意提供帮助,那就太好了。
谢谢!
最佳答案
沿着 Thread.sleep()
的 while
循环将阻塞并重新绘制或更改 UI,直到循环完成。
相反,您需要为延迟实现一个 javax.swing.Timer
,并为滴答数保留一个计数器,以停止它。您可以在 How to Use Swing Timers 查看更多信息
基本结构是
Timer ( int delayInMillis, ActionListener listener )
其中 delayInMillis
是 ActionEvent
触发之间的毫秒延迟。此事件由 listener
监听。因此,每次触发事件时,都会调用监听器的 actionPerfomed
。所以你可以这样做:
Timer timer = new Timer(delay, new ActionListener()(
@Override
public void actionPerformed(ActionEvent e) {
if (count == 0) {
((Timer)e.getSource()).stop();
} else {
//make a change to your label
count--;
}
}
));
您可以调用timer.start()
来启动计时器。每 delay
毫秒,标签将更改为您需要的内容,直到某个任意计数达到 0,然后计时器停止。然后,您可以将 count 变量设置为您需要的任何值,如果您想要随机的,请根据轮子旋转的硬度说:D
关于java - JLabel.setText() 仅为循环中的最后一个元素设置文本,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23538005/