如何在JavaFX 8中使用AnchorPane覆盖图表绘图?

7
这是问题的续篇。
我正在尝试使用AnchorPane(我称之为buffer)覆盖图表绘制。

enter image description here

这是一个代码示例。
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());
    }
}

一切都正常工作,直到我调整舞台大小。当我调整AnchorPane(缓冲区)的大小时,它不能正确覆盖图表绘图。即它不适合尺寸。

如何修复或以正确的方式执行?

3个回答

2
希望这可以解决问题:
第一种解决方案:
    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
    ));

(它需要在resetBuffer中,并且它只需要在primaryStage.show()之后的课程开始时调用一次)

第二个解决方案:

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

这基于轴标签和图例中宽度和高度是固定的事实,因此我们只需要计算 scene 大小上的差异并应用于 buffer

完整代码如下:

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

    }
}

非常高效 -> double dif =oldValue.doubleValue()-newValue.doubleValue();. +1 - Velaniv Jr

0

更新: 不要将监听器添加到widthProperty,而是添加到prefWidthProperty,例如:

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

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

翻译

你可以尝试将缓冲区的prefWidth和prefHeight与anchorPane的prefWidth和prefHeight绑定,例如:

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

它将绑定缓冲区的宽度和高度与锚点面板的宽度和高度,因此每当锚点面板的大小改变时,缓冲区的大小也会改变。您也不需要调整缓冲区的大小,只需在您的类中使用此代码即可。
@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());

    }

你可以将AnchorPane替换为Chart。 - Mustahsan
请检查更新的答案,它已经解决了问题,并且即使调整大小也可以正常工作。 - Mustahsan
我也尝试过了,问题一样。你可能会注意到,当你快速调整大小时,大小不匹配。 - Velaniv Jr
这里是演示视频。注:很抱歉帧率较低,我没有这样高端的系统。 - Mustahsan
让我们在聊天中继续这个讨论。 - Velaniv Jr

0
只需在调用 resetBuffer 的代码中加入 Platform.runLater,就像这样:
anchorPane.widthProperty().addListener((observable, oldValue, newValue) -> {
    Platform.runLater(() -> {
        resetBuffer(chart, buffer, anchorPane);
    });
});

通过这种方式,您可以确保在图表布局完成后执行您的代码


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接