0

I am trying to create a menu for my game using JavaFX. I want to have a "Continue" button that I only want to be visible when a game is running. I'm trying to bind the button's visibility property to a controller, but it doesn't appear to be working- the button is just invisible.

I have looked around Google and StackExchange, and I've found information on how to set it programmatically, but I'd rather not couple the Java code any tighter to the FXML than I really need to.

Here is my code for the FXML page...

<?xml version="1.0" encoding="UTF-8"?>
    <?import javafx.geometry.*?>
    <?import javafx.scene.control.*?>
    <?import javafx.scene.layout.*?>
    <?import javafx.scene.text.*?>

<GridPane fx:controller="com.silferein.erq.gui.MenuController" 
xmlns:fx="http://javafx.com/fxml" alignment="center" hgap="10" vgap="10">
    <padding><Insets top="25" right="25" bottom="25" left="25"/></padding>

    <Text id="welcome-text" text="Main Menu" GridPane.columnIndex="0" GridPane.rowIndex="0" GridPane.columnSpan="2"/>
    <Button text="New" onAction="#handleNew" GridPane.rowIndex="1"/>
    <Button text="Continue" onAction="#handleContinue" GridPane.rowIndex="2" visible="${controller.gameRunning}" />
    <Button text="Load" onAction="#handleLoad" GridPane.rowIndex="3"/>
    <Button text="Save" onAction="#handleSave" GridPane.rowIndex="4"/>
    <Button text="Quit" onAction="#handleQuit" GridPane.rowIndex="5"/>
</GridPane>

Here is my code for the controller (trimmed somewhat):

@FXML protected void handleContinue(ActionEvent event) {
    System.out.println("Continue!");
    parent.handle(new GUIEvent(GUIEvent.Type.CONTINUE));
}
// ...
@FXML protected boolean getGameRunning() {
    System.out.println("Test!");
    // Some check to see if there's a game in progress...
    return true;
}

Any idea what I'm doing wrong? My code compiles and all buttons except "Continue" are visible and working.

John
  • 1,440
  • 1
  • 11
  • 18
  • Do I understand correct: You code provides a BooleanProperty that will be true if the game is running and the method BooleanProperty gameRunning() returns that property? Or has the method getGameRunning() to be polled to obtain the running status? – Jens-Peter Haack Nov 20 '14 at 07:14
  • You might be interested in the techniques used in the answer to [Is there a way to implement a property like “rendered” on JAVAFX?](http://stackoverflow.com/questions/19666982/is-there-a-way-to-implement-a-property-like-rendered-on-javafx), which discusses manipulating visibility based on conditions (in that case it's Role based conditions, so not exactly applicable to your situation, but still probably useful to understand). – jewelsea Nov 20 '14 at 22:07

2 Answers2

2

Create a BooleanProperty:

BooleanProperty isGameRunning = new SimpleBooleanProperty(false);

Give your 'continue'-button a fx:id (lets say btnContinue) and inject it into a controller.

@Inject Button btnContinue;

Bind the buttons visibility property to your isGameRunning property. (Do this in your initialize method)

btnContinue.visibleProperty().bind(isGameRunning);

Now whenever you change the value of isGameRunning, the visibility of your button will change.

haisi
  • 1,035
  • 1
  • 10
  • 30
2

As sketched out by haisi, the missing link is to extend the Initialize() method to create a property binding from yout gameRunning boolean (Property) to the visibleProperty() of the button:

FXML:

xmlns:fx="http://javafx.com/fxml" alignment="center" hgap="10" vgap="10">
    <padding><Insets top="25" right="25" bottom="25" left="25"/></padding>

    <Text id="welcome-text" text="Main Menu" GridPane.columnIndex="0" GridPane.rowIndex="0" GridPane.columnSpan="2"/>
    <Button text="New" onAction="#handleNew" GridPane.rowIndex="1"/>
    <Button fx:id="continueBtn" text="Continue" onAction="#handleContinue" GridPane.rowIndex="2" />
    <Button text="Load" onAction="#handleLoad" GridPane.rowIndex="3"/>
    <Button text="Save" onAction="#handleSave" GridPane.rowIndex="4"/>
    <Button text="Quit" onAction="#handleQuit" GridPane.rowIndex="5"/>
</GridPane>

Class:

public class GameController implements Initializable {
    private BooleanProperty gameRunning = new SimpleBooleanProperty(false);

    @FXML Button continueBtn;

    @FXML protected void handleNew(ActionEvent event) {
        gameRunning.set(true);
    }
    @FXML protected void handleLoad(ActionEvent event) {

    }
    @FXML protected void handleSave(ActionEvent event) {

    }
    @FXML protected void handleQuit(ActionEvent event) {
        gameRunning.set(false);
    }
    @FXML protected void handleContinue(ActionEvent event) {
        System.out.println("Continue!");
        //parent.handle(new GUIEvent(GUIEvent.Type.CONTINUE));
    }
    @Override
    public void initialize(URL arg0, ResourceBundle arg1) {
        continueBtn.visibleProperty().bind(gameRunning);  
    }
}

I had the expectation, that it should be sufficient to implement gameRunning as full javafx bean property (setGameRunning, getGameRunning, gameRunningProperty) and the visible="${gameRunning}" shall work out automatically, but was unable to achieve that properly. It had been discussed in: Binding a Label's text property (in an FXML file) to an IntegerProperty (in a controller)

Community
  • 1
  • 1
Jens-Peter Haack
  • 1,887
  • 13
  • 18