javafxgriffongroovyfx

Griffon groovyfx controller access


Real newbie to the JavaFX scene so here goes.

griffon 1.4.0 - jdk 1.7.0_45

griffon plugins ( groovyfx-0.9.1, javafx-0.10.0)

I'm trying to implement a simple focus listener to one of my textfields. The idea is that once the textfield is focused I want to change the message of a label within the same view. I'm sure the answer is simple but I think I've over complicated matters.

For overall context, I'm trying to implement my views by reading in fxml and using the groovy view for binding and such.

application(title: 'Myapp', sizeToScene: true, resizable: false, centerOnScreen: true) {
scene(fill: WHITE) {
    fxml(app.getResourceAsURL('fxtemplates/login.fxml').text) {
         // my bindings and onActions ( which are working great ) go in here
}

Looking at the groovyfx docs there doesn't appear to be a method for onFocus like that of onAction and such so I have to add a listener to the focusedProperty - great no sweat. I first tried writing a closure for the ChangeListener :

aTextField.focusedProperty().addListener({ obsVal, oldVal, newVal ->
       // do something...    
})

But Uberbuilder complained and I'm obviously doing that wrong ( a nudge in this direction would help )

So I wrote an empty FocusListener Class that implements a ChangeListener and then bound that in my view.

class FocusListener implements ChangeListener<Boolean> {

@Override
public void changed(ObservableValue<? extends Boolean> observableValue, Boolean oldVal, Boolean newVal ) {
    // for the view to override...
}

}

Then in my view

aTextField.focusedProperty().addListener(new FocusListener () {

            @Override
            public void changed(ObservableValue<? extends Boolean> observableValue, Boolean oldVal, Boolean newVal ) {
                if(newVal != null && newVal == Boolean.TRUE) {
                    execInsideUIAsync {
                    println 'focus gained'

                    }
                }
            }

        });

The code executes just fine ( focus gained prints ) but of course I'm down in scope so I don't have access to my controller or view components. For grins ( not really liking it but trying it out ) I passed in my controller to the constructor of my FocusListener and called a method on my controller.

class FocusListener implements ChangeListener<Boolean> {

def controller

public FocusListener(controller) {
    this.controller = controller
}

@Override
public void changed(ObservableValue<? extends Boolean> observableValue, Boolean oldVal, Boolean newVal ) {
    // for the view to override...
}

}

and then in my view

aTextField.focusedProperty().addListener(new FocusListener (controller) {

            @Override
            public void changed(ObservableValue<? extends Boolean> observableValue, Boolean oldVal, Boolean newVal ) {
                if(newVal != null && newVal == Boolean.TRUE) {
                    println "Gained Focus"
                    execInsideUIAsync {
                       println 'focus gained'
                        controller.&clearMessages
                    }
                }
            }

        });

Nothing complained but my controller method never exectued ( nothing complained either, the output was 'focus gained'. In my debugger I do see a reference to the controller... but at this point, I'm down the rabbit hole and sure of an incorrect implementation...

Could someone please help me?

Thanks!


Solution

  • Ok - so after more tinkering around ( and a good run ). It's quite easy.

    In the view I added a listener to the focusedProperty of the textfield. That listener is referenced in the model thus :

    aTextField.focusedProperty().addListener(model.fieldFocusListener)
    

    then in the model I implement changes to the already bound values

    @FXBindable String field_one
    @FXBindable String field_two
    @FXBindable String message
    
    //...
    
    ChangeListener fieldFocusListener
    
    void mvcGroupInit(Map args) {
    
        fieldFocusListener = new ChangeListener() {
            @Override
            void changed(ObservableValue observableValue, Object t, Object t1) {
               this.setMessage('your message here')
            }
        }
    
    }
    

    Which makes total sense to me in the model as I have all the access I need to manipulate my view. Anyway, I hope this helps someone else in need.