Sie sind auf Seite 1von 44

En este capítulo, aprenderá:

 Qué es FXML
 Cómo editar un documento FXML
 La estructura de un documento FXML
 Cómo crear objetos en un documento FXML
 Cómo especificar la ubicación de los recursos en documentos FXML
 Cómo usar paquetes de recursos en docsum entos de FXML
 Cómo hacer referencia a otros documentos FXML desde un documento FXML
 Cómo hacer referencia a constantes en documentos FXML
 Cómo hacer referencia a otros elementos y cómo copiar elementos en documentos
FXML
 Cómo buscar propiedades en documentos FXML
 Cómo crear controles personalizados usando FXML

FXML es un lenguaje basado en XML diseñado para construir la interfaz de usuario para
aplicaciones JavaFX. Puede usar FXML para construir una escena completa o parte de una
escena. FXML permite a los desarrolladores de aplicaciones separar la lógica para construir la
interfaz de usuario desde la lógica comercial. Si la parte de la interfaz de usuario de la
aplicación cambia, no necesita volver a compilar el código de JavaFX. En su lugar, puede
cambiar el FXML utilizando un editor de texto y volver a ejecutar la aplicación. Aún usa JavaFX
para escribir lógica comercial usando el lenguaje Java. Un documento FXML es un documento
XML. Se requiere un conocimiento básico de XML para comprender este capítulo.

Un gráfico de escena JavaFX es una estructura jerárquica de objetos Java. El formato XML es
muy adecuado para almacenar información que representa algún tipo de jerarquía. Por lo
tanto, usar FXML para almacenar la escena-gráfico es muy intuitivo. Es común usar FXML para
construir un gráfico de escena en una aplicación JavaFX. Sin embargo, el uso de FXML no se
limita a construir solo gráficos de escena. Puede construir un objeto-gráfico jerárquico de
objetos Java. De hecho, se puede usar para crear solo un objeto, como un objeto de una clase
Person.

Veamos una vista previa rápida de cómo se ve un documento FXML. Primero, cree una interfaz
de usuario simple, que consiste en un VBox con una etiqueta y un botón. El listado 29-1
contiene el código JavaFX para construir la interfaz de usuario, que le es familiar. El listado 29-
2 contiene la versión FXML para construir la misma interfaz de usuario.
La primera línea en FXML es la declaración XML estándar que utilizan los analizadores XML. Es
opcional en FXML. Si se omite, se supone que la versión y la codificación son 1 y UTF-8,
respectivamente. Las siguientes tres líneas son declaraciones de importación que
corresponden a las instrucciones de importación en código Java. Los elementos que
representan la IU, como VBox, Etiqueta y Botón, tienen el mismo nombre que las clases
JavaFX. La etiqueta <children> especifica los elementos secundarios de VBox. La propiedad de
texto para la Etiqueta y el Botón se especifica utilizando los atributos de texto de los
elementos respectivos.

Edición de documentos FXML


Un documento FXML es simplemente un archivo de texto. Normalmente, el nombre del
archivo tiene una extensión .fxml (por ejemplo, hello.fxml). Por ejemplo, puede usar el Bloc de
notas para crear un documento FXML en Windows. Si usó XML, sabe que no es fácil editar un
documento XML grande en un editor de texto. Oracle Corporation proporciona un editor visual
llamado Scene Builder para editar documentos FXML. Scene Builder es de código abierto.
Puede descargar su última versión desde
www.oracle.com/technetwork/java/javase/downloads/index.html. Scene Builder también se
puede integrar en NetBeans IDE, por lo que puede editar documentos FXML utilizando Scene
Builder desde el NetBeans IDE. Scene Builder no se trata en este libro.

Fundamentos de FXML
Esta sección cubre los conceptos básicos de FXML. Desarrollará una aplicación JavaFX simple,
que consiste en lo siguiente :

 Un VBox
 Una etiqueta
 A Buton

La propiedad de espaciado para el VBox se establece en 10 px. Las propiedades de texto para
la etiqueta y el botón están configuradas en "¡FXML es genial!" Y "Diga hola". Cuando se hace
clic en el botón, el texto de la etiqueta cambia a "¡Hola desde FXML!". La Figura 29-1 muestra
dos instancias de la ventana que muestra la aplicación.

El programa en el listado 29-3 es la implementación de JavaFX de la aplicación de ejemplo. El


programa debería ser fácil si has llegado a este capítulo en el libro.
Creando el archivo FXML
Vamos a crear un archivo FXML sayhello.fxml. Almacene el archivo en el directorio resources /
fxml donde se incluirá el directorio de recursos en CLASSPATH para la aplicación.

Agregar elementos de UI
El elemento raíz del documento FXML es el objeto de nivel superior en el objeto-gráfico. Su
objeto de nivel superior es un VBox. Por lo tanto, el elemento raíz de su FXML sería

<VBox> </ VBox>

¿Cómo sabe que para representar un VBox en el objeto-gráfico, necesita usar una etiqueta
<VBox> en FXML? Es a la vez difícil y fácil. Es difícil porque no hay documentación para las
etiquetas FXML. Es fácil porque FXML tiene algunas reglas que explican qué constituye un
nombre de etiqueta. Por ejemplo, si un nombre de etiqueta es el nombre simple o totalmente
calificado de una clase, la etiqueta creará un objeto de esa clase. El elemento anterior creará
un objeto de la clase VBox. El FXML anterior se puede reescribir utilizando el nombre de clase
completamente calificado:

<javafx.scene.layout.VBox> </javafx.scene.layout.VBox>

En JavaFX, los paneles de diseño tienen hijos. En FXML, los paneles de diseño tienen elementos
secundarios como elementos secundarios. Puede agregar una etiqueta y un botón al VBox de
la siguiente manera.

<VBox>

<Etiqueta> </ Etiqueta>

<Botón> </ Botón>

</ VBox>

Esto define la estructura básica del objeto-gráfico para esta aplicación de ejemplo. Creará un
VBox con una etiqueta y un botón. El resto de la discusión se centrará en agregar detalles, por
ejemplo, agregar texto para controles y establecer estilos para el VBox.

