简体   繁体   English

JavaFX如何使Node始终位于前面并完全可见?

[英]JavaFX How make a Node to be always in front and fully visible?

This program generates a chart and displays the coordinate values when the mouse enters the plotted dots by replacing the dot for a label. 当鼠标通过将点替换为标签来输入绘制的点时,该程序将生成图表并显示坐标值。

But the problem is that the label does not appear completely if the dot is in the border of the chart. 但是问题是,如果圆点在图表的边框中,标签将不会完全显示。

I couldn't solve this issue using the toFront() and toBack() functions. 使用toFront()toBack()函数无法解决此问题。

My code was adapted from the answer to this question JavaFX LineChart Hover Values, which has the same bug. 我的代码是从该问题的答案JavaFX LineChart Hover Values改编而来的,它具有相同的错误。

Chart.java 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 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;
}
}

I have done a some searching trying to make this work and the reason toFront doesn't work as the Javadoc states 我进行了一些搜索以尝试完成这项工作,并且toFront不能按Javadoc所述工作

Moves this Node to the front of its sibling nodes in terms of z-order. 根据z顺序将此节点移动到其兄弟节点的前面。 This is accomplished by moving this Node to the last position in its parent's content ObservableList. 这是通过将该节点移动到其父对象的内容ObservableList中的最后一个位置来实现的。 This function has no effect if this Node is not part of a group. 如果此节点不属于组,则此功能无效。

So I could not get that to work in any sense. 所以我无法在任何意义上使它起作用。 This is the only solution I could come up with it involves figuring out the width/height of the label/2 and shifting the label if it on the X or Y axis so you could see it 这是我能提出的唯一解决方案,它涉及弄清楚标签/ 2的宽度/高度,并在X或Y轴上移动标签(如果它可以看到的话)

I made no changes in the Main other than hardcoding a testing value and removing the toFront Calls 除了对测试值进行硬编码并删除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); }

}

Here is where I added 2 If statements to translate the label if on one of the axises 这是我在其中添加2条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;
    }
}

I use the applyCSS() to calculate the size of the label before it is added to the window The JavaDoc states: 在将标签添加到窗口之前,我使用applyCSS()计算标签的大小。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. 通常不需要直接调用此方法,但可以将其与Parent.layout()结合使用,以在下一个脉冲之前(如果场景不在舞台中)确定节点的大小。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM