2016-11-15 25 views
2

我有一个大小一致的正方形的20x20 GridPane,它代表来自相同大小的二维数组的数据,放置在一个ScrollPane中,以便人们可以使用它来平移。 GridPane的宽度和高度(以像素为单位)都大于ScrollPane的相应尺寸。ScrollPane Viewport中的GridPane Square中心

我的问题是,我一直无法制作一个功能方法,该方法将ScrollPane的视口居中在位于一组指定坐标的GridPane正方形上。

我对scrollPane.setHvalue(double)scrollPane.setVvalue(double)的理解,我一直试图利用的是,传递给它们的double值是它设置滚动的轴的百分比。然而,当我写的代码假设,它无法同方甚至没有正对视的任何位置居中预期广场的看法,有时会:

private void centerViewOn(double x, double y){ 
    scrollPane.setHvalue(x/grid.getDimensionX()); 
    scrollPane.setVvalue(y/grid.getDimensionY()); 
} 

grid是一个类的实例,只有其与此问题的相关性在于它具有网格的维度,并且double xdouble y是用于居中的正方形GridPane中的x,y坐标。

我在做什么错,我该如何解决这个问题?

编辑: 按照James_D的建议下,我包括我作为一个最小的,完整的和可验证的例子进行:

private ScrollPane scrollPane; 
private GridPane gridPane; 
private double dimensionX; 
private double dimensionY; 

@Override 
public void start(Stage primaryStage) { 
    scrollPane = new ScrollPane(); 
    gridPane = new GridPane(); 
    dimensionX = 20; 
    dimensionY = 20; 

    Pane temp; 
    for(int x = 0; x < dimensionX; ++x){ 
     for(int y = 0; y < dimensionY; ++y){ 
      temp = new Pane(); 
      temp.setPrefSize(100, 100); 
      temp.setOnMouseClicked(e -> { 
       centerViewOn(GridPane.getColumnIndex((Pane)e.getSource()), GridPane.getRowIndex((Pane)e.getSource())); 
       ((Pane)e.getSource()).setStyle("-fx-background-color: blue"); 
      }); 
      gridPane.add(temp, x, y); 
     } 
    } 

    gridPane.setGridLinesVisible(true); 
    scrollPane.setContent(gridPane); 

    primaryStage.setScene(new Scene(scrollPane)); 
    primaryStage.show(); 
} 

private void centerViewOn(double x, double y){ 
    double viewportWidth = scrollPane.getViewportBounds().getWidth(); 
    double maxHscrollPixels = gridPane.getWidth() - viewportWidth; 
    double hscrollPixels = viewportWidth/2 - (x + 0.5) * dimensionX/20; 
    scrollPane.setHvalue(hscrollPixels/maxHscrollPixels); 

    double viewportHeight = scrollPane.getViewportBounds().getHeight(); 
    double maxVscrollPixels = gridPane.getHeight() - viewportHeight; 
    double vscrollPixels = viewportHeight/2 - (y + 0.5) * dimensionY/20; 
    scrollPane.setVvalue(vscrollPixels/maxVscrollPixels); 
} 
+0

所以,你想要的'ScrollPane'到中心看的'grid'当他们停止滚动? –

回答

3

滚动窗格的水平滚动值scrollPane.getHmin()scrollPane.getHmax()之间变化。这些是以任意单位,像素滚动量在整个范围内线性插值。

以像素为单位的可能水平滚动量范围从零到(网格窗格宽度 - 滚动窗口视口宽度)。

所以,你必须

(hvalue - hmin)/(hmax - hmin) = scrollPixels/(gridPaneWidth - viewportWidth) 

等等一些代数后,你会得到

hvalue = hmin + (hmax - hmin) * scrollPixels/(gridPaneWidth - viewportWidth) 

假设每一列都是相同的宽度,并有dimensionX列,x列将总宽度x * gridPaneWidth/dimensionX像素。既然您想滚动到单元格的中心,请添加另一个半单元格,并且由于您希望单元格的中心位于视口的中心,请减去viewportWidth/2。所以你有:

hscrollPixels = (x + 0.5) * gridPane.getWidth()/dimensionX - viewportWidth/2 

