Java 如何在接受下一个MouseeEvent之前等待当前MouseeEventHandler结束?
在我的棋盘游戏中取得进展,因此,只需单击鼠标,就会执行一些任务,如播放一些动画、接收棋盘的新窗格(我问了这个问题,我的最后一个问题,现在效果很好)、更改玩家数据等 这是我的事件处理程序Java 如何在接受下一个MouseeEvent之前等待当前MouseeEventHandler结束?,java,javafx,event-handling,javafx-2,mouseevent,Java,Javafx,Event Handling,Javafx 2,Mouseevent,在我的棋盘游戏中取得进展,因此,只需单击鼠标,就会执行一些任务,如播放一些动画、接收棋盘的新窗格(我问了这个问题,我的最后一个问题,现在效果很好)、更改玩家数据等 这是我的事件处理程序 grid.setOnMouseReleased(new EventHandler<MouseEvent> () { public void handle(MouseEvent me) { //make changes to player data //recei
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
}
});
但是如果我使用线程(不知道为什么,我用许多不同的方法测试了它,总是无法进行GUI更改),那么GUI更改就不会发生,所以我想这是行不通的
那么,在处理一个鼠标事件时,我能做些什么来避免任何鼠标点击呢?我认为这个问题不需要更多的代码,但如果有必要,我会编辑并添加一些代码
编辑:
所以我制作了一个动画类数组,因为我需要很多这样的窗格,并且需要跟踪每一个窗格
当我需要播放动画时,我调用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();
}
});
最后,我按照Brad的建议,在MouseEvent事件处理程序中使用了anyAnimating
的值作为标志
grid.setOnMouseReleased(new EventHandler<MouseEvent> () {
public void handle(MouseEvent me) {
if(!anyAnimating.get()){
//make changes to player data
//receive new panes for the board
//make some gui changes
//play some animations
}
}
});
grid.setOnMouseReleased(新的EventHandler(){
公共无效句柄(MouseEvent me){
如果(!anyAnimating.get()){
//更改播放器数据
//接收董事会的新窗格
//进行一些gui更改
//播放一些动画
}
}
});
我认为这可以通过两种不同的方式来处理。想到的一种方法是使用一个简单的信号量。要做到这一点,只需在类的顶部声明一个名为isupdate的布尔字段
private boolean isUpdating = false;
当您输入鼠标单击时,该方法要做的第一件事是检查IsUpdate是否为false。如果是这样的话,下一步就是将isupdate设置为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;
}
}
});
工作线程:
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();
}
});
然后将侦听器添加到需要访问的对象:
public class MyUIClass() {
private List<GridListener> listeners;
}
public MyUIClass(){
listeners = new ArrayList<GridListener>();
}
public void addListener(GridListener listener) {
listeners.add(listener);
}
public类MyUIClass(){
私人名单听众;
}
公共MyUIClass(){
侦听器=新的ArrayList();
}
公共void addListener(GridListener侦听器){
添加(侦听器);
}
这可能比您想编写的代码要多,以解决您当前的问题,这些只是我在阅读您的问题时想到的一些建议。我不太确定这里的细节,因为您的问题中没有太多关于如何管理动画的细节,但这应该能让您大致了解 向
动画
类添加一个标志,指示动画是否正在进行:
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();
}
}
});
然后,事件处理代码可以执行以下操作:
// 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 ;});
}
}
});
//在实例级别声明:
私有布尔动画=false;
setOnMouseReleased(新的EventHandler(){
公共无效句柄(MouseEvent me){
如果(!设置动画){
动画=真;
//更改播放器数据
//接收董事会的新窗格
//进行一些gui更改
//播放一些动画
播放动画(()->{animating=false;});
}
}
});
或
grid.setOnMouseReleased(新的EventHandler(){
公共无效句柄(MouseEvent me){
grid.setDisable(true);
//更改播放器数据
//接收董事会的新窗格
//进行一些gui更改
//播放一些动画
播放动画(()->{grid.setDisable(false);});
}
});
哇,这么多解决方案,我会尝试一下,然后告诉你。我尝试了第一个,布尔值更新。布尔值将在任务完成之前更改,因此它对我不起作用。带有线程的解决方案不起作用。您不应该从FX应用程序线程调用join()
:它将阻止FX应用程序线程上的执行,并阻止更新UI。另外,revalidate()
和repaint()
是JavaFXAPI中不存在的方法。哦,这是我的错误-我没有意识到问题在于JavaFX。AWT/Swing也会出现同样的问题:你不能阻止事件分派线程。哦,对了,我同意这一点。事实上,我甚至没有注意到有一个加入,直到你提到它。但是关于重新验证和重新绘制,我知道它们在JavaFX中不存在,但我还不太熟悉JavaFXUI框架,所以我无法对正确的方式发表评论。。。我只同意我的建议是无效的。你能更详细地介绍一下你是如何启动动画的吗?如果动画正在运行,您不需要在处理程序中执行任何操作,您可以通过检查动画的状态属性来执行该操作。@James\u D,提供了更多的信息说实话,如果我给出有关如何管理动画的代码,那么这个问题将增加近250行。关于你的回答,我到现在还没有使用过听众。假设我在示例中使用的someAnimationObject
对另外10个动画对象调用playAnimation()
。在EventHandler中,我们仅为someAnimationObject
检查isNowAnimating
,如果其他对象仍在动画中呢?它还能工作吗?不,您需要确保只有在完成所有操作后,才将属性设置为false。(例如,它可以注册自己的侦听器)。如果您使用的是paralleltransformation
和/或SequentialTransition
,那么它应该很简单(只需将状态侦听器注册为代表整个thi的“大”转换即可)
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);
}
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();
}
});
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);});
}
});