GUI更新前线程休眠(Java 6)

时间:2013-02-12 16:52:19

标签: java multithreading user-interface

public static void moveTo(Coordinate destination) {

    changeState(State.NAVIGATION);
    controlPnl.addRemote(Remote.createRemote(remoteType.NAVIGATION));

    dmc.moveTo(destination);

    changeState(State.IMMEDIATE);
    controlPnl.addRemote(Remote.createRemote(remoteType.IMMEDIATE));
}

在此代码中,addRemote方法使用新按钮更新controlPnl GUI。 dmc.moveTo方法中最多有两个Thread.sleep调用,我认为它们是在更新controlPnl GUI之前调用的。我已经注释掉dmc.moveTo之后的两个方法调用,它将GUI更改回调用之前的状态,并且controlPnl在moveTo完成执行之前不会完成更新。我需要的是GUI在moveTo方法开始执行之前完成更新并将Thread置于休眠状态。有什么办法可以在Java 6中实现这个目标吗?

如果重要,moveTo方法会将LEGO Mindstorm机器人移动到用户定义的路径上的指定点。正在更新的GUI为用户提供Swing组件(JButtons和JRadioButtons),以便在导航时控制机器人。 addRemote方法更改用户要使用的Swing组件集,moveTo方法向机器人发送命令以实际执行移动(通过告诉其电机移动,睡眠正确的时间,然后告诉其电机停止移动)。我正在使用状态机模式,此方法是处理来自UI的事件的控制器的一部分。

2 个答案:

答案 0 :(得分:0)

您有一个GUI线程。不要用它来打电话给其他东西;如果你这样做,那些事情必须在你的GUI中发生任何其他事情之前完成。

至少你会想要开始一个新线程来执行你的dmc.moveTo(destination)。很可能这不是您正在执行此操作的唯一地方,并且可能需要Executor设置来执行这些任务。

在不了解您的代码的情况下(特别是因为您使用的是静态方法)我无法评论您希望如何设置Executor,而是使用Thread的最简单示例将是:

 public static void moveTo(final Coordinate destination) {

    changeState(State.NAVIGATION);
    controlPnl.addRemote(Remote.createRemote(remoteType.NAVIGATION));

    new Thread(new Runnable() {
                   public void run() {
                       dmc.moveTo(destination);
                       changeState(State.IMMEDIATE);
                       controlPnl.addRemote(Remote.createRemote(remoteType.IMMEDIATE));
                   }
               }).start();
}

这会创建一个新的Thread,用于执行执行Runnable的(匿名)moveTo()。请注意,这比准备好运行任务的Executor效率低得多;它必须每次创建一个新的Thread。但是,如果这不是你需要的性能问题那么它就完全没问题了。另请注意,因为我在匿名内部类中直接引用destination,所以在传递给您的方法时必须将其声明为final

答案 1 :(得分:0)

由于moveTo需要很长时间,因此不应在主事件处理线程上执行它。相反,让moveTo更新GUI并在单独的线程中开始实际移动。移动完成后,使用SwingUtilities.invokeLater进行第二组GUI更新。

private static ExecutorService executor = Executors.newCachedThreadPool();

public static void moveTo(final Coordinate destination) {

    changeState(State.NAVIGATION);
    controlPnl.addRemote(Remote.createRemote(remoteType.NAVIGATION));

    executor.execute(new Runnable() {
      public void run() {
        dmc.moveTo(destination);
        SwingUtilities.invokeLater(new Runnable() {
          public void run() {
            changeState(State.IMMEDIATE);
            controlPnl.addRemote(Remote.createRemote(remoteType.IMMEDIATE));
          }
        });
      }
    });
}

这种方式moveTo执行初始的GUI更新集,然后立即返回,释放事件循环以保持GUI响应,但第二个changeState被延迟,直到dmc.moveTo为止完整。

(将这些东西分解为单独的方法而不是使用Runnable-in-a-Runnable匿名类可能更有意义)