Velaniv Jr
Velaniv Jr

Reputation: 164

How to cover chart plot with AnchorPane in JavaFX 8?

This is a continuation of this question.

I am trying to cover chart plot with an AnchorPane, i called it buffer.

enter image description here

Here is a code example.

package launcher;

import javafx.application.Application;
import javafx.geometry.Bounds;
import javafx.geometry.Side;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.chart.LineChart;
import javafx.scene.chart.NumberAxis;
import javafx.scene.layout.AnchorPane;
import javafx.stage.Stage;

public class Main extends Application {

    @Override
    public void start(Stage primaryStage) throws Exception {

        NumberAxis numberAxis = new NumberAxis();
        LineChart<Number, Number> chart = new LineChart<>(numberAxis, new NumberAxis());
        chart.getYAxis().setSide(Side.RIGHT);

        AnchorPane buffer = new AnchorPane();
        buffer.setStyle("-fx-background-color: gray;" +
                "-fx-opacity: 0.5");

        AnchorPane anchorPane = new AnchorPane();
        AnchorPane.setTopAnchor(chart, 0.0);
        AnchorPane.setRightAnchor(chart, 0.0);
        AnchorPane.setBottomAnchor(chart, 0.0);
        AnchorPane.setLeftAnchor(chart, 0.0);

        anchorPane.getChildren().addAll(chart, buffer);

        Scene scene = new Scene(anchorPane);
        primaryStage.setScene(scene);
        primaryStage.setMaximized(true);

        primaryStage.show();

        resetBuffer(chart, buffer, anchorPane);

        anchorPane.widthProperty().addListener((observable, oldValue, newValue) -> {

            resetBuffer(chart, buffer, anchorPane);
        });
    }

    private void resetBuffer(LineChart<Number, Number> chart, AnchorPane buffer,
                             AnchorPane anchorPane) {
        Node chartPlot = chart.lookup(".chart-plot-background");

        Bounds bounds = anchorPane.sceneToLocal(
                chartPlot.localToScene(chartPlot.getBoundsInLocal()));

        buffer.setPrefWidth(bounds.getWidth());
        buffer.setPrefHeight(bounds.getHeight());

        AnchorPane.setLeftAnchor(buffer, bounds.getMinX());
        AnchorPane.setTopAnchor(buffer, bounds.getMinY());
    }
}

Everything works fine until I resize the stage. When I resize the AnchorPane (buffer) is not covering a chart plot properly. i.e. it is not fitting the size.

How to fix it or do it in proper way?

Upvotes: 7

Views: 370

Answers (3)

negste
negste

Reputation: 323

Simply wrap your call to resetBuffer in a Platform.runLater, like this:

anchorPane.widthProperty().addListener((observable, oldValue, newValue) -> {
    Platform.runLater(() -> {
        resetBuffer(chart, buffer, anchorPane);
    });
});

This way you will be sure that your code is executed after the chart has been laid out

Upvotes: 0

Sarel Foyerlicht
Sarel Foyerlicht

Reputation: 927

Hope this will solve it:

First solution:

    double sideSizeWidth = (anchorPane.getWidth()-bounds.getWidth());
    double sideSizeHeight= (anchorPane.getHeight()-bounds.getHeight());

    buffer.prefWidthProperty().bind(Bindings.add(
            chart.widthProperty(),
            -sideSizeWidth
    ));
    buffer.prefHeightProperty().bind(Bindings.add(
            chart.heightProperty(),
            -sideSizeHeight
    ));

(it need to be in resetBuffer and it needs to call only one time at the beginning of course after primaryStage.show())

Second solution:

 scene.widthProperty().addListener(new ChangeListener<Number>() {
            @Override
            public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
                double dif =oldValue.doubleValue()-newValue.doubleValue();
                buffer.setPrefWidth(buffer.getWidth()-(dif));
            }
        });
        scene.heightProperty().addListener(new ChangeListener<Number>() {
            @Override
            public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
                double dif =oldValue.doubleValue()-newValue.doubleValue();
                buffer.setPrefHeight(buffer.getHeight()-(dif));
            }
        });