垂直滚动是完全相似的。

hminhmax的默认值分别为01,因此如果您认为这些值不会发生变化,您可以简化一些操作。

所以我觉得你最终

private void centerViewOn(double x, double y){ 
    double viewportWidth = scrollPane.getViewportBounds().getWidth(); 
    double maxHscrollPixels = gridPane.getWidth() - viewportWidth; 
    double hscrollPixels = (x + 0.5) * gridPane.getWidth()/dimensionX - viewportWidth/2; 
    scrollPane.setHvalue(hscrollPixels/maxHscrollPixels); 

    double viewportHeight = scrollPane.getViewportBounds().getHeight(); 
    double maxVscrollPixels = gridPane.getHeight() - viewportHeight; 
    double vscrollPixels = (y + 0.5) * gridPane.getHeight()/dimensionY - viewportHeight/2; 
    scrollPane.setVvalue(vscrollPixels/maxVscrollPixels); 
} 

请注意,并非所有的细胞可以滚动到中心:如果他们太靠近边缘,他们将滚动尽可能接近到中心,但滚动窗格不允许空白(除非内容小于视口)。

下面是完整的例子:

import javafx.application.Application; 
import javafx.scene.Scene; 
import javafx.scene.control.ScrollPane; 
import javafx.scene.layout.GridPane; 
import javafx.scene.layout.Pane; 
import javafx.stage.Stage; 

public class ScrollToCenter extends Application { 

    private ScrollPane scrollPane; 
    private GridPane gridPane; 
    private double dimensionX; 
    private double dimensionY; 

    @Override 
    public void start(Stage primaryStage) { 
     scrollPane = new ScrollPane(); 
     gridPane = new GridPane(); 
     dimensionX = 20; 
     dimensionY = 20; 

     for(int x = 0; x < dimensionX; ++x){ 
      for(int y = 0; y < dimensionY; ++y){ 
       Pane temp = new Pane(); 
       temp.setPrefSize(100, 100); 
       temp.setOnMouseClicked(e -> { 
        centerViewOn(GridPane.getColumnIndex(temp), GridPane.getRowIndex(temp)); 
        temp.setStyle("-fx-background-color: blue"); 
       }); 
       gridPane.add(temp, x, y); 
      } 
     } 

     gridPane.setGridLinesVisible(true); 
     scrollPane.setContent(gridPane); 

     primaryStage.setScene(new Scene(scrollPane)); 
     primaryStage.show(); 
    } 

    private void centerViewOn(double x, double y){ 
     double viewportWidth = scrollPane.getViewportBounds().getWidth(); 
     double maxHscrollPixels = gridPane.getWidth() - viewportWidth; 
     double hscrollPixels = (x + 0.5) * gridPane.getWidth()/dimensionX - viewportWidth/2; 
     scrollPane.setHvalue(hscrollPixels/maxHscrollPixels); 

     double viewportHeight = scrollPane.getViewportBounds().getHeight(); 
     double maxVscrollPixels = gridPane.getHeight() - viewportHeight; 
     double vscrollPixels = (y + 0.5) * gridPane.getHeight()/dimensionY - viewportHeight/2; 
     scrollPane.setVvalue(vscrollPixels/maxVscrollPixels); 
    } 

    public static void main(String[] args) { 
     launch(args); 
    } 
} 
+0

尽管这很有帮助,但最终并没有奏效。我认为这是因为我在解释'grid.getDimensionX()'方面做得不好。为了澄清,该方法返回网格中的列数,在本例中为20。 (这是一种方法,而不是硬编码的数字,因为我最终将实现调整网格大小的功能,所以我正在寻找一种解决方案,适用于任意数量的行和列的网格) – narf0708

+0

@ narf0708可能是您最好的选择是创建一个[MCVE]并编辑你的问题来包含它。 –

+0

我正在离开'hmin'和'hmax'的默认值,所以如果我正确读取,最后一行应该简化为'scrollPane.setHvalue(hscrollPixels/maxHscrollPixels);' 另外,我必须承认我是有点困惑于你的号码来自哪里。 “viewportWidth/2 - (x + 0.5)”中2和0.5的用途是什么? – narf0708