JavaFX 如何使节点始终位于最前面并完全可见?
JavaFX How make a Node to be always in front and fully visible?
此程序生成图表并在鼠标进入绘制点时显示坐标值,将点替换为标签。
但问题是如果点在图表的边框中,标签不会完全显示。
我无法使用 toFront()
和 toBack()
函数解决此问题。
我的代码改编自这个问题的答案 JavaFX LineChart Hover Values,它有同样的错误。
Chart.java
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.chart.LineChart;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart;
import javafx.stage.Stage;
public class Chart extends Application {
@Override
public void start(Stage stage) {
// Random chart
// Defining the Axis
final NumberAxis xAxis = new NumberAxis();
final NumberAxis yAxis = new NumberAxis();
// Creating the chart
LineChart<Number, Number> lineChart = new LineChart(xAxis, yAxis);
// This didn't solve the bug
xAxis.toBack();
yAxis.toBack();
// Preparing the series
XYChart.Series series = new XYChart.Series();
series.setName("Chart");
for (double x = 0; x <= 10; x++) {
double y = Math.random() * 100;
XYChart.Data chartData;
chartData = new XYChart.Data(x, y);
chartData.setNode(new ShowCoordinatesNode(x, y));
series.getData().add(chartData);
}
// Adding series to chart
lineChart.getData().add(series);
Scene scene = new Scene(lineChart, 800, 600);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
ShowCoordinatesNode.java
import java.text.DecimalFormat;
import javafx.event.EventHandler;
import javafx.scene.Cursor;
import javafx.scene.control.Label;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.StackPane;
public class ShowCoordinatesNode extends StackPane {
public ShowCoordinatesNode(double x, double y) {
final Label label = createDataThresholdLabel(x, y);
setOnMouseEntered(new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent mouseEvent) {
setScaleX(1);
setScaleY(1);
getChildren().setAll(label);
setCursor(Cursor.NONE);
toFront(); // This didn't solve the bug
}
});
setOnMouseExited(new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent mouseEvent) {
getChildren().clear();
setCursor(Cursor.CROSSHAIR);
}
});
}
private Label createDataThresholdLabel(double x, double y) {
DecimalFormat df = new DecimalFormat("0.##");
final Label label = new Label("(" + df.format(x) + "; " + df.format(y) + ")");
label.getStyleClass().addAll("default-color0", "chart-line-symbol", "chart-series-line");
label.setStyle("-fx-font-size: 10; -fx-font-weight: bold;");
label.setMinSize(Label.USE_PREF_SIZE, Label.USE_PREF_SIZE);
label.setId("show-coord-label");
return label;
}
}
我进行了一些搜索,试图使这项工作正常进行,toFront 无法像 Javadoc 所述那样工作的原因
Moves this Node to the front of its sibling nodes in terms of z-order. This is accomplished by moving this Node to the last position in its parent's content ObservableList. This function has no effect if this Node is not part of a group.
所以我无法让它在任何意义上发挥作用。这是我能想到的唯一解决方案,它涉及找出 label/2 的 width/height 并移动标签(如果它在 X 或 Y 轴上)以便您可以看到它
除了硬编码测试值和删除 toFront 调用外,我在 Main 中没有做任何更改
public class Main extends Application {
@Override
public void start(Stage stage) throws Exception{
// Random chart
// Defining the Axis
final NumberAxis xAxis = new NumberAxis();
final NumberAxis yAxis = new NumberAxis();
// Creating the chart
LineChart<Number, Number> lineChart = new LineChart<>(xAxis, yAxis);
// Preparing the series
XYChart.Series series = new XYChart.Series();
series.setName("Chart");
boolean firstRun = true;//First point at 0,0 to test
for (double x = 0; x <= 10; x++) {
double y;
if(firstRun) {
y = 0.0;
firstRun = false;
}else
y = Math.random() * 100;
XYChart.Data chartData;
chartData = new XYChart.Data<>(x, y);
chartData.setNode(new ShowCoordinatesNode(x, y));
series.getData().add(chartData);
}
// Adding series to chart
lineChart.getData().add(series);
Scene scene = new Scene(lineChart, 800, 600);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) { launch(args); }
}
我在此处添加了 2 个 If 语句以在其中一个轴上翻译标签 if
public class ShowCoordinatesNode extends StackPane {
public ShowCoordinatesNode(double x, double y) {
final Label label = createDataThresholdLabel(x, y);
setOnMouseEntered(mouseEvent -> {
setScaleX(1);
setScaleY(1);
getChildren().setAll(label);
if(x == 0.0) {
applyCss();
layout();
label.setTranslateX(label.getWidth()/2);
}
if(y == 0.0){
applyCss();
layout();
label.setTranslateY(-label.getHeight()/2);
}
setCursor(Cursor.NONE);
});
setOnMouseExited(mouseEvent -> {
getChildren().clear();
setCursor(Cursor.CROSSHAIR);
});
}
private Label createDataThresholdLabel(double x, double y) {
DecimalFormat df = new DecimalFormat("0.##");
final Label label = new Label("(" + df.format(x) + "; " + df.format(y) + ")");
label.getStyleClass().addAll("default-color0", "chart-line-symbol", "chart-series-line");
label.setStyle("-fx-font-size: 10; -fx-font-weight: bold;");
label.setMinSize(Label.USE_PREF_SIZE, Label.USE_PREF_SIZE);
label.setId("show-coord-label");
return label;
}
}
我使用 applyCSS() 来计算标签的大小,然后再添加到 window JavaDoc 指出:
If required, apply styles to this Node and its children, if any. This method does not normally need to be invoked directly but may be used in conjunction with Parent.layout() to size a Node before the next pulse, or if the Scene is not in a Stage.
此程序生成图表并在鼠标进入绘制点时显示坐标值,将点替换为标签。
但问题是如果点在图表的边框中,标签不会完全显示。
我无法使用 toFront()
和 toBack()
函数解决此问题。
我的代码改编自这个问题的答案 JavaFX LineChart Hover Values,它有同样的错误。
Chart.java
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.chart.LineChart;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart;
import javafx.stage.Stage;
public class Chart extends Application {
@Override
public void start(Stage stage) {
// Random chart
// Defining the Axis
final NumberAxis xAxis = new NumberAxis();
final NumberAxis yAxis = new NumberAxis();
// Creating the chart
LineChart<Number, Number> lineChart = new LineChart(xAxis, yAxis);
// This didn't solve the bug
xAxis.toBack();
yAxis.toBack();
// Preparing the series
XYChart.Series series = new XYChart.Series();
series.setName("Chart");
for (double x = 0; x <= 10; x++) {
double y = Math.random() * 100;
XYChart.Data chartData;
chartData = new XYChart.Data(x, y);
chartData.setNode(new ShowCoordinatesNode(x, y));
series.getData().add(chartData);
}
// Adding series to chart
lineChart.getData().add(series);
Scene scene = new Scene(lineChart, 800, 600);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
ShowCoordinatesNode.java
import java.text.DecimalFormat;
import javafx.event.EventHandler;
import javafx.scene.Cursor;
import javafx.scene.control.Label;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.StackPane;
public class ShowCoordinatesNode extends StackPane {
public ShowCoordinatesNode(double x, double y) {
final Label label = createDataThresholdLabel(x, y);
setOnMouseEntered(new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent mouseEvent) {
setScaleX(1);
setScaleY(1);
getChildren().setAll(label);
setCursor(Cursor.NONE);
toFront(); // This didn't solve the bug
}
});
setOnMouseExited(new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent mouseEvent) {
getChildren().clear();
setCursor(Cursor.CROSSHAIR);
}
});
}
private Label createDataThresholdLabel(double x, double y) {
DecimalFormat df = new DecimalFormat("0.##");
final Label label = new Label("(" + df.format(x) + "; " + df.format(y) + ")");
label.getStyleClass().addAll("default-color0", "chart-line-symbol", "chart-series-line");
label.setStyle("-fx-font-size: 10; -fx-font-weight: bold;");
label.setMinSize(Label.USE_PREF_SIZE, Label.USE_PREF_SIZE);
label.setId("show-coord-label");
return label;
}
}
我进行了一些搜索,试图使这项工作正常进行,toFront 无法像 Javadoc 所述那样工作的原因
Moves this Node to the front of its sibling nodes in terms of z-order. This is accomplished by moving this Node to the last position in its parent's content ObservableList. This function has no effect if this Node is not part of a group.
所以我无法让它在任何意义上发挥作用。这是我能想到的唯一解决方案,它涉及找出 label/2 的 width/height 并移动标签(如果它在 X 或 Y 轴上)以便您可以看到它
除了硬编码测试值和删除 toFront 调用外,我在 Main 中没有做任何更改
public class Main extends Application {
@Override
public void start(Stage stage) throws Exception{
// Random chart
// Defining the Axis
final NumberAxis xAxis = new NumberAxis();
final NumberAxis yAxis = new NumberAxis();
// Creating the chart
LineChart<Number, Number> lineChart = new LineChart<>(xAxis, yAxis);
// Preparing the series
XYChart.Series series = new XYChart.Series();
series.setName("Chart");
boolean firstRun = true;//First point at 0,0 to test
for (double x = 0; x <= 10; x++) {
double y;
if(firstRun) {
y = 0.0;
firstRun = false;
}else
y = Math.random() * 100;
XYChart.Data chartData;
chartData = new XYChart.Data<>(x, y);
chartData.setNode(new ShowCoordinatesNode(x, y));
series.getData().add(chartData);
}
// Adding series to chart
lineChart.getData().add(series);
Scene scene = new Scene(lineChart, 800, 600);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) { launch(args); }
}
我在此处添加了 2 个 If 语句以在其中一个轴上翻译标签 if
public class ShowCoordinatesNode extends StackPane {
public ShowCoordinatesNode(double x, double y) {
final Label label = createDataThresholdLabel(x, y);
setOnMouseEntered(mouseEvent -> {
setScaleX(1);
setScaleY(1);
getChildren().setAll(label);
if(x == 0.0) {
applyCss();
layout();
label.setTranslateX(label.getWidth()/2);
}
if(y == 0.0){
applyCss();
layout();
label.setTranslateY(-label.getHeight()/2);
}
setCursor(Cursor.NONE);
});
setOnMouseExited(mouseEvent -> {
getChildren().clear();
setCursor(Cursor.CROSSHAIR);
});
}
private Label createDataThresholdLabel(double x, double y) {
DecimalFormat df = new DecimalFormat("0.##");
final Label label = new Label("(" + df.format(x) + "; " + df.format(y) + ")");
label.getStyleClass().addAll("default-color0", "chart-line-symbol", "chart-series-line");
label.setStyle("-fx-font-size: 10; -fx-font-weight: bold;");
label.setMinSize(Label.USE_PREF_SIZE, Label.USE_PREF_SIZE);
label.setId("show-coord-label");
return label;
}
}
我使用 applyCSS() 来计算标签的大小,然后再添加到 window JavaDoc 指出:
If required, apply styles to this Node and its children, if any. This method does not normally need to be invoked directly but may be used in conjunction with Parent.layout() to size a Node before the next pulse, or if the Scene is not in a Stage.