2015-10-19 71 views
0

我已经创建了我的自定义图表,它扩展了javafx中的LineChart。我想要做的是操纵用于渲染XYData的节点。所以我忽略了以下内容:XYData中的自定义节点

@Override 
protected void dataItemAdded(Series<X, Y> series, int itemIndex, 
          Data<X, Y> item) { 

    super.dataItemAdded(series, itemIndex, item); 
    StackPane itemNode = new StackPane(); 
    itemNode.prefHeight(0.5); 
    itemNode.prefWidth(0.5);    
    item.setNode(itemNode); 

    itemNode.setOnMousePressed(new EventHandler<MouseEvent>() { 

      @Override 
      public void handle(MouseEvent event) { 
       // TODO Auto-generated method stub 
       LOG.info("node clicked"); 

      } 
     }); 
} 

但它似乎并没有工作。代码是否正确?是否可以设置为较小的高度和宽度?创建透明(不可见)节点的最佳方式是什么,但仍然可以单击它?

+0

为什么重写该方法?你可以调用['setNode(...)'](http://docs.oracle.com/javase/8/javafx/api/javafx/scene/chart/XYChart.Data.html#setNode-javafx.scene .Node-),当你创建它时,直接在'Data'上。 –

+0

:)虽然这不能回答我的问题,但你是正确的。我已经改变了实现并将我的自定义图表中的覆盖生存。大小的确与它有关。有人知道数据节点的大小是否有限制? – Apostolos

+0

我不认为大小很重要,但当然如果它太小,无法点击。覆盖不起作用的原因是如何以及何时将默认节点添加到数据中。例如,如果首先将数据添加到系列,然后将该系列添加到图表,则不调用'dataItemAdded'方法;你需要重写'seriesAdded'来处理这个用例。 OTOH如果您将该系列添加到图表,然后将数据添加到该系列,您的方法可以正常工作。这是子类的一般问题:您需要知道实现。 “子类喙封装” –

回答

1

子类LineChart可能是这里糟糕的选择。问题是您需要确切知道LineChart实现如何设置数据上的节点。 (让我们忽略了可怕的设计决定了JavaFX队在这里取得:?为什么数据有一个参考,以它在所有视觉节点应该有一个Callback<Data<X,Y>, Node> symbolFactory财产属于图表代替)

事实证明,如果你该系列添加到图表,然后再添加数据系列,每个数据点的dataItemAdded方法被调用,因此,在这种使用情况下,你的方法的工作原理:

import java.util.Random; 
import java.util.logging.Logger; 
import java.util.stream.Collectors; 
import java.util.stream.IntStream; 

import javafx.application.Application; 
import javafx.event.EventHandler; 
import javafx.scene.Scene; 
import javafx.scene.chart.LineChart; 
import javafx.scene.chart.NumberAxis; 
import javafx.scene.chart.XYChart.Data; 
import javafx.scene.chart.XYChart.Series; 
import javafx.scene.input.MouseEvent; 
import javafx.scene.layout.BorderPane; 
import javafx.scene.layout.StackPane; 
import javafx.stage.Stage; 

public class LineChartClickableDataPoints extends Application { 

    private static final Logger LOG = Logger.getLogger("LineChartClickableDataPoints"); 

