Frage JavaFX ScrollPane bewegt programmatisch den Inhalt des Ansichtsfensters


Ich kann die Methoden setVvalue (double) und setHvalue (double) verwenden, um ein Ansichtsfenster in einem JavaFX ScrollPane zu verschieben. Was ich zu tun habe, ist, einen bestimmten Knoten im Inhalt des Bildlauffensters basierend auf seiner Position zu zentrieren. Ich habe alle möglichen Kombinationen von localToScene () und boundsInParent () ausprobiert. Ich habe (viel) gelesen und dieses Beispiel gesehen

Wie scrollt man, um einen Knoten innerhalb des Inhalts eines ScrollPane sichtbar zu machen?

Was nah ist, aber die Objekte nicht zentriert, macht sie nur sichtbar. Das eingebaute Maus-Panning ist genial, aber ich mache schweres Wetter mit dem programmatischen Panning.

Letztendlich muss ich auch in der Lage sein, einen Zoom zu machen, also habe ich die tatsächlichen Formen in eine Gruppe eingefügt und die Gruppe dem Inhalt des Bildlauffensters hinzugefügt. Ich denke, ich sollte die Gruppe zoomen und wieder muss ich in der Lage sein, um die Mitte der Gruppe zu zoomen, so dass wir zurück sind, um die aktuelle Mittelposition zu manipulieren und zu identifizieren. Irgendwelche Zeiger oder Beispiele, die zur Verfügung gestellt werden können, würden wirklich wirklich geschätzt. Das Codebeispiel im obigen Link ist ein guter SSCCE.

Danke im Voraus,

Andy


5
2018-04-05 18:01


Ursprung


Antworten:


Ich werde versuchen, das ohne Code zu erklären, weil ich das hier nicht für nötig halte.

Sagen wir das Inhalt deiner Scrollpane hat Höhe hund die Höhe des Ansichtsfensters ist v. Ob h = v, dann würde der Inhalt perfekt in das Ansichtsfenster passen, und Sie würden keine Bildlaufleiste benötigen. In dieser Situation (mit einer nicht beweglichen Bildlaufleiste) müsste ein zu zentrierendes Element in der Mitte des Inhalts der Bildlaufleiste positioniert werden. Sie können es nicht durch Scrollen in die Mitte des Ansichtsfensters verschieben.

Jetzt überlegen h doppelt so groß sein wie v (d.h. h = 2v). In dieser Situation konnten das obere 1/4 und das untere 1/4 des Inhalts der Bildlaufleiste nicht durch Scrollen zentriert werden.

(Wenn Sie eine Komponente unbedingt durch Scrollen zentrieren müssen, sollten Sie den Inhalt des Inhaltsbereichs auffüllen, aber wir fahren hier mit der ungepufferten Lösung fort)

Wenn Sie darüber nachdenken, werden Sie feststellen, dass die scrollbare Entfernung der Bildlaufleiste ist h - v, und Sie scrollen diesen Betrag durch Einstellung vvalue bis 1,0.

Einen Punkt zentrieren y (Hier ist der Punkt y eine Koordinate des Inhaltsbereichs des Scrollpanels.) Sie können den folgenden vvalue verwenden:

vvalue = (y - 0.5 * v) / (h - v) 

Der Nominator dieses Ausdrucks ist die Y-Koordinate dessen, was am oberen Rand des Ansichtsfensters angezeigt wird, wenn der Punkt y innerhalb des Ansichtsfensters zentriert ist. Der Nenner ist die gesamte scrollbare Distanz.

Edit: Irgendeinen Code trotzdem hinzufügen!

public void centerNodeInScrollPane(ScrollPane scrollPane, Node node) {
    double h = scrollPane.getContent().getBoundsInLocal().getHeight();
    double y = (node.getBoundsInParent().getMaxY() + 
                node.getBoundsInParent().getMinY()) / 2.0;
    double v = scrollPane.getViewportBounds().getHeight();
    scrollPane.setVvalue(scrollPane.getVmax() * ((y - 0.5 * v) / (h - v)));
}

