1

这是在单元测试的背景下(发生时)。

在测试结束时,无论结果如何,我都希望代码检查JFileChooser对话框的存在(可见性)......如果可见,则将其关闭。

当然,有不同的方法可以解除对话,但为了模仿人类行为(并举一个我在这里关心的问题的例子),我选择使用java.awt.Robot. 后者的方法应该在非 EDT 线程中运行。

事实上,我已经扩展了 Robot 以包含一个名为 的便捷方法type_input,所以

robot.type_input( KeyEvent.VK_F4, KeyEvent.VK_ALT )

先按 Alt,然后 F4,然后释放 F4,然后 Alt:就像人类关闭窗口/对话框一样。

我提交Runnable使用invokeAndWait,因为我不希望代码在此对话框被关闭之前运行到下一个测试。我必须在 EDT 中测试可见性和焦点。但正如我所说,Robot 方法必须在非 EDT 中运行。

get()在 EDT 中这样进行是否有任何潜在问题?它是否可能导致 GUI 无响应?问题是,我听说该框架能够在某些条件下“启动一个新的 EDT 泵”。我不得不承认,这是我觉得自己最不了解的与 EDT 相关的问题之一……

import java.awt.EventQueue;
import java.awt.Robot;
import java.awt.event.KeyEvent;
import java.lang.reflect.InvocationTargetException;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadPoolExecutor;
import javax.swing.JDialog;
import javax.swing.JFileChooser;
import javax.swing.JFrame;

class MainFrame extends JFrame {
    JFileChooser update_target_file_chooser;
    JDialog file_chooser_dlg;

    // ... rest of class

}

public class ThreadWithinThread {

    public static void main(String[] args) throws InvocationTargetException, InterruptedException {

        final ExecutorService thread_pool_exec_serv = Executors.newFixedThreadPool( 5 );

        class DismissDlg implements Runnable {
            MainFrame main_frame;
            Robot robot;

            @Override
            public void run() {
                boolean focus_on_dlg = main_frame.file_chooser_dlg.hasFocus();
                if( main_frame.file_chooser_dlg.isVisible() ){
                    if( ! focus_on_dlg ){
                        main_frame.file_chooser_dlg.requestFocus();
                    }
                    class AltF4 implements Callable<Void>{
                        public Void call(){
                            return robot.type_input( KeyEvent.VK_F4, KeyEvent.VK_ALT );
                        }
                    }
                    Future<Void> future_result = thread_pool_exec_serv.submit( new AltF4() );
                    try {
                        // this is the line I'm worried about
                        future_result.get();
                    } catch (InterruptedException | ExecutionException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
        EventQueue.invokeAndWait( new DismissDlg() );
    }

}

之后

正如我在回复中所说,这不是针对手头案例的一个特别实用的解决方案:我真的想了解另一个 EDT“事件泵”是否以及何时启动并Future.get()阻塞 EDT。正如我所说,我发现这整个方面很难理解。我使用JOptionPane's 的静态方法(必须在 EDT 中运行,请参阅 SO ad 上的帖子)向我证明这些方法(确实会阻止 EDT!)实际上似乎并没有阻止 GUI 运行(注意不要与这些JOptionPanes 或它们JDialog的 s 是模态的还是非模态的混淆)。

我的理解是,这是因为“框架”随后启动了另一个“事件泵”。那么它可以在这里这样做吗?

4

2 回答 2

3

所以,从JavaDocs

如有必要,等待计算完成,然后检索其结果。

这表明该方法是一种阻塞方法,如果在事件调度线程的上下文中你不应该做一件事,它会在事件调度线程的上下文中调用阻塞方法

啊,但是怎么办?您可以使用 aSwingWorker代替,它在内部使用它自己的ExecutorService,或者submit您自己的工作人员ExecutorServiceSwingWorker实现Runnable),然后您应该能够使用 aPropertyChangeListener来监视状态,SwingWorker当它是时DONE,您可以从它的get方法中检索值而不会阻塞

于 2016-01-21T21:44:21.180 回答
0

在 EDT 上执行必要的步骤,并通知测试线程是否需要额外的步骤:

class PrepDlgDismiss implements Runnable {
  boolean file_chooser_visible;
  @Override
  public void run() {
    boolean focus_on_dlg = main_frame.file_chooser_dlg.hasFocus();
    if( main_frame.file_chooser_dlg.isVisible() ){
      file_chooser_visible = true;
      if( ! focus_on_dlg ){
        main_frame.file_chooser_dlg.requestFocus();
      }
    }
  }
}
PrepDlgDismiss task = new PrepDlgDismiss();
EventQueue.invokeAndWait( task );
if( task.file_chooser_visible ){
  robot.type_input( KeyEvent.VK_F4, KeyEvent.VK_ALT );
}
于 2016-01-21T22:26:59.933 回答