Как добавить всплывающую подсказку в прямоугольную область холста JavaFX - PullRequest
0 голосов
/ 12 декабря 2018

В моем приложении JavaFX у меня есть TableView с несколькими столбцами, один из которых отображает данные в графической форме.Для этого я создал CanvasCell объект, который создает и управляет собственным Canvas для работы с чертежом.Часть прорисовки работает просто отлично.

Теперь я бы хотел поставить Tooltips над некоторыми областями в пределах Canvas / Cell.Может быть несколько Tooltips на Cell (что мешает мне добавить Tooltip на уровне Cell), и они должны срабатывать только в определенных областях графика.Однако мне не удается заставить его работать вообще.Кажется, я недостаточно хорошо понимаю взаимодействия иерархии Display Node (читай «вообще»), чтобы можно было разместить Tooltip в любом месте, где он будет работать.

Документация для JavaFX редкая иGoogle + SO оказался пустым для всех поисков, которые я пробовал.Есть ли кто-нибудь, кто знает, как делать такие вещи, или я должен просто сейчас списать это как «не вариант».

Для информации CanvasCell вызывает функцию draw() внутри расширенногоCanvas объект на updateItem().Код, в котором я пытался создать Tooltip, находится внутри этой функции draw() и выглядит следующим образом:

    Rectangle rect = new Rectangle(leftVal, topVal, width, height);
    gc.fillRect(rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight());
    Tooltip tooltip = new Tooltip("Tooltip Text");
    Tooltip.install(rect, tooltip);

, но этот код был написан больше в надежде, чем что-либо еще, и не генерируетчто-нибудь полезное в интерфейсе.

Если кто-то может указать мне правильное направление, я буду очень признателен.

Ответы [ 2 ]

0 голосов
/ 14 декабря 2018

Если вам не нужен элемент управления временем, показанный здесь , вы можете просто установить Tooltip на корпус Canvas и рычаг Shape::contains для подготовки текста, как показано ниже.

node.setOnMouseMoved(e -> {
    tooltips.forEach((color, bounds) -> {
        if (bounds.contains(e.getX(), e.getY())) {
            tooltip.setText(color.toString());
        }
    });
});

Как предлагается здесь , Java 9 и более поздние версии обеспечивают контроль над Tooltip синхронизация через свойства showDelay и showDuration.

Аналогичный подход иллюстрируется здесь для Swing.

image

import javafx.application.Application;
import javafx.scene.shape.Rectangle;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.paint.Color;
import javafx.scene.control.Tooltip;
import javafx.scene.layout.StackPane;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.stage.Stage;

import java.util.HashMap;
import java.util.Map;

/**
 * @see https://stackoverflow.com/a/53785468/230513
 * @see https://stackoverflow.com/a/53753537/230513
 */
public class CanvasTooltipDemo extends Application {

    @Override
    public void start(Stage stage) throws Exception {
        StackPane root = new StackPane();
        Scene sc = new Scene(root, 400, 400);
        stage.setScene(sc);
        Canvas canvas = new Canvas(200, 200);
        root.getChildren().add(canvas);

        Map<Color, Rectangle> tooltips = new HashMap<>();
        tooltips.put(Color.RED, new Rectangle(0, 0, 100, 100));
        tooltips.put(Color.BLUE, new Rectangle(100, 0, 100, 100));
        tooltips.put(Color.YELLOW, new Rectangle(0, 100, 100, 100));
        tooltips.put(Color.GREEN, new Rectangle(100, 100, 100, 100));
        GraphicsContext gc = canvas.getGraphicsContext2D();
        tooltips.forEach((color, bounds) -> {
            gc.setFill(color);
            gc.fillRect(bounds.getX(), bounds.getY(), bounds.getWidth(), bounds.getHeight());
        });

        setToolTips(canvas, tooltips);
        stage.show();
    }

    private void setToolTips(Node node, Map<Color, Rectangle> tooltips) {
        Tooltip tooltip = new Tooltip();
        Tooltip.install(node, tooltip);
        node.setOnMouseMoved(e -> {
            tooltips.forEach((color, bounds) -> {
                if (bounds.contains(e.getX(), e.getY())) {
                    tooltip.setText(color.toString());
                }
            });
        });
        node.setOnMouseExited(e -> {
            tooltip.hide();
        });
    }

