【问题标题】:JavaFX ScrollPane programmatically moving the viewport - centering contentJavaFX ScrollPane 以编程方式移动视口 - 使内容居中
【发布时间】:2013-03-28 06:10:24
【问题描述】:

我可以使用 setVvalue(double) 和 setHvalue(double) 方法在 JavaFX ScrollPane 中移动视口。我正在努力做的是根据其位置在滚动窗格的内容中将特定节点居​​中。我已经尝试了 localToScene() 和 boundsInParent() 的各种组合。我已经阅读(很多)并看到了这个例子

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

靠近但不使对象居中只是使它们可见。拥有内置的鼠标平移非常棒,但我正在为程序化平移带来恶劣天气。

最终我也需要能够进行缩放,所以我将实际形状放在一个组中,并将该组添加到滚动窗格内容中。我想我应该对组进行缩放,并且我需要能够围绕组的中心进行缩放,这样我们才能重新操作和识别当前的中心位置。任何可以提供的指针或示例将不胜感激。上面链接中的代码示例是一个很好的 SSCCE。

提前致谢,

安迪

【问题讨论】:

  • 嗯,在我看来,如果问题真的很简单,提问者是个白痴,或者真的很难,没有人会费心去解决问题,那么 StackOverflow 就不会回答这些问题一个答案!我很高兴被告知我是个白痴!

标签: java javafx-2 viewport panning scrollpane


【解决方案1】:

我将尝试不使用代码来解释这一点,因为我认为这里没有必要。

假设滚动窗格的内容高度为h,视口高度为v。如果h = v,那么内容将完全适合视口,并且您不需要滚动条。在这种情况下(使用不可移动的滚动条),要使元素居中,它需要位于滚动窗格内容的中心。您不能通过滚动将其移动到视口的中心。

现在考虑h 的大小是v 的两倍(即h = 2v)。在这种情况下,滚动窗格内容的上 1/4 和下 1/4 无法通过滚动居中。

(如果您绝对需要通过滚动使任何组件居中,您应该考虑填充内容窗格,但我们将在此处继续使用未填充的解决方案)

细想一下,您会发现滚动条的可能滚动距离是h - v,您可以通过将vvalue 设置为1.0 来滚动该距离。

要将点y 居中(这里的点 y 是滚动窗格内容窗格的坐标),您可以使用以下 vvalue:

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

这个表达式的命名者是当 y 点在视口内居中时在视口顶部显示的 y 坐标。分母是总的可滚动距离。

编辑:还是添加一些代码!

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

(请注意,这假定节点是滚动窗格内容窗格的直接子节点)

希望这会有所帮助! :)

【讨论】:

  • 谢谢,即使该节点不是滚动窗格的直接子节点,它也能完美运行:我中间有一个 AnchorPane。
【解决方案2】:

我知道,有点晚了,但也许有人会觉得它有用。:)

关于居中,这不是一项艰巨的任务,只需要一点点数学知识。你需要两件事。 ScrollPane 的全部内容的大小(可滚动区域的宽度和高度,不仅是带有滚动条的框架,而且就像没有滚动条一样完整)以及 ScrollPane 内容内的居中对象的位置。

你会得到这样的内容大小:scrollPane.getContent().getBoundsInLocal().getHeight() or .getWidth()

对象的位置:node.getBoundsInParent().getMinY() or .getMinX() - 对象的最小位置。你也可以得到它的高度和宽度。

然后根据这个公式计算你的中心位置并移动滚动条。

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

【讨论】:

  • 这不会精确地居中组件,因为您假设滚动窗格可以滚动到其内容窗格的整个高度。
【解决方案3】:

这是一个关于如何使旋转的图片居中的示例。 该代码在 Scala 中,因此适用于 ScalaFX,但 JavaFX 和 Java 开发人员将能够阅读/使用它:

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

【讨论】:

  • 您需要在创建答案时格式化代码,这完全不可读。
猜你喜欢
  • 2016-08-11
  • 2011-03-28
  • 1970-01-01
  • 2017-03-30
  • 2022-11-19
  • 2016-07-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多