tutorial español botones javafx-2 fxml

español - ¿Cómo crear componentes personalizados en JavaFX 2.0 usando FXML?



javafx tutorial español (3)

La respuesta rápida es la etiqueta <fx: include>; sin embargo, deberá establecer ChoiceModel en la clase Controller.

<VBox xmlns:fx="http://javafx.com/fxml" fx:controller="fxmltestinclude.ChoiceDemo" > <children> **<fx:include source="Choice.fxml" />** <ListView fx:id="choices" /> </children> </VBox>

Parece que no puedo encontrar ningún material sobre el tema. Para dar un ejemplo más concreto, digamos que quiero crear un componente simple que combine una casilla de verificación y una etiqueta. A continuación, complete un ListView con instancias de este componente personalizado.

ACTUALIZACIÓN: ver mi respuesta para el código completo

ACTUALIZACIÓN 2: para obtener un tutorial actualizado, consulte la documentación oficial . Hubo muchas cosas nuevas que se agregaron en 2.2. Finalmente, la Introducción a FXML cubre prácticamente todo lo que necesita saber sobre FXML.

ACTUALIZACIÓN 3: Hendrik Ebbers hizo una publicación de blog extremadamente útil sobre los controles personalizados de interfaz de usuario.


Para JavaFx 2.1, puede crear un componente de control FXML personalizado de esta manera:

<?xml version="1.0" encoding="UTF-8"?> <?import java.lang.*?> <?import java.util.*?> <?import javafx.scene.*?> <?import javafx.scene.control.*?> <?import javafx.scene.layout.*?> <?import customcontrolexample.myCommponent.*?> <VBox xmlns:fx="http://javafx.com/fxml" fx:controller="customcontrolexample.FXML1Controller"> <children> <MyComponent welcome="1234"/> </children> </VBox>

Código de componente:

MyComponent.java

package customcontrolexample.myCommponent; import java.io.IOException; import javafx.beans.property.StringProperty; import javafx.fxml.FXMLLoader; import javafx.scene.Node; import javafx.scene.layout.Pane; import javafx.util.Callback; public class MyComponent extends Pane { private Node view; private MyComponentController controller; public MyComponent() { FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("myComponent.fxml")); fxmlLoader.setControllerFactory(new Callback<Class<?>, Object>() { @Override public Object call(Class<?> param) { return controller = new MyComponentController(); } }); try { view = (Node) fxmlLoader.load(); } catch (IOException ex) { } getChildren().add(view); } public void setWelcome(String str) { controller.textField.setText(str); } public String getWelcome() { return controller.textField.getText(); } public StringProperty welcomeProperty() { return controller.textField.textProperty(); } }

MyComponentController.java

package customcontrolexample.myCommponent; import java.net.URL; import java.util.ResourceBundle; import javafx.fxml.FXML; import javafx.fxml.Initializable; import javafx.scene.control.TextField; public class MyComponentController implements Initializable { int i = 0; @FXML TextField textField; @FXML protected void doSomething() { textField.setText("The button was clicked #" + ++i); } @Override public void initialize(URL location, ResourceBundle resources) { textField.setText("Just click the button!"); } }

myComponent.fxml

<?xml version="1.0" encoding="UTF-8"?> <?import java.lang.*?> <?import java.util.*?> <?import javafx.scene.*?> <?import javafx.scene.control.*?> <?import javafx.scene.layout.*?> <VBox xmlns:fx="http://javafx.com/fxml" fx:controller="customcontrolexample.myCommponent.MyComponentController"> <children> <TextField fx:id="textField" prefWidth="200.0" /> <Button mnemonicParsing="false" onAction="#doSomething" text="B" /> </children> </VBox>

Este código debe verificar si no hay pérdida de memoria.


Actualización: para obtener un tutorial actualizado, consulte la documentación oficial . Hubo muchas cosas nuevas que se agregaron en 2.2. Además, la Introducción a FXML cubre prácticamente todo lo que necesita saber sobre FXML. Finalmente, Hendrik Ebbers hizo una publicación de blog extremadamente útil sobre los controles de interfaz de usuario personalizados.

Después de unos días de mirar alrededor de la API y leer algunos documentos ( Introducción a FXML , Primeros pasos con el enlace de propiedades FXML , Futuro de FXML ), he encontrado una solución bastante sensata. La información menos directa que aprendí de este pequeño experimento fue que la instancia de un controlador (declarado con fx: controller en FXML) está en manos de FXMLLoader que cargó el archivo FXML ... Lo peor de todo es que este hecho importante solo se menciona en un lugar en todos los documentos que vi:

