简体   繁体   English

如何清除javafx条形图中添加的文本?

[英]How to clear text added in a javafx barchart?

I add some text at the top of bars (the value of each bar). 我在栏的顶部添加了一些文本(每个栏的值)。 It's working but the problem is I want to remove this text each time I update the chart. 它正在工作,但是问题是我想在每次更新图表时都删除此文本。 In fact, text stays after updating data. 实际上,文本在更新数据后保留。

For the first chart, since there is no previous data it's displaying correctly. 对于第一个图表,由于没有先前的数据,因此显示正确。 first chart displaying correctly without previous data

But after I update chart's data, here is what I get (it's working but previous added text remains...): 但是,在更新图表数据之后,这就是我所得到的(它正在工作,但是先前添加的文本仍然保留...):

I highlighted in red the wrong part 我用红色突出显示了错误的部分 second chart displaying wrong with previous data

I add the text on top of each bar with this method: 我使用此方法将文本添加到每个栏的顶部:

private void displayLabelForData(XYChart.Data<String, Number> data) {
    final Node node = data.getNode();
    final Text dataText = new Text(data.getYValue() + "");
    node.parentProperty().addListener(new ChangeListener<Parent>() {
      @Override public void changed(ObservableValue<? extends Parent> ov, Parent oldParent, Parent parent) {
        Group parentGroup = (Group) parent;
        parentGroup.getChildren().add(dataText);
      }
    });

    node.boundsInParentProperty().addListener(new ChangeListener<Bounds>() {
      @Override public void changed(ObservableValue<? extends Bounds> ov, Bounds oldBounds, Bounds bounds) {
        dataText.setLayoutX(
          Math.round(
            bounds.getMinX() + bounds.getWidth() / 2 - dataText.prefWidth(-1) / 2
          )
        );
        dataText.setLayoutY(
          Math.round(
            bounds.getMinY() - dataText.prefHeight(-1) * 0.5
          )
        );
      }
    });
}

My full code is available on Gist 我的完整代码可在Gist上找到

Still no answer to this... 仍然没有答案...

Thanks ! 谢谢 !

Personally I'd prefer subclassing BarChart and overriding the proper methods. 我个人更喜欢继承BarChart并覆盖适当的方法。

This is just a demo for your needs, there's refinement to be done, ie overriding all related methods, formatter for the text, centering the text, resize chart area to fit the added text, etc. But I guess you'll get the drift: 这只是一个满足您需求的演示,需要完善,即覆盖所有相关方法,文本格式化,文本居中,调整图表区域的大小以适合添加的文本等。但是我想您会发现:

import java.util.HashMap;
import java.util.Map;

import javafx.application.Application;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.chart.Axis;
import javafx.scene.chart.BarChart;
import javafx.scene.chart.CategoryAxis;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart;
import javafx.scene.control.Button;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.VBox;
import javafx.scene.text.Text;
import javafx.stage.Stage;

public class BarChartSample extends Application {

    final static String austria = "Austria";
    final static String brazil = "Brazil";
    final static String france = "France";
    final static String italy = "Italy";
    final static String usa = "USA";

    /**
     * Barchart with a clear button
     */
    @Override
    public void start(Stage stage) {

        final CategoryAxis xAxis = new CategoryAxis();
        final NumberAxis yAxis = new NumberAxis();
        final BarChartExt<String, Number> bc = new BarChartExt<String, Number>(xAxis, yAxis);

        bc.setTitle("Country Summary");
        xAxis.setLabel("Country");
        yAxis.setLabel("Value");

        XYChart.Series series1 = new XYChart.Series();
        series1.setName("2003");
        series1.getData().add(new XYChart.Data(austria, 25601.34));
        series1.getData().add(new XYChart.Data(brazil, 20148.82));
        series1.getData().add(new XYChart.Data(france, 10000));
        series1.getData().add(new XYChart.Data(italy, 35407.15));
        series1.getData().add(new XYChart.Data(usa, 12000));

        XYChart.Series series2 = new XYChart.Series();
        series2.setName("2004");
        series2.getData().add(new XYChart.Data(austria, 57401.85));
        series2.getData().add(new XYChart.Data(brazil, 41941.19));
        series2.getData().add(new XYChart.Data(france, 45263.37));
        series2.getData().add(new XYChart.Data(italy, 117320.16));
        series2.getData().add(new XYChart.Data(usa, 14845.27));

        XYChart.Series series3 = new XYChart.Series();
        series3.setName("2005");
        series3.getData().add(new XYChart.Data(austria, 45000.65));
        series3.getData().add(new XYChart.Data(brazil, 44835.76));
        series3.getData().add(new XYChart.Data(france, 18722.18));
        series3.getData().add(new XYChart.Data(italy, 17557.31));
        series3.getData().add(new XYChart.Data(usa, 92633.68));

        bc.getData().addAll(series1, series2, series3);

        Button clearButton = new Button("Clear");
        clearButton.setOnAction(e -> {

            bc.getData().clear();

        });

        HBox toolbar = new HBox();
        toolbar.getChildren().addAll(clearButton);

        VBox root = new VBox();
        VBox.setVgrow(bc, Priority.ALWAYS);
        root.getChildren().addAll(toolbar, bc);

        Scene scene = new Scene(root, 800, 600);

        stage.setScene(scene);
        stage.show();
    }

