删除JavaFX 2 LineChart图例项

时间:2014-01-07 22:17:55

标签: charts javafx-2

我有一个包含许多系列的折线图。这些系列分为一个或多个超级系列。每个超级系列可能在行中有许多“中断”,以便准确地描述监视器进程何时没有主动收集数据。每个数据中断实际上都是开始一个新系列。

我已经成功克服了一些技术问题,例如图表为每个新系列分配了一种新颜色,图表线符号颜色与系列颜色不匹配等等。现在一切都很好,除了每次我向图表添加新系列时,它都会向图例添加一个项目。

有没有办法从图例中删除项目,还是我必须隐藏默认图例并添加我自己的自定义图例窗格?

4 个答案:

答案 0 :(得分:14)

Don't show the legend

chart.setLegendVisible(false);

然后,您可以创建自己的自定义窗格以制作自己的图例,并按照您的意愿进行渲染。

答案 1 :(得分:1)

在尝试实施各种建议失败后,我发现允许用户在JavaFx图表(或其子类)中显示/隐藏数据系列的最佳方法是扩展您要使用的图表类并覆盖其updateLegend()方法。

实际上它非常简单。这是一个使用基本HBox作为包含复选框作为图例项的图例的示例。在这个例子中,我决定使用固定轴类型(CategoryAxis和NumberAxis)创建LineChart。你可以选择让你的子类使用轴的泛型。

public class AtopLineChart<X, Y> extends LineChart<String, Number>
{

   /**
    * @param xAxis
    * @param yAxis
    */
   public AtopLineChart(final CategoryAxis xAxis, final NumberAxis yAxis)
   {
      super(xAxis, yAxis);
   }

   /* (non-Javadoc)
    * @see javafx.scene.chart.LineChart#updateLegend()
    */
   @Override
   protected void updateLegend()
   {
      final HBox legend = new HBox();
      legend.setVisible(true);
      for (final javafx.scene.chart.XYChart.Series<String, Number> series : getData())
      {
         final CheckBox cb = new CheckBox(series.getName());
         cb.setUserData(series);
         cb.setSelected(true);
         cb.addEventHandler(ActionEvent.ACTION, e ->
         {
            final CheckBox box = (CheckBox) e.getSource();
            @SuppressWarnings("unchecked")
            final Series<String, Number> s = (Series<String, Number>) box.getUserData();
            s.getNode().setVisible(box.isSelected());
         });
         legend.getChildren().add(cb);
      }
      setLegend(legend);
   }
}

我会将其作为练习让读者更具可读性,例如,每个复选框周围的边框,并将系列的颜色绑定到系列复选框中显示该颜色的内容。

另外一件事,您可能需要检查getLegendSide()方法以确定要用于图例的布局容器类型,即用于TOP和BOTTOM的HBox,用于LEFT和RIGHT的VBOX。你的选择。

答案 2 :(得分:0)

您可以使用此方法找到基于其类型(以及可选的样式名称)的节点:

private static Node findNode(final Parent aParent, final String aClassname, final String aStyleName) {

    if (null != aParent) {
        final ObservableList<Node> children = aParent.getChildrenUnmodifiable();
        if (null != children) {
            for (final Node child : children) {

                String className = child.getClass().getName();

                if (className.contains("$")) {
                    className = className.substring(0, className.indexOf("$"));
                }

                if (0 == aClassname.compareToIgnoreCase(className)) {
                    if ((null == aStyleName) || (0 == aStyleName.length())) {
                        // No aStyleName, just return this:
                        return child;
                    }
                    else {
                        final String styleName = child.getStyleClass().toString();
                        if (0 == aStyleName.compareToIgnoreCase(styleName)) {
                            return child;
                        }
                    }
                }

                if (child instanceof Parent) {
                    final Node node = findNode((Parent) child, aClassname, aStyleName);

                    if (null != node) {
                        return node;
                    }
                }
            }
        }
    }

    return null;
}

使用相关图表调用它以检索Legend节点:

Legend legend = (Legend) findNode(chart, Legend.class.getName(), "chart-legend");

然后您可以遍历子项并删除不想显示的项目:

    for (final Node legendItem : legend.getChildren()) {

        final Label legendLabel = (Label) legendItem;

        if (0 == legendLabel.getText().compareToIgnoreCase("the name of the legend I want hidden (or replaced with some other test)")) {
            legend.getChildren().remove(legendItem);
            break;
        }
    }

JavaFX还有一个lookup函数,它根据给定的CSS选择器“查找此节点或第一个子节点”。并且与此答案中的findNode函数类似。

答案 3 :(得分:0)

在类似情况下,https://stackoverflow.com/a/27819227/2341336

此解决方案利用Java中的流并直接修改Legend对象。

但是,此方法已被弃用,因此不建议使用。

  

由于您已经在处理Legend,因此可以使用它的   项,删除不需要的项,因此图例仅显示两个   项目。

     

使用流,您可以将前两个项目标记为“有效” /“无效”   剩下的作为“删除”,最后,您只需删除   这些最后的项目。

private void updateStyleSheet() {
    Legend legend = (Legend)lineChart.lookup(".chart-legend");
    AtomicInteger count = new AtomicInteger();
    legend.getItems().forEach(item->{
        if(count.get()==0){
            item.setText("Valid");
        } else if(count.get()==1){
            item.setText("Invalid");
        } else {
            item.setText("Remove");
        }
        count.getAndIncrement();
    });
    legend.getItems().removeIf(item->item.getText().equals("Remove"));

    ...
}