    @Override 
    public void start(Stage primaryStage) { 

     NumberAxis xAxis = new NumberAxis(); 
     NumberAxis yAxis = new NumberAxis(); 
     LineChart<Number, Number> chart = new LineChart<Number, Number>(xAxis, yAxis) { 
      @Override 
      protected void dataItemAdded(Series<Number, Number> series, int itemIndex, 
             Data<Number, Number> item) { 

       super.dataItemAdded(series, itemIndex, item); 
       StackPane itemNode = new StackPane(); 
       itemNode.setPrefHeight(0.5); 
       itemNode.setPrefWidth(0.5);    
       item.setNode(itemNode); 

       itemNode.setOnMousePressed(new EventHandler<MouseEvent>() { 

         @Override 
         public void handle(MouseEvent event) { 
          LOG.info("node clicked"); 
         } 
        }); 
      } 
     }; 

     Random rng = new Random(); 
     Series<Number, Number> data = new Series<>(); 
     chart.getData().add(data); 
     data.setName("Data"); 
     data.getData().addAll(IntStream.rangeClosed(1, 10) 
       .mapToObj(x -> new Data<Number, Number>(x, rng.nextDouble())) 
       .collect(Collectors.toList())); 
     BorderPane root = new BorderPane(chart); 
     Scene scene = new Scene(root, 600, 600); 
     primaryStage.setScene(scene); 
     primaryStage.show(); 
    } 



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

在另一方面,如果您将数据添加到系列,然后将该系列添加到图表,然后dataItemAdded不会被调用。为此,您需要覆盖seriesAdded。所以你可以这样做,但更深层的问题是你依靠LineChart的实现,而不是仅仅依赖于它的规范。因此,即使您阅读了source code并且现在涵盖了所有可能性,但如果未来版本中的实现发生更改,您不能保证代码仍然有效。总之,"Inheritance violates encapsulation"

相反,你可以设置数据的节点,当您创建数据:

import java.util.Random; 
import java.util.logging.Logger; 
import java.util.stream.Collectors; 
import java.util.stream.IntStream; 

import javafx.application.Application; 
import javafx.event.EventHandler; 
import javafx.scene.Scene; 
import javafx.scene.chart.LineChart; 
import javafx.scene.chart.NumberAxis; 
import javafx.scene.chart.XYChart.Data; 
import javafx.scene.chart.XYChart.Series; 
import javafx.scene.input.MouseEvent; 
import javafx.scene.layout.BorderPane; 
import javafx.scene.layout.StackPane; 
import javafx.stage.Stage; 

public class LineChartClickableDataPoints extends Application { 

    private static final Logger LOG = Logger.getLogger("LineChartClickableDataPoints"); 

    @Override 
    public void start(Stage primaryStage) { 

     NumberAxis xAxis = new NumberAxis(); 
     NumberAxis yAxis = new NumberAxis(); 
     LineChart<Number, Number> chart = new LineChart<>(xAxis, yAxis) ; 

     Random rng = new Random(); 
     Series<Number, Number> data = new Series<>(); 
     data.setName("Data"); 
     data.getData().addAll(IntStream.rangeClosed(1, 10) 
       .mapToObj(x -> new Data<Number, Number>(x, rng.nextDouble())) 
       .peek(this::addNodeToItem) 
       .collect(Collectors.toList())); 
     chart.getData().add(data); 
     BorderPane root = new BorderPane(chart); 
     Scene scene = new Scene(root, 600, 600); 
     primaryStage.setScene(scene); 
     primaryStage.show(); 
    } 

    private void addNodeToItem(Data<Number, Number> item) { 
     StackPane itemNode = new StackPane(); 
     itemNode.setPrefHeight(0.5); 
     itemNode.setPrefWidth(0.5);    
     item.setNode(itemNode); 

     itemNode.setOnMousePressed(new EventHandler<MouseEvent>() { 

       @Override 
       public void handle(MouseEvent event) { 
        LOG.info(String.format("node clicked: [%.2f, %.2f]%n", 
          item.getXValue().doubleValue(), item.getYValue().doubleValue())); 
       } 
      }); 
    } 



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

这种方法适用于任何一种情况下。

据我所知,对节点的大小没有要求。需要注意的是默认的样式表应用以下样式规则:

.chart-symbol { /* solid circle */ 
    -fx-background-color: CHART_COLOR_1; 
    -fx-background-radius: 5px; 
    -fx-padding: 5px; 
} 

所以,只要节点具有应用到它的CSS,它会添加到它的填充的5个像素。你当然可以在外部样式表中定义你自己的css设置。

+0

最后一个问题什么是Chart_color_1 – Apostolos