我曾经是recommended而不是InteractionDialog
来使用Dialog
,但是我没有看到优点。我看到的是一个问题。我需要的是让用户输入PIN或其他密码,然后等待他们的回答。 EDT线程(用户选择保存PIN)和其他线程(网页需要PIN进行登录)都需要这样做。
带有Dialog
,
getFromGui
。带有InteractionDialog
,
wait
/ notifyAll
魔术从其他线程轻松使用它。okBtn.addActionListener(...)
这样的回调,它很冗长又丑陋。所以我很困惑,问:
InteractionDialog
中得到什么?这里有两件事:
对话框可以是模式对话框,也可以是非模式对话框,但它不像InteractionDialog
那样具有交互性。模态对话框在内部使用InvokeAndBlock
阻止EDT,因此当前线程将停止,直到对话框发出响应为止。这很方便,但存在一些极端情况。例如。启动对话框的事件可能会触发其他事件,这些事件在关闭对话框后会发生并导致异常行为。
但是那不是模态中的大事。情态有效地意味着您身后的形式“不存在”。重要的是对话框的内容,在完成之前,我们不关心后面的表格。这个核心思想意味着对话框可以有效地派生形式,因此它的行为就像显示另一个有效禁用当前形式的形式一样。在对话框后面看到的是先前表格的图形,而不是实际的表格。
文本字段可能会引起问题。因为对话框的放置方式(使用边距将其有效地填充到其窗体内的适当位置),所以当虚拟键盘抬起时,UI不能按照文本字段的要求滚动。由于人们在这种情况下使用对话框,因此我们尝试解决大多数这些问题,但有时很难,例如如果对话框顶部有很多空白,则将虚拟键盘打开并覆盖它。或者,如果用户旋转屏幕,此时对话框的边距将无效。
请注意,在InteractionDialog
中,某些问题(例如定位余量)也适用。
现在InteractionDialog
是完全不同的野兽,它源于完全不同的用例。如果我们想要一个对话框,例如“浮动在ui顶部的调色板,该怎么办?
我们可以将其从一个位置移动到另一个位置,但仍与基础表单交互。这是InteractionDialog
的核心用例。由于这种模态不再是我们所需要的,因此尽管从技术上来说本来可以做到的,但它从未被纳入InteractionDialog
中(但对于核心用例而言这没有意义)。
它被实现为Container
,放置在当前表单的分层窗格中,因此其周围的表单是真实的。因为表单是“实时”的,所以布局效果更好,而删除模态会使与编辑有关的一些边缘情况变得更好。但是,对话框的定位和旋转仍然存在一些固有的问题。它还允许您在进行输入时在对话框外单击,这对于您的用例而言可能是理想的/不良的效果。
总体上,我仅尝试在非常简单的情况下使用对话框,并尽可能避免输入。如果我使用输入,则永远不会使用多个字段(例如,无用户名和密码字段),因此无需滚动。这些事情也对本机UI不利,例如虚拟键盘遮盖了提交按钮等。由于这些行为很难在所有分辨率/虚拟键盘方案中正确实现。
根据Shai的回答,我编写了一个表单,用作大多数对话框的基类。基本上,它显示了子类的内容,并添加了“确定”和“取消”按钮。
有一种可以在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
是两类类,其中调用set
的线程将boolean
传递给调用await
的线程。