JavaFX ScrollPane programmatically moving the viewport - centering content

有些话、适合烂在心里 提交于 2019-12-19 03:24:35

问题


I can use the setVvalue(double) and setHvalue(double) methods to move a viewport in a JavaFX ScrollPane. What I'm struggling to do is center a particular node in the content of the scroll pane based on its position. I've tried all sorts of combos of localToScene() and boundsInParent(). I've read (a lot) and seen this example

How to scroll to make a Node within the content of a ScrollPane visible?

Which is close but doesn't center the objects just puts them visible. Having the built in mouse panning is brilliant but I'm making heavy weather of the programmatic panning.

Ultimately I need to be able to do a zoom too so I have put the actual shapes in a Group and added the group to the scroll pane content. I think I'm supposed to do the zooming on the group and again I need to be able to zoom around the center of the group so we are back to manipulating and identifying the current center position. Any pointers or examples that can be provided would be really really appreciated. The code sample in the link above is a good SSCCE.

Thanks in advance,

Andy


回答1:


I'll try explaining this without code, because I don't think that's necessary here.

Let's say the content of your scrollpane has height h, and the height of the viewport is v. If h = v, then the content would fit perfectly into the viewport, and you would need no scrollbar. In this situation (with a non-movable scrollbar), for an element to be centered, it would need to be positioned at the center of the scrollpane's content. You can't move it to the viewport's center by means of scrolling.

Now consider h to be twice the size of v (i.e. h = 2v). In this situation the upper 1/4 and the lower 1/4 of the scrollpane's content could not be centered by scrolling.

(If you absolutely needed to center any component by scrolling you should consider padding your content pane, but we'll continue with the unpadded solution here)

When you think about it, you'll realize the possible scrollable distance of the scrollbar is h - v, and you will scroll that amount by setting vvalue to 1.0.

To center a point y (here the point y is a coordinate of the scrollpane's content pane) you can use the following vvalue:

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

The nominator of this expression is the y-coordinate of what is shown at the top of the viewport when the point y is centered inside the viewport. The denominator is the total scrollable distance.

Edit: Adding some code anyway!

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

(Please note this assumes that the node is a direct child of the scrollpane's contentpane)

Hope this helps! :)




回答2:


I know, it is little bit late, but maybe someone will find it useful.:)

As regards centering, this is not hard task it takes only little bit of math. You need two things. Size of whole content of ScrollPane (width and height of scrollable area, not only of frame with scrollbars, but complete as if no scrollbars are present) and position of centered object inside of ScrollPane content.

You get size of content like this: scrollPane.getContent().getBoundsInLocal().getHeight() or .getWidth()

And position of your object: node.getBoundsInParent().getMinY() or .getMinX() - minimal position of object. You can get its height and width too.

Then calculate position of your center and move scrollbars according this formula.

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




回答3:


Here is an example on how to center a pic that has been rotated. The code is in Scala and therefore applicable to ScalaFX, but JavaFX and Java developers will be able to read/use it :

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


来源:https://stackoverflow.com/questions/15840513/javafx-scrollpane-programmatically-moving-the-viewport-centering-content

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!