Charts 删除JavaFX2线条图图例项
我有很多系列的折线图。这些系列分为一个或多个超级系列。每一个超级系列在一行中可能有许多“中断”,以便准确地描述监视器进程何时没有积极地收集数据。每个数据中断实际上都在开始一个新的系列 我已经成功地克服了一些技术问题,例如图表为每个新系列分配了新颜色,图表线条符号颜色与系列颜色不匹配,等等。现在一切都运行得很好,只是每次我向图表添加新系列时,都会在图例中添加一个项目 有没有办法从图例中删除项目,或者我必须隐藏默认图例并添加自己的自定义图例窗格?:Charts 删除JavaFX2线条图图例项,charts,javafx-2,Charts,Javafx 2,我有很多系列的折线图。这些系列分为一个或多个超级系列。每一个超级系列在一行中可能有许多“中断”,以便准确地描述监视器进程何时没有积极地收集数据。每个数据中断实际上都在开始一个新的系列 我已经成功地克服了一些技术问题,例如图表为每个新系列分配了新颜色,图表线条符号颜色与系列颜色不匹配,等等。现在一切都运行得很好,只是每次我向图表添加新系列时,都会在图例中添加一个项目 有没有办法从图例中删除项目,或者我必须隐藏默认图例并添加自己的自定义图例窗格?: 然后,您可以创建自己的自定义窗格来创建自己的图例,
然后,您可以创建自己的自定义窗格来创建自己的图例,并按照自己的意愿进行渲染。您可以使用以下方法根据节点的类型(以及可选的样式名称)查找节点:
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;
}
然后,您可以遍历子项并删除不希望显示的子项:
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还有一个函数,它“根据给定的CSS选择器查找此节点或第一个子节点”,其作用类似于此答案中的
findNode
函数。在多次尝试实现各种建议失败后,我发现允许用户在JavaFX图表中显示/隐藏数据序列的最佳方法(或其子类)是扩展要使用的图表类并重写其UpdateGend()方法
实际上很简单。下面是一个使用基本HBox作为图例的示例,其中包含复选框作为图例项。在这个示例中,我决定使用固定轴类型(CategoryAxis和NumberAxis)制作线条图。您可以选择在子类中留下轴的泛型
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);
}
}
公共类AtopLineChart扩展线形图
{
/**
*@param xAxis
*@param yAxis
*/
公共ATOLINECHART(最终分类为yAxis,最终编号为yAxis)
{
超级(xAxis,yAxis);
}
/*(非Javadoc)
*@see javafx.scene.chart.LineChart#updateLegend()
*/
@凌驾
受保护的void updateGend()
{
最终HBox图例=新HBox();
图例.setVisible(真);
对于(最终的javafx.scene.chart.XYChart.Series系列:getData())
{
最终复选框cb=新复选框(series.getName());
cb.setUserData(系列);
cb.已选择(正确);
cb.addEventHandler(ActionEvent.ACTION,e->
{
最终复选框=(复选框)e.getSource();
@抑制警告(“未选中”)
最终系列s=(系列)box.getUserData();
s、 getNode().setVisible(box.isSelected());
});
legend.getChildren().add(cb);
}
设置图例(图例);
}
}
我将把它作为一个练习留给读者,让图例更具可读性,例如,每个复选框周围都有边框,并将系列的颜色绑定到在系列复选框中显示该颜色的内容上
还有一件事,您可能需要检查getLegendSide()方法以确定图例使用哪种布局容器,即HBox表示顶部和底部,而VBOX表示左侧和右侧。您可以选择。来自类似案例
此解决方案利用Java中的流,直接修改Legend
对象
但是,不推荐使用此选项,因此不建议使用此选项
由于您已经在处理图例
,因此可以使用其
项目,删除不需要的项目,因此图例仅显示两个项目
项目
使用streams,您可以将前两项标记为“有效”/“无效”
其他的都是“移除”,例如,最后你只是移除
这些是最后的项目
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"));
...
}
谢谢!这就是我害怕的。:)嘿@jewelsea,如果你不介意的话,还有一个问题。我已经创建了自己的自定义窗格来显示自定义图例。它看起来几乎和原作一模一样。我唯一的问题是,当只有几个系列时,它会缩小宽度。图表和图例位于对话框的VBox中,图例位于VBox底部的堆栈窗格中。高度会适当变化。你还有什么智慧的话可以帮我吗?是的,但是请提出一个新的问题,并将你当前的代码作为一个答案加入其中。再次感谢。我能够在我的图例上使用
setPrefColumns()
方法克服我的挑战,该图例是TilePane
的一个实例。您可以更改标准图例,请参见下面的示例代码。getChildren()方法对图例类不可见。方法getchildren()在父类中受保护,并按区域等扩展到Legend类。此外,我们无法从图例中删除元素。getChildrenUnmodifiable()@Kishore运行在Java 8.0.25上,图例的类层次结构是:对象-->节点-->父-->区域-->窗格-->平铺-->图例。窗格中有一个公共getChildren。@Kishore似乎正是这样做的:
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);
}
}
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"));
...
}