El FXML anterior muestra que la etiqueta y el botón son elementos secundarios de VBox. En el
sentido de la GUI, eso es cierto. Sin embargo, técnicamente, pertenecen a la propiedad de los
niños del objeto VBox, no directamente al VBox. Para ser más técnico (y un poco detallado),
puede volver a escribir el FXML anterior como se muestra a continuación.

<VBox>

< niños >

<Etiqueta> </ Etiqueta>

<Botón> </ Botón>

< niños >

</ VBox>

¿Cómo sabe que puede ignorar la etiqueta <children> en el FXML anterior y obtener los
mismos resultados? La biblioteca JavaFX contiene una Anotación DefaultProperty en el
paquete javafx.beans. Se puede usar para anotar clases. Contiene un elemento de valor del
tipo de Cadena. El elemento especifica la propiedad de la clase, que debe tratarse como la
propiedad predeterminada en FXML. Si un elemento secundario en FXML no representa una
propiedad de su elemento primario, pertenece a la propiedad predeterminada del elemento
primario. La clase VBox hereda de la clase Pane, cuya declaración es la siguiente.

@DefaultProperty ( value = "children")

el panel de clase pública extiende Región {...}

La anotación en la clase Pane hace que la propiedad children sea la propiedad predeterminada
en FXML. VBox hereda esta anotación de la clase Pane. Esta es la razón por la cual la etiqueta
<children> se puede omitir en el FXML anterior. Si ve la anotación DefaultProperty en una
clase, significa que puede omitir la etiqueta de la propiedad predeterminada en FXML.

Importación de tipos de Java en FXML


Para usar los nombres simples de las clases de Java en FXML, debe importar las clases como lo
hace en los programas Java. Hay una excepción En los programas de Java, no es necesario
importar clases del paquete java.lang. Sin embargo, en FXML, necesita importar clases de
todos los paquetes, incluido el paquete java.lang. Una instrucción de procesamiento de
importación se usa para importar una clase o todas las clases de un paquete. Las siguientes
instrucciones de procesamiento importan las clases VBox, Etiqueta y Botón.

<? import javafx.scene.layout.VBox?>

<? import javafx.scene.control.Label?>

<? import javafx.scene.control.Button?>

Las siguientes instrucciones de procesamiento de importación importan todas las clases de los
paquetes javafx.scene.control y java.lang :

<? import javafx.scene.control. *?>

<? import java.lang. *?>

La importación de miembros estáticos no es compatible con FXML. Tenga en cuenta que la


instrucción de importación no usa un punto y coma al final.

Establecer propiedades en FXML


Puede establecer propiedades para objetos Java en FXML. Una propiedad para un objeto se
puede establecer en FXML si la declaración de propiedad sigue las convenciones de JavaBean.
Hay dos formas de establecer propiedades:

 Usar atributos de un elemento FXML


 El uso de elemento de propiedad s
El nombre del atributo o el nombre del elemento de propiedad es el mismo que el nombre de
la propiedad que se está configurando. El siguiente FXML crea una etiqueta y establece su
propiedad de texto usando un atributo.

<Label text = "¡FXML es genial!" />

El siguiente FXML logra lo mismo usando un elemento de propiedad.

<Etiqueta>

< text> ¡ FXML es genial! </ text>

</ Label>

El siguiente FXML crea un Rectángulo y establece sus propiedades de x, y, ancho, alto y relleno
usando atributos.

<Rectángulo x = "10" y = "10" ancho = "100" alto = "40" relleno = "rojo" />

FXML especifica valores para atributos como cadenas. La conversión apropiada se aplica
automáticamente para convertir los valores de cadena a los tipos requeridos. En el caso
anterior, el valor "rojo" para la propiedad de relleno se convertirá automáticamente a un
objeto Color; el valor "100" para la propiedad de ancho se convertirá a un valor doble, y así
sucesivamente.

Usar elementos de propiedad para establecer las propiedades del objeto es más flexible. Los
atributos se pueden usar cuando la conversión de tipo automática de String es posible.
Supongamos que quiere establecer un objeto de una clase Persona en una propiedad de un
objeto. Se puede hacer usando un elemento de propiedad. El siguiente FXML establece la
propiedad persona de un objeto de la clase MyCls.

Una propiedad de solo lectura es una propiedad que tiene un getter, pero ningún setter. Se
pueden establecer dos tipos especiales de propiedades de solo lectura en FXML utilizando un
elemento de propiedad:

 Una propiedad de lista de solo lectura


 Una propiedad de mapa de solo lectura

Use un elemento de propiedad para establecer una propiedad de lista de solo lectura. Todos
los hijos del elemento de propiedad se agregarán a la Lista devuelta por el comprador de la
propiedad. El siguiente FXML establece la propiedad de solo lectura para niños de un VBox.
Puede usar los atributos del elemento de propiedad para agregar entradas a una propiedad de
mapa de solo lectura. Los nombres y valores de los atributos se convierten en las claves y los
valores en el Mapa. El siguiente fragmento de código declara un elemento de clase, que tiene
una propiedad de mapa de solo lectura.

El siguiente FXML crea un objeto Item y establece su propiedad de mapa con dos entradas
("n1", 100) y ("n2", 200). Observe que los nombres de los atributos n1 y n2 se convierten en las
claves en el Mapa.

Hay un tipo especial de propiedad para objetos Java conocido como propiedad estática. La
propiedad estática no está declarada en la clase del objeto. Por el contrario, se establece
utilizando un método estático de otra clase. Supongamos que desea establecer el margen para
un Botón que se colocará en un VBox. El código JavaFX se muestra a continuación.

Puede lograr lo mismo en FXML estableciendo una propiedad VBox.margin para el Botón.
No puede crear un objeto Insets a partir de una Cadena, y por lo tanto, no puede usar un
atributo para establecer la propiedad de margen. Necesita usar un elemento de propiedad
para establecerlo. Cuando utiliza un GridPane en FXML, puede establecer rowIndex y
columnIndex estáticos como se muestra a continuación.

Debido a que las propiedades rowIndex y columnIndex también se pueden representar como
cadenas, puede usar atributos para establecerlas.

Especificación del espacio de nombres FXML