un controlador generalmente solo es visible para el cargador FXML que lo crea

Por lo tanto, recuerde, para programar (desde código Java) obtener una referencia a la instancia de un controlador que se declaró en FXML con fx:controller use FXMLLoader.getController() (consulte la implementación de la clase ChoiceCell a continuación para obtener un completo ejemplo).

Otra cosa a tener en cuenta es que Property.bindBiderctional() establecerá el valor de la propiedad de llamada en el valor de la propiedad pasada como argumento. Dadas dos propiedades booleanas target (originalmente configurado como false ) y source (inicialmente configurado como true ), la llamada target.bindBidirectional(source) establecerá el valor de target en true . Obviamente, cualquier cambio posterior a cualquiera de las propiedades cambiará el valor de la otra propiedad ( target.set(false) hará que el valor de la source se establezca en false ):

BooleanProperty target = new SimpleBooleanProperty();//value is false BooleanProperty source = new SimpleBooleanProperty(true);//value is true target.bindBidirectional(source);//target.get() will now return true target.set(false);//both values are now false source.set(true);//both values are now true

De todos modos, aquí está el código completo que demuestra cómo FXML y Java pueden funcionar juntos (así como algunas otras cosas útiles)

Estructura del paquete:

com.example.javafx.choice ChoiceCell.java ChoiceController.java ChoiceModel.java ChoiceView.fxml com.example.javafx.mvc FxmlMvcPatternDemo.java MainController.java MainView.fxml MainView.properties

FxmlMvcPatternDemo.java

package com.example.javafx.mvc; import java.util.ResourceBundle; import javafx.application.Application; import javafx.fxml.FXMLLoader; import javafx.scene.Parent; import javafx.scene.Scene; import javafx.stage.Stage; public class FxmlMvcPatternDemo extends Application { public static void main(String[] args) throws ClassNotFoundException { Application.launch(FxmlMvcPatternDemo.class, args); } @Override public void start(Stage stage) throws Exception { Parent root = FXMLLoader.load ( FxmlMvcPatternDemo.class.getResource("MainView.fxml"), ResourceBundle.getBundle(FxmlMvcPatternDemo.class.getPackage().getName()+".MainView")/*properties file*/ ); stage.setScene(new Scene(root)); stage.show(); } }

MainView.fxml

<?xml version="1.0" encoding="UTF-8"?> <?import java.lang.*?> <?import javafx.scene.*?> <?import javafx.scene.control.*?> <?import javafx.scene.layout.*?> <VBox xmlns:fx="http://javafx.com/fxml" fx:controller="com.example.javafx.mvc.MainController" prefWidth="300" prefHeight="400" fillWidth="false" > <children> <Label text="%title" /> <ListView fx:id="choicesView" /> <Button text="Force Change" onAction="#handleForceChange" /> </children> </VBox>

MainView.properties

title=JavaFX 2.0 FXML MVC demo

MainController.java

package com.example.javafx.mvc; import com.example.javafx.choice.ChoiceCell; import com.example.javafx.choice.ChoiceModel; import java.net.URL; import java.util.ResourceBundle; import javafx.collections.FXCollections; import javafx.event.ActionEvent; import javafx.fxml.FXML; import javafx.fxml.Initializable; import javafx.scene.control.ListCell; import javafx.scene.control.ListView; import javafx.util.Callback; public class MainController implements Initializable { @FXML private ListView<ChoiceModel> choicesView; @Override public void initialize(URL url, ResourceBundle rb) { choicesView.setCellFactory(new Callback<ListView<ChoiceModel>, ListCell<ChoiceModel>>() { public ListCell<ChoiceModel> call(ListView<ChoiceModel> p) { return new ChoiceCell(); } }); choicesView.setItems(FXCollections.observableArrayList ( new ChoiceModel("Tiger", true), new ChoiceModel("Shark", false), new ChoiceModel("Bear", false), new ChoiceModel("Wolf", true) )); } @FXML private void handleForceChange(ActionEvent event) { if(choicesView != null && choicesView.getItems().size() > 0) { boolean isSelected = choicesView.getItems().get(0).isSelected(); choicesView.getItems().get(0).setSelected(!isSelected); } } }

