我有一个包含许多系列的折线图。这些系列分为一个或多个超级系列。每个超级系列可能在行中有许多“中断”,以便准确地描述监视器进程何时没有主动收集数据。每个数据中断实际上都是开始一个新系列。
我已经成功克服了一些技术问题,例如图表为每个新系列分配了一种新颜色,图表线符号颜色与系列颜色不匹配等等。现在一切都很好,除了每次我向图表添加新系列时,它都会向图例添加一个项目。
有没有办法从图例中删除项目,还是我必须隐藏默认图例并添加我自己的自定义图例窗格?
答案 0 :(得分:14)
答案 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")); ... }