从javaFX折线图中的CategoryAxis检索字符串值-getValueForDisplay(double-dis



我有一个JavaFXline图表,其中包含月份与数值。每次单击图表时,我都试图在控制台中打印月份和折线图中的值。问题是,当我调用CategoryAxis对象中的方法getValueForDisplay时,它会返回null
当我单击(x,y):jan,3
我想打印:
X value = jan Y value: 3
但程序正在打印:
X value = **null** Y value: 2.7796610169491527

另一个问题
2)为什么当试图打印坐标时,它似乎没有校准(如果我点击3,程序打印2.779661016949152?你可以注意到这个问题,检查控制台上打印的值。

这是我正在使用的代码:

public class LineChartTest extends Application {
String xValue;
Number yValue;
private void init(Stage primaryStage) {
Group root = new Group();
primaryStage.setScene(new Scene(root));
final CategoryAxis xAxis = new CategoryAxis();
final NumberAxis yAxis = new NumberAxis("Values for Y-Axis", 0, 3, 1);
yAxis.setUpperBound(5);
ObservableList<XYChart.Series<String,Double>> lineChartData = FXCollections.observableArrayList(
new LineChart.Series<String,Double>("en", FXCollections.observableArrayList(
new XYChart.Data<String,Double>("jan", 1.0),
new XYChart.Data<String,Double>("feb", 2.0),
new XYChart.Data<String,Double>("mar", 3.0),
new XYChart.Data<String,Double>("apr", 4.0),
new XYChart.Data<String,Double>("may", 0.5)
)),
new LineChart.Series<String,Double>("to", FXCollections.observableArrayList(
new XYChart.Data<String,Double>("jan", 1.6),
new XYChart.Data<String,Double>("feb", 0.4),
new XYChart.Data<String,Double>("mar", 2.9),
new XYChart.Data<String,Double>("apr", 1.3),
new XYChart.Data<String,Double>("may", 0.9)
))
);

//define a new line
final Series<String,Double> otherSeries = new Series<String,Double>();
//set points
otherSeries.getData().add(new XYChart.Data("jan",3));
otherSeries.getData().add(new XYChart.Data("feb",2));
otherSeries.getData().add(new XYChart.Data("mar",4));
//set name to the line
otherSeries.setName("tre");
//add the new line to the graph
lineChartData.add(otherSeries);
final LineChart chart = new LineChart(xAxis, yAxis, lineChartData);
//set title to the figure
chart.setTitle("Line Chart Test");
root.getChildren().add(chart);
chart.setOnMouseClicked(new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent t) {
//Why this seems to be not working properly?
double sceneX = t.getSceneX();
double sceneY = t.getSceneY();
//gives the point of the graph
xValue = xAxis.getValueForDisplay(sceneX);
yValue = yAxis.getValueForDisplay(sceneY);

System.out.println("sceneX-25: "+ sceneX);
System.out.println("getDisplayPosition: " + xAxis.getValueForDisplay(sceneX));
//Test
System.out.println(" X value = " +  
xValue + " Y value: " + yValue );  
}
});
}
@Override public void start(Stage primaryStage) throws Exception {
init(primaryStage);
primaryStage.show();

}

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

答案:

感谢Sergey Grinev和Uluk Biy

在之前的代码中,您必须修改:

折线图代码:

chart.setOnMouseClicked(new EventHandler<MouseEvent>() {

@Override
public void handle(MouseEvent e) {
Node chartPlotBackground = chart.lookup(".chart-plot-background");
final double shiftX = xSceneShift(chartPlotBackground);
final double shiftY = ySceneShift(chartPlotBackground);    
double x = e.getSceneX() - shiftX;
double y = e.getSceneY() - shiftY;
xValue = xAxis.getValueForDisplay(x);
yValue = yAxis.getValueForDisplay(y );
System.out.println("shiftX = " + shiftX + " shiftY: " + shiftY);
System.out.println("X value = "
+ xValue + " nY value: " + yValue);
}
});

}
//recursive calls    
private double xSceneShift(Node node) {
return node.getParent() == null ? 0 : node.getBoundsInParent().getMinX() +    xSceneShift(node.getParent());
}
private double ySceneShift(Node node) {
return node.getParent() == null ? 0 : node.getBoundsInParent().getMinY() + ySceneShift(node.getParent());
}
@Override 
public void start(Stage primaryStage) throws Exception {
init(primaryStage);
primaryStage.show();

}

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

在您必须修改的CategoryAxis源代码中(查看注释!):

@Override public String getValueForDisplay(double displayPosition) {
if (getSide().equals(Side.TOP) || getSide().equals(Side.BOTTOM)) { // HORIZONTAL
if (displayPosition < 0 || displayPosition > getHeight()) return null; //   <-------------- WRONG SHOULD BE displayPosition > getWidth()
double d = (displayPosition - firstCategoryPos.get()) / categorySpacing.get();
return toRealValue(d);
} else { // VERTICAL
if (displayPosition < 0 || displayPosition > getWidth()) return null; // <-------------- WRONG SHOULD BE displayPosition > getHeight()
double d = (displayPosition - firstCategoryPos.get()) / (categorySpacing.get() * -1);
return toRealValue(d);
}
} 