(Bitte beachten Sie, dass der Knoten ein direktes Kind des Inhaltsbereichs des Scrollpanels ist)

Hoffe das hilft! :)


9
2018-05-07 12:49



Ich weiß, es ist ein bisschen spät, aber vielleicht findet es jemand nützlich.

In Bezug auf die Zentrierung ist dies keine schwere Aufgabe, es braucht nur ein bisschen Mathematik. Du brauchst zwei Dinge. Größe des gesamten Inhalts von ScrollPane (Breite und Höhe des scrollbaren Bereichs, nicht nur des Rahmens mit Bildlaufleisten, sondern vollständig, als ob keine Bildlaufleisten vorhanden wären) und Position des zentrierten Objekts innerhalb des ScrollPane-Inhalts.

Sie erhalten die Größe des Inhalts wie folgt: scrollPane.getContent().getBoundsInLocal().getHeight() or .getWidth()

Und Position Ihres Objekts: node.getBoundsInParent().getMinY() or .getMinX() - minimale Position des Objekts. Sie können seine Höhe und Breite auch erhalten.

Dann berechne die Position deines Zentrums und verschiebe die Bildlaufleisten nach dieser Formel.

double vScrollBarPosition = scrollPane.getVMax() * (yPositionOfCenter / heightOfScrollPaneContent)


0
2018-01-23 13:26



Hier ist ein Beispiel, wie man ein gedrehtes Bild zentriert. Der Code ist in Scala und somit für ScalaFX anwendbar, aber JavaFX- und Java-Entwickler können ihn lesen / benutzen:

  def turnPic(angle:Int) {
    val virtualSurfaceMultiplier = 8.0;
    currentAngle = ( floor((currentAngle % 360) / 90) * 90 + angle + 360 ) % 360;
    imageView.rotate = currentAngle;
    val orientationSwitched = (currentAngle / 90) % 2 > 0;
    val width= scrollPane.getViewportBounds().getWidth();
    val height= scrollPane.getViewportBounds().getHeight();
    val viewPort = new Rectangle2D(0, 0, image.width.value, image.height.value);
    imageView.setViewport(viewPort);
    imageView.fitHeight.value = virtualSurfaceMultiplier * height;
    imageView.fitWidth.value = 0 //virtualSurfaceMultiplier * width;
    def centerV(picHeight:Double) {
      val node  = scrollPane.getContent();
      val totalHeight = scrollPane.getContent().getBoundsInLocal().getHeight();
      val offsetToCenter = (node.getBoundsInParent().getMaxY() + node.getBoundsInParent().getMinY()) / 2.0;
      val viewportWidth = scrollPane.getViewportBounds().getHeight();
      val res = (scrollPane.getVmax() * ((offsetToCenter - 0.5 * picHeight * zoomFactor) / (totalHeight - picHeight * zoomFactor)));
      scrollPane.setVvalue(res);
    }
    def centerH(picWidth:Double) {
      val node  = scrollPane.getContent();
      val totalWidth = scrollPane.getContent().getBoundsInLocal().getWidth();
      val offsetToCenter = (node.getBoundsInParent().getMaxX() + node.getBoundsInParent().getMinX()) / 2.0;
      val viewportWidth = scrollPane.getViewportBounds().getWidth();
      val res = (scrollPane.getHmax() * ((offsetToCenter - 0.5 * picWidth * zoomFactor) / (totalWidth - picWidth * zoomFactor)));
      scrollPane.setHvalue(res);
      System.err.println(s"trace centerH> $FILE:$LINE:" + " totalWidth:" + totalWidth + " offsetToCenter=" + offsetToCenter + " vWidth=" + viewportWidth + "res=" + res);
    }
    if (orientationSwitched) {
      zoomFactor = 1.0 / (virtualSurfaceMultiplier * image.width.value / image.height.value);
      centerH(height);
      centerV(width);
    }
    else
    {
      zoomFactor = 1.0 / virtualSurfaceMultiplier;
      centerH(width);
      centerV(height);
    }
    imageView.setScaleX(zoomFactor);
    imageView.setScaleY(zoomFactor);
  }

-1
2018-06-02 19:51