JavaFX ObjectBinding不会触发computeValue,bound属性不会更改

时间:2019-05-10 11:15:33

标签: java javafx properties binding

我正在尝试绑定JavaFX Circle Shape的ObjectProperty<Paint> (fillProperty)的颜色(填充)。为此,我正在使用低级别的ObjectBinding。我想使用Color.hsb()通过色相值创建新颜色,该色相值将根据存储在Car类中的所需SpeedProperty和汽车的实际速度进行缩放。

我尝试了多种方法来绑定Car的速度值,包括DoubleBinding来存储速度值。我还假设我的问题是由Java的懒惰引起的,因此也明确尝试了getFill()的Circle形状。但是仍然没有成功。

Circle carShape  = new Circle();
ObjectBinding<Paint> colorObjectBinding = new ObjectBinding<Paint>() {
            {
                super.bind(car.getSpeed().getXProperty(),car.getSpeed().getYProperty(),car.getParameters().desiredSpeedProperty());
            }
            @Override
            protected Paint computeValue() {
                double speedX = car.getSpeed().getX();
                double speedY = car.getSpeed().getY();
                Color color = Color.hsb(Math.sqrt(speedX*speedX+speedY*speedY)*110/car.getParameters().getDesiredSpeed(),0.94,0.94,0.94);
                return color;
            }
        };
        carShape.fillProperty().bind(colorObjectBinding);

car.speed类型为Vector2D,它使用DoubleProperty存储向量的x和y值。

public class Vector2D implements Iterable<DoubleProperty>{

    private DoubleProperty xProperty = new SimpleDoubleProperty(0);
    private DoubleProperty yProperty = new SimpleDoubleProperty(0);

    public DoubleProperty getXProperty() { return xProperty; }
    public DoubleProperty getYProperty() { return yProperty; }

    public double getX() { return xProperty.getValue(); }
    public double getY() { return yProperty.getValue(); }

desiredSpeed也是DoubleProperty

private DoubleProperty desiredSpeed = new SimpleDoubleProperty(0);

public double getDesiredSpeed() { return desiredSpeed.get(); }

我希望汽车的颜色随着速度的变化而变化。但是,圆在创建时仅用红色(0xf00e0ef0)上色(我怀疑这是因为初始速度为零,因此色相为0,红色为红色)

更新

我发现了自己的错误,问题出在方法car.getSpeed()

public Vector2D getSpeed() { return new Vector2D(speed);  }

如您所见,这将返回速度对象的一个​​副本,该副本随后被绑定,这当然是无意义的,因为该副本极有可能永远不会被更改或再次使用。 :(:0

2 个答案:

答案 0 :(得分:1)

创建自定义绑定的最简单方法是使用Bindings类的实用程序(在您的情况下为Bindings#createObjectBinding())。例如:

Bindings.createObjectBinding(() -> {
    double speedX = car.getSpeed().getX();
    double speedY = car.getSpeed().getY();
    Color color = Color.hsb(Math.sqrt(speedX*speedX+speedY*speedY)*110/car.getParameters().getDesiredSpeed(),0.94,0.94,0.94);
    return color;
}, car.getSpeed().getXProperty(),car.getSpeed().getYProperty(),car.getParameters().desiredSpeedProperty()) ;

此外,还有类似的类似问题,您可能会找到答案。 How to create custom binding types in JavaFx

答案 1 :(得分:0)

这是一个有效的最小,完整,可验证的示例,它说明了我如何最终bind形状为fillProperty的{​​{1}}。时间轴只是检查颜色变化是否正在响应的一种方式。

Circle

以及import javafx.animation.Animation; import javafx.animation.KeyFrame; import javafx.animation.Timeline; import javafx.application.Application; import javafx.beans.binding.Bindings; import javafx.beans.binding.ObjectBinding; import javafx.scene.Group; import javafx.scene.Scene; import javafx.scene.paint.Color; import javafx.scene.shape.Circle; import javafx.stage.Stage; import javafx.util.Duration; import tomek.szypula.math.Vector2D; import java.util.concurrent.Callable; public class ColorBindingTest extends Application { public static void main(String[] args) { launch(args); } final private double maxSpeed = 10; final private double maxColor = 110; //Green @Override public void start(Stage primaryStage) { Group root = new Group(); Scene theScene = new Scene( root,1100, 800 ); primaryStage.setTitle("ColorBindingTest"); primaryStage.setScene(theScene); Circle carShape = new Circle(); Vector2D speed = new Vector2D(); carShape.setCenterX(100); carShape.setCenterY(100); carShape.setRadius(10); root.getChildren().add(carShape); ObjectBinding<Color> colorObjectBinding1 = Bindings.createObjectBinding( new Callable<Color>() { @Override public Color call() throws Exception { double speedX = speed.getX(); double speedY = speed.getY(); Color color = Color.hsb(Math.sqrt(speedX*speedX+speedY*speedY)*maxColor/maxSpeed,0.94,0.94,0.94); return color; } },speed.getXProperty(),speed.getYProperty() ); carShape.fillProperty().bind(colorObjectBinding1); Timeline timeline = new Timeline(new KeyFrame( Duration.millis(200), ae -> { speed.setX(Math.random()*maxSpeed); })); timeline.setCycleCount(Animation.INDEFINITE); timeline.play(); primaryStage.show(); } } 类的最小版本,也可以将其替换为Vector2D

DoubleProperty