ChoiceView.fxml

<?xml version="1.0" encoding="UTF-8"?> <?import java.lang.*?> <?import javafx.scene.*?> <?import javafx.scene.control.*?> <?import javafx.scene.layout.*?> <HBox xmlns:fx="http://javafx.com/fxml" fx:controller="com.example.javafx.choice.ChoiceController" > <children> <CheckBox fx:id="isSelectedView" /> <Label fx:id="labelView" /> </children> </HBox>

ChoiceController.java

package com.example.javafx.choice; import javafx.beans.value.ChangeListener; import javafx.beans.value.ObservableValue; import javafx.fxml.FXML; import javafx.fxml.Initializable; import javafx.scene.control.CheckBox; import javafx.scene.control.Label; public class ChoiceController { private final ChangeListener<String> LABEL_CHANGE_LISTENER = new ChangeListener<String>() { public void changed(ObservableValue<? extends String> property, String oldValue, String newValue) { updateLabelView(newValue); } }; private final ChangeListener<Boolean> IS_SELECTED_CHANGE_LISTENER = new ChangeListener<Boolean>() { public void changed(ObservableValue<? extends Boolean> property, Boolean oldValue, Boolean newValue) { updateIsSelectedView(newValue); } }; @FXML private Label labelView; @FXML private CheckBox isSelectedView; private ChoiceModel model; public ChoiceModel getModel() { return model; } public void setModel(ChoiceModel model) { if(this.model != null) removeModelListeners(); this.model = model; setupModelListeners(); updateView(); } private void removeModelListeners() { model.labelProperty().removeListener(LABEL_CHANGE_LISTENER); model.isSelectedProperty().removeListener(IS_SELECTED_CHANGE_LISTENER); isSelectedView.selectedProperty().unbindBidirectional(model.isSelectedProperty()) } private void setupModelListeners() { model.labelProperty().addListener(LABEL_CHANGE_LISTENER); model.isSelectedProperty().addListener(IS_SELECTED_CHANGE_LISTENER); isSelectedView.selectedProperty().bindBidirectional(model.isSelectedProperty()); } private void updateView() { updateLabelView(); updateIsSelectedView(); } private void updateLabelView(){ updateLabelView(model.getLabel()); } private void updateLabelView(String newValue) { labelView.setText(newValue); } private void updateIsSelectedView(){ updateIsSelectedView(model.isSelected()); } private void updateIsSelectedView(boolean newValue) { isSelectedView.setSelected(newValue); } }

ChoiceModel.java

package com.example.javafx.choice; import javafx.beans.property.BooleanProperty; import javafx.beans.property.SimpleBooleanProperty; import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.StringProperty; public class ChoiceModel { private final StringProperty label; private final BooleanProperty isSelected; public ChoiceModel() { this(null, false); } public ChoiceModel(String label) { this(label, false); } public ChoiceModel(String label, boolean isSelected) { this.label = new SimpleStringProperty(label); this.isSelected = new SimpleBooleanProperty(isSelected); } public String getLabel(){ return label.get(); } public void setLabel(String label){ this.label.set(label); } public StringProperty labelProperty(){ return label; } public boolean isSelected(){ return isSelected.get(); } public void setSelected(boolean isSelected){ this.isSelected.set(isSelected); } public BooleanProperty isSelectedProperty(){ return isSelected; } }

ChoiceCell.java

package com.example.javafx.choice; import java.io.IOException; import java.net.URL; import javafx.fxml.FXMLLoader; import javafx.fxml.JavaFXBuilderFactory; import javafx.scene.Node; import javafx.scene.control.ListCell; public class ChoiceCell extends ListCell<ChoiceModel> { @Override protected void updateItem(ChoiceModel model, boolean bln) { super.updateItem(model, bln); if(model != null) { URL location = ChoiceController.class.getResource("ChoiceView.fxml"); FXMLLoader fxmlLoader = new FXMLLoader(); fxmlLoader.setLocation(location); fxmlLoader.setBuilderFactory(new JavaFXBuilderFactory()); try { Node root = (Node)fxmlLoader.load(location.openStream()); ChoiceController controller = (ChoiceController)fxmlLoader.getController(); controller.setModel(model); setGraphic(root); } catch(IOException ioe) { throw new IllegalStateException(ioe); } } } }