Adding a listener to a variable in Java/JavaFX whi

2020-07-09 02:51发布

问题:

I know that there are listeners in JavaFX, and i'm sure Java. But I'm confused as how to implement them.

I have a boolean variable that is changed throughout my program. Everytime the boolean is changed, I want a function myFunc() to be ran.

Can this be done easily?

回答1:

As simple as this:

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

and whenever you want to change the boolean flag, you should do it via this method.



回答2:

If you are using JavaFX 2 then it provides an out-of-box solutions for both JavaBeans component architecture and Observer design pattern. Moreover it gives a great flexibility of associating the state of variables by the property bindings. The code below illustrates the property changed events and the binding of property variables. Of course you can wrap the property accessors to hide details by like getFlag() and setFlag() below, and use them in the rest of application.

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);
    }
}


回答3:

I would do it using PropertyChangeListener. Here is a nice tutorial: http://docs.oracle.com/javase/tutorial/uiswing/events/propertychangelistener.html

Example of code:

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);
    }
}


回答4:

U can use Observer design pattern. Just like this:

 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..
      }
  }


回答5:

There are 2 solutions for your problem

  1. Using plain Java, in that case, you shall add listeners to your bean (by yourself) and then invoke the listener methods on the setter method (again by yourself), and make the variable private, so it can only be modified by your setter method.
  2. The second solution is using a pure AOP framework (I know AspectJ can do this), which can intercept modification of your variable, and then call your listener using an aspect. I shall mention that using @AspectJ (annotation support of AspectJ), your aspects would be pure Java classes, and there is no need to an AspectJ support IDE.