PropertyChangeSupport для SpinnerNumberModel - PullRequest
7 голосов
/ 07 августа 2011

Я хочу прослушать изменения значения SpinnerNumberModel для JSpinner.
Я создаю PropertyChangeSupport и помещаю в него модель.

Мне нужен propertyChangeListener, потому что он показывает мнестарая и новая стоимость имущества.

Фрагмент не работает: метод propertyChange ничего не печатает, когда я нажимаю на JSpinner.
Простой ChangeListener дает только новое значение, но мне нужно также старое значение, как можноЯ понял?

package de.unikassel.jung;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;

import javax.swing.JFrame;
import javax.swing.JSpinner;
import javax.swing.SpinnerNumberModel;

public class PropertyChangeTest implements PropertyChangeListener {

    public static void main(String[] args) {
        new PropertyChangeTest();
    }

    public PropertyChangeTest() {
        JFrame frame = new JFrame();
        frame.setBounds(100, 100, 450, 300);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        int value = 1;
        int min = 0;
        int max = 10;
        int step = 1;
        SpinnerNumberModel spinnerModel = new SpinnerNumberModel(value, min, max, step);

        PropertyChangeSupport pcs = new PropertyChangeSupport(spinnerModel);
        pcs.addPropertyChangeListener("value", this);

        JSpinner spinner = new JSpinner(spinnerModel);
        frame.getContentPane().add(spinner);
        frame.setVisible(true);
    }

    @Override
    public void propertyChange(PropertyChangeEvent evt) {
        System.out.println(evt);
        System.out.println(evt.getSource());
    }

}

Ответы [ 4 ]

6 голосов
/ 07 августа 2011

Вместо прослушивания модели, прослушайте редактор JFormattedTextField, как предлагается ниже.

JSpinner spinner = new JSpinner(new SpinnerNumberModel(1, 0, 10, 1));
JSpinner.DefaultEditor editor = (JSpinner.DefaultEditor) spinner.getEditor();
editor.getTextField().addPropertyChangeListener("value", this);
5 голосов
/ 08 августа 2011

Утро понедельника ... классическое время, чтобы не сопротивляться нескольким комментариям: -)

@ timaschew

  • " нужен propertyChangeListener, потому что он показывает мнестарое и новое значение свойства."- (придирки - но всегда есть сильное стремление отделить требование и решение :), я думаю, что все наоборот: в уведомлении об изменении вам нужен доступ как к старому, так и к старому.новое значение, propertyChangeEvent / Listener - это тип уведомления, который поддерживает его, могут быть другие
  • PropertyChangeSupport не должен использоваться для части кода наблюдения , он должен бытьиспользуется на стороне obervable (так же, как это сделал @Hovercraft в своем примере): единственная ответственность - управлять и время от времени уведомлять слушателей, зарегистрированных на наблюдаемом
  • , availableContext предоставляет ловушку дляхаки - тем не менее, это хак, чтобы зацепить его (за исключением того, что вам действительно нужно поддерживать доступность, что можеттак и будет :-) Как и в случае со всеми взломами, это хрупкое решение, которое, скорее всего, вызовет боль в будущем.Гораздо более стабильно переходить по ссылке о том, как Action и AbstractButton взаимодействуют

@ Hovercraft

  • , улучшая модель с помощью более подробных уведомлений об изменениях.-to-go (как в: мой самый любимый: -)
  • просто небольшая деталь: если у вас есть раб, пусть он сделает все работу - PropertyChangeSupport имеет методы, которые берут старое/ Новое значение, не нужно кормить, чтобы создать событие на наблюдаемой.В любом случае, оно будет выброшено, когда old и new равны
  • для newValue в событии уведомления, не используйте параметр, но вместо этого используйте getValue снова (super, возможно, отклонил изменение)

@ trashgod

ха-ха - вы уже догадались, что мне не нравится решение: оно нарушает инкапсуляцию в том смысле, что оно опирается на детали реализации, так что не делайте этого, кроме случаев полного контроля над созданием JSpinner иабсолютно уверены, что его редактор никогда не меняется

