2

我想将 Java Swing JTextField 绑定到我的数据模型的 String 属性。

因此,我想使用PropertyChangeListener来侦听模型中文本属性的变化,然后更新 GUI 中的文本字段(模型--> GUI)。

对于另一个方向(GUI--> 模型) ,当用户更改字段中的文本时,我想在 JTextField 的文档上使用DocumentListener来更新模型。

当我这样做时,只要我更改文本字段中的文本,就会得到IllegalStateException 。

java.lang.IllegalStateException: Attempt to mutate in notification
  at javax.swing.text.AbstractDocument.writeLock(AbstractDocument.java:1323)
  at javax.swing.text.AbstractDocument.replace(AbstractDocument.java:644)
  at javax.swing.text.JTextComponent.setText(JTextComponent.java:1693)
      ...

我怎样才能避免这种情况?

顺便说一句:BeansBinding 对我来说并不是一个真正令人满意的解决方案,因为它被放弃了,此外,我必须在对象图中实例化一些对象,然后才能写入它们。

4

3 回答 3

4

这不是竞争条件,因为一切都发生在同一个线程上。问题就像异常所说的那样:“在通知听众文本已更改的同时尝试更改文本”。

由于在这种情况下您尝试用相同的文本替换文本,因此您可以跳过属性更改侦听器中的更新:

if(!modelText.equals(textField.getText())) {
  textField.setText(modelText);
}
于 2012-07-31T15:29:29.073 回答
2

这个问题之前已经讨论过:https ://stackoverflow.com/a/2789307/474189 。

简而言之,文档侦听器不应该修改文档的内容。

于 2012-07-31T14:47:29.943 回答
2

好吧,一个丑陋的解决方法可能是使用 SwingUtilities.invokeLater() 将 GUI 更新推迟到通知之外。

但是,我认为立即将第二级模型对象与 GUI 同步的整个方法是有缺陷的。GUI 有自己的模型(TextField 使用的文档)。您的模型应该实现它,然后您不需要做任何特殊的事情(然后您的模型对象将替换普通的 Document 作为模型)。

或者您决定在哪里同步 GUI 和您的数据模型的适当点。通常好的一点是当窗口/对话框打开以及用户单击确定/保存时。如果您立即同步模型,您将如何实施“取消”?

于 2012-07-31T14:47:57.367 回答