Fumée Noire
Fumée Noire

Reputation: 123

How do I get the ImageView contained inside a Pane?

Situation

I have an application which contains a GridPane thats composed of multiple Panes. Inside of every Pane is an ImageView that allows me to display an Image inside that Pane. My application follows the MVC pattern and I would like my setPaneImage( ) function to dynamically change one Pane's ImageView image.

Problem

I don't know how to access the Pane's ImageView ? I know you can use the ImageView's setImage( ) to change its image. To access the ImageView contained inside the Pane, I suppose you have to use the .getChildren( ) method but I can't figure out how I can implement this...

Here's the simplified code :

public class ViewController extends Application implements EventHandler
{
    final Image paneVide = new Image( "sample/img/paneVide.png" );

    @Override
    public void start(Stage primaryStage) throws Exception
    {
        // Initializing attributes
        BorderPane borderPane = new BorderPane( );
        gridPane = new GridPane( );

        Pane p = new Pane( );

        // Adding ImageView to the Pane
        ImageView imv = new ImageView( );
        imv.setPreserveRatio( true );
        imv.setFitHeight( p.getHeight() );
        imv.setFitWidth( p.getWidth() );
        p.getChildren().add( imv );

        // Setting handler
        p.setOnMouseEntered( this );

        // Adding to GridPane
        gridPane.add( p, i, j );

        // [...] Rest of the display code
    }


    @Override
    public void handle(Event event)
    {
        Pane p;

        if( event.getSource() instanceof Pane ) {
            p = (Pane) event.getSource();

            // MOUSE HOVER
            if( event.getEventType().toString() == "MOUSE_ENTERED" )
                setPaneImage( p, "VIDE" );
        }
    }


    // Here's the function where I don't really know what to do...
    // How do I access the Pane's ImageView so that I can dynamically
    // change its image ??
    public void setPaneImage( Pane p, String img )
    {
        switch( img )
        {
            case "VIDE":
                p.getChildren().add( new ImageView(paneVide) );  // Setting pane's image
                break;
        }
    }
}

Thank you very much !

Upvotes: 0

Views: 694

Answers (1)

fabian
fabian

Reputation: 82461

The simplest way would be to store a reference to the ImageView in a field:

private ImageView imv;

public void start(Stage primaryStage) throws Exception {
    ...
    this.imv = new ImageView();
    ...
}

public void setPaneImage(Pane p, String img) {
    ...
    imv.setImage(paneVide);
    ...
}

Assuming the ImageView is the only child of the Pane, you could also retrieve the ImageView from the child list:

public void setPaneImage(Pane p, String img) {
    ImageView imv = (ImageView) p.getChildren().get(0);
    ...
}

Additional notes:

Some parts of your code could be considered bad practice:

if(event.getEventType().toString() == "MOUSE_ENTERED")
  1. You're comparing Strings using == instead of equals
  2. Instead of comparing the type converted to String you should compare to the event type: event.getEventType() == MouseEvent.MOUSE_ENTERED
  3. You don't need that check. It's the only event the handler listens to. Handling different types of events should be done using a different handler. You could create such a handler using anonymus classes or lambda expressions easily. You could avoid the source check using the same strategy.
public void setPaneImage(Pane p, String img) {
    switch( img )
    {
        case "VIDE":

Using magic strings is a bad idea. It's hard to find the error if you've got a typo in the string. You could simply just pass the Image itself (paneVide). This way you don't need the switch at all and any typos would become obvious on compilation.

imv.setFitHeight(p.getHeight());
imv.setFitWidth(p.getWidth());

You do this before the first layout pass. At that time the size of p is still 0. You should use bindings instead to accommodate for later updates of the properties:

imv.fitHeightProperty.bind(p.heightProperty());
imv.fitWidthProperty.bind(p.widthProperty());
imv.setManaged(false); // make sure p can shrink

It would also be beneficial to make sure the GridPane resizes p.

public class ViewController extends Application implements EventHandler

The Application class is the entry point to the program. Using it as controller and event handler violates the seperation of concerns principle. Also it's preferable to specify the type parameter for EventHandler.

Upvotes: 1

Related Questions