7

JSpinnerのSpinnerNumberModelの値の変化を聞きたいです。
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

4 に答える 4

6

以下に示すように、モデルを聞く代わりに、エディターのを聞いてくださいJFormattedTextField

JSpinner spinner = new JSpinner(new SpinnerNumberModel(1, 0, 10, 1));
JSpinner.DefaultEditor editor = (JSpinner.DefaultEditor) spinner.getEditor();
editor.getTextField().addPropertyChangeListener("value", this);
于 2011-08-07T01:53:48.723 に答える
5

月曜日の朝...いくつかのコメントに抵抗しないための古典的な時間:-)

@timaschew

  • propertyChangeListenerが必要です。これは、プロパティの新旧の値を表示するためです。」-(nitpicking-ただし、要件とソリューションを分離するという強い衝動が常にあります:)、逆だと思います。変更通知で古い値と新しい値の両方にアクセスする必要があります。propertyChangeEvent/Listenerはそれをサポートする通知タイプであり、他の値が存在する可能性があります
  • PropertyChangeSupportは、監視コードの一部で使用されることは想定されていません。(@ Hovercraftが彼の例で行ったように)監視可能側で使用されることになっています。監視対象に登録されているリスナーを管理して通知するのは、その唯一の責任です。
  • 時折、accessibleContextはハッキングのフックを提供します-それにもかかわらず、それはそれにフックするハックです(あなたが本当にアクセシビリティをサポートする必要がある場合を除いて、それはそうかもしれません:-)すべてのハックと同様に、それはおそらく原因となる脆弱な解決策です将来のいつか痛み。ActionとAbstractButtonがどのように相互作用するかについてのリンクをたどるとはるかに安定します

@ホバークラフト

  • より豊富な変更通知でモデルを強化するのが道のりです(私の絶対的なお気に入り:-)
  • ほんの少しの詳細:スレーブがいる場合は、スレーブにすべての作業を任せます-PropertyChangeSupportには、古い/新しい値を取得するメソッドがあり、オブザーバブルでイベントを作成するためにフィードする必要はありません。古いものと新しいものが等しい場合、とにかく捨てられます
  • 通知イベントのnewValueの場合、パラメーターを使用せず、代わりにgetValueを再度使用します(superが変更を拒否した可能性があります)

@trashgod

ハハ-あなたはすでに私が解決策が好きではないことを推測しました:それは実装の詳細に依存するという点でカプセル化を壊します、それでJSpinnerの作成を完全に制御しているときを除いてはいけませんそしてそのエディタが決して変更されないことを絶対に確信しています

于 2011-08-08T08:10:36.560 に答える
4

PropertyChangeSupportが機能するには、そのfirePropertyChangeメソッドを呼び出す必要がありますが、さらに重要なことに、サポートオブジェクトは、リッスンしているプロパティのsetXXXメソッドにアクセスできる必要があり、そのメソッドでは、PropertyChangeSupportのfirePropertyChangeメソッドを呼び出す必要があります。したがって、あなたのアイデアが機能するためには、モデルのクラスを拡張し、PropertyChangeSupportオブジェクトを指定し、リスナーの追加と削除のメソッドを指定し、モデルの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();
         }
      });
   }
}
于 2011-08-07T04:01:47.417 に答える
1

http://docs.oracle.com/javase/tutorial/javabeans/writing/properties.html#bound セッターでfireThePropertyChangeを実行する必要があります。

于 2012-05-03T15:58:39.533 に答える