JavaFX ObjectBinding не вызывает computeValue, свойство привязки не изменяется - PullRequest
0 голосов
/ 10 мая 2019

Я пытаюсь связать цвет (заливка), который является ObjectProperty<Paint> (fillProperty) формы круга JavaFX. Для этого я использую низкоуровневую объектную привязку. Я хочу использовать Color.hsb(), чтобы создать новый цвет, используя значение оттенка, которое будет масштабироваться в соответствии с требуемым значением SpeedProperty, которое хранится в классе Car, и фактической скоростью автомобиля.

Я пробовал несколько способов привязки значения скорости автомобиля, включая DoubleBinding, чтобы сохранить значение скорости. Я также явно пытался getFill() формы Круга, поскольку я предполагал, что моя проблема была вызвана ленью Java. Но все равно безуспешно.

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 ]

1 голос
/ 10 мая 2019

Самый простой способ создать пользовательские привязки - использовать утилиту класса 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()) ;

Кроме того, есть подобные вопросы, на которые вы можете найти ответы. Как создать пользовательские типы привязки в JavaFx

0 голосов
/ 13 мая 2019

Это рабочий минимальный, полный, проверяемый пример того, как мне наконец удалось bind fillProperty формы 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


import javafx.beans.property.DoubleProperty;
import javafx.beans.property.SimpleDoubleProperty;

public class Vector2D {

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

    public Vector2D(double x, double y) {
        this.setX(x);
        this.setY(y);
    }

    public Vector2D(final Vector2D v) {
        this(v.getX(), v.getY());
    }

    public Vector2D(){this(0,0); }

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

    public void setX(double x) {  this.xProperty.setValue(x);   }

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

    public void setY(double y) {
        this.yProperty.setValue(y);
    }

    public void setVector(Vector2D vector2D) {
        setY(vector2D.getY());
        setX(vector2D.getX());
    }

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