JavaFX Tooltips für XYChart-Knoten werden nicht angezeigt!

xerxatin

Mitglied
Hallo liebe Community,

ich versuche vergeblich Tooltips für einzelne Knoten eines Charts anzuzeigen. Das Chart wird angezeigt nur die jeweiligen Tooltips nicht. Hier mein Code:

Java:
public class MainPageController implements Initializable {
...
  @FXML
  private StackedAreaChart<Number, Number> stockChart; 
...

  private void getDataMainTab(){
     int stockCounter = 0;
     stockChart.getXAxis().setLabel("Zeit (12 Monate)");
     stockChart.getYAxis().setLabel("Wert");

     XYChart.Series<Number, Number> daxSeries  = new XYChart.Series<>();

     Stock4Period sp = new Stock4Period();

     // Füllen der Liste
     List<Double> daxData  = sp.findStockRate("DAX", 2015, 01, 01, 2016, 02, 01, "m"); 

     for (int i = daxData.size() - 1; i >= 0; i--) {
          if(stockCounter != 13){
             daxSeries.getData().add(new XYChart.Data(stockCounter, daxData.get(i)));
          }
      stockCounter++;
   }

    stockChart.getData().add(daxSeries);

     //Tooltips für die Charts
      for (XYChart.Series<Number, Number> s : stockChart.getData()) {
         for (XYChart.Data<Number, Number> d : s.getData()) {
            Tooltip.install(d.getNode(), new Tooltip("hallo"));
         }
      }
}

Wieso funktioniert der Code nicht?
 
Hm. Schwer zu sagen. Ich nehme an, du hast diesen Code hier als Basis genutzt:
http://stackoverflow.com/questions/25892695/tooltip-on-line-chart-showing-date
Oder?

Ich habe es seinerzeit mit einer etwas... "exotischeren"... Lösung gemacht:
Nenne es "HoveredThresholdNode" in einem Graphen, der Speed-Test-Zwischenergebnisse darstellt:

Java:
    private class HoveredThresholdNode extends StackPane {
      
        protected HoveredThresholdNode(final long index, final long value) {
          
            // war wichtig, weil der originale Node (der kleine Kreis) "beibehalten" werden sollte
            setPrefSize(2, 2);
            // Label mit den Daten, die beim Hovern angezeigt werden sollen
            final Label label = createDataThresholdLabel(index, value);
            // der normalerweise sichtbare Kreis
            final Circle circle = new Circle(2);
            // innere Farbe
            circle.setFill(Paint.valueOf("white"));
            // der Stroke, der Rahmen, wird über CSS definiert (abhängig vom Index)
            circle.getStyleClass().addAll(String.format("default-color%d", index), "chart-line-symbol", "chart-series-line");
            // eigentlich blöd, weil diese "ID" nicht eindeutig ist, ich nehme an, das hatte auch was mit dem CSS zu tun
            circle.setId("label-chart-line-desc");
            circle.setVisible(true);
          
            setOnMouseEntered(new EventHandler<MouseEvent>() {
                @Override
                public void handle(MouseEvent mouseEvent) {
                    // Label als Content-Node, Kreis weg
                    getChildren().setAll(label);
                    // Cursor verbergen... Muss man wissen, ob man das will
                    setCursor(Cursor.NONE);
                    toFront(); // IMHO obsolet
                }
            });
            setOnMouseExited(new EventHandler<MouseEvent>() {
                @Override
                public void handle(MouseEvent mouseEvent) {
                    // wieder den Kreis sichtbar machen
                    getChildren().setAll(circle);
                    // und den normalen Cursor anzeigen
                    setCursor(Cursor.DEFAULT);
                }
            });

            // per default wird nur der Kreis angezeigt (siehe #setOnMouseExited)
            getChildren().setAll(circle);
        }
      
        // selbsterklärend: Inhalt des Labels darstellen
        private Label createDataThresholdLabel(long index, long value) {
            final Label label = new Label(SpeedFormatter.formatSpeed(value, SpeedFormatter.LIMIT_GBIT));
            label.getStyleClass().addAll(String.format("default-color%d", index), "chart-line-symbol", "chart-series-line");
            label.setId("label-chart-line-desc");
            label.setMinSize(Label.USE_PREF_SIZE, Label.USE_PREF_SIZE);
            return label;
        }
    }

Das ist kein Tooltip und somit nicht notwendigerweise dass, was du willst, aber bei mir klappt das ganz gut.
Das ganze wird bei mir an der Stelle initialisiert, wo bei dir der Tooltip installiert wird (d.setNode(new HoveredThresholdNode([...]);).

Weiss jetzt nicht, ob es wichtig ist lineChart.setCreateSymbols(true); zu setzen. Bei mir klappt es gerade mit den Tooltips, wie du es versucht hast, auch nicht. 😀

#edit: Hast du mal überprüft, dass der Node (d.getNode()) auch wirklich existiert und nicht null ist?
 
Hallo dzim,

vielen Dank für die schnelle Antwort. Ja genau, ich haben den Code aus der von dir genannten Seite.

Ich habe deine Vermutung eben überprüft. Du hast recht d.getNode() ist null. Ich habe aber keine Idee wieso die Knoten leer sind 🙁.

Deine Lösung werde ich im Hinterkopf behalten. Falls das mit Tooltip nicht zu lösen ist werde ich deine exotische Variante in meinen Code implementieren 🙂.
 
Eine pragmatische Lösung für das Problem könnte sein, wie ich ein Shape - z.B. einen Circle - auf den Node zu setzen, und dann auf diesem das Tooltip zu installieren. Probier' das doch mal.
Einzig die Farbe des Strokes könnte noch ein Problem sein (dafür habe ich ja extra den Index mitliefern müssen). Allerdings kann man diese aus dem CSS holen (es sind 8 vordefinierte Farben (CSS-Klassen, glaube ich), die sich wiederholen. Also mit einer Modulo-Operation nicht so schwer nachzubilden.

Den Code der modena.css (JavaFX8-Default-CSS) findet man z.B. im jfxrt.jar des JRE. Oder aber auf Github in einem Gist:
https://gist.github.com/maxd/63691840fc372f22f470#file-modena-css-L2717
Die Markierte Zeile #2717 ist die erste Farbe. Index ist 0-7, also 8 Farben. Kann man da also zur Not rausfinden, wenn man den Index mit hochzählt.

Happy Coding 🙂
 

Zurück
Oben