你可以在这里找到源代码:

http://hg.openjdk.java.net/openjfx/2.1/master/rt/file/5c3b3d524f07/javafx-ui-controls/src/javafx/scene/chart/CategoryAxis.java

如果您的目标是显示用户在图表上单击的数据点,那么您可以直接访问下划线数据。将鼠标悬停在本例中的数据X-Y交叉点:

import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.scene.Cursor;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.chart.CategoryAxis;
import javafx.scene.chart.LineChart;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart;
import javafx.scene.control.Label;
import javafx.scene.control.LabelBuilder;
import javafx.scene.effect.DropShadow;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.text.Font;
import javafx.scene.text.FontWeight;
import javafx.stage.Stage;
public class ChartDemo extends Application {
private DropShadow ds = new DropShadow();
@Override
public void start(Stage stage) {
stage.setTitle("Linear plot");
final CategoryAxis xAxis = new CategoryAxis();
final NumberAxis yAxis = new NumberAxis(0, 22, 0.5);
yAxis.setTickLabelFormatter(new NumberAxis.DefaultFormatter(yAxis) {
@Override
public String toString(Number object) {
return String.format("%7.2f", object);
}
});
final LineChart<String, Number> lineChart = new LineChart<String, Number>(xAxis, yAxis);
lineChart.setCreateSymbols(true);
lineChart.setAlternativeRowFillVisible(false);
lineChart.setLegendVisible(false);
final XYChart.Series series1 = new XYChart.Series();
series1.getData().add(new XYChart.Data("Jan", 1));
series1.getData().add(new XYChart.Data("Feb", 1.5));
series1.getData().add(new XYChart.Data("Mar", 2));
series1.getData().add(new XYChart.Data("Apr", 2.5));
series1.getData().add(new XYChart.Data("May", 3));
series1.getData().add(new XYChart.Data("Jun", 4));
series1.getData().add(new XYChart.Data("Jul", 6));
series1.getData().add(new XYChart.Data("Aug", 9));
series1.getData().add(new XYChart.Data("Sep", 12));
series1.getData().add(new XYChart.Data("Oct", 15));
series1.getData().add(new XYChart.Data("Nov", 20));
series1.getData().add(new XYChart.Data("Dec", 22));
final Label lbl = LabelBuilder.create().font(Font.font("Arial", FontWeight.BOLD, 25))
.textFill(Color.BLUEVIOLET).translateY(-200).build();
StackPane pane = new StackPane();
pane.getChildren().addAll(lineChart, lbl);
Scene scene = new Scene(pane, 800, 600);
lineChart.getData().addAll(series1);
for (Object obj : series1.getData()) {
final XYChart.Data data = (XYChart.Data) obj;
final Node node = data.getNode();
node.setOnMouseEntered(new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent arg0) {
node.setEffect(ds);
node.setCursor(Cursor.HAND);
lbl.setText("X-value=" + data.getXValue().toString() + "nY-value=" + data.getYValue().toString());
System.out.println("X-value=" + data.getXValue().toString() + ", Y-value=" + data.getYValue().toString());
}
});
node.setOnMouseExited(new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent arg0) {
node.setEffect(null);
node.setCursor(Cursor.DEFAULT);
lbl.setText("");
}
});
}
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}

有2个问题。

1)您使用了错误的坐标。getValueForDisplay需要相对于图表绘制区域的坐标,而不是相对于场景的坐标。

要解决这个问题,你可以使用下一个技巧。

引入下一个递归调用来计算场景偏移:

private double xSceneShift(Node node) {
return node.getParent() == null ? 0 : node.getBoundsInParent().getMinX() + xSceneShift(node.getParent());
}
private double ySceneShift(Node node) {
return node.getParent() == null ? 0 : node.getBoundsInParent().getMinY() + ySceneShift(node.getParent());
}

查找图表绘制区域的偏移:

Node chartPlotBackground = chart.lookup(".chart-plot-background");
final double shiftX = xSceneShift(chartPlotBackground);
final double shiftY = ySceneShift(chartPlotBackground);

并在鼠标处理程序中使用它们:

public void handle(MouseEvent e) {
double x = e.getSceneX() - shiftX;
double y = e.getSceneY() - shiftY;
xValue = xAxis.getValueForDisplay(x );
yValue = yAxis.getValueForDisplay(y);
System.out.println(" X value = "
+ xValue + " nY value: " + yValue);
}

2)您在CategoryAxis中遇到一个问题,该问题已修复,但在下一版本(8.0)中:http://javafx-jira.kenai.com/browse/RT-25899

作为一种变通方法,您可以下载CategoryAxis源代码,将其重命名为MyCategoryAxis,并修复方法getValueForDisplay()中的一个错误——只需切换getWidth()getHeight()调用的位置。

http://hg.openjdk.java.net/openjfx/2.1/master/rt/file/5c3b3d524f07/javafx-ui-controls/src/javafx/scene/chart/CategoryAxis.java

最新更新