如何在任何线程上从对话框中获取值?

How to get a value from a dialog when on any thread?

我想知道这是否是从对话框中获取 PIN 码的正确方法?

public static <T> T getFromGui(Supplier<T> supplier) {
    if (CN.isEdt()) return supplier.get();
    final Object[] holder = new Object[1];
    CN.callSeriallyAndWait(() -> holder[0] = supplier.get());
    @SuppressWarnings("unchecked") final T result = (T) holder[0];
    return result;
}

public static String askPin() {
    if (!CN.isEdt()) return getFromGui(() -> askPin(bankzugang));

    ...
    final boolean cont = Dialog.show(
        "Your PIN", BoxLayout.encloseY(pin, label), ok, cancel) == ok;
    return cont? pin.getText() : "";
}

好像可以(试过一次),但是我对callSeriallyAndWait有点疑惑:它是SwingUtilities.invokeAndWait的类比吗?有什么区别?

实际上,我需要几个对话框来处理每个线程,包括 EDT。有没有比将 "getFromGui" 行添加到上面的每个行更好的方法?

是的,callSeriallyAndWait 相当于 SwingUtilities.invokeAndWait。没有逻辑上的区别。

这可行,但这里有几个问题...首先:

如果两个线程同时显示这样的对话框怎么办?第一个将显示第二个对话框,第二个对话框可能会在无限循环中显示第一个对话框...即使您实际在 EDT 上,也会发生这种情况,因为代码不是正常应用程序流程的一部分。

与 Swing 不同,我们一次只有一个 Form,因此一个对话框 "goes back" 可能会很棘手。

因此,首先,您的 GUI 代码需要检查您当前是否没有请求 pin,最好的方法是让一个 class 负责获取如有必要,请从用户那里获取密码,并且它应该处于静态状态。如果还应该检查此时是否没有显示其他对话框,如果是这样,它可能希望避免显示例如:

if(getCurrentForm() instanceof Dialog) {
   // ... don't show yet
}

如果我正确理解你的问题,你有可能需要 pin 的后台线程。在那种情况下,可能会在没有 pin 的情况下捕获多个线程,并且需要来自 GUI 的线程。所以两个线程都需要暂停,但只有其中一个应该调用 callSeriallyAndWait...这意味着当前的方法无论如何都低于标准。

通常我们会避免使用 callSeriallyAndWait,因为它要慢得多(在 Swing 上也是如此)。我还会使用 InteractionDialog 或类似的东西,它比常规对话框的侵入性更小。但是,它不是模态的。但在这种情况下应该无关紧要。

您需要为后台线程开发自己的线程阻塞代码,它可以响应标准回调以释放所有等待的后台线程。然后,您可以使用任何您想要创建 GUI 的代码并使用任何侦听器,然后使用新 pin 更新 class 中的共享状态并调用 notifyAll() 来唤醒等待的线程别针。例如

synchronized(LOCK) {
     if(pin == null && !dialogIsShowing) {
         dialogIsShowing = true;
         callSerially(() -> promptForPin());
     }
     while(pin == null) {
         LOCK.wait();
     }
}

然后UI逻辑:

private void onUserSubmittedPin(String pin) {
     synchronized(LOCK) {
         this.pin = pin;
         dialogIsShowing = false;
         LOCK.notifyAll();
     }
}