Хорошо, у меня проблема с прослушивателем событий Swing... Краткое введение Я разрабатываю приложение Java с пользовательским интерфейсом Swing, структурированным по шаблону MVC.
- MyView -> Текст изменяется пользователем, и представление должно информировать модель контроллером
- MyModel -> Хранить данные и информировать представление об изменениях через контроллер
- MyController -> Интерфейс, используемый для информирования модели и представления об изменениях
На основе этих классов модель и представление связаны только через класс контроллера. Класс представления содержит текстовое поле для пользовательского ввода, которое должно обновлять класс модели пользовательским вводом без нажатия кнопки. Это означает, что мне нужен прослушиватель для JTextField, который ожидает ввода/изменения текста пользователем...
Я пробовал DocumentListener
, но это не работает, выдается исключение: java.lang.IllegalStateException: Attempt to mutate in notification
Я думаю, что проблема здесь в том, что класс модели также вызывает контроллер, если свойства изменились, и контроллер снова информирует/меняет представление -> Результат: бесконечный цикл
Оба решения, которые я нашел, не сработали для меня:
Swing JTextField при изменении текста
Прослушиватель JTextField при изменении текста, который изменяет текст textField
МояМодель.java
public void setHost(String host) // Method called by controller to change model
{
String oldHost = this.host;
this.host = host;
this.firePropertyChange("Host", oldHost, this.host); // Model inform view about changes
}
MyView.java
@Override public void modelPropertyChange(final PropertyChangeEvent event)
{
// Method used to update view and called by controller
if(event.getPropertyName().equals("Username"))
{
String username = (String) event.getNewValue();
this.nameField.setText(username);
}
}
Проблема заключается в том, что когда вызывается прослушиватель документа, потому что пользователь вводит что-то, модель изменена, вызовите свойство измененного метода просмотра, а просмотр замените текст тем же текстом, который снова вызывает событие изменения документа, и вызывается прослушиватель... Бесконечность петля
Я пытался работать с ActionListener
, все работает нормально, но пользователю необходимо нажать клавишу возврата, чтобы назначить изменения... Есть ли какие-либо другие варианты прослушивания текстовых изменений в JTextField без DocumentListener
? Или что я должен изменить в своем шаблоне MVC, чтобы решить эту проблему?
ИЗМЕНИТЬ
Я попробовал решение Peter Walser, но возникло новое исключение:
java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.x1c1b.carrierpigeon.service.mvc.AbstractController.setModelProperty(AbstractController.java:62)
at org.x1c1b.carrierpigeon.desktop.ui.controller.LoginController.changeUsername(LoginController.java:12)
at org.x1c1b.carrierpigeon.desktop.ui.view.LoginView$UsernameChangedListener.updateFieldState(LoginView.java:221)
at org.x1c1b.carrierpigeon.desktop.ui.view.LoginView$UsernameChangedListener.insertUpdate(LoginView.java:203)
at javax.swing.text.AbstractDocument.fireInsertUpdate(AbstractDocument.java:201)
at javax.swing.text.AbstractDocument.handleInsertString(AbstractDocument.java:748)
at javax.swing.text.AbstractDocument.insertString(AbstractDocument.java:707)
at javax.swing.text.PlainDocument.insertString(PlainDocument.java:130)
at org.x1c1b.carrierpigeon.desktop.ui.util.TextFieldLimit.insertString(TextFieldLimit.java:26)
at javax.swing.text.AbstractDocument.replace(AbstractDocument.java:669)
at javax.swing.text.JTextComponent.replaceSelection(JTextComponent.java:1328)
at javax.swing.text.DefaultEditorKit$DefaultKeyTypedAction.actionPerformed(DefaultEditorKit.java:884)
at javax.swing.SwingUtilities.notifyAction(SwingUtilities.java:1668)
at javax.swing.JComponent.processKeyBinding(JComponent.java:2882)
at javax.swing.JComponent.processKeyBindings(JComponent.java:2929)
at javax.swing.JComponent.processKeyEvent(JComponent.java:2845)
at java.awt.Component.processEvent(Component.java:6316)
at java.awt.Container.processEvent(Container.java:2239)
at java.awt.Component.dispatchEventImpl(Component.java:4889)
at java.awt.Container.dispatchEventImpl(Container.java:2297)
at java.awt.Component.dispatchEvent(Component.java:4711)
at java.awt.KeyboardFocusManager.redispatchEvent(KeyboardFocusManager.java:1954)
at java.awt.DefaultKeyboardFocusManager.dispatchKeyEvent(DefaultKeyboardFocusManager.java:835)
at java.awt.DefaultKeyboardFocusManager.preDispatchKeyEvent(DefaultKeyboardFocusManager.java:1103)
at java.awt.DefaultKeyboardFocusManager.typeAheadAssertions(DefaultKeyboardFocusManager.java:974)
at java.awt.DefaultKeyboardFocusManager.dispatchEvent(DefaultKeyboardFocusManager.java:800)
at java.awt.Component.dispatchEventImpl(Component.java:4760)
at java.awt.Container.dispatchEventImpl(Container.java:2297)
at java.awt.Window.dispatchEventImpl(Window.java:2746)
at java.awt.Component.dispatchEvent(Component.java:4711)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:760)
at java.awt.EventQueue.access$500(EventQueue.java:97)
at java.awt.EventQueue$3.run(EventQueue.java:709)
at java.awt.EventQueue$3.run(EventQueue.java:703)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:74)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:84)
at java.awt.EventQueue$4.run(EventQueue.java:733)
at java.awt.EventQueue$4.run(EventQueue.java:731)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:74)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:730)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:205)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:116)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:105)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:93)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:82)
Caused by: java.lang.IllegalStateException: Attempt to mutate in notification
at javax.swing.text.AbstractDocument.writeLock(AbstractDocument.java:1338)
at javax.swing.text.AbstractDocument.replace(AbstractDocument.java:658)
at javax.swing.text.JTextComponent.setText(JTextComponent.java:1669)
at org.x1c1b.carrierpigeon.desktop.ui.view.LoginView.modelPropertyChange(LoginView.java:76)
at org.x1c1b.carrierpigeon.service.mvc.AbstractController.propertyChange(AbstractController.java:47)
at java.beans.PropertyChangeSupport.fire(PropertyChangeSupport.java:335)
at java.beans.PropertyChangeSupport.firePropertyChange(PropertyChangeSupport.java:327)
at java.beans.PropertyChangeSupport.firePropertyChange(PropertyChangeSupport.java:263)
at org.x1c1b.carrierpigeon.service.mvc.AbstractModel.firePropertyChange(AbstractModel.java:27)
at org.x1c1b.carrierpigeon.desktop.ui.model.LoginModel.setUsername(LoginModel.java:39)
... 52 more
Похоже, что документ JTextField
все еще заблокирован во время информирования модели, потому что он вызывает метод setText
, возникает исключение, и эта операция недопустима, но я не могу понять, почему?!
ИЗМЕНИТЬ
На данный момент я решил эту ошибку с помощью инструкций и первого решения Peter Walser в сочетании с выполнением инструкций, установленных DocumentListener
на EDT!
JTextField
каждый раз когда он изменил себя, потому что есть второй контроллер, который меняет модель по данным сокета... Поэтому необходимо, чтобы модель могла изменить текст JTextField, но в этом особом случае, когда пользователь, а не сокет, меняет JTextField текст, чем не предполагается, что модель снова изменит вид... - person 0x1C1B   schedule 13.07.2018I tried the solution of Peter Walser
- Петр предложил два решения. Мы не знаем, что вы пробовали? Я бы использовал первый подход.but I got a new exception:...
- уже было дано решение, как избежать этой проблемы. Опубликуйте правильный минимально воспроизводимый пример, демонстрирующий проблему, чтобы нам не пришлось гадать, что вы делаете. Это все, что вам нужно, это JFrame с текстовым полем и кнопкой. Пользователь может ввести текст в текстовое поле, чтобы обновить модель. Кнопка добавит текст прямо в модель. Тогда, возможно, мы сможем помочь отладить. - person camickr   schedule 13.07.2018