FXML no tiene un esquema XML. Utiliza un espacio de nombres que debe especificarse
utilizando el prefijo de espacio de nombres "fx". En su mayor parte, el analizador FXML
descubrirá los nombres de las etiquetas, como los nombres de las etiquetas que son clases, las
propiedades de las clases, etc. FXML utiliza elementos especiales y nombres de atributos, que
deben calificarse con el prefijo de espacio de nombres "fx". El siguiente FXML declara el prefijo
de espacio de nombres "fx".

<VBox xmlns: fx = "http://javafx.com/fxml"> ... </ VBox>

Opcionalmente, puede agregar la versión de FXML en el URI del espacio de nombres. El


analizador FXML verificará que pueda analizar el especificado. En el momento de escribir esto,
la única versión admitida es 1.0.

<VBox xmlns: fx = "http://javafx.com/fxml/1.0"> ... </ VBox>

La versión de FXML puede incluir puntos, guiones bajos y guiones. Solo se comparan los
números anteriores a la primera aparición de los guiones bajos y guiones. Todas las siguientes
tres declaraciones especifican la versión de FXML como 1.0.

<VBox xmlns: fx = "http://javafx.com/fxml/1"> ... </ VBox> <VBox xmlns: fx =


"http://javafx.com/fxml/1.0-ea">. .. </ VBox> <VBox xmlns: fx = "http://javafx.com/fxml/1.0-
rc1-2014_03_02"> ... </ VBox>

El siguiente FXML usa el prefijo de espacio de nombres "fx" para definir un bloque de script
que define una función sayHello ( ).
FXML necesita especificar el nombre del lenguaje de scripting para el script usando una
instrucción de procesamiento de lenguaje. El FXML anterior especifica javascript como el
lenguaje de scripting. Puede usar cualquier otro lenguaje de scripting como Python, Ruby y
Groovy. Puede usar cualquier lenguaje de scripting para definir un bloque de script en un
documento FXML.

Asignar un identificador a un objeto


Un objeto creado en FXML puede ser referido a otro lugar en el mismo documento. Es común
obtener la referencia de los objetos UI creados en FXML dentro del código JavaFX. Puede
lograrlo identificando primero los objetos en FXML con un atributo fx : id . El valor del atributo
fx : id es el identificador del objeto. Si el tipo de objeto tiene una propiedad de id, el valor
también se establecerá para la propiedad. Tenga en cuenta que cada nodo en JavaFX tiene una
propiedad de id. Que se puede usar para referirse a ellos en CSS. El siguiente es un ejemplo de
especificación del atributo fx : id para una etiqueta.

<Label fx : id = "msgLbl" text = "¡FXML es genial!" />

Ahora, puede consultar la etiqueta utilizando msgLbl. El siguiente FXML tiene un bloque de
script escrito en JavaScript para establecer la propiedad del texto para la etiqueta, suponiendo
que tanto la etiqueta como los elementos del script existan en el mismo FXML.

El atributo fx : id tiene varios usos. También se usa para inyectar la referencia de elementos de
UI en las variables de instancia de una clase JavaFX en el momento en que se carga FXML.
Discutiré otros usos en secciones separadas.

Agregar manejadores de eventos


Puede establecer manejadores de eventos para nodos en FXML. Configurar un controlador de
eventos es similar a establecer cualquier otra propiedad. Las clases de JavaFX definen las
propiedades de Xxx para configurar un controlador de eventos para el evento Xxx. Por
ejemplo, la clase Button contiene una propiedad onAction para establecer un controlador
ActionEvent. En FXML, puede especificar dos tipos de controladores de eventos:
 Controladores de eventos de script
 Controladores de eventos del controlador

El controlador de eventos de script se utiliza cuando el controlador de eventos se define en un


lenguaje de scripting. El valor del atributo es el script en sí, como una llamada a función o una
o más declaraciones. El siguiente fragmento de FXML configura el controlador ActionEvent
para un Botón que llama a la función f1 ( ) definida mediante JavaScript.

Si desea ejecutar ambas funciones f1 ( ) y f2 () cuando se hace clic en el botón, puede


configurar el controlador de eventos como

<Botón text = "Cerrar" onAction = " f1 ( ); f2 ();" />

El siguiente fragmento de FXML es la versión más corta de la que se muestra arriba. Imprime
una cadena en la consola cuando se hace clic en el botón. La llamada a la función println ( ) se
realiza directamente como parte del valor del atributo onAction.

Discutiré cómo especificar controladores de eventos de controlador en la sección Uso de un


controlador en FXML. El listado 29-4 es el documento FXML para este ejemplo. Creará el
elemento raíz para la escena que se muestra en la Figura 29-1 .
Ha establecido la propiedad de espaciado para VBox, el atributo fx : id para los controles de
Etiqueta y Botón. Ha establecido la propiedad de estilo de VBox utilizando un elemento de
propiedad <style>. Tuviste la opción de establecer el estilo usando un atributo de estilo o un
elemento de propiedad. Eligió usar un elemento de propiedad porque el valor del estilo es una
cadena grande y es más legible escribirlos en varias líneas. El elemento <fx : script > define un
bloque de script con una función sayHello (). La función establece la propiedad de texto de la
etiqueta identifica por el atributo msgLbl fx : id .

Cargando documentos FXML


Un documento FXML define la vista (la GUI) parte de una aplicación JavaFX. Debe cargar el
documento FXML para obtener el objeto-gráfico que representa. La carga de un FXML se
realiza mediante una instancia de la clase FXMLLoader, que se encuentra en el paquete
javafx.fxml.

La clase FXMLLoader proporciona varios constructores que le permiten especificar la


ubicación, el juego de caracteres, el paquete de recursos y otros elementos que se utilizarán
para cargar el documento. Debe especificar al menos la ubicación del documento FXML, que es
una URL. La clase contiene métodos load ( ) para realizar la carga real del documento. El
siguiente fragmento de código carga un documento FXML desde un sistema de archivos local
en Windows:

El método load ( ) tiene un tipo de devolución genérico. En el fragmento de código anterior, ha


dejado clara su intención en la llamada al método load ( ) (loader. <VBox> load ()) de que está
esperando una instancia de VBox del documento FXML. Si lo prefiere, puede omitir el
parámetro genérico.