4 голосов
/ 07 августа 2011

Для работы PropertyChangeSupport необходимо вызвать его метод firePropertyChange, но, что более важно, объект поддержки должен иметь доступ к методу setXXX свойства, которое он слушает, и в этом методе ему необходимо вызвать метод PropertyChangeSupportметод firePropertyChange.И поэтому я думаю, что для того, чтобы ваша идея сработала, вам нужно расширить класс модели, дать ему объект PropertyChangeSupport, дать ему методы add и remove listener и обязательно прослушать изменения, сделанные в методе setValue модели, который являетсяключ.В моем примере этот метод выглядит следующим образом:

   @Override
   public void setValue(Object newValue) {
      // store old value and set the new one
      Object oldValue = getValue();
      super.setValue(newValue);

      // construct the event object using these saved values
      PropertyChangeEvent evt = new PropertyChangeEvent(this, VALUE, oldValue,
               newValue);

      // notify all of the listeners
      pcs.firePropertyChange(evt);
   }

Вот мой пример класса модели, который использует PropertyChangeSupport:

import java.beans.*;
import javax.swing.*;
import javax.swing.event.*;

@SuppressWarnings("serial")
class MySpinnerNumberModel extends SpinnerNumberModel {
   public static final String VALUE = "value";
   private SwingPropertyChangeSupport pcs = new SwingPropertyChangeSupport(this);

   // you will likely need to create multiple constructors to match
   // the ones available to the SpinnerNumberModel class
   public MySpinnerNumberModel(int value, int min, int max, int step) {
      super(value, min, max, step);
   }

   public void addPropertyChangeListener(PropertyChangeListener listener) {
      pcs.addPropertyChangeListener(listener);
   }

   public void removePropertyChangeListener(PropertyChangeListener listener) {
      pcs.removePropertyChangeListener(listener);
   }

   @Override
   public void setValue(Object newValue) {
      // store old value and set the new one
      Object oldValue = getValue();
      super.setValue(newValue);

      // construct the event object using these saved values
      PropertyChangeEvent evt = new PropertyChangeEvent(this, VALUE, oldValue,
               newValue);

      // notify all of the listeners
      pcs.firePropertyChange(evt);
   }
}

И, наконец, тестовый класс для проверки вышеуказанного класса, чтобы увидеть,он работает правильно:

import java.beans.*;
import javax.swing.*;

public class TestSpinnerPropChange {

   private static void createAndShowUI() {
      final MySpinnerNumberModel myModel = new MySpinnerNumberModel(1, 0, 10, 1);
      final JSpinner spinner = new JSpinner(myModel);

      final JTextField oldValueField = new JTextField(10);
      final JTextField newValueField = new JTextField(10);

      JPanel panel = new JPanel();
      panel.add(spinner);
      panel.add(new JLabel("old value:"));
      panel.add(oldValueField);
      panel.add(new JLabel("new value:"));
      panel.add(newValueField);

      myModel.addPropertyChangeListener(new PropertyChangeListener() {
         public void propertyChange(PropertyChangeEvent evt) {
            // checking the property name is overkill here, but is a good habit
            // to get into, especially if listening to more than one property.
            if (evt.getPropertyName().equals(MySpinnerNumberModel.VALUE)) {
               oldValueField.setText(evt.getOldValue().toString());
               newValueField.setText(evt.getNewValue().toString());
            }
         }
      });

      JFrame frame = new JFrame("TestSpinnerPropChange");
      frame.getContentPane().add(panel);
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.pack();
      frame.setLocationRelativeTo(null);
      frame.setVisible(true);
   }

   public static void main(String[] args) {
      java.awt.EventQueue.invokeLater(new Runnable() {
         public void run() {
            createAndShowUI();
         }
      });
   }
}
1 голос
/ 03 мая 2012

http://docs.oracle.com/javase/tutorial/javabeans/writing/properties.html#bound Вы должны запустить thePropertyChange в установщиках.

...