Rouman
Rouman

Reputation: 137

JavaFX - Adjusting the ImageView in the center

I'm working on a Picture Viewer with JavaFX. My current problem is following:

Every time a new Image is showing in the ImageViewer (when the user clicks "Previous" or "Next") the ImageViewer shall get recentered in its Parent node, in this case it's a HBox. I'm using the setTranslate methods and it's working fine, BUT it doesn't work properly because the ImageView is taking different positions each time when a new Image was loaded.

I'm using this method to recenter the ImageView:

public void adjustImageViewBounds()
{
    double windowWidth = MAIN.getWindow().getScene().getWidth();
    double windowHeight = MAIN.getWindow().getScene().getHeight();
    double imageWidth = GUI.getImageView().getImage().getWidth();
    double imageHeight = GUI.getImageView().getImage().getHeight();
    boolean isFullScreen = MAIN.getWindow().isFullScreen();

    GUI.getImageView().setFitWidth(windowWidth - 50 > imageWidth ? imageWidth : windowWidth - 50);

    // 50 ~ 25px space on the left and right side

    boolean scrollBarVisible = false;
    Set<Node> nodes = GUI.getImageViewScrollPane().lookupAll(".scroll-bar");
    for(Node currentNode : nodes)
    {
        if(currentNode instanceof ScrollBar)
            if(((ScrollBar) currentNode).getOrientation() == Orientation.VERTICAL)
                if(currentNode.isVisible())
                    scrollBarVisible = true;    
    }
    if(!scrollBarVisible && !isFullScreen)
    {
        // 80 ~ GUI.getInfoBoxAndImageView().getLayoutY() -> The Y position within the window of my whole ImageView container (HBox)
        // 65 ~ GUI.getLowerControl().getHeight() -> The height of the controlbar under the ImageView
        double newTranslateY = (windowHeight / 2) - 80 - (VISIBLE_IMAGE_HEIGHT.divide(2).doubleValue());
        GUI.getInfoBoxAndImageView().setTranslateY(newTranslateY >= 0 && (newTranslateY + 80 + VISIBLE_IMAGE_HEIGHT.doubleValue()) < (windowHeight - 65) ? newTranslateY : 0);
    }
    else if(scrollBarVisible)
    {
        GUI.getInfoBoxAndImageView().setTranslateY(0);
    }
    else if(isFullScreen)
    {
        double newTranslateY = (windowHeight / 2) - 80 - (VISIBLE_IMAGE_HEIGHT.divide(2).doubleValue());
        GUI.getInfoBoxAndImageView().setTranslateY(newTranslateY >= 0 && (newTranslateY + 80 + VISIBLE_IMAGE_HEIGHT.doubleValue()) < (windowHeight - 65) ? newTranslateY : 0);
    }
}

The method's working as long as I call it AFTER the Image was loaded, but it doesn't work when I'm calling it after setting a new Image. Here is an example of when a new Image is set:

public void nextClicked()
     {
        if(PICTURE_INDEX < picturePaths.size() - 1)
        {
            String path = picturePaths.get(PICTURE_INDEX + 1).toURI().toString();
            GUI.getImageView().setImage(new Image(path));
            adjustImageViewBounds(); 
            PICTURE_INDEX += 1;
        }
     }

To solve this I've been trying to use different Listeners:

GUI.getImageViewer().imageProperty().addListener(newImage -> 
{
   while(newImage.getProgress() < 1.0)
   {
      //Do nothing until the Image is completely loaded
   }
   adjustImageViewBounds();
   System.out.println("End reached");
});

The end was reached actually, but the method didn't affect the ImageView's position?!? Also not working:

public void nextClicked()
{
   if(PICTURE_INDEX < picturePaths.size() - 1)
   {
      String path = picturePaths.get(PICTURE_INDEX + 1).toURI().toString();
      Image newImage = new Image(path);
      newImage.progressProperty().addListener((obs, oldV, newV) -> 
      {
         if(newV.doubleValue() == 1.0)
            adjustImageViewBounds();
      });
      GUI.getImageView().setImage(newImage); 
      PICTURE_INDEX += 1;
    }
}

Just for fun I tried this and it worked but it's not a reasonable solution of course:

GUI.getImageView().setOnMouseClicked(event -> adjustImageViewBounds());

To summarize all that confusing information: I want my ImageView to get recentered by the adjustImageViewBounds() method, which works itself! Recenter means to place my ImageView in the mid of the Scene, either the X and Y position.

Thanks in advance for your support.

Upvotes: 0

Views: 1288

Answers (1)

James_D
James_D

Reputation: 209330

Instead of moving the ImageView from the position that its parent determines for it, using setTranslateY(...), it's almost certainly better to choose and configure a parent that will position it the way you want in the first place. Both HBox and VBox, for example, have a setAlignment(..) method that determines the overall alignment of the child nodes within the parent. The most "general" (i.e. flexible) predefined layout is the GridPane, in which child nodes are positioned in a grid, and can span multiple cells in the grid. Different columns and rows in the grid can have different widths and heights, and you can configure how a child node behaves if its allocated cell(s) have more space than the node's preferred size.

Some useful links:

An overview of all the layout panes is given in the tutorial. A slightly old, but still useful, presentation on the overall layout mechanism is available on parleys.com (registration required).

Upvotes: 1

Related Questions