    public static void main(String[] args) {
        Application.launch(args);
    }
}
0 голосов
/ 13 декабря 2018

У меня такое же решение, как предложено @Slaw.Моя идея состоит в том, чтобы сделать его более централизованным, чтобы вы могли передавать свой узел и его регионы, в которых вы хотите показать всплывающие подсказки.

В приведенной ниже демонстрации вы можете использовать setToolTips () как метод статической точности для нескольких узлов..

Примечание: некоторая часть логики упоминается из реализации ядра Tooltip;)

import javafx.animation.Animation;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.geometry.Bounds;
import javafx.geometry.Rectangle2D;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Tooltip;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import javafx.util.Duration;

import java.util.HashMap;
import java.util.Map;

public class MultiTooltipDemo extends Application {
    private double lastMouseX;
    private double lastMouseY;
    private static int TOOLTIP_XOFFSET = 10;
    private static int TOOLTIP_YOFFSET = 7;

    @Override
    public void start(Stage stage) throws Exception {
        StackPane root = new StackPane();
        Scene sc = new Scene(root, 600, 600);
        stage.setScene(sc);
        stage.show();

        StackPane box1 = new StackPane();
        box1.setMaxSize(200, 200);
        box1.setStyle("-fx-background-color:red, blue, yellow, green; -fx-background-insets: 0 100 100 0, 0 0 100 100, 100 100 0 0, 100 0 0 100;");
        root.getChildren().add(box1);

        Map<String, Rectangle2D> tooltips = new HashMap<>();
        tooltips.put("I am red", new Rectangle2D(0, 0, 100, 100));
        tooltips.put("I am blue", new Rectangle2D(100, 0, 100, 100));
        tooltips.put("I am yellow", new Rectangle2D(0, 100, 100, 100));
        tooltips.put("I am green", new Rectangle2D(100, 100, 100, 100));
        setToolTips(box1, tooltips);

    }

    private void setToolTips(Node node, Map<String, Rectangle2D> tooltips) {
        Duration openDelay = Duration.millis(1000);
        Duration hideDelay = Duration.millis(5000);
        Tooltip toolTip = new Tooltip();

        Timeline hideTimer = new Timeline();
        hideTimer.getKeyFrames().add(new KeyFrame(hideDelay));
        hideTimer.setOnFinished(event -> {
            toolTip.hide();
        });

        Timeline activationTimer = new Timeline();
        activationTimer.getKeyFrames().add(new KeyFrame(openDelay));
        activationTimer.setOnFinished(event -> {
            Bounds nodeScreenBounds = node.localToScreen(node.getBoundsInLocal());
            double nMx = nodeScreenBounds.getMinX();
            double nMy = nodeScreenBounds.getMinY();
            toolTip.setText("");
            tooltips.forEach((str, bounds) -> {
                double mnX = nMx + bounds.getMinX();
                double mnY = nMy + bounds.getMinY();
                double mxX = mnX + bounds.getWidth();
                double mxY = mnY + bounds.getHeight();
                if (lastMouseX >= mnX && lastMouseX <= mxX && lastMouseY >= mnY && lastMouseY <= mxY) {
                    toolTip.setText(str);
                }
            });
            if (!toolTip.getText().isEmpty()) {
                toolTip.show(node.getScene().getWindow(), lastMouseX + TOOLTIP_XOFFSET, lastMouseY + TOOLTIP_YOFFSET);
                hideTimer.playFromStart();
            }
        });

        node.setOnMouseMoved(e -> {
            double buffPx = 2;
            double eX = e.getScreenX();
            double eY = e.getScreenY();
            // Not hiding for slight mouse movements while tooltip is showing
            if (hideTimer.getStatus() == Animation.Status.RUNNING) {
                if (lastMouseX - buffPx <= eX && lastMouseX + buffPx >= eX && lastMouseY - buffPx <= eY && lastMouseY + buffPx >= eY) {
                    return;
                }
            }
            lastMouseX = e.getScreenX();
            lastMouseY = e.getScreenY();
            toolTip.hide();
            hideTimer.stop();
            activationTimer.playFromStart();
        });

        node.setOnMouseExited(e -> {
            toolTip.hide();
            activationTimer.stop();
            hideTimer.stop();
        });
    }

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