在我的棋盘游戏中取得进步,所以在点击鼠标时,会执行一些任务,比如播放一些动画,接收新的棋盘(我问过这个问题,现在效果很好),对玩家进行更改数据等。
所以,这是我的EventHandler
grid.setOnMouseReleased(new EventHandler<MouseEvent> () {
public void handle(MouseEvent me) {
//make changes to player data
//receive new panes for the board
//make some gui changes
//play some animations
}
});
这里grid
是一个GridPane对象,它包含了每个单元格的其他窗格,动画窗格等。
一个鼠标事件需要2-3秒才能处理。在这种情况下,我看到另一个鼠标点击也将开始与已经正在进行的点击并行处理。
我想要的是在第一个鼠标事件完成之前不应该处理另一个鼠标事件。如果收到的任何点击都会被丢弃,那会更好。
我尝试使用线程:
grid.setOnMouseReleased(new EventHandler<MouseEvent> () {
public void handle(MouseEvent me) {
Thread t = new Thread(new Runnable() {
public void run() {
//completing the necessary tasks here
}
});
t.start();
t.join();
}
});
但是如果我使用线程不会发生GUI更改(不知道为什么,我以多种不同的方式测试它,总是无法进行GUI更改),所以这就行不通了。
那么在处理一个鼠标事件时,我该怎么办才能不接受任何鼠标点击?我认为这个问题不需要更多代码,但如果有必要,我会编辑并添加一些代码。
编辑:
class Animations {
public Pane getAnimationPane() {
//returns Pane which would be used for transition
}
public void playAnimation() {
//called only when the timeline transition is to be played
}
}
所以我创建了一个Animations类的数组,因为我需要很多这样的窗格,需要跟踪它们中的每一个。
当我需要播放动画时,我调用playAnimation()
方法。
现在这个playAnimation()
方法就像一个动画开始。
完成此窗格上的动画后,将根据播放器的进度对电路板进行更改,如果需要,此playAnimation()
方法将调用其他几个动画的playAnimation()
方法对象。
grid.setOnMouseReleased(new EventHandler<MouseEvent> () {
public void handle(MouseEvent me) {
//make changes to player data
//receive new panes for the board
//make some gui changes
//play some animations
someAnimationObject.playAnimation();
}
});
这可能会高达10-20(更多,如果网格大小很大)其他动画对象用于playAnimation()
。
编辑2:
playAnimation()
的{{1}}可以在0-8个其他动画对象上调用Animations
。这可以继续下去。
编辑3:
我终于解决了我的问题,这就是我做到的。
我在playAnimation()
类(实例变量,即非静态)中添加了SimpleBooleanProperty
isAnimating
,默认情况下将其设置为Animations
。
当时间轴动画开始播放时,我将其设置为false
,当时间轴动画完成后,我将其设置为true
。
在主要课程(比如false
)中,我添加了Game
BooleanBinding
。
我使用我创建的数组将anyAnimating
绑定到每个anyAnimating
对象的isAnimating
。
Animations
最后我使用anyAnimating = Bindings.or(anyAnimating, AnimationsObj[i][j].isAnimatingProperty());
的值作为BradEvent EventHandler中的标志,如Brad所建议。
anyAnimating
答案 0 :(得分:2)
我对这里的细节不太确定,因为关于如何管理动画的问题中没有很多细节,但这应该给你一般的想法。
在Animations
课程中添加一个标记,指示动画是否正在进行中:
class Animations {
private ReadOnlyBooleanWrapper animating = new ReadOnlyBooleanWrapper() ;
public ReadOnlyBooleanProperty animatingProperty() {
return animating.getReadOnlyProperty();
}
public boolean isAnimating() {
return animatingProperty().get();
}
public Pane getAnimationPane() {
//returns Pane which would be used for transition
}
public void playAnimation() {
//called only when the timeline transition is to be played
Animation animation = ... ;
animation.statusProperty().addListener((obs, oldStatus, newStatus) ->
animating.set(newStatus == Animation.Status.RUNNING));
animation.play(); // etc
}
}
现在你可以做到
grid.setOnMouseReleased(new EventHandler<MouseEvent> () {
public void handle(MouseEvent me) {
if (! someAnimationObject.isAnimating()) {
//make changes to player data
//receive new panes for the board
//make some gui changes
//play some animations
someAnimationObject.playAnimation();
}
}
});
或者
grid.setOnMouseReleased(new EventHandler<MouseEvent> () {
public void handle(MouseEvent me) {
grid.setDisable(true);
//make changes to player data
//receive new panes for the board
//make some gui changes
//play some animations
someAnimationObject.animatingProperty().addListener((obs, wasAnimating, isNowAnimating) -> {
if (! isNowAnimating) {
grid.setDisable(false);
}
});
someAnimationObject.playAnimation();
}
});
另一种方法是让playAnimation()
接受回调在动画完成时执行(或者当所有动画完成时,如果你正在执行多个动画)。
这看起来像是:
class Animations {
public Pane getAnimationPane(Runnable finishedCallback) {
//returns Pane which would be used for transition
}
public void playAnimation() {
//called only when the timeline transition is to be played
Animation animation = ... ;
animation.statusProperty().addListener((obs, oldStatus, newStatus) -> {
if (newStatus == Animation.Status.STOPPED) {
finishedCallback.run();
}
});
animation.play(); // etc
}
}
然后您的事件处理代码可以执行:
// declared at instance level:
private boolean animating = false ;
grid.setOnMouseReleased(new EventHandler<MouseEvent> () {
public void handle(MouseEvent me) {
if (! animating) {
animating = true ;
//make changes to player data
//receive new panes for the board
//make some gui changes
//play some animations
someAnimationObject.playAnimation( () -> {animating = false ;});
}
}
});
或
grid.setOnMouseReleased(new EventHandler<MouseEvent> () {
public void handle(MouseEvent me) {
grid.setDisable(true);
//make changes to player data
//receive new panes for the board
//make some gui changes
//play some animations
someAnimationObject.playAnimation( () -> {grid.setDisable(false);});
}
});
答案 1 :(得分:0)
我认为这可以用几种不同的方式处理。想到的一种方法是使用简单的信号量。要做到这一点,你只需在类的顶部声明一个名为isUpdating的布尔字段。
private boolean isUpdating = false;
当您单击鼠标时,该方法首先要做的是检查isUpdating是否为false。如果是这样,接下来就是将isUpdating设置为true,执行工作,然后再将其设置为false。
grid.setOnMouseReleased(new EventHandler<MouseEvent> () {
public void handle(MouseEvent me) {
if(!isUpdating){
isUpdating = true;
//make changes to player data
//receive new panes for the board
//make some gui changes
//play some animations
isUpdating = false;
}
}
});
关于线程为什么不更新GUI的评论,这是因为您在重新绘制UI时在一个线程中的更改是在另一个线程中处理的。如果您的匿名线程/ mouselistener与正在更新的UI位于同一个类中,则可以创建一个刷新方法并在工作线程结束时调用它。
UI类:
private void refresh(){
this.revalidate();
this.repaint();
}
工作人员主题:
grid.setOnMouseReleased(new EventHandler<MouseEvent> () {
public void handle(MouseEvent me) {
Thread t = new Thread(new Runnable() {
public void run() {
//completing the necessary tasks here
refresh();
}
});
t.start();
t.join();
}
});
如果您的UI位于不同的类中,则可以创建外部操作侦听器并向其注册UI组件。
public interface GridListener {
public void gridUpdated();
}
然后将您的侦听器添加到需要访问的对象:
public class MyUIClass() {
private List<GridListener> listeners;
}
public MyUIClass(){
listeners = new ArrayList<GridListener>();
}
public void addListener(GridListener listener) {
listeners.add(listener);
}
这可能是更多代码,然后您正在寻找补救当前问题,这些只是我在阅读您的问题时想到的一些建议。