Как избежать расовых условий при использовании PropertyChangeListener и DocumentListener для привязки модели и графического интерфейса?


Я хочу, чтобы привязать Java на базе Swing jtextfield, чтобы строковый атрибут в моей модели данных.

Поэтому я хочу использоватьPropertyChangeListener , который прослушивает изменения в текстовом атрибуте в модели, а затем обновляет текстовое поле в GUI (model-->GUI).

Для другого направления (GUI-- > model) я хочу использовать DocumentListener на документе JTextField, который должен обновить модель, когда пользователь изменяет текст в поле.

Когда я это делаю, Я получаю 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 на самом деле не является статистическим решением для меня, поскольку она заброшена, и кроме того, я должен создать экземпляр некоторых объектов в объектном графе, прежде чем быть в состоянии написать к ним.

3 2

3 ответа:

Это не условие гонки, так как все происходит в одном потоке. Проблема заключается в том, как говорится в исключении:"попытайтесь изменить текст, уведомляя слушателей, что текст был изменен".

Поскольку в этом сценарии вы пытаетесь заменить текст тем же текстом, Вы можете просто пропустить обновление в прослушивателе изменения свойств:

if(!modelText.equals(textField.getText())) {
  textField.setText(modelText);
}

Этот вопрос рассматривался ранее: https://stackoverflow.com/a/2789307/474189 .

Короче говоря, прослушиватели документов не должны изменять содержимое документа.

Ну, вероятно, уродливым обходным путем было бы использование SwingUtilities.invokeLater () для переноса обновления графического интерфейса за пределы уведомления.

Однако я думаю, что весь подход синхронизации объекта модели второго уровня с графическим интерфейсом немедленно является ошибочным. Графический интерфейс имеет своюсобственную модель (документ, используемый текстовым полем). Либо ваша модель должна реализовать это, тогда вам не нужно делать ничего особенного (тогда ваш объект модели заменит обычный документ как модель).

Или вы определяете правильную точку, где синхронизировать графический интерфейс и вашу модель данных. Обычно хороший момент - это когда открывается окно / диалог и когда пользователь нажимает Ok/Save. Как бы вы реализовали "отмену", если бы синхронизировали свои модели мгновенно?