【问题标题】:JavaFX LineChart - move a line in front when click on legendJavaFX LineChart - 单击图例时在前面移动一条线
【发布时间】:2019-08-09 10:20:03
【问题描述】:

这是接口代码:

@Override
public void start(Stage primaryStage){

    NumberAxis xAxis = new NumberAxis();
    xAxis.setLabel("XX");

    NumberAxis yAxis = new NumberAxis();
    yAxis.setLabel("YY");

    LineChart<Number, Number> lineChart = new LineChart<>(xAxis, yAxis);
    lineChart.setLegendVisible(false);

    XYChart.Series<Number, Number> series1 = new XYChart.Series<>();
    series1.setName("Line1");
    series1.getData().add(new XYChart.Data<>(1, 1));
    series1.getData().add(new XYChart.Data<>(2, 2));
    series1.getData().add(new XYChart.Data<>(3, 2));
    series1.getData().add(new XYChart.Data<>(4, 1));

    XYChart.Series<Number, Number> series2 = new XYChart.Series<>();
    series2.setName("Line2");
    series2.getData().add(new XYChart.Data<>(2, 2));
    series2.getData().add(new XYChart.Data<>(3, 2));
    series2.getData().add(new XYChart.Data<>(4, 2));

    XYChart.Series<Number, Number> series3 = new XYChart.Series<>();
    series3.setName("Line3");
    series3.getData().add(new XYChart.Data<>(1, 3));
    series3.getData().add(new XYChart.Data<>(2, 2));
    series3.getData().add(new XYChart.Data<>(3, 1));
    series3.getData().add(new XYChart.Data<>(3, 2));

    List<XYChart.Series<Number, Number>> seriesList = Arrays.asList(series1, series2, series3);

    lineChart.getData().addAll(seriesList);

    HBox legendBox = new HBox();
    legendBox.setStyle("-fx-alignment: center; -fx-padding: 10;");

    Insets insets = new Insets(0, 10, 0, 10);

    for(Node legend : lineChart.lookupAll(".chart-legend-item")){

        Label label = (Label)legend;

        label.setOnMouseClicked(e -> {

            XYChart.Series<Number, Number> toFront = seriesList.stream()
                                                                .filter(e1 -> e1.getName().equals(label.getText()))
                                                                .findFirst().get();

            System.out.println(toFront);


            //put series toFront over all other series
            //i don't know how//

            /*I have tried this
            Platform.runLater(() -> {

                lineChart.getData().remove(toFront);
                lineChart.getData().add(toFront); //first time click: Duplicate, after only NullPointer

            });*/

        });

        legendBox.getChildren().add(label);
        HBox.setMargin(label, insets);

    }

    BorderPane borderPane = new BorderPane();
    borderPane.setCenter(lineChart);
    borderPane.setBottom(legendBox);

    primaryStage.setScene(new Scene(borderPane));
    primaryStage.sizeToScene();
    primaryStage.centerOnScreen();

    primaryStage.show();

}

界面是这样的:

正如您在图片中看到的,您无法知道Line1Line2 的确切路径。

我想在图例上加上EventHandler。当您单击其中一个图例时,将图例线放在图表前面,覆盖所有其他线。

如您所见,带有EventHandler 的代码已写入。确定系列后,我不知道该怎么办。我试图从图表中删除并再次添加:

Platform.runLater(() -> {

    lineChart.getData().remove(toFront);
    lineChart.getData().add(toFront);

});

仅删除行和结果错误:

1. First click: "Duplicate series added" //at line with add
2. Next clicks: "NullPointerException" //at line with add

【问题讨论】:

  • 我相信这些线/点都是在同一个父节点中绘制的,这意味着您可以尝试设置该系列的节点的view order 以及该系列中每个数据的节点。跨度>
  • 但是我如何找到父节点?
  • Node 有一个 parent 属性。但是,您不需要父节点。查看顺序应在Series#node 属性和每个Data#node 属性中的Node 上设置(在所说的Series 中)。注意我还没有尝试过,所以如果你发现它不起作用,请告诉我。
  • @Slaw toFront.getNode().setViewOrder(10); - toFront.getData().forEach(e1 -&gt; e1.getNode().setViewOrder(10)); - 发生了一些事情,但这不是我想要的,我也不太明白发生了什么,因为有时把它放回去,有时什么也没发生。你能帮我写代码吗?如果你有时间。
  • @Slaw 我找到了。 toFront() 有一个方法 Node 有它。感谢您的时间。同样首先我理解错误setViewOrder 使用。我以为它设置了z-coord。实际上它就像在数组中使用索引一样(较低的值表示第一个元素)。

标签: java javafx


【解决方案1】:

我知道了。

我的代码很好:

 Platform.runLater(() -> {

    lineChart.getData().remove(toFront);
    lineChart.getData().add(toFront);

});

问题出在移除时的动画。

修复我设置的问题:lineChart.setAnimated(false);

更新

我找到了一个不妥协的更好的解决方案setAnimated

删除系列并重新添加它,您可以简单地使用toFront() 类具有它的方法Node

这是替换上面代码的代码。

toFront.getNode().toFront();
toFront.getData().forEach(e1 -> e1.getNode().toFront());

如果您更改系列的颜色,此代码也会更好。如果 remove-add 需要重新着色前面移动的行,但如果 Node#toFront 不需要。

【讨论】:

  • @Sedrick 也许这个信息可以帮助你。
  • 很高兴您找到了toFront() 形式的解决方案,但请注意,该方法会导致子列表在结构上被修改。如果这不是问题,请随时继续使用toFront();也就是说,我建议 viewOrder 的原因是因为该属性可以修改 z 顺序 结构上修改子列表。当然,您需要“重置”“旧”系列的viewOrder
  • structurally modified?你能解释一下吗?
  • toFront() 方法实际上改变了子列表的顺序。如果您查看实现,您会看到它删除了Node,然后将其重新添加到列表的末尾(toBack() 将其重新添加到列表的开头)。这样做是因为 the z-order is solely determined by the order of the children list——也就是说,直到他们在 JavaFX 9 中添加了 viewOrder 属性(但请阅读该属性的文档,它与结构修改完全不同孩子名单)。
  • 源代码包含在发行版中(包括 OpenJDK 和 OpenJFX)。如果您通过构建工具(例如 Maven 或 Gradle)包含 JavaFX,则可以通过您的 IDE 下载源代码。然后,您只需使用 IDE 导航代码(您可能必须“链接”源代码)。例如,在 IntelliJ 中,只需将鼠标悬停在您感兴趣的方法上并 Ctrl+单击它;如果 IDE 知道适当的源文件,它将带您到它。
猜你喜欢
  • 2015-06-10
  • 1970-01-01
  • 2014-01-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多