it base on the fact that width and hight is permanent in the axis label and legend, so we just need to calculate the diffrent on the scene size an apply on buffer.

the all code:

public class Main extends Application {

    @Override
    public void start(Stage primaryStage) throws Exception {
        NumberAxis numberAxis = new NumberAxis();
        LineChart<Number, Number> chart = new LineChart<>(numberAxis, new NumberAxis());
        chart.getYAxis().setSide(Side.RIGHT);

        AnchorPane buffer = new AnchorPane();
        buffer.setStyle("-fx-background-color: gray;" +
                "-fx-opacity: 0.5");

        AnchorPane anchorPane = new AnchorPane();
        AnchorPane.setTopAnchor(chart, 0.0);
        AnchorPane.setRightAnchor(chart, 0.0);
        AnchorPane.setBottomAnchor(chart, 0.0);
        AnchorPane.setLeftAnchor(chart, 0.0);

        anchorPane.getChildren().addAll(chart, buffer);

        Scene scene = new Scene(anchorPane);
        primaryStage.setScene(scene);
        primaryStage.setMaximized(true);

        primaryStage.show();

        resetBuffer(chart, buffer, anchorPane,scene);



    }

    private void resetBuffer(LineChart<Number, Number> chart, AnchorPane buffer,
                             AnchorPane anchorPane,Scene scene) {
        Node chartPlot = chart.lookup(".chart-plot-background");

        Bounds bounds = anchorPane.sceneToLocal(
                chartPlot.localToScene(chartPlot.getBoundsInLocal()));

        buffer.setPrefWidth(bounds.getWidth());
        buffer.setPrefHeight(bounds.getHeight());

        AnchorPane.setLeftAnchor(buffer, bounds.getMinX());
        AnchorPane.setTopAnchor(buffer, bounds.getMinY());

        scene.widthProperty().addListener(new ChangeListener<Number>() {
            @Override
            public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
                double dif =oldValue.doubleValue()-newValue.doubleValue();
                buffer.setPrefWidth(buffer.getWidth()-(dif));
            }
        });
        scene.heightProperty().addListener(new ChangeListener<Number>() {
            @Override
            public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
                double dif =oldValue.doubleValue()-newValue.doubleValue();
                buffer.setPrefHeight(buffer.getHeight()-(dif));
            }
        });

    }
}

Upvotes: 2

Mustahsan
Mustahsan

Reputation: 3862

Update: Instead of Adding Listener to widthProperty add Listener to prefWidthProperty e.g:

anchorPane.prefWidthProperty().addListener((observable, oldValue, newValue) -> {

            resetBuffer(chart, buffer, anchorPane);
        }); 

OLD

you can try to bind buffer prefWidth and prefHeight with anchorPane's prefWidth and prefHeight e.g

buffer.prefWidthProperty().bind(anchorPane.widthProperty());
buffer.prefHeightProperty().bind(anchorPane.heightProperty());

It will bind the buffers width and height with anchorPane's width and height so whenever the size of anchorPane change buffer's size also changes. You also dont need resize buffer just use this code in your class

@Override
    public void start(Stage primaryStage) throws Exception {

        NumberAxis numberAxis = new NumberAxis();
        LineChart<Number, Number> chart = new LineChart<>(numberAxis, new NumberAxis());
        chart.getYAxis().setSide(Side.RIGHT);

        AnchorPane buffer = new AnchorPane();
        buffer.setStyle("-fx-background-color: gray;"
                + "-fx-opacity: 0.5");

        AnchorPane anchorPane = new AnchorPane();
        AnchorPane.setTopAnchor(chart, 0.0);
        AnchorPane.setRightAnchor(chart, 0.0);
        AnchorPane.setBottomAnchor(chart, 0.0);
        AnchorPane.setLeftAnchor(chart, 0.0);

        anchorPane.getChildren().addAll(chart, buffer);

        Scene scene = new Scene(anchorPane);
        primaryStage.setScene(scene);
        primaryStage.setMaximized(true);

        primaryStage.show();

        buffer.prefWidthProperty().bind(anchorPane.widthProperty());
        buffer.prefHeightProperty().bind(anchorPane.heightProperty());

    }

Upvotes: 0

Related Questions