JavaFX StackPane快照不显示背景层

时间:2019-12-18 15:40:32

标签: java javafx desktop-application snapshot

我在StackPane中覆盖了两个图表(一个条形图和一个包含3个系列的折线图)。

折线图位于第一个栏的顶部,并在应用程序中正确显示。但是,当我尝试拍摄快照时,条形图不会显示。

我尝试拍摄该节点以及整个场景的快照,但是仍然没有显示。我想这与它是一个背景节点有关,但我似乎无法弄清楚如何使其显示。

 WritableImage snapshot = stackPane.snapshot(new SnapshotParameters(),null);

 ImageIO.write(SwingFXUtils.fromFXImage(snapshot,null),"png",new File("chart.png"));

我正在编辑以便添加其余代码:

控制器:

public class Controller {
    @FXML StackPane stackPane;


    public void onBtnClick(ActionEvent actionEvent) {
        Platform.runLater(new Runnable() {
            @Override
            public void run() {
                try {
                    Graphs graphs = new Graphs();
                    StackPane secondaryStackpane = graphs.call();

                    stackPane.getChildren().addAll(secondaryStackpane.getChildren());

                    WritableImage snapshot = stackPane.snapshot(new SnapshotParameters(),null);
                    ImageIO.write(SwingFXUtils.fromFXImage(snapshot,null),"png",new File("chart.png"));


                } catch (Exception ex) {
                    ex.printStackTrace();
                }
            }
        });

    }
}

Graphs类:

public class Graphs extends Task {

    StackPane stackPane;
    NumberAxis yAxis;
    NumberAxis yAxisRight;
    CategoryAxis xAxis;
    NumberAxis yAxisRightBlank;

    public Graphs() {

        stackPane = new StackPane();

        xAxis = new CategoryAxis();
        xAxis.setCategories(FXCollections.<String>observableArrayList("Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"));

        yAxis = new NumberAxis(0, 70, 10);
        yAxisRight = new NumberAxis(0, 14, 1);
        yAxisRightBlank = new NumberAxis(0, 15, 1);
        yAxisRightBlank.setSide(Side.RIGHT);

        xAxis.setLabel("Month");
        yAxis.setLabel("Level");
        yAxisRight.setLabel("Level (u)");


    }


    void createGraph() {


        BarChart<String, Number> barChart = new BarChart<String, Number>(xAxis, yAxis);
        barChart.setLegendVisible(false);
        barChart.setAnimated(false);
        barChart.getXAxis().setVisible(true);

        barChart.getData().addAll(getAverageLoadPerFTE());


        LineChart<String, Number> lineChartEffective = new LineChart<String, Number>(xAxis, yAxisRight);
        lineChartEffective.setLegendVisible(false);
        lineChartEffective.setAnimated(false);
        lineChartEffective.setCreateSymbols(true);
        lineChartEffective.setAlternativeRowFillVisible(false);
        lineChartEffective.setAlternativeColumnFillVisible(false);
        lineChartEffective.setHorizontalGridLinesVisible(false);
        lineChartEffective.setVerticalGridLinesVisible(false);
        lineChartEffective.getXAxis().setVisible(true);
        lineChartEffective.getYAxis().setVisible(false);
        lineChartEffective.getYAxis().setTickLabelsVisible(false);
        lineChartEffective.getYAxis().setOpacity(0);

        lineChartEffective.getData().addAll(getEffectiveCustomerSupport());

        barChart.setAnimated(false);
        barChart.applyCss();
        barChart.layout();

        lineChartEffective.setAnimated(false);
        lineChartEffective.applyCss();
        lineChartEffective.layout();


        stackPane.getChildren().addAll(barChart, lineChartEffective);
    }

    public StackPane call() {

        createGraph();

        Platform.runLater(new Runnable() {
            @Override
            public void run() {
                updateProgress(100, 100);
                System.out.println("from call " + progressProperty());
            }
        });

        return this.stackPane;
    }

