1

I'm using JavaFX, fxml, and css to display buttons with an image. When I change the size of the window, the image of the button nicely moves with the center of the button. I also want the image to scale up to, say, 80% of the button, but I can't figure out how to do that. A Java solution would be fine as well, if it can't be done in just fxml or css. The code is below, but I also made a repo with a MWE on GitHub.

fxml

<?import javafx.geometry.Insets?>
<?import javafx.scene.layout.GridPane?>

<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.RowConstraints?>
<GridPane fx:controller="sample.Controller"
          xmlns:fx="http://javafx.com/fxml"
          alignment="center"
          hgap="10"
          vgap="10">
    <rowConstraints>
        <RowConstraints percentHeight="50"/>
        <RowConstraints percentHeight="50"/>
    </rowConstraints>

    <Button
            fx:id="buttonUp"
            GridPane.columnIndex="0"
            GridPane.rowIndex="0"
            maxHeight="Infinity"
            maxWidth="Infinity"
            onMousePressed="#buttonUp"
            onMouseReleased="#buttonUp">
    </Button>

    <Button
            fx:id="buttonDown"
            GridPane.columnIndex="0"
            GridPane.rowIndex="1"
            maxHeight="Infinity"
            maxWidth="Infinity"
            onMousePressed="#buttonUp"
            onMouseReleased="#buttonUp">
    </Button>
</GridPane>

css

#buttonUp {
     -fx-graphic: url('resources/up_small.png');
     -fx-focus-color: transparent;
     -fx-faint-focus-color: transparent;
     -fx-effect: null;
     -fx-background-color: transparent;
 }

#buttonUp:pressed  {
    -fx-graphic: url("resources/up_pressed_small.png");
}

#buttonDown {
    -fx-graphic: url('resources/down_small.png');
    -fx-focus-color: transparent;
    -fx-faint-focus-color: transparent;
    -fx-effect: null;
    -fx-background-color: transparent;
}

#buttonDown:pressed  {
    -fx-graphic: url("resources/down_pressed_small.png");
}

Controller.java

package sample;

import javafx.fxml.FXML;
import javafx.scene.input.MouseEvent;

public class Controller {

    @FXML
    protected void buttonUp(MouseEvent event) {
        if(event.getEventType().equals(MouseEvent.MOUSE_PRESSED)) {
            System.out.println("Up button pressed.");
        } else { // mouse released
            System.out.println("Up button released.");
        }
    }

    @FXML
    protected void buttonDown(MouseEvent event) {
        if(event.getEventType().equals(MouseEvent.MOUSE_PRESSED)) {
            System.out.println("Down button pressed.");
        } else { // mouse released
            System.out.println("Down button released.");
        }
    }
}

Main.java

package sample;

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;

import java.io.File;

public class Main extends Application {

    @Override
    public void start(Stage primaryStage) throws Exception{
        Parent root = FXMLLoader.load(getClass().getResource("sample.fxml"));
        primaryStage.setTitle("Resizing");
        Scene scene = new Scene(root, 650, 350);
        File file = new File("src/sample/stylesheet.css");
        scene.getStylesheets().add(file.toURI().toString());
        primaryStage.setScene(scene);
        primaryStage.show();
    }


    public static void main(String[] args) {
        launch(args);
    }
}
Abby
  • 1,610
  • 3
  • 19
  • 35
  • Post a [mcve].. – user1803551 Oct 30 '16 at 14:11
  • @user1803551 I created a repo on GitHub with an example. – Abby Oct 30 '16 at 15:59
  • Please post the code in the question and not in an external site. – user1803551 Oct 30 '16 at 17:35
  • @user1803551 I added all the code. – Abby Oct 30 '16 at 18:28
  • Can you recheck the paths? The FXML is inside recources but not referenced as such, the images in the css give an error unless you add a `/` in front of their path, and even then when it loads with no errors I don't see any buttons. – user1803551 Oct 31 '16 at 07:00
  • -fx-background-size: 100px 100px; See if this works. Try using this in the css that you want to use to grow the picture. Play with the numbers. – SedJ601 Oct 31 '16 at 16:04
  • @SedrickJefferson Sure, that works, if you don't want the buttons to be growing/shrinking when changing the size of the window, right? – Abby Oct 31 '16 at 16:18
  • Didn't take that into account. It seems you need a way to bind your image size to the button size. Which probably can be done programmatically. – SedJ601 Oct 31 '16 at 16:23
  • @SedrickJefferson Binding the image size to the button size sounds logical. Yet your suggestion didn't work. – Abby Oct 31 '16 at 16:33
  • 1
    My last try lol. Read here http://stackoverflow.com/questions/23229149/javafx-automatic-resizing-and-button-padding – SedJ601 Oct 31 '16 at 18:21

1 Answers1

1

This works!

    @Override
    public void initialize(URL url, ResourceBundle rb) {


        try {
            // TODO
            File selectedFile = new File("splash.png");
            if(selectedFile.exists())
            {
                System.out.println(selectedFile.getAbsolutePath());
            }
            //Image image = new Image(selectedFile.toURI().toURL().toString());
            //Image image = new Image(getClass().getResourceAsStream(selectedFile.getCanonicalPath()));
            Image image = new Image(selectedFile.toURI().toURL().toString());
            ImageView ivMain = new ImageView(image);
            ivMain.fitHeightProperty().bind(apMain.heightProperty());
            ivMain.fitWidthProperty().bind(apMain.widthProperty());
            Button btn2 = new Button("", ivMain);
            apMain.getChildren().add(btn2);
            btn2.setMaxWidth(Double.MAX_VALUE);
            btn2.setMaxHeight(Double.MAX_VALUE);


            apMain.widthProperty().addListener(new ChangeListener<Number>(){
                @Override
                public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
                    btn2.setPrefWidth(newValue.intValue());
                }

            });

            apMain.heightProperty().addListener(new ChangeListener<Number>(){
                @Override
                public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
                    btn2.setPrefHeight(newValue.intValue());
                }

            });
        } catch (MalformedURLException ex) {
            Logger.getLogger(FXMLDocumentController.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            Logger.getLogger(FXMLDocumentController.class.getName()).log(Level.SEVERE, null, ex);
        }



    }  

Before:

After:

SedJ601
  • 12,173
  • 3
  • 41
  • 59
  • What is `apMain`? – Abby Nov 01 '16 at 09:03
  • apMain is an AnchorPane. – SedJ601 Nov 01 '16 at 12:04
  • 2
    Aaah yes, thank you! Knowing that I got it working. All I had to do was set the image as background image of the `Button` (using CSS, `-fx-background-size: contain` did the trick to keep the image fully on the `Button`), then give my `GridPane` an `fx:id` so I could refer to it from the `Controller`. Then add the `ChangeListener` to the `GridPane` like you did. – Abby Nov 01 '16 at 15:44