Добавление прослушивателя к переменной в Java / JavaFX, которая вызывается при изменении переменной

Я знаю, что в JavaFX есть слушатели, и я уверен, что Java. Но я не понимаю, как их реализовать.

У меня есть логическая переменная, которая изменяется в моей программе. Каждый раз, когда логическое значение изменяется, я хочу, чтобы функция myFunc() была запущена.

Это можно сделать легко?

5 ответов


так просто:

public void changeBooleanFlag(boolean bEnabled)
{
    if(booleanFlag == bEnabled) return;
    booleanFlag = bEnabled;
    myFunc();
}

и всякий раз, когда вы хотите изменить флаг типа boolean, вы должны сделайте это с помощью этого метода.


Если вы используете JavaFX 2, то он предоставляет готовые решения для архитектуры компонентов JavaBeans и Шаблона дизайна наблюдателя. Кроме того, это дает большую гибкость связывания состояния переменных привязками свойств. В приведенном ниже коде показаны события изменения свойств и привязка переменных свойств. Конечно, вы можете обернуть аксессоры свойств, чтобы скрыть детали, как getFlag() и setFlag() ниже, и используйте их в остальной части приложение.

public class Demo extends Application {

    private BooleanProperty booleanProperty = new SimpleBooleanProperty(true);

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

    @Override
    public void start(Stage primaryStage) {

        // Add change listener
        booleanProperty.addListener(new ChangeListener<Boolean>() {

            @Override
            public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
                System.out.println("changed " + oldValue + "->" + newValue);
                myFunc();
            }
        });

        Button btn = new Button();
        btn.setText("Toggle boolean flag");
        btn.setOnAction(new EventHandler<ActionEvent>() {

            @Override
            public void handle(ActionEvent event) {
                booleanProperty.set(!booleanProperty.get()); //toggle
                System.out.println("toggled to " + booleanProperty.get());
            }
        });

        // Bind to another property variable
        btn.underlineProperty().bind(booleanProperty);

        StackPane root = new StackPane();
        root.getChildren().add(btn);
        primaryStage.setScene(new Scene(root, 300, 250));
        primaryStage.show();
    }

    public boolean getFlag() {
        return booleanProperty.get();
    }

    public void setFlag(boolean val) {
        booleanProperty.set(val);
    }
}

Я бы сделал это, используя PropertyChangeListener. Вот хороший учебник: http://docs.oracle.com/javase/tutorial/uiswing/events/propertychangelistener.html

пример кода:

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.List;

public class MyClass {
    private final List<PropertyChangeListener> listeners = new ArrayList<>();
    private boolean b1, b2;

    public MyClass() {
    }

    public boolean isB1() {
        return b1;
    }

    public void setB1(boolean b1) {
        boolean oldValue = this.b1;
        this.b1 = b1;
        firePropertyChange("b1", oldValue, b1);
    }

    public boolean isB2() {
        return b2;
    }

    public void setB2(boolean b2) {
        boolean oldValue = this.b2;
        this.b2 = b2;
        firePropertyChange("b2", oldValue, b2);
    }

    public void addPropertyChangeListener(PropertyChangeListener listener) {
        listeners.add(listener);
    }

    private void firePropertyChange(String property, Object oldValue, Object newValue) {
        for (PropertyChangeListener l : listeners) {
            l.propertyChange(new PropertyChangeEvent(this, property, oldValue, newValue));
        }
    }

    /**
     * Main method for tests.
     * @param args
     */
    public static void main(String[] args) {
        MyClass m = new MyClass();

        m.addPropertyChangeListener(new PropertyChangeListener() {
            @Override
            public void propertyChange(PropertyChangeEvent e) {
                String changedProperty = e.getPropertyName();
                System.out.println("Changed property: " + changedProperty);
                System.out.println("New value: " + e.getNewValue());
                System.out.println("Old value: " + e.getOldValue());
                System.out.println();
            }
        });

        m.setB1(true);
        m.setB2(false);
    }
}

U может использовать шаблон проектирования Observer. Просто такой:

 public interface Listener
  {
      public void handle(Object o) ;
  }

  public class PropertiesChangeListener
  {
      public void handle(Object o) {
        //DO SOMETHING...
      }
  }

  public class Bean {
      private boolean flag;
      private List<Listener> listeners = new ArrayList<Listener>();

      public setFlag(boolean flag) {
        this.flag = flag;
        if (listeners.size() > 0 ) {
            for (Listener l : this.listeners ) {
                l.handle(flag); //invoke 
            }
        }
      }

      public registerListener(Listener listener) {
        this.listeners.add(listener);
      }

      //..... other fields and methods

  }

  public class Main{

      public static void main(String[] args) {
        Bean bean  = new Bean();
        bean.registerListener(new PropertiesChangeListener());
        bean.setFlag(true); //handler method will be invoked..
      }
  }

есть 2 решения вашей проблемы

  1. используя простую Java, в этом случае вы должны добавить слушателей в свой bean (самостоятельно), а затем вызвать методы прослушивателя в методе setter (снова самостоятельно) и сделать переменную частная, поэтому его можно изменить только с помощью метода setter.
  2. второе решение использует чистую структуру AOP (я знаю, что AspectJ может это сделать), которая может перехватить модификацию вашей переменной, а затем вызвать ваш слушатель использует аспект. Я упомяну, что с помощью @AspectJ (поддержка аннотаций AspectJ) ваши аспекты будут чистыми классами Java, и нет необходимости поддерживать IDE AspectJ.