    private XYChart.Series<String,Number> getEffectiveCustomerSupport() {
        XYChart.Series<String, Number> series = new XYChart.Series<String, Number>();
        series.getData().add(new XYChart.Data<String,Number>("Jan", 2.9 ));
        series.getData().add(new XYChart.Data<String,Number>("Feb", 2.7 ));
        series.getData().add(new XYChart.Data<String,Number>("Mar", 3.3 ));
        series.getData().add(new XYChart.Data<String,Number>("Apr", 3.4 ));
        series.getData().add(new XYChart.Data<String,Number>("May", 3.3 ));
        series.getData().add(new XYChart.Data<String,Number>("Jun", 3.2 ));
        series.getData().add(new XYChart.Data<String,Number>("Jul", 3.3 ));
        series.getData().add(new XYChart.Data<String,Number>("Aug", 4 ));
        series.getData().add(new XYChart.Data<String,Number>("Sep", 3.8 ));
        series.getData().add(new XYChart.Data<String,Number>("Oct", 4.1 ));
        series.getData().add(new XYChart.Data<String,Number>("Nov", 0 ));
        series.getData().add(new XYChart.Data<String,Number>("Dec", 0 ));


        series.setName("Effective customer support");

        return series;
    }

    private XYChart.Series<String,Number> getAverageLoadPerFTE() {
        XYChart.Series<String, Number> series = new XYChart.Series<String, Number>();
        series.getData().add(new XYChart.Data<String,Number>("Jan", 58 ));
        series.getData().add(new XYChart.Data<String,Number>("Feb", 54 ));
        series.getData().add(new XYChart.Data<String,Number>("Mar", 47 ));
        series.getData().add(new XYChart.Data<String,Number>("Apr", 34 ));
        series.getData().add(new XYChart.Data<String,Number>("May", 33 ));
        series.getData().add(new XYChart.Data<String,Number>("Jun", 32 ));
        series.getData().add(new XYChart.Data<String,Number>("Jul", 30 ));
        series.getData().add(new XYChart.Data<String,Number>("Aug", 36 ));
        series.getData().add(new XYChart.Data<String,Number>("Sep", 29 ));
        series.getData().add(new XYChart.Data<String,Number>("Oct", 33 ));
        series.getData().add(new XYChart.Data<String,Number>("Nov", 0 ));
        series.getData().add(new XYChart.Data<String,Number>("Dec", 0 ));



        series.setName("Average load per FTE");

        return series;
    }

}

1 个答案:

答案 0 :(得分:0)

这个问题本质上是重复的:

但是我将根据您问题中的代码提供一个答案,以便您可以更好地了解在特定情况下如何应用该答案。

基本上,主要问题是您没有将图形的背景色设置为透明色,因此当一个图表绘制在另一图表上时,后面的图表将不可见。这与快照例程无关,如果您只是尝试在场景中显示图表而不尝试对其进行快照,则图表将不会如您所愿的显示。

以下是使用以下更新的示例代码捕获的png:

sample png

Graphs.java

import javafx.collections.FXCollections;
import javafx.geometry.Side;
import javafx.scene.chart.*;
import javafx.scene.layout.StackPane;

public class Graphs {

    private StackPane stackPane;
    private NumberAxis yAxis;
    private NumberAxis yAxisRight;
    private CategoryAxis xAxis;
    private NumberAxis yAxisRightBlank;

    public Graphs() {
        stackPane = new StackPane();

        xAxis = new CategoryAxis();
        xAxis.setCategories(FXCollections.observableArrayList(
                "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
        ));

        yAxis = new NumberAxis(0, 70, 10);
        yAxisRight = new NumberAxis(0, 14, 1);
        yAxisRightBlank = new NumberAxis(0, 15, 1);
        yAxisRightBlank.setSide(Side.RIGHT);

        xAxis.setLabel("Month");
        yAxis.setLabel("Level");
        yAxisRight.setLabel("Level (u)");
    }

    StackPane createGraphs() {
        BarChart<String, Number> barChart = new BarChart<>(xAxis, yAxis);
        barChart.setLegendVisible(false);
        barChart.setAnimated(false);
        barChart.getXAxis().setVisible(true);

        barChart.getData().addAll(getAverageLoadPerFTE());

        LineChart<String, Number> lineChartEffective = new LineChart<>(xAxis, yAxisRight);
        lineChartEffective.setLegendVisible(false);
        lineChartEffective.setAnimated(false);
        lineChartEffective.setCreateSymbols(true);
        lineChartEffective.setAlternativeRowFillVisible(false);
        lineChartEffective.setAlternativeColumnFillVisible(false);
        lineChartEffective.setHorizontalGridLinesVisible(false);
        lineChartEffective.setVerticalGridLinesVisible(false);
        lineChartEffective.getXAxis().setVisible(true);
        lineChartEffective.getYAxis().setVisible(false);
        lineChartEffective.getYAxis().setTickLabelsVisible(false);
        lineChartEffective.getYAxis().setOpacity(0);

        lineChartEffective.getData().addAll(getEffectiveCustomerSupport());

        stackPane.getStylesheets().addAll(getClass().getResource("overlay-chart.css").toExternalForm());
        stackPane.getChildren().addAll(
                barChart,
                lineChartEffective
        );

        return stackPane;
    }