    /**
     * Custom barchart with text on top of bars
     *
     * @param <X>
     * @param <Y>
     */
    private static class BarChartExt<X, Y> extends BarChart<X, Y> {

        /**
         * Registry for text nodes of the bars
         */
        Map<Node, Node> nodeMap = new HashMap<>();

        public BarChartExt(Axis xAxis, Axis yAxis) {
            super(xAxis, yAxis);
        }

        /**
         * Add text for bars
         */
        @Override
        protected void seriesAdded(Series<X, Y> series, int seriesIndex) {

            super.seriesAdded(series, seriesIndex);

            for (int j = 0; j < series.getData().size(); j++) {

                Data<X, Y> item = series.getData().get(j);

                Node text = new Text(String.valueOf(item.getYValue()));
                nodeMap.put(item.getNode(), text);
                getPlotChildren().add(text);

            }

        }

        /**
         * Remove text of bars
         */
        @Override
        protected void seriesRemoved(final Series<X, Y> series) {

            for (Node bar : nodeMap.keySet()) {

                Node text = nodeMap.get(bar);
                getPlotChildren().remove(text);

            }

            nodeMap.clear();

            super.seriesRemoved(series);
        }

        /**
         * Adjust text of bars, position them on top
         */
        @Override
        protected void layoutPlotChildren() {

            super.layoutPlotChildren();

            for (Node bar : nodeMap.keySet()) {

                Node text = nodeMap.get(bar);

                text.relocate(bar.getBoundsInParent().getMinX(), bar.getBoundsInParent().getMinY() - 30);

            }

        }
    }

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

Screenshot: 屏幕截图:

在此处输入图片说明

Thanks to Roland I was able to create the following chart with fixed alignments. 多亏了Roland,我得以创建以下具有固定路线的图表。 This might be helpful for someone due the lack of proposed solutions for this problem. 由于缺少针对此问题的建议解决方案,这可能对某人有所帮助。

在此处输入图片说明

public class CustomBarChart<X, Y> extends BarChart<X, Y> {

    Map<Node, TextFlow> nodeMap = new HashMap<>();

    public CustomBarChart(Axis xAxis, Axis yAxis) {
        super(xAxis, yAxis);
        this.setBarGap(0.0);
    }

    @Override
    protected void seriesAdded(Series<X, Y> series, int seriesIndex) {

        super.seriesAdded(series, seriesIndex);

        for (int j = 0; j < series.getData().size(); j++) {

            Data<X, Y> item = series.getData().get(j);

            Text text = new Text(item.getYValue().toString());
            text.setStyle("-fx-font-size: 10pt;");

            TextFlow textFlow = new TextFlow(text);
            textFlow.setTextAlignment(TextAlignment.CENTER);

            nodeMap.put(item.getNode(), textFlow);
            this.getPlotChildren().add(textFlow);

        }

    }

    @Override
    protected void seriesRemoved(final Series<X, Y> series) {

        for (Node bar : nodeMap.keySet()) {

            Node text = nodeMap.get(bar);
            this.getPlotChildren().remove(text);

        }

        nodeMap.clear();

        super.seriesRemoved(series);
    }

    @Override
    protected void layoutPlotChildren() {

        super.layoutPlotChildren();

        for (Node bar : nodeMap.keySet()) {

            TextFlow textFlow = nodeMap.get(bar);

            if (bar.getBoundsInParent().getHeight() > 30) {
                ((Text) textFlow.getChildren().get(0)).setFill(Color.WHITE);
                textFlow.resize(bar.getBoundsInParent().getWidth(), 200);
                textFlow.relocate(bar.getBoundsInParent().getMinX(), bar.getBoundsInParent().getMinY() + 10);
            } else {
                ((Text) textFlow.getChildren().get(0)).setFill(Color.GRAY);
                textFlow.resize(bar.getBoundsInParent().getWidth(), 200);
                textFlow.relocate(bar.getBoundsInParent().getMinX(), bar.getBoundsInParent().getMinY() - 20);
            }
        }
    }
}

I have found only one solution, which is to clear every parentNode of each Data when you receive an update. 我发现只有一种解决方案,即在收到更新时清除每个数据的每个父节点。 You'll reconstruct the whole series then. 然后,您将重建整个系列。 As follow, it works but I didn't check the performance. 如下所示,它可以工作,但是我没有检查性能。 On my environment it's pretty fast : 在我的环境中,速度非常快:

ObservableList<Series<String, Number>> allSeries = yourBarChart.getData();
    if (updateReceived) {
        for (XYChart.Series<String, Number> series : allSeries) {
            for (XYChart.Data<String, Number> data : series.getData()) {
                Node node = data.getNode();
                Parent parent = node.parentProperty().get();
                if (parent != null && parent instanceof Group) {
                    Group group = (Group) parent;
                    group.getChildren().clear();
                }
            }
        }
        allSeries.clear();
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM