如何在接受下一个MouseEvent之前等待当前的MouseEvent事件处理程序结束



在我的棋盘游戏中取得进展,所以在鼠标点击时,一些任务将被执行,如播放一些动画,接收棋盘的新窗格(我问过我的最后一个问题,现在工作得很好),更改玩家数据等。

这是我的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秒。当这个过程进行的时候,我看到另一个鼠标点击也开始被并行处理。

我想要的是在第一个鼠标事件完成之前不处理另一个鼠标事件。如果收到的任何点击都被丢弃,那就更好了。

我尝试使用threading:

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:

AnimationsplayAnimation()可以在0-8个其他动画对象上调用playAnimation()。这还可以继续。

编辑3:

我终于解决了我的问题,我是这样做的。

我添加了一个SimpleBooleanProperty isAnimating到我的Animations类(实例变量,即非静态),默认设置为false

当时间轴动画开始播放时,我将其设置为true,当时间轴动画完成时,我将其设置为false

在主类中(例如Game),我添加了BooleanBinding anyAnimating。我使用我所说的创建的数组将每个Animations对象的anyAnimating绑定到isAnimating

anyAnimating = Bindings.or(anyAnimating, AnimationsObj[i][j].isAnimatingProperty());

最后,我使用anyAnimating的值作为MouseEvent eventandler中的标志,正如Brad建议的。

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
        }
    } 
});

我不是很确定这里的细节,因为在你的问题中没有很多关于如何管理动画的细节,但这应该给你一个大致的想法。

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);});
    }
});

我认为这可以通过几种不同的方式来处理。想到的一种方法是使用一个简单的信号量。要做到这一点,只需在类的顶部声明一个布尔字段,类似于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重绘是在另一个线程处理。如果你的匿名线程/mousellistener与正在更新的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);
}

这可能是更多的代码,然后你想写来补救你目前的问题,这些只是一些建议,我认为,而阅读你的问题。

相关内容

  • 没有找到相关文章

最新更新