FXMLLoader admite la carga de un documento FXML utilizando un InputStream. El siguiente


fragmento de código carga el mismo documento FXML utilizando un InputStream.

Internamente, FXMLLoader lee el documento utilizando flujos, lo que puede arrojar una
IOException. Todas las versiones del método load ( ) en la clase FXMLLoader lanzan
IOException. Ha omitido el código de excepción de manejo en este código de ejemplo anterior.
En su aplicación, deberá manejar la excepción.

La clase FXMLLoader contiene varias versiones del método load ( ). Algunos de ellos son
métodos de instancia y algunos métodos estáticos. Debe crear una instancia de FXMLLoader y
usar el método load ( ) de instancia , si desea recuperar más información del cargador, como la
referencia del controlador, el paquete de recursos, la ubicación, el juego de caracteres y el
objeto raíz. Si solo desea cargar un documento FXML sin tener en cuenta ningún otro detalle,
debe utilizar los métodos static load ( ). El siguiente fragmento de código usa un método static
load ( ) para cargar un documento FXML.
FXML document.

¿Qué haces después de cargar un documento FXML? En este punto, el rol de FXML ha
terminado y su código JavaFX debería tomar el control. Discutiré el cargador más adelante en
el texto.

El programa en el listado 29-5 tiene el código JavaFX para este ejemplo. Carga el documento
FXML almacenado en el archivo sayHello.fxml. El programa carga el documento desde
CLASSPATH. El cargador devuelve un VBox, que se establece como la raíz de la escena. El resto
del código es el mismo que ha estado usando excepto una diferencia en la declaración del
método start ( ). El método declara que puede arrojar una IOException, que debe agregar
porque ha llamado al método load ( ) del FXMLLoader dentro del método. Cuando ejecuta el
programa, muestra una ventana como se muestra en la Figura 29-1. Haga clic en el botón y el
texto de la etiqueta cambiará.

Has completado el ejemplo que comenzaste al principio de esta sección. Debe tener en cuenta
algunos puntos sobre esta implementación:
 FXML creó la interfaz de usuario y también proporcionó el código de manejo de
eventos en JavaScript
 No tiene referencias a los elementos de la interfaz de usuario, como la etiqueta y el
botón en su código JavaFX. Las referencias a los elementos de la interfaz de usuario son
necesarias para conectar el código de manejo de eventos y vincular la interfaz de usuario
al modelo

En resumen, le falta el enlace entre la IU y el código JavaFX. Puede crear este enlace
especificando un controlador en FXML, que se trata en la siguiente sección.

Usando un controlador en FXML


Un controlador es simplemente un nombre de clase cuyo objeto ha sido creado por FXML y se
utiliza para inicializar los elementos de la interfaz de usuario. FXML le permite especificar un
controlador en el elemento raíz utilizando el atributo fx : controller . Tenga en cuenta que solo
se permite un controlador por documento FXML y, si se especifica, debe especificarse en el
elemento raíz. El siguiente FXML especifica un controlador para el elemento VBox.

Un controlador debe cumplir con algunas reglas y puede usarse por diferentes motivos:

El controlador es instanciado por el cargador FXML

El controlador debe tener un constructor público no args. S i no existe, el cargador FXML no


será capaz de crear una instancia, que será una excepción en el momento de la carga.

El controlador puede tener métodos accesibles, que se pueden especificar como controladores
de eventos en FXML. Por favor refiérase a la discusión a continuación para el significado de
"accesible".

El cargador FXML buscará automáticamente las variables de instancia accesibles del


controlador. Si el nombre de una variable de instancia accesible coincide con el atributo fx : id
de un elemento, la referencia de objeto de FXML se copia automáticamente en la variable de
instancia del controlador. Esta característica hace que las referencias de los elementos de la
interfaz de usuario en FXML estén disponibles para el controlador. El controlador puede
usarlos más tarde, como vincularlos al modelo

El controlador puede tener un acceso Método initialize ( ), que no debe tomar


argumentos y tener un tipo de retorno de vacío. El cargador FXML llamará al método initialize (
) una vez que se haya completado la carga del documento FXML.
La clase de controlador usa una anotación @FXML en algunos miembros. La anotación @FXML
se puede usar en campos y métodos. No puede ser usado en clases y constructores. Al usar
una anotación @FXML en un miembro, declara que el cargador FXML puede acceder al
miembro incluso si es privado. Un miembro público utilizado por el cargador de FXML no
necesita ser anotado con @FXML. Sin embargo, anotar a un miembro público con @FXML no
es un error. Es mejor anotar todos los miembros, públicos y privados, utilizados por el cargador
FXML con la anotación @FXML. Esto le dice al lector de su código cómo se están utilizando los
miembros.
El siguiente FXML establece el método sayHello ( ) de la clase de controlador como el
controlador de eventos para el Botón.

La ubicación es la ubicación del documento FXML. Los recursos son la referencia del
ResourceBundle utilizado, si existe, en el FXML.

Cuando el valor del atributo del manejador de eventos comienza con un símbolo hash (#),
indica al cargador FXML que decirHello es el método en el controlador, no en un script. El
método del controlador de eventos en el controlador debe cumplir con algunas reglas:

 El método no puede tomar argumentos o un solo argumento. Si toma un argumento,


el tipo de argumento debe ser una asignación de tipo compatible con el evento que se
supone que debe manejar.
 No es un error tener ambas versiones del método : una que no toma argumentos y
con un solo argumento. En tal caso, se usa el método con un solo argumento.
 Convencionalmente, el tipo de retorno del método debe ser nulo, porque no hay
tomador del valor devuelto.
 El método debe ser accesible para el cargador de FXML: hacerlo público o anotarlo con
@FXML

Cuando el cargador FXML termina de cargar el documento FXML, llama al método initialize ( )
del controlador. El método no debe tomar ningún argumento. Debería ser accesible para el
cargador FXML. En el controlador, usaste la anotación @FXML para que esté accesible para el
cargador FXML.

La clase FXMLLoader le permite configurar un controlador para el elemento raíz en el código


utilizando el método setController ( ). Use el método getController ( ) para obtener la
referencia del controlador desde el cargador. Los desarrolladores cometen un error común al
obtener la referencia del controlador. El error se debe a la forma en que se diseñó el método
load ( ). Hay siete versiones sobrecargadas del método load ( ): dos de ellas son métodos de
instancia y cinco son métodos estáticos. Para utilizar el método getController ( ), debe crear un
objeto de la clase FXMLLoader y asegurarse de que utiliza uno de los métodos de instancia de
la clase para cargar el documento. A continuación se muestra un ejemplo del error común.
El código anterior crea un objeto de la clase FXMLLoader. Sin embargo, el método de carga (
url URL) que se llama en la variable del cargador es el método load () estático, no el método
load () de la instancia. Por lo tanto, la instancia del cargador nunca obtuvo un controlador y
cuando le pides un controlador, devuelve un valor nulo. Para despejar la confusión, a
continuación se muestran las versiones estáticas y de instancia del método load ( ), de las
cuales sollas primeras dos versiones son métodos de instancia:

El siguiente fragmento de código es la forma correcta de utilizar el método load ( ), por lo que
puede obtener la referencia del controlador en el código JavaFX.
Ahora tiene el controlador para esta aplicación de ejemplo. Modifiquemos el FXML para que
coincida con el controlador. El listado 29-7 muestra el FXML modificado. Se guarda en el
archivo sayhellowithcontroller.fxml en el directorio resources / fxml.

El programa en el listado 29-8 es la aplicación JavaFX para este ejemplo. El código es muy
similar al que se muestra en el listado 29-5. La principal diferencia es el documento FXML que
usa un controlador. Cuando se carga el documento, el cargador llama al método initialize ( )
del controlador. El método imprime un mensaje, la ubicación y el paquete de recursos la
referencia. Cuando hace clic en el botón, se llama al método sayHello ( ) del controlador que
establece el texto en la etiqueta. Tenga en cuenta que la referencia de etiqueta se inyecta
automáticamente en el controlador mediante el cargador FXML.

Crear objetos en FXML


El objetivo principal de usar FXML es crear un objeto-gráfico. Los objetos de todas las clases no
se crean de la misma manera. Por ejemplo, algunas clases proporcionan constructores para
crear sus objetos, algunos métodos staticOf ( ) y algunos métodos de fábrica. FXML debería ser
capaz de crear objetos de todas las clases, o al menos debería darle algún control sobre la
decisión de cómo crear esos objetos. En las siguientes secciones, discutiré diferentes formas
de crear objetos en FXML.

Usando el Constructor sin args


Usar el constructor no-args para crear objetos en FXML es fácil. Si el nombre de un elemento
es un nombre de clase, que tiene un constructor sin argumentos, el elemento creará un objeto
de esa clase. El siguiente elemento crea un objeto VBox ya que la clase VBox tiene un
constructor sin args.

Usando el método estático valueOf ( )


A veces, las clases inmutables proporcionan un método valueOf ( ) para construir un objeto. Si
el método valueOf ( ) se declara estático; puede aceptar un único argumento de cadena y
devuelve un objeto. Puede usar el atributo fx : value para crear un objeto usando el método.
Supongamos que tiene una clase Xxx, que contiene un método estático valueOf ( String s). El
siguiente es el código de Java:

Tenga en cuenta que ha declarado que el método valueOf ( ) debería poder aceptar un
argumento String, que califica los dos métodos de esta categoría.

Tenga en cuenta que la clase String contiene un constructor sin argumentos que crea una
cadena vacía. Si necesita un objeto String con una cadena vacía como contenido, aún puede
usar el constructor no-args:

No olvides importar clases, Long and String cuando uses los elementos anteriores ya que FXML
no importa clases automáticamente desde el paquete java.lang .

Vale la pena señalar que el tipo de objeto que crea el atributo fx : value es el tipo del objeto
devuelto del objeto valueOf (), no del tipo de clase del elemento. Considere la siguiente
declaración de método para una clase Yyy.

Si tu respuesta es Yyy, está mal. Comúnmente se piensa que el nombre del elemento es Yyy,
por lo que crea un objeto de tipo Yyy. El elemento anterior es lo mismo que invocar
Yyy.valueOf ( "Hola"), que devuelve un objeto de tipo Zzz. Por lo tanto, el elemento anterior
crea un objeto de tipo Zzz, no de tipo Yyy. Aunque es posible tener este caso de uso, esta es
una forma confusa de diseñar tu clase. Normalmente, un método valueOf ( ) en la clase Xxx
devuelve un objeto de tipo Xxx.
Usando un método de fábrica
A veces, una clase proporciona métodos de fábrica para crear su objeto. Si una clase contiene
un método estático, no args que devuelve un objeto, puede usar el método con el atributo fx :
factory . El siguiente elemento crea un LocalDate en FXML utilizando el método de fábrica now
( ) de la clase LocalDate.

Algunas veces, necesita crear colecciones JavaFX en FXML. La clase FXCollections contiene
varios métodos de fábrica para crear colecciones. El siguiente fragmento de FXML crea una
<List> ObservableList que agrega cuatro nombres de fruta a la lista.

El FXML en el listado 29-9 es un ejemplo del uso del atributo fx : factory para crear un
ObservableList. La lista se usa para configurar los elementos de un ComboBox. El valor
"Naranja" de la lista se establece como el valor predeterminado. El VBox mostrará una
etiqueta y un ComboBox con la lista de cuatro nombres de fruta.
Usando constructores
Si FXMLLoader no puede crear un objeto de una clase, busca un constructor que pueda crear el
objeto. Un constructor es una implementación de la interfaz del constructor. La interfaz está
en el paquete javafx.util y contiene un método build ( ).

FXMLLoader le permite usar una BuilderFactory. Cuando no puede crear el objeto de una clase
utilizando todos los demás métodos, llama al método getBuilder ( ) de BuilderFactory pasando
el tipo del objeto como argumento del método. Si BuilderFactory devuelve un generador no
nulo, el cargador establece todas las propiedades del objeto que se está creando en el
generador. Finalmente, llama al método build ( ) del generador para obtener el objeto. La
clase FXMLLoader usa una instancia de JavaFXBuilderFactory como BuilderFactory por defecto.
FXMLLoader es compatible con dos tipos de constructores:

 Si el Constructor implementa la interfaz de Mapa, el método put ( ) se usa para pasar


las propiedades del objeto al Constructor. El método put ( ) pasa el nombre y el valor de
la propiedad.
 Si el Constructor no implementa la interfaz de Mapa, el Constructor debe contener los
métodos getter y setter, basados en la convención JavaBeans, para todas las
propiedades especificadas en el FXML.

Considere la declaración de la clase de artículo en el listado 29-10. Por defecto, FXML no podrá
crear un objeto Item ya que no tiene un constructor no-args. La clase tiene dos propiedades, id
y nombre.
El listado 29-11 contiene el contenido de un archivo FXML items.fxml. Crea una ArrayList con
tres objetos de la clase Item. Si carga este archivo con FXMLLoader, recibirá un error que indica
que el cargador no puede crear una instancia de la clase Item.

Vamos a crear un generador para construir el objeto de la clase Item. La clase ItemBuilder en
el listado 29-12 es el generador para la clase Item. Declara las variables de instancia id y name.
Como FXMLLoader encuentra estas propiedades, el cargador llamará a los setters
correspondientes. Los setters almacenan los valores en la variable de instancia. Cuando el
cargador necesita el objeto, llama al método build ( ), que crea y devuelve un objeto Item.
Ahora, necesita crear una BuilderFactory para el tipo de artículo. La clase ItemBuilderFactory
que se muestra en el listado 29-13 implementa la interfaz BuilderFactory. Cuando getBuilder ( )
pasa el tipo de elemento, devuelve un objeto ItemBuilder. De lo contrario, devuelve el
constructor JavaFX predeterminado.
Los listados 29-14 y 29-15 tienen un código para la implementación de Builder y BuilderFactory
para el tipo de artículo. Esta vez, el Constructor implementa la interfaz de Mapa extendiendo
la clase AbstractMap. Anula el método put ( ) para leer las propiedades aprobadas y sus
valores. El método entrySet ( ) debe ser anulado ya que se define como abstracto en la clase
AbstractMap. No tienes ninguna implementación útil para eso. Usted acaba de lanzar una
excepción de tiempo de ejecución. El método build ( ) crea y devuelve un objeto del tipo de
Artículo. La implementación de BuilderFactory es similar a la del Listado 29-13, excepto que
devuelve un ItemBuilderMap como el Constructor para el tipo de Artículo.
Probemos ambos constructores para la clase de artículo. El programa en el listado 29-16 usa
ambos constructores para la clase de artículo. Carga la lista de elementos del archivo
items.fxml, suponiendo que el archivo se encuentra en CLASSPATH en el directorio resources /
fxml.
Consejo: la BuilderFactory que suministra al FXMLLoader reemplaza a la BuilderFactory
predeterminada. Debe asegurarse de que su BuilderFactory devuelva un Builder específico
para su tipo personalizado y devuelva el Builder predeterminado para el resto. Actualmente,
FXMLLoader no permite el uso de más de un BuilderFactory.

Crear objetos reutilizables en FXML


Algunas veces, necesita crear objetos que no sean directamente parte del objeto-gráfico. Sin
embargo, pueden usarse en otro lugar en el documento FXML. Por ejemplo, es posible que
desee crear un Insets o un Color una vez y volver a utilizarlos en varios lugares. Usar un
ToggleGroup es un caso de uso típico. Un ToggleGroup se crea una vez y se usa con varios
objetos RadioButton.

Puede crear un objeto en FXML sin hacerlo parte del grupo de objetos usando el bloque <fx :
define >. Puede referirse a los objetos creados en el bloque <fx : define > por su fx: id en el
valor del atributo de otros elementos. El valor del atributo debe ir precedido de un símbolo de
dólar ($).

Consejo: si el valor de un atributo comienza con un símbolo $, se considera una referencia a un


objeto. si desea usar un símbolo $ adelantado como parte del valor, evítelo con una barra
invertida ("\ $ hola").

Especificación de ubicaciones en atributos


Un valor de atributo que comienza con un símbolo @ se refiere a una ubicación. Si el símbolo
@ es seguido por una barra inclinada (@ /), la ubicación se considera relativa a CLASSPATH. Si
el símbolo @ no es seguido por una barra inclinada, la ubicación se considera relativa a la
ubicación del archivo FXML que se está procesando.

En el siguiente FXML, la URL de la imagen se resolverá en relación con la ubicación del archivo
FXML que contiene el elemento.
Uso de paquetes de recursos
Usar un ResourceBundle en FXML es mucho más fácil que usarlo en código Java. Al especificar
las claves de un paquete de recursos en los valores de atributo, se utilizan los valores
correspondientes para la configuración regional predeterminada. Si un valor de atributo
comienza con un símbolo%, se considera como el nombre de clave del paquete de recursos. En
tiempo de ejecución, el valor del atributo vendrá del ResourceBundle especificado en el
FXMLLoader. Si desea utilizar un símbolo de% inicial en un valor de atributo, escúpelo con una
barra inclinada hacia atrás (por ejemplo, "\% hola").

Considere el contenido de FXML en el listado 29-17. Utiliza "% greetingText" como el valor
para la propiedad de texto de la etiqueta. El valor del atributo comienza con un símbolo%.
FXMLLoader buscará el valor de "greetingText" en el ResourceBundle y lo usará para la
propiedad del texto. ¡Todo está hecho para ti sin escribir ni una sola línea de código!

Los listados 29-18 y 29-19 tienen contenidos para los archivos ResourceBundle: uno para
Locale predeterminado llamado greetings.properties, y otro para Locale indio denominado
greetings_hi.properties. El sufijo _hi en el nombre del archivo significa el idioma hindi Hindi.

El programa en el listado 29-20 utiliza un paquete de recursos con el cargador FXML.


ResourceBundle se carga desde el directorio resources / resourcebundles en CLASSPATH. El
archivo FXML se carga desde resources / fxml / greetings.fxml en CLASSPATH. El programa
carga la etiqueta del archivo FXML dos veces: una vez para la configuración regional
predeterminada de EE. UU. Y una vez para cambiar la configuración regional predeterminada a
India Hindi. Ambas etiquetas se muestran en el VBox como se muestra en la Figura 29-2.
Incluyendo archivos FXML
Un documento FXML puede incluir otro documento FXML utilizando el elemento <fx : include
>. El gráfico de objetos generado por el documento anidado se incluye en la posición en la que
se encuentra el documento anidado en el documento que lo contiene. El elemento <fx :
include > toma un atributo de origen cuyo valor es la ruta del documento anidado.

<fx : include source = "nested_document_path" />

Si la ruta del documento anidado comienza con una barra diagonal anterior, la ruta se resuelve
en relación con CLASSPATH. De lo contrario, se resuelve en relación con la ruta del documento
que lo contiene.

El elemento <fx : include > puede tener el atributo fx: id y todos los atributos que están
disponibles para el objeto incluido. Los atributos especificados en el documento contenedor
anulan los atributos correspondientes en el documento incluido. Por ejemplo, si incluye un
documento FXML, que crea un Botón, puede especificar la propiedad del texto en el
documento incluido, así como también el documento que lo contiene. Cuando se carga el
documento que lo contiene, se usará la propiedad de texto del documento que lo contiene.

Un documento FXML puede especificar opcionalmente un controlador utilizando el atributo fx


: controller para el elemento raíz. La regla es que puede tener un máximo de un controlador
por documento FXML. Cuando anida documentos, cada documento puede tener su propio
controlador. FXMLLoader le permite inyectar la referencia del controlador anidado en el
controlador del documento principal. Debe seguir una convención de nomenclatura para
inyectar el controlador anidado. El controlador para el documento principal debe tener una
variable de instancia accesible con el nombre como:

Nombre de variable de instancia = "fx : id del elemento fx: include" + "Controller"

Si fx : id para el elemento <fx: include> es "xxx", el nombre de la variable de instancia debe ser
xxxController.

Considere los dos documentos FXML que se muestran en los listados 29-21 y 29-22. El archivo
closebutton.fxml crea un Botón, establece su propiedad de texto en Cerrar y conecta un
controlador de eventos de acción. El controlador de eventos usa el lenguaje JavaScript. Cierra
la ventana que contiene.

El maindoc.fxml incluye closebutton.fxml, suponiendo que ambos archivos están en el mismo


directorio. Especifica los atributos text y fx : id para el elemento <fx: include>. Tenga en cuenta
que el FXML incluido especifica "Cerrar" como la propiedad de prueba y el maindoc.fxml lo
anula y lo establece en "Cerrar".
Ambos documentos de FXML especifican un controlador listado en los listados 29-23 y 29-24.
Tenga en cuenta que el controlador para el documento principal declara dos variables de
instancia: una se referirá al botón incluido y la otra se referirá al controlador del documento
incluido. Tenga en cuenta que la referencia del botón también se incluirá en el controlador del
documento anidado.

The program in Listing 29-25 loads the maindoc.fxml and adds the loaded VBox to the scene. It
displays a window with the Hide button from the closebutton.fxml file. Clicking the Hide
button will close the window.
Usando constantes
Las clases, las interfaces y las enumeraciones pueden definir constantes, que son variables
estáticas y finales. Puede referirse a esas constantes usando el atributo fx : constant . El valor
del atributo es el nombre de la constante. El nombre del elemento es el nombre del tipo que
contiene la constante. Por ejemplo, para Long.MAX_VALUE, puede usar el siguiente elemento.

<Long fx : constant = "MAX_VALUE" />


Tenga en cuenta que todas las constantes enum pertenecen a esta categoría y se puede
acceder utilizando el atributo fx : constant . El siguiente elemento accede a la constante de
entrada Pos.CENTER.

<Pos fx : constante = "CENTRO" />

El siguiente contenido de FXML tiene acceso a las constantes de las clases Integer y Long, y a la
enunciada Pos. Establece la propiedad de alineación de un VBox en Pos.CENTER.

Usando constantes
Las clases, las interfaces y las enumeraciones pueden definir constantes, que son variables
estáticas y finales. Puede referirse a esas constantes usando el atributo fx : constant . El valor
del atributo es el nombre de la constante. El nombre del elemento es el nombre del tipo que
contiene la constante. Por ejemplo, para Long.MAX_VALUE, puede usar el siguiente elemento.

<Long fx : constant = "MAX_VALUE" />

Tenga en cuenta que todas las constantes enum pertenecen a esta categoría y se puede
acceder utilizando el atributo fx : constant . El siguiente elemento accede a la constante de
entrada Pos.CENTER.
<Pos fx : constante = "CENTRO" />

El siguiente contenido de FXML tiene acceso a las constantes de las clases Integer y Long, y a la
enunciada Pos. Establece la propiedad de alineación de un VBox en Pos.CENTER.

Hacer referencia a otro elemento


Puede hacer referencia a otro elemento en el documento utilizando el elemento <fx :
reference >. El atributo fx : id especifica el fx: id del elemento referido.
Tenga en cuenta que también puede volver a escribir el contenido FXML anterior utilizando el
método de eliminación de referencias variable de la siguiente manera:

Copia de elementos
A veces, quieres copiar un elemento. Copiar en este contexto es crear un nuevo objeto
copiando los atributos del objeto fuente. Puede hacerlo usando el elemento <fx : copy >.

<fx : copy source = "fx: id del objeto fuente" />

Para copiar un objeto, la clase debe proporcionar un constructor de copia. Un constructor de


copia toma un objeto de la misma clase. Supongamos que tiene una clase de artículo que
contiene un constructor de copia.

El siguiente documento FXML crea un objeto Item dentro del bloque <fx : define >. Copia el
objeto Item varias veces y lo agrega a la lista de elementos para un ComboBox. Tenga en
cuenta que el elemento fuente se agrega a la lista de elementos utilizando un elemento <fx :
referenc >.

Propiedades de unión en FXML


FXML admite enlaces de propiedades simples. Necesita usar un atributo para la propiedad
para vincularlo a la propiedad de otro elemento o una variable de documento. El valor del
atributo comienza con un símbolo $, seguido de un par de llaves. El siguiente contenido de
FXML crea un VBox con dos campos de texto. La propiedad de texto del campo mirrorText está
vinculada a la propiedad de texto del campo mainText.

Creando controles personalizados


Puede crear controles personalizados usando FXML. Creemos un formulario de inicio de sesión
con dos etiquetas, un campo de texto, un campo de contraseña y dos botones. El listado 29-26
contiene el contenido de FXML para el formulario. Tenga en cuenta que el elemento raíz es un
<fx : root >. El elemento <fx : root > crea una referencia al elemento creado previamente. El
valor para el elemento <fx : root > se establece en el FXMLLoader utilizando el método setRoot
(). El atributo tipo especifica el tipo de raíz que se inyectará.
La clase del listado 29-27 representa la parte JavaFX del control personalizado. Creará un
objeto de la clase LogInControl y lo usará como cualquier otro control estándar. Esta clase
también se usa como controlador para login.fxml. En el constructor, la clase carga el contenido
de FXML. Antes de cargar el contenido, se establece como la raíz y el controlador en el
FXMLLoader. Las variables de instancia permiten la inyección de los controles userId y pwd en
la clase. Cuando se hace clic en los botones, simplemente imprime un mensaje en la consola.
Este control necesita más trabajo, si desea usarlo en una aplicación real. Deberá proporcionar
una forma para que los usuarios enlacen la notificación de eventos cuando se haga clic en los
botones Aceptar y Cancelar.
El programa en el listado 29-28 muestra cómo usar el control personalizado. Usar el control
personalizado es tan fácil como crear un objeto Java. El control personalizado extiende el
GridPane, por lo tanto, se puede usar como un GridPane. Usar el control en FXML no es
diferente a usar otros controles. El control proporciona un constructor sin argumentos, lo que
permitirá crearlo en FXML utilizando un elemento con el nombre de clase <LoginControl>.

Resumen
FXML es un lenguaje basado en XML para construir una interfaz de usuario para una aplicación
JavaFX. Puede usar FXML para construir una escena completa o parte de una escena. FXML
permite a los desarrolladores de aplicaciones separar la lógica para construir la interfaz de
usuario desde la lógica comercial. Si la parte de la interfaz de usuario de la aplicación cambia,
no es necesario volver a compilar el código de JavaFX: cambie el FXML con un editor de texto y
vuelva a ejecutar la aplicación. Aún usa JavaFX para escribir lógica comercial usando el
lenguaje Java. Un documento FXML es un documento XML.
Es común usar FXML para construir un gráfico de escena en una aplicación JavaFX. Sin
embargo, el uso de FXML no se limita a construir solo gráficos de escena. Puede construir un
objeto-gráfico jerárquico de objetos Java. De hecho, se puede usar para crear solo un objeto,
como un objeto de una clase Person.

Un documento FXML es simplemente un archivo de texto. Normalmente, el nombre del


archivo tiene una extensión .fxml (por ejemplo, hello.fxml). Puede usar cualquier editor de
texto para editar un documento FXML. Oracle Corporation proporciona un editor visual de
código abierto llamado Scene Builder para editar documentos FXML. Puede descargar su
última versión desde el enlace . Scene Builder también se puede integrar en NetBeans IDE, por
lo que puede editar documentos FXML utilizando Scene Builder desde el NetBeans IDE.

FXML le permite crear un objeto utilizando el constructor no-args, el método valueOf ( ), un


método de fábrica y un constructor.

Algunas veces, necesita crear objetos que no sean directamente parte del objeto-gráfico. Sin
embargo, pueden usarse en otro lugar en el documento FXML. Puede crear un objeto en FXML
sin hacerlo parte del grupo de objetos usando el bloque <fx : define >. Puede referirse a los
objetos creados en el bloque <fx : define > por su fx: id en el valor del atributo de otros
elementos. El valor del atributo debe ir precedido de un símbolo de dólar ($).

XML le permite consultar los recursos especificando sus ubicaciones. Un valor de atributo que
comienza con un símbolo @ se refiere a una ubicación. Si se sigue el símbolo @ con una barra
inclinada (@ /), la ubicación se considera relativa a CLASSPATH. Si el símbolo @ no es seguido
por una barra inclinada, la ubicación se considera relativa a la ubicación del archivo FXML que
se está procesando.

Usar un ResourceBundle en FXML es mucho más fácil que usarlo en código Java. Al especificar
las claves de un paquete de recursos en los valores de atributo, se utilizan los valores
correspondientes para la configuración regional predeterminada. Si un valor de atributo
comienza con un símbolo%, se considera como el nombre de clave del paquete de recursos. En
tiempo de ejecución, el valor del atributo vendrá del ResourceBundle especificado en el
FXMLLoader. Si desea utilizar un símbolo de% inicial en un valor de atributo, escúpelo con una
barra inclinada hacia atrás (por ejemplo, "\% hola").

Un documento FXML puede incluir otro documento FXML utilizando el elemento <fx : include
>. El objeto-gráfico generado por el documento anidado se incluye en la posición donde se
produce el documento anidado en el documento que lo contiene.

Las clases, las interfaces y las enumeraciones pueden definir constantes, que son variables
estáticas y finales. Puede referirse a esas constantes usando el atributo fx : constant . El valor
del atributo es el nombre de la constante. El nombre del elemento es el nombre del tipo que
contiene la constante. Por ejemplo, para Long.MAX_VALUE, puede usar el elemento <Long fx :
constant = "MAX_VALUE" />.

Puede hacer referencia a otro elemento en el documento utilizando el elemento <fx :


reference >. El atributo fx : id especifica el fx: id del elemento referido. Puede copiar un
elemento usando el elemento <fx : copy >. Creará un nuevo objeto copiando los atributos del
objeto fuente.

FXML admite enlaces de propiedades simples. Necesita usar un atributo para la propiedad
para vincularlo a la propiedad de otro elemento o una variable de documento. El valor del
atributo comienza con un símbolo $, seguido de un par de llaves. Puede crear controles
personalizados usando FXML. El siguiente capítulo tratará sobre la impresión de API en JavaFX
que le permite configurar impresoras e imprimir nodos en aplicaciones JavaFX.

Das könnte Ihnen auch gefallen