JavaFX Как сделать так, чтобы Node всегда был впереди и был полностью виден? - PullRequest
0 голосов
/ 04 февраля 2019

Эта программа генерирует диаграмму и отображает значения координат, когда мышь вводит нанесенные точки путем замены точки на метку.

Но проблема в том, что метка не отображается полностью, если точка находится вграница диаграммы.

Я не смог решить эту проблему с помощью функций toFront() и toBack().

Мой код был адаптирован из ответа на этот вопрос Значения при наведении курсора JavaFX LineChart, которая имеет ту же ошибку.

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;
}
}

1 Ответ

0 голосов
/ 04 февраля 2019

Я провел некоторый поиск, пытаясь заставить эту работу работать, и причина, по которой toFront не работает, поскольку Javadoc заявляет

Перемещает этот узел к передней части его родственных узлов с точки зрения z-порядок.Это достигается путем перемещения этого узла на последнюю позицию в содержимом родительского объекта ObservableList. Эта функция не действует, если этот узел не является частью группы.

Так что я не мог заставить это работать в любом смысле.Это единственное решение, которое я мог придумать, заключающееся в определении ширины / высоты метки / 2 и смещении метки, если она на оси X или Y, чтобы вы могли ее видеть

Я не внес никаких измененийв Main, кроме жесткого кодирования значения тестирования и удаления вызовов toFront

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 для перевода метки, если он находится на одной из осей

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 (), чтобы вычислить размер метки перед ее добавлением в окно. JavaDoc сообщает:

Если необходимо, примените стили к этому Узлу и его дочерним элементам, если таковые имеются.Этот метод обычно не нужно вызывать напрямую, но его можно использовать вместе с Parent.layout () для определения размера узла перед следующим импульсом или если сцена не находится в рабочей области.

...