    private XYChart.Series<String, Number> getEffectiveCustomerSupport() {
        XYChart.Series<String, Number> series = new XYChart.Series<>();
        series.getData().add(new XYChart.Data<>("Jan", 2.9));
        series.getData().add(new XYChart.Data<>("Feb", 2.7));
        series.getData().add(new XYChart.Data<>("Mar", 3.3));
        series.getData().add(new XYChart.Data<>("Apr", 3.4));
        series.getData().add(new XYChart.Data<>("May", 3.3));
        series.getData().add(new XYChart.Data<>("Jun", 3.2));
        series.getData().add(new XYChart.Data<>("Jul", 3.3));
        series.getData().add(new XYChart.Data<>("Aug", 4));
        series.getData().add(new XYChart.Data<>("Sep", 3.8));
        series.getData().add(new XYChart.Data<>("Oct", 4.1));
        series.getData().add(new XYChart.Data<>("Nov", 0));
        series.getData().add(new XYChart.Data<>("Dec", 0));

        series.setName("Effective customer support");

        return series;
    }

    private XYChart.Series<String, Number> getAverageLoadPerFTE() {
        XYChart.Series<String, Number> series = new XYChart.Series<>();
        series.getData().add(new XYChart.Data<>("Jan", 58));
        series.getData().add(new XYChart.Data<>("Feb", 54));
        series.getData().add(new XYChart.Data<>("Mar", 47));
        series.getData().add(new XYChart.Data<>("Apr", 34));
        series.getData().add(new XYChart.Data<>("May", 33));
        series.getData().add(new XYChart.Data<>("Jun", 32));
        series.getData().add(new XYChart.Data<>("Jul", 30));
        series.getData().add(new XYChart.Data<>("Aug", 36));
        series.getData().add(new XYChart.Data<>("Sep", 29));
        series.getData().add(new XYChart.Data<>("Oct", 33));
        series.getData().add(new XYChart.Data<>("Nov", 0));
        series.getData().add(new XYChart.Data<>("Dec", 0));

        series.setName("Average load per FTE");

        return series;
    }
}

GraphsApp.java

import javafx.application.Application;
import javafx.embed.swing.SwingFXUtils;
import javafx.scene.Scene;
import javafx.scene.SnapshotParameters;
import javafx.scene.image.WritableImage;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;

import javax.imageio.ImageIO;
import java.io.File;

public class GraphsApp extends Application {
    @Override
    public void start(Stage stage) throws Exception {
        Graphs graphs = new Graphs();
        Pane graphPane = graphs.createGraphs();

        stage.setScene(new Scene(graphPane));
        stage.show();

        WritableImage snapshot = graphPane.snapshot(new SnapshotParameters(),null);
        File graphFile = new File("chart.png");
        ImageIO.write(
                SwingFXUtils.fromFXImage(snapshot,null),
                "png",
                graphFile
        );

        System.out.println("Wrote: " + graphFile.getAbsolutePath());
    }

    public static void main(String[] args) {
        launch(args);
    }
}

overlay-chart.css

该文件的生成目录应与Graphs Java类的类文件位于同一生成目录。

/** file: overlay-chart.css (place in same directory as LayeredXyChartsSample */
.chart-plot-background {
    -fx-background-color: transparent;
}
.default-color0.chart-series-line {
    -fx-stroke: forestgreen;
}

您的代码有很多奇怪的东西,涉及JavaFX TaskPlatform.runLater调用。对于这样的任务,不需要或不需要调用JavaFX并发结构,因此我删除了所有这些。

此外,当要求提供mcve时,请提供一些极少的内容(例如,如果不需要它来复制问题,则不要使用FXML)并且要完整,以供将来参考。只需复制并粘贴即可运行,而不必花时间进行修改,而只是试图复制问题。

请注意,使用我提供的更新代码,它现在可以绘制和快照堆积的图表,但是,我不知道它实际上是否按照您希望的那样绘制图表。例如,每个图表相对于彼此的x轴或y轴的比例和范围可能不如您希望的相对,因此,图表可能会或可能不会以对您的组合数据系列“正确”的方式绘制。如果不正确,则需要分别解决这些问题。