Interaction Dialog 相对于 Dialog 的优势?
Advantages of InteractionDialog over Dialog?
我 使用 InteractionDialog
而不是 Dialog
,但我没有看到优势。我能看到的是一个问题。我需要的是让用户输入 PIN 或其他内容并等待他们的回答。这在 EDT 线程(用户选择保存 PIN)和其他线程(网页需要 PIN 才能登录)上都是需要的。
与Dialog
、
- 我可以从 EDT 线程调用它,而且效果很好。
- 当在不同的线程上时,我可以通过被调用方中的一行进行微不足道的调整(请参阅我的链接问题中的
getFromGui
)。
和InteractionDialog
,
- 我可以通过一些简单的
wait
/notifyAll
魔法从其他线程轻松使用它。
- 我不能从 EDT 线程使用它,除非通过像
okBtn.addActionListener(...)
这样的回调,它冗长且丑陋。
所以我很困惑,请教:
- 我从
InteractionDialog
中得到了什么?
- 有没有简单的方法无论我在什么线程都可以统一使用它?
这里有两个独立的东西:
- 模态
- 工作原理
对话框可以是模态的或非模态的,但它不像 InteractionDialog
那样具有交互性。模态对话框使用 InvokeAndBlock
在内部阻止 EDT,因此当前线程停止,直到对话框有响应。这很方便,但有一些边缘情况问题。例如。启动对话框的事件可能会触发对话框关闭后发生的其他事件并导致奇怪的行为。
但这不是模态中的大事。模态实际上意味着你身后的形式 "doesn't exist"。重要的是对话的内容,在对话结束之前我们不关心背后的形式。这个核心思想意味着对话框有效地派生了表单,因此它的行为就像显示另一个表单有效地禁用当前表单一样。您在对话框后面看到的是以前表格的绘图,而不是实际表格。
文本字段可能会带来问题。由于对话框的定位方式(使用边距有效地填充到其表单内),当虚拟键盘升起时,UI 无法作为文本字段 requires 滚动。由于人们在这种情况下使用对话框,我们尝试解决大部分这些问题,但有时这非常困难,例如如果对话框有很多上边距,则虚拟键盘打开并覆盖它。或者,如果用户旋转屏幕,此时对话框的边距定位将变得无效。
请注意,在 InteractionDialog
中,其中一些问题(例如头寸保证金)也适用。
现在 InteractionDialog
是一个完全不同的野兽,源于一个完全不同的用例。如果我们想要一个对话框,例如“漂浮在 ui 顶部的调色板?
我们可以将它从一个地方移动到另一个地方,但仍然与底层表单进行交互。这是 InteractionDialog
的核心用例。由于这种模式不再是我们需要的东西,所以它从未被纳入 InteractionDialog
,尽管它在技术上本可以(但它对核心用例没有意义)。
它被实现为 Container
放置在当前表单的分层窗格中,因此它周围的表单是真实的。因为表单是 "live" 布局效果更好,并且模态的移除使得一些与编辑相关的边缘情况稍微好一些。不过,对话框定位和旋转仍然存在一些固有问题。它还允许您在输入正在进行时单击对话框外部,这可能对您的用例产生 desirable/undesirable 效果。
总的来说,我尽量只在非常简单的情况下使用对话框,并尽可能避免输入。如果我使用输入,我从不使用多个字段(例如无用户名和密码字段),因此我不需要滚动。这些东西对原生 UIs 也很糟糕,例如虚拟键盘遮住了提交按钮等。因为这些行为很难在所有 resolution/virtual 键盘场景中得到正确处理。
根据 Shai 的回答,我编写了一个表单作为我大部分对话的基础 class。基本上,它显示 subclass 的内容并添加 "OK" 和 "Cancel" 按钮。
有一种方法可以从 EDT 线程中使用,例如
public void showAndThen(BooleanConsumer consumer) {
assert CN.isEdt();
...
okBtn.addActionListener(a -> {
lastForm.show();
consumer.accept(true);
});
cancelBtn.addActionListener(a -> {
lastForm.showBack();
consumer.accept(false);
});
}
其中 BooleanConsumer
是一个普通的 void accept(boolean b)
接口。
还有其他线程可以使用的方法
@Override public final boolean ask() {
assert !CN.isEdt();
final BooleanTransfer transfer = new BooleanTransfer();
CN.callSerially(() -> showAndThen(result -> transfer.set(result)));
return transfer.await();
}
其中 BooleanTransfer
是两种方法 class,其中调用 set
的线程将 boolean
传递给调用 await
.[=18 的线程=]
我 InteractionDialog
而不是 Dialog
,但我没有看到优势。我能看到的是一个问题。我需要的是让用户输入 PIN 或其他内容并等待他们的回答。这在 EDT 线程(用户选择保存 PIN)和其他线程(网页需要 PIN 才能登录)上都是需要的。
与Dialog
、
- 我可以从 EDT 线程调用它,而且效果很好。
- 当在不同的线程上时,我可以通过被调用方中的一行进行微不足道的调整(请参阅我的链接问题中的
getFromGui
)。
和InteractionDialog
,
- 我可以通过一些简单的
wait
/notifyAll
魔法从其他线程轻松使用它。 - 我不能从 EDT 线程使用它,除非通过像
okBtn.addActionListener(...)
这样的回调,它冗长且丑陋。
所以我很困惑,请教:
- 我从
InteractionDialog
中得到了什么? - 有没有简单的方法无论我在什么线程都可以统一使用它?
这里有两个独立的东西:
- 模态
- 工作原理
对话框可以是模态的或非模态的,但它不像 InteractionDialog
那样具有交互性。模态对话框使用 InvokeAndBlock
在内部阻止 EDT,因此当前线程停止,直到对话框有响应。这很方便,但有一些边缘情况问题。例如。启动对话框的事件可能会触发对话框关闭后发生的其他事件并导致奇怪的行为。
但这不是模态中的大事。模态实际上意味着你身后的形式 "doesn't exist"。重要的是对话的内容,在对话结束之前我们不关心背后的形式。这个核心思想意味着对话框有效地派生了表单,因此它的行为就像显示另一个表单有效地禁用当前表单一样。您在对话框后面看到的是以前表格的绘图,而不是实际表格。
文本字段可能会带来问题。由于对话框的定位方式(使用边距有效地填充到其表单内),当虚拟键盘升起时,UI 无法作为文本字段 requires 滚动。由于人们在这种情况下使用对话框,我们尝试解决大部分这些问题,但有时这非常困难,例如如果对话框有很多上边距,则虚拟键盘打开并覆盖它。或者,如果用户旋转屏幕,此时对话框的边距定位将变得无效。
请注意,在 InteractionDialog
中,其中一些问题(例如头寸保证金)也适用。
现在 InteractionDialog
是一个完全不同的野兽,源于一个完全不同的用例。如果我们想要一个对话框,例如“漂浮在 ui 顶部的调色板?
我们可以将它从一个地方移动到另一个地方,但仍然与底层表单进行交互。这是 InteractionDialog
的核心用例。由于这种模式不再是我们需要的东西,所以它从未被纳入 InteractionDialog
,尽管它在技术上本可以(但它对核心用例没有意义)。
它被实现为 Container
放置在当前表单的分层窗格中,因此它周围的表单是真实的。因为表单是 "live" 布局效果更好,并且模态的移除使得一些与编辑相关的边缘情况稍微好一些。不过,对话框定位和旋转仍然存在一些固有问题。它还允许您在输入正在进行时单击对话框外部,这可能对您的用例产生 desirable/undesirable 效果。
总的来说,我尽量只在非常简单的情况下使用对话框,并尽可能避免输入。如果我使用输入,我从不使用多个字段(例如无用户名和密码字段),因此我不需要滚动。这些东西对原生 UIs 也很糟糕,例如虚拟键盘遮住了提交按钮等。因为这些行为很难在所有 resolution/virtual 键盘场景中得到正确处理。
根据 Shai 的回答,我编写了一个表单作为我大部分对话的基础 class。基本上,它显示 subclass 的内容并添加 "OK" 和 "Cancel" 按钮。
有一种方法可以从 EDT 线程中使用,例如
public void showAndThen(BooleanConsumer consumer) {
assert CN.isEdt();
...
okBtn.addActionListener(a -> {
lastForm.show();
consumer.accept(true);
});
cancelBtn.addActionListener(a -> {
lastForm.showBack();
consumer.accept(false);
});
}
其中 BooleanConsumer
是一个普通的 void accept(boolean b)
接口。
还有其他线程可以使用的方法
@Override public final boolean ask() {
assert !CN.isEdt();
final BooleanTransfer transfer = new BooleanTransfer();
CN.callSerially(() -> showAndThen(result -> transfer.set(result)));
return transfer.await();
}
其中 BooleanTransfer
是两种方法 class,其中调用 set
的线程将 boolean
传递给调用 await
.[=18 的线程=]