Proposal for improving nested controller interaction in JavaFX 2.2
Richard Bair
richard.bair at oracle.com
Tue Feb 21 11:27:57 PST 2012
Initial reaction is positive, it matches more closely with what my intuition was (and, since FXML doesn't _require_ extending from Controller, nobody is forced to use it, but if you do use it you get more for free). I had also thought about having some subclasses that work with different types of controllers, such as a PresentationModel style, etc that might add additional code or conventions. I like the idea of having an abstract class.
One question: is there a way that somebody externally could do this themselves? That is, although we could (and perhaps should) provide this API ourselves, what would perhaps be even more useful is if the underlying plumbing were rich enough that somebody else would be able to build their on "Controller" base class with this support, rather than requiring that they extend our Controller.
Richard
On Feb 21, 2012, at 7:36 AM, Greg Brown wrote:
> A recent thread in the discussion forum (https://forums.oracle.com/forums/thread.jspa?messageID=10142434�) revealed a shortcoming in how nested controllers are currently handled in FXML. The problem is that it is not easy to access nested controllers from an including controller. This is particularly problematic when attempting to use FXML for code modularization. While the including controller can access the root element of an included document, it is not possible to access that document's controller. This effectively makes it impossible to access any application-specific functionality defined by the include.
>
> To resolve this issue, I would like to propose the following solution. A new abstract Controller class will be defined in the javafx.fxml package. This class will supersede the existing Initializable interface. The public API for this class will be as follows:
>
> public abstract class Controller {
> public URL getLocation() { ... }
> protected void setLocation(URL location) { ... }
>
> public ResourceBundle getResources() { ... }
> protected void setResources(ResourceBundle resources) { ... }
>
> public Map<String, Controller> getIncludes() { ... }
>
> public void initialize() { ... }
> }
>
> The "location" and "resources" properties mirror the values passed to the current Initializable#initialize() method. The initialize() method itself has been updated to take no arguments. This allows us to more easily add additional initialization properties in the future without breaking API compatibility. Further, since "controller" is an implicit variable in the document's namespace as of JavaFX 2.1, script code can access these properties as "controller.location" and "controller.resources" (something that is not currently possible).
>
> The getIncludes() method is the key feature. It allows extending classes to access functionality defined by included controllers. The map keys are the IDs of any <fx:include> elements, and the values are the controllers defined by the included documents. When combined with bi-directional binding feature we will hopefully be adding in 2.2, this makes it much easier to get data into and out of dialogs.
>
> For example, the following markup defines a basic dialog for editing a simple contact record:
>
> <Scene fx:id="scene" fx:controller="examples.fxml.dialog.DialogSceneController"
> xmlns:fx="http://javafx.com/fxml">
> <VBox>
> <TextField text="#{controller.contact.firstName}"/>
> <TextField text="#{controller.contact.lastName}"/>
> <TextField text="#{controller.contact.emailAddress}"/>
>
> <Button text="OK" onAction="#handleOKButtonAction"/>
> </VBox>
> </Scene>
>
> Note that the values of the text fields are bound to the properties of the Contact, which is itself defined as a property of the dialog's controller. The controller for the application's main window might invoke code such as this to populate and show the dialog:
>
> protected void handleEditButtonAction() {
> // Get the selected contact
> Contact contact = contactChoiceBox.getSelectionModel().getSelectedItem();
>
> // Populate the dialog with the contact information
> DialogSceneController dialogSceneController = (DialogSceneController)getIncludes().get("dialog");
> dialogSceneController.setContact(contact);
>
> // Show the dialog
> Stage dialogStage = new Stage();
> dialogStage.setScene(dialog);
> dialogStage.initOwner(scene.getWindow());
> dialogStage.initModality(Modality.APPLICATION_MODAL);
> dialogStage.show();
> }
>
> Calling setContact() on the dialog's controller causes the UI elements to be populated with the values from the contact record. Because the fields are bound bi-directionally, when the dialog closes, the contact record will contain the updated values from the dialog.
>
> I have prototyped this and done some preliminary testing and I think it works well. I would be interested to hear what others think.
>
> Thanks,
> Greg
>
More information about the openjfx-dev
mailing list