Interfaz gráfica¶

Introducción¶
JavaFX fue desarrollado por Chris Oliver. Inicialmente, el proyecto se denominó Form Follows Functions (F3). Está destinado a proporcionar las funcionalidades más ricas para el desarrollo de aplicaciones GUI. Posteriormente, Sun Micro-systems adquirió el proyecto F3 como JavaFX en junio de 2005.
Sun Micro-systems lo anuncia oficialmente en 2007 en la Conferencia W3. En octubre de 2008, se lanzó JavaFX 1.0. En 2009, la corporación ORACLE adquiere Sun Micro-Systems y lanzó JavaFX 1.2. la última versión de JavaFX es JavaFX 23.
JavaFX es una tecnología que nos permite crear aplicaciones de escritorio RIA (Ritch Internet Applications), esto es, aplicaciones web que tienen las características y capacidades de aplicaciones de escritorio, incluyendo aplicaciones multimedia interactivas que pueden ejecutarse en una amplia variedad de dispositivos. JavaFX está destinado a reemplazar a Swing como la biblioteca de GUI estándar para Java SE.
La biblioteca de JavaFX está escrita como una API de Java, las aplicaciones JavaFX pueden hacer referencia a APIs de código de cualquier biblioteca Java. Por ejemplo, las aplicaciones JavaFX pueden utilizar las bibliotecas de API de Java para acceder a las capacidades del sistema nativas y conectarse a aplicaciones de middleware basadas en servidor.
La apariencia de las aplicaciones JavaFX se pueden personalizar. Las Hojas de Estilo en Cascada (CSS) separan la apariencia y estilo de la lógica de la aplicación para que los desarrolladores puedan concentrarse en el código. Los diseñadores gráficos pueden personalizar fácilmente el aspecto y el estilo de la aplicación a través de CSS. Si se tiene un diseño de fondo de la web, o si se desea separar la interfaz de usuario (UI) y la lógica de servidor, entonces, se pueden desarrollar los aspectos de la presentación de la interfaz de usuario en el lenguaje de scripting FXML y utilizar el código de Java para la aplicación lógica. Si se prefiere diseñar interfaces de usuario sin necesidad de escribir código, entonces, utilizaremos JavaFXSceneBuilder . Al diseñar la interfaz de usuario con javaFX Scene Builder el crea código de marcado FXML que puede ser portado a un entorno de desarrollo integrado (IDE) de forma que los desarrolladores pueden añadir la lógica de negocio.
Gráfico de escena¶
Descripción general¶
Un gráfico de escena es una estructura de datos de árbol que organiza (y agrupa) objetos gráficos para una representación lógica más sencilla. También permite que el motor de gráficos represente los objetos de la manera más eficiente al omitir total o parcialmente los objetos que no se verán en la imagen final. La siguiente figura muestra un ejemplo de la arquitectura del gráfico de escena JavaFX.

En la parte superior de la arquitectura hay un Stage. Una etapa es una representación JavaFX de una ventana de sistema operativo nativo. En un momento dado, un escenario puede tener un solo Sceneadjunto. Una escena es un contenedor para el gráfico de escena JavaFX.
Todos los elementos en el gráfico de escena JavaFX se representan como Nodeobjetos. Hay tres tipos de nudos: raíz, rama y hoja. El nodo raíz es el único nodo que no tiene un padre y está contenido directamente en una escena, que se puede ver en la figura anterior. La diferencia entre una rama y una hoja es que un nodo hoja no tiene hijos.
En el gráfico de escena, los nodos secundarios comparten muchas propiedades de un nodo principal. Por ejemplo, una transformación o un evento aplicado a un nodo padre también se aplicará recursivamente a sus hijos. Como tal, una jerarquía compleja de nodos se puede ver como un solo nodo para simplificar el modelo de programación. Exploraremos transformaciones y eventos en secciones posteriores.
En la siguiente figura se puede ver un ejemplo de un gráfico de escena "Hola Mundo".

Una posible implementación que producirá un gráfico de escena que coincida con la figura anterior es la siguiente.
E01_HolaMundo.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | |
El resultado de ejecutar el código se ve en la siguiente figura.

Notas importantes:
- Un nodo puede tener como máximo 1 padre.
- Un nodo en el gráfico de escena "activo" (adjunto a una escena actualmente visible) solo se puede modificar desde el subproceso de la aplicación JavaFX.
Transformaciones¶
Usaremos la siguiente aplicación como ejemplo para demostrar las 3 transformaciones más comunes.
E02_TransformApp.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | |
Ejecutar la aplicación dará como resultado la primera imagen (y si descomentamos por grupos, las siguientes).
| Sin transformaciones | Traslación | Escalado | Rotación |
|---|---|---|---|
![]() | ![]() | ![]() | ![]() |
En JavaFX, puede ocurrir una transformación simple en uno de los 3 ejes: X, Y o Z. La aplicación de ejemplo está en 2D, por lo que solo consideraremos los ejes X e Y.
Traslación¶
En JavaFX y gráficos por computadora, translate significa moverse. Podemos trasladar nuestra caja en 100 píxeles en el eje X y 200 píxeles en el eje Y.
1 2 | |
Escala¶
Puede aplicar la escala para hacer un nodo más grande o más pequeño. El valor de escala es una relación. Por defecto, un nodo tiene un valor de escala de 1 (100%) en cada eje. Podemos agrandar nuestra caja aplicando una escala de 1.5 en los ejes X e Y.
1 2 | |
Rotación¶
La rotación de un nodo determina el ángulo en el que se representa el nodo. En 2D el único eje de rotación sensible es el eje Z. Giremos la caja 30 grados.
1 | |
Manejo de eventos¶
Un evento notifica que ha ocurrido algo importante. Los eventos suelen ser lo "primitivo" de un sistema de eventos (también conocido como bus de eventos). Generalmente, un sistema de eventos tiene las siguientes 3 responsabilidades:
fire(desencadenar) un evento,- notificar
listeners(a las partes interesadas) sobre el evento y handle(procesar) el evento.
El mecanismo de notificación de eventos lo realiza la plataforma JavaFX automáticamente. Por lo tanto, solo consideraremos cómo disparar (fire) eventos, escuchar (listen) eventos y cómo manejarlos (handle).
Primero, vamos a crear un evento personalizado.
E03_EventoUsuario.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | |
Dado que los tipos de eventos son fijos, generalmente se crean dentro del mismo archivo de origen que el evento. Podemos ver que hay 2 tipos específicos de eventos: LOGIN_SUCCEEDEDy LOGIN_FAILED. Podemos escuchar estos tipos específicos de eventos:
1 2 3 4 | |
Alternativamente, podemos manejar cualquier UserEvent:
1 2 3 4 | |
Finalmente, podemos construir y disparar nuestros propios eventos:
1 2 3 | |
Por ejemplo, LOGIN_SUCCEEDEDo LOGIN_FAILED podría activarse cuando un usuario intenta iniciar sesión en una aplicación. Según el resultado del inicio de sesión, podemos permitir que el usuario acceda a la aplicación o bloquearlo. Si bien se puede lograr la misma funcionalidad con una if declaración simple, hay una ventaja significativa de un sistema de eventos. Los sistemas de eventos se diseñaron para permitir la comunicación entre varios módulos (subsistemas) en una aplicación sin acoplarlos estrechamente. Como tal, un sistema de audio puede reproducir un sonido cuando el usuario inicia sesión. Por lo tanto, mantiene todo el código relacionado con el audio en su propio módulo. Sin embargo, no profundizaremos en los estilos arquitectónicos.
Eventos de entrada¶
Los eventos de teclado y ratón son los tipos de eventos más comunes utilizados en JavaFX. Cada Node proporciona los llamados "métodos de conveniencia" para manejar estos eventos. Por ejemplo, podemos ejecutar algún código cuando se presiona un botón:
1 2 3 4 | |
Para mayor flexibilidad también podemos usar lo siguiente:
1 2 3 4 5 | |
El objeto e anterior es de tipo MouseEvent y se puede consultar para obtener información diversa sobre el evento, por ejemplo, x posiciones y, número de clics, etc. Finalmente, podemos hacer lo mismo con las teclas:
1 2 3 | |
El objeto e aquí es de tipo KeyEvent y lleva información sobre el código de la tecla, que luego se puede asignar a una tecla física real en el teclado.
Veremos más ejemplos más adelante en este tema.
Controles de la interfaz de usuario¶
Label¶
La clase Label que reside en el paquete javafx.scene.control de la API de JavaFX se puede usar para mostrar un elemento de texto.
La etiqueta de la izquierda es un elemento de texto de color azul, que se auto-ajusta si cambiamos el tamaño de la ventana, la etiqueta del centro representa texto girado y la etiqueta de la derecha representa un texto con imagen, que además aumenta su tamaño cuando pasamos por encima.

La API de JavaFX proporciona tres constructores de la clase Label para crear etiquetas en su aplicación.
1 2 3 4 5 6 7 8 9 | |
Una vez que haya creado una etiqueta, puede cambiar sus propiedades con los métodos;
setText(String text)especifica el texto para la etiqueta.setGraphic(Node graphic): especifica el icono gráfico,setTextFillespecifica el color para pintar el elemento de texto de la etiqueta.setGraphicTextGappara establecer el espacio entre ellos.setWrapTextpara indicar si debe autoajustarse (true) o no (false)setTextAlignmentpuede variar la posición del contenido de la etiqueta dentro de su área de diseñosetContentDisplaypuede definir la posición del gráfico en relación con el texto aplicando el método y especificando una de las siguientes constantesContentDisplay:LEFT,RIGHT,CENTER,TOP,BOTTOM.
Cuando se activa el evento MOUSE_ENTERED en la etiqueta, se establece el factor de escala de 1,5 para los métodos setScaleX y setScaleY. Cuando un usuario mueve el cursor del ratón fuera de la etiqueta y ocurre el evento MOUSE_EXITED, el factor de escala se establece en 1.0 y la etiqueta se representa en su tamaño original.
1 2 3 4 5 6 7 8 9 | |
E05_Label.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 | |
Button¶
La clase Button disponible a través de la API de JavaFX permite a los desarrolladores procesar una acción cuando un usuario hace clic en un botón. La clase Button es una extensión de la clase Labeled. Puede mostrar texto, una imagen o ambos.

Puede crear un control Button en una aplicación JavaFX usando tres constructores de la clase Button como se muestra a continuación
1 2 3 4 5 6 7 | |
La clase Button puede usar los siguientes métodos:
setText(String text): especifica el título de texto para el botónsetGraphic(Node graphic): especifica el icono gráficosetOnAction: La función principal de cada botón es producir una acción cuando se hace clic en él. En nuestro ejemplo cambiar el texto de un label.
1 2 3 | |
Vemos cómo procesar un ActionEvent, de modo que cuando un usuario presiona button2 el título de texto de la etiqueta label se establece en "Aceptado".
Puede usar la clase Button para establecer tantos métodos de manejo de eventos como necesite para causar el comportamiento específico o aplicar efectos visuales.
Debido a que la clase Button amplía la clase Node, puede aplicar cualquiera de los efectos del paquete javafx.scene.effect para mejorar la apariencia visual del botón. En este caso añadimos una sobra al botón con imagen cuando pasamos el ratón sobre el.
1 2 3 4 5 6 7 8 9 10 11 | |
El siguiente paso para mejorar la apariencia visual de un botón es aplicar estilos CSS definidos por la clase Skin. Usar CSS en aplicaciones JavaFX 2 es similar a usar CSS en HTML, porque cada caso se basa en la misma especificación de CSS.
Puede definir estilos en un archivo CSS separado y habilitarlos en la aplicación usando el método getStyleClass.
El fichero style.css:
1 2 3 4 | |
La propiedad -fx-font establece el nombre y el tamaño de la fuente para el button1. La propiedad -fx-base anula el color predeterminado aplicado al botón.
Y desde java usamos:
1 2 3 4 5 | |
Como resultado, el button1 es de color verde claro con un tamaño de texto mayor.
E06_Button.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 | |
RadioButton¶
Un control RadioButton se puede seleccionar o deseleccionar. Por lo general, se combinan en un grupo donde solo se puede seleccionar un botón a la vez.
Abajo se muestran tres capturas de pantalla del ejemplo RadioButton, en las que se agregan tres botones de opción a un grupo.
| Opción 1 | Opción 2 | Opción 3 |
|---|---|---|
![]() | ![]() | ![]() |
La clase RadioButton disponible en el paquete javafx.scene.control del SDK de JavaFX proporciona dos constructores con los que puede crear un botón de opción.
1 2 3 4 5 6 | |
Puede seleccionar explícitamente un botón de radio utilizando el método setSelected y especificando su valor como true. Si necesita verificar si un usuario seleccionó un botón de radio en particular, aplique el método isSelected.
Debido a que la clase RadioButton es una extensión de la clase Labeled, puede especificar no solo una leyenda de texto, sino también una imagen. Utilice el método setGraphic para especificar una imagen.
1 2 3 | |
Los RadioButton se utilizan normalmente en un grupo para presentar varias opciones mutuamente excluyentes. El objeto ToggleGroup proporciona referencias a todos los botones de radio asociados con él y los administra para que solo se pueda seleccionar uno de los botones de radio a la vez. A continuación se muestra como se crea un grupo de alternancia y especifica qué botón debe seleccionarse cuando se inicia la aplicación.
1 2 3 4 5 6 | |
Normalmente, la aplicación realiza una acción cuando se selecciona uno de los botones de opción del grupo. En este caso cambiará la imágen que acompaña al grupo de alternancia.
1 2 3 4 5 6 7 8 9 10 11 | |
Los datos de usuario se asignaron para cada botón de opción. El objeto ChangeListener<Toggle> verifica un conmutador seleccionado en el grupo. Utiliza el método getSelectedToggle para identificar qué botón de opción está actualmente seleccionado y extrae sus datos de usuario llamando al método getUserData. Luego, los datos del usuario se aplican para construir un nombre de archivo de imagen para cargar.
Por ejemplo, cuando se selecciona rButton3, el método getSelectedToggle devuelve "rButton3" y el método getUserData devuelve "coche" Por lo tanto, la imágen será "UD09/coche.png".
E07_RadioButton.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 | |
CheckBox¶
Aunque las casillas de verificación se parecen a los RadioButton, no se pueden combinar en grupos de alternancia.
Más abajo se muestra una captura de pantalla de una aplicación en la que se usan tres casillas de verificación para habilitar o desactivar iconos en la barra de herramientas de una aplicación.
A continuación se crean tres casillas de verificación simples.
1 2 3 4 5 6 7 8 9 10 11 | |
Una vez que haya creado una casilla de verificación, puede modificarla utilizando los métodos disponibles a través de las API de JavaFX. Por ejemplo el método setText define el título de texto de la casilla de verificación check1. El método setSelected se establece en true para que la casilla de verificación check3 se seleccione cuando se inicie la aplicación.
La casilla de verificación puede estar definida o indefinida. Cuando está definido, puede seleccionarlo o deseleccionarlo. Sin embargo, cuando la casilla de verificación está indefinida, no se puede seleccionar ni deseleccionar. Se usa una combinación de los métodos setSelected y setIndeterminate de la clase CheckBox para especificar el estado de la casilla de verificación. En la tabla se muestran tres estados de una casilla de verificación en función de sus propiedades INDETERMINADO y SELECCIONADO.
| Valores de propiedad | Apariencia de la casilla de verificación |
|---|---|
INDETERMINADO = falsoSELECCIONADO = falso | ![]() |
INDETERMINADO =falsoSELECCIONADO = verdadero | ![]() |
INDETERMINADO = verdaderoSELECCIONADO = verdadero/falso | ![]() |
Es posible que deba habilitar tres estados para las casillas de verificación en su aplicación cuando representan elementos de la interfaz de usuario que pueden estar en estados mixtos, por ejemplo, "Sí", "No", "No aplicable". La propiedad allowIndeterminate del objeto CheckBox determina si la casilla de verificación debe pasar por los tres estados: seleccionada, deseleccionada e indefinida. Si la variable es "verdadera", el control recorrerá los tres estados. Si es falso, el control recorrerá los estados seleccionado y deseleccionado. La aplicación descrita en la siguiente sección construye tres casillas de verificación y habilita solo dos estados para ellas.
1 2 3 4 5 6 7 8 9 | |
En la siguiente imagen se puede observar como la columna derecha de checkbox permite los 3 estados:

E08_CheckBox.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 | |
TextField y PasswordField¶
Ahora veremos los componentes para campos de texto, la clase TextField implementa un control de interfaz de usuario que acepta y muestra la entrada de texto. Junto con otro control de entrada de texto, PasswordField, esta clase amplía la clase TextInput, una superclase para todos los controles de texto disponibles a través de la API de JavaFX.

Puede aplicar el método setPrefColumnCount de la clase TextInput para establecer el tamaño del campo de texto, definido como el número máximo de caracteres que puede mostrar a la vez.
1 2 3 4 | |
Puede crear un campo de texto campo con un dato de texto particular en él. Para crear un campo de texto con el texto predefinido:
1 2 3 4 5 | |
En lugar de añadir etiquetas para acompañar a los campos de texto en este fragmento de código se han añadido los subtítulos, que notifican a los usuarios qué tipo de datos deben ingresar en los campos de texto. El método setPromptText define la cadena que aparece en el campo de texto cuando se inicia la aplicación.
1 2 | |
Puede obtener el valor de un campo de texto en cualquier momento llamando al método getText. Aquí por ejemplo hacemos que se muestre el campo oculto en un label:
1 2 3 4 5 | |
Revise algunos métodos útiles que puede usar con los campos de texto.
copy()– transfiere el rango actualmente seleccionado en el texto al portapapeles, dejando la selección actual.cut()– transfiere el rango actualmente seleccionado en el texto al portapapeles, eliminando la selección actual.selectAll()- selecciona todo el texto en la entrada de texto.pegar()– transfiere el contenido del portapapeles a este texto, reemplazando la selección actual.
E09_TextBox.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 | |
Mucho más¶
https://docs.oracle.com/javase/8/javafx/user-interface-tutorial/ui_controls.htm
Diseño (Layouts)¶
VBox y HBox¶
El diseño en JavaFX comienza con la selección de los controles de contenedor correctos. Los dos controles de diseño que uso con más frecuencia son VBoxy HBox.
VBoxes un contenedor que organiza a sus hijos en una pila vertical.HBoxordena a sus hijos en una fila horizontal.
El poder de estos dos controles proviene de envolverlos y establecer algunas propiedades clave: alineación, hgrow y vgrow.
Este artículo demostrará estos controles a través de un proyecto de ejemplo. Una maqueta del proyecto muestra una interfaz de usuario con lo siguiente:
- Una fila de controles superiores que contiene Actualizar
Buttony Cerrar sesiónHyperlink, - Una Tabla
TableViewque crecerá para ocupar el espacio vertical adicional, y - Un
ButtonCerrar.
La interfaz de usuario también presenta un Separatorpanel que divide la parte superior de la pantalla con lo que puede convertirse en un panel inferior estándar (Guardar Button, Cancelar Button, etc.) para la aplicación.

Estructura¶
VBox será el contenedor más externo "vbox". Este será el Parent proporcionado a la Escena. El simple hecho de colocar los controles de la interfaz de usuario en este VBox permitirá que los controles, sobre todo el TableView , se estiren para adaptarse al espacio horizontal disponible. Los controles superiores, Actualizar Button y Cerrar sesión Hyperlink, están envueltos en un contenedor HBox. Del mismo modo, se envolverá el Button inferior Cerrar en un HBox, lo que permite botones adicionales.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | |
Esta imagen muestra la maqueta desglosada por contenedor. El padre VBox es el rectángulo azul más externo. Los HBoxes son los rectángulos interiores (rojo y verde).

Alineación y Hgrow¶
El Button Actualizar está alineado a la izquierda mientras que el Hyperlink Cerrar sesión está alineado a la derecha. Esto se logra usando dos HBoxes. controlesArriba es un HBox que contiene el Button Actualizar y también contiene un HBoxcon el Hyperlink Cerrar sesión. A medida que la pantalla se hace más ancha, el Hyperlink Cerrar sesión se desplazará hacia la derecha, mientras que el Button Actualizar mantendrá su alineación izquierda.
La alineación es la propiedad que le dice a un contenedor dónde colocar un control. controlesArriba establece la alineación en BOTTOM_LEFT. controlesArribaDerecha establece la alineación con BOTTOM_RIGHT. BOTTOM se asegura de que la línea de base del texto Actualizar coincida con la línea de base del texto Cerrar sesión.
Para que el Hyperlink Cerrar sesión se mueva hacia la derecha cuando la pantalla se ensancha, es necesario Priority.ALWAYS. Esta es una señal para que JavaFX amplíe controlesArribaDerecha. De lo contrario, controlesArriba mantendrá el espacio y controlesArribaDerecha aparecerá a la izquierda. El Hyperlink Cerrar sesión todavía estaría alineado a la derecha pero en un contenedor más estrecho.
Tenga en cuenta que setHgrow() es un método estático y no se invoca el HBox controlesArriba ni en sí mismo, controlesArribaDerecha. Esta es una faceta de la API de JavaFX que puede resultar confusa porque la mayoría de las API establece propiedades a través de setters en objetos.
1 2 3 | |
El Button Cerrar se envuelve en un HBox y se posiciona usando la prioridad BOTTOM_RIGHT.
1 | |
Crecer¶
Dado que el contenedor más externo es VBox, el hijo TableView se expandirá para ocupar espacio horizontal adicional cuando se amplíe la ventana. Sin embargo, cambiar el tamaño vertical de la ventana producirá un espacio en la parte inferior de la pantalla. VBox no cambia automáticamente el tamaño de ninguno de sus elementos secundarios . Al igual que con el HBox controlesArribaDerecha, se puede configurar un indicador de crecimiento. En el caso del HBox, se trataba de una instrucción de cambio de tamaño horizontal setHgrow(). Para el contenedor VBox TableView, será setVgrow().
1 | |
Margen¶
Hay algunas formas de espaciar los controles de la interfaz de usuario. Nosotros usaremos la propiedad margin en varios de los contenedores para agregar espacios en blanco alrededor de los controles. Estos se configuran individualmente en lugar de usar un espacio en el VBox para que el Separador abarque todo el ancho.
1 2 3 | |
El Insets usado por tblClientes omite cualquier espacio superior para mantener el espacio uniforme. JavaFX no consolida los espacios en blanco como en el diseño web. Si el Recuadro superior se estableciera en 10.0d para el tblClientes, la distancia entre los controles superiores y el TableView sería el doble de ancha que la distancia entre cualquiera de los otros controles.
Tenga en cuenta que estos son métodos estáticos como el Priority.
Esta imagen muestra la aplicación cuando se ejecuta en su tamaño inicial de 800x600.

Esta imagen muestra la aplicación redimensionada a un alto y ancho más pequeños.

Seleccione los contenedores correctos¶
La filosofía del diseño de JavaFX es la misma que la filosofía de Swing. Seleccione el contenedor adecuado para la tarea en cuestión. Aquí hemos mostrado los dos contenedores más versátiles: VBox y HBox. Al establecer propiedades como alineación, hgrow y vgrow, puede crear diseños increíblemente complejos mediante el anidamiento. Estos son los contenedores que más uso y, a menudo, son los únicos contenedores que necesitaras.
Código completo¶
El código se puede probar con un par de archivos .java. Hay un POJO para la clase Cliente utilizado por el TableView
Cliente.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | |
y la subclase JavaFX completa y principal:
VBoxAndHBoxApp.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 | |
StackPane¶
El layout StackPane coloca a sus hijos uno encima de otro. El último Node agregado es el más alto. Por defecto StackPane alineará los hijos usando Pos.CENTER, como se puede ver en la siguiente imagen, donde están los 3 hijos (en orden de creación): Rectangle, Circle y Button.

Esta imagen fue producida por el siguiente fragmento:
StackPaneApp.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | |
Podemos cambiar la alineación predeterminada descomentando la linea pane.setAlignment(Pos.CENTER_LEFT);para producir el siguiente efecto:

Posicionamiento absoluto con panel (Pane)¶
Contenedores como VBox o BorderPane alinear y distribuir a sus hijos. La superclase Pane también es un contenedor, pero no impone un orden a sus hijos. Los hijos se posicionan a sí mismos a través de propiedades como x, centerX y layoutX. Esto se llama posicionamiento absoluto y es una técnica para colocar un Shape o un Node en un lugar determinado de la pantalla.
Esta captura de pantalla muestra una vista Acerca de. La vista Acerca de contiene un Hyperlink en el medio de la pantalla "Acerca de esta aplicación". La vista Acerca de utiliza varias formas JavaFX para formar un diseño que se recorta para que parezca una tarjeta de presentación.

Tamaño del panel¶
A diferencia de la mayoría de los contenedores, Pane cambia de tamaño para adaptarse a su contenido y no al revés. Esta imagen es una captura de pantalla de Scenic View tomada antes de agregar el Arco inferior derecho. El Pane es el área resaltada en amarillo. Tenga en cuenta que no ocupa la totalidad Stage.

A continuación se muestra una captura de pantalla tomada después de agregar la esquina inferior derecha Arc. Esto Arcse colocó más cerca del borde inferior derecho del archivo Stage. Esto obliga al Panel a estirarse para acomodar los contenidos expandidos.

El panel (Pane)¶
El contenedor más externo de la vista Acerca de es un VBox cuyo único contenido es el archivo Pane. El VBox se utiliza para encajar en el conjunto Stage y proporciona un fondo.
1 2 3 4 5 6 7 8 | |
Las formas (Shape)¶
En la parte superior izquierda de la pantalla, hay un grupo de 4 Arcos y 1 Círculo. Este código posiciona largeArc en (0,0) a través de los argumentos centerX y centerY en el constructor Arc. Observa que backgroundArc también se coloca en (0,0) y aparece debajo de largeArc. Pane no intenta eliminar el conflicto de formas superpuestas y, en este caso, lo que se busca es la superposición. smArc1 se coloca en (0,160), que está abajo en el eje Y. smArc2 está posicionado en (160,0) que está justo en el eje X. smCircle se coloca a la misma distancia que smArc1 y smArc2, pero en un ángulo de 45 grados.
1 2 3 4 5 6 7 8 9 10 11 12 13 | |
En la parte inferior derecha el Arc se coloca en función de la altura total del archivo Stage. Los 20 restados de la altura son los 10 píxeles de Insets (Margen) de VBox (10 para la izquierda + 10 para la derecha).
1 2 3 4 5 | |
El hipervínculo¶
El Hyperlink está posicionado compensado el centro (284,160) que es el ancho y alto de Stage ambos dividido por dos. Esto coloca el texto del Hyperlinken el cuadrante inferior derecho de la pantalla, por lo que se necesita un desplazamiento basado en el ancho y el alto de Hyperlink. Las dimensiones del Hyperlink no están disponibles hasta que se muestra la pantalla, por lo que se realiza un ajuste posterior a la visualización de la posición.
1 2 3 4 5 6 | |
El Hyperlinkno está colocado en el verdadero centro de la pantalla. El valor de layoutX se basa en una operación de división por tres que lo aleja de las formas de la esquina superior izquierda.
Orden Z¶
Como se mencionó anteriormente, Pane admite la superposición de los hijos. Esta imagen muestra la vista Acerca de con profundidad.

El orden z en este ejemplo está determinado por el orden en que se agregan los elementos secundarios al archivo Pane. backgroundArc está oscurecido por elementos agregados más tarde, más notablemente largeArc. Para reorganizar los elementos secundarios, use los métodos toFront() y toBack() después de agregar los elementos al archivo Pane.
1 2 | |
Recomendación
Al comenzar con JavaFX, es tentador construir un diseño absoluto. Tenga en cuenta que los diseños absolutos son frágiles y, a menudo, se rompen cuando se cambia el tamaño de la pantalla (como en este caso) o cuando se agregan elementos durante la fase de mantenimiento del software. Sin embargo, existen buenas razones para utilizar el posicionamiento absoluto. El juego es uno de esos usos. En un juego, puede ajustar la coordenada (x,y) de una Shape para mover una pieza del juego por la pantalla.
Código completo¶
Esta es la aplicación JavaFX completa y principal.
PaneApp.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 | |
GridPane¶
Los formularios en las aplicaciones comerciales a menudo usan un diseño que imita un registro de base de datos. Para cada columna de una tabla, se agrega un encabezado en el lado izquierdo que coincide con un valor de fila en el lado derecho. JavaFX tiene un control de propósito especial llamado GridPane para este tipo de diseño que mantiene los contenidos alineados por fila y columna. GridPane también admite expansión para diseños más complejos.
La siguiente captura de pantalla muestra un diseño básico de GridPane. En el lado izquierdo del formulario, hay una columna de nombres de campo: Correo-e, Prioridad, Problema, Descripción. En el lado derecho del formulario, hay una columna de controles que mostrará el valor del campo correspondiente. Los nombres de campo son de tipo Label y los controles de valor son una mezcla que incluye TextField, TextArea y ComboBox.

El siguiente código muestra los objetos creados para el formulario. "vbox" es la raíz del Sceney también contendrá el ButtonBar en la base del formulario.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | |
GridPane tiene un método útil setGridLinesVisible() que muestra la estructura de la cuadrícula y los espacios. Es especialmente útil en diseños más complejos donde se involucra la expansión porque los espacios en las asignaciones de filas/columnas pueden causar cambios en el diseño.

Espaciado¶
Como contenedor, GridPane tiene una propiedad de relleno que se puede configurar para rodear el contenedor GridPane con espacios en blanco. setPadding() tomará un objeto Inset como parámetro. En este ejemplo, se aplican 10 píxeles de espacio en blanco a todos los lados, por lo que se usa un constructor de formato corto para Inset.
Dentro de GridPane, vgap y hgap controlan los espacios. El hgap se establece en 4 para mantener los campos cerca de sus valores. vgap es un poco más grande para ayudar con la navegación del mouse.
1 2 3 | |
Para mantener consistente la parte inferior del formulario, Priority.ALWAYS se establece a en la clase VBox sobre el GridPane (recuerda que es estático). Sin embargo, esto no cambiará el tamaño de las filas individuales. Para especificaciones de cambio de tamaño individuales, debes usar ColumnConstraints y RowConstraints.
1 | |
Adición de elementos¶
A diferencia de los contenedores como BorderPane o HBox, los nodos deben especificar su posición dentro del contenedor GridPane. Esto se hace con el método add() en GridPane y no con el método add() en una propiedad secundaria del contenedor. El método add() de GridPane recibe una posición de columna de base cero y una posición de fila de base cero. En este código ponemos dos declaraciones en la misma línea para facilitar la lectura.
1 2 3 4 5 | |
lblTitle se coloca en la segunda columna de la primera fila. No hay ninguna entrada en la primera columna de la primera fila.
Las adiciones posteriores se presentan por parejas. Los objetos de nombre de campo Label se colocan en la primera columna (índice de columna=0) y los controles de valor se colocan en la segunda columna (índice de columna=1). Las filas se agregan por el segundo valor incrementado. Por ejemplo, lblPriority se coloca en la cuarta fila junto con su ComboBox.
GridPane es un contenedor importante en el diseño de aplicaciones empresariales JavaFX. Cuando tenga un requisito de pares de nombre/valor, GridPaneserá una manera más fácil de organizar la estructura del formulario.
Código completo¶
La siguiente clase es el código completo del ejemplo. Esto incluye la definición de la ButtonBarque no se presentó en las secciones anteriores enfocadas en GridPane.
GridPaneApp.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 | |
GridPane Spanning (expansión)¶
Para formularios más complejos implementados con GridPane, se admite la expansión. La expansión permite que un control reclame el espacio de columnas vecinas (colspan) y filas vecinas (rowspan). Esta captura de pantalla muestra un formulario que amplía el ejemplo de la sección anterior. El diseño de dos columnas de la versión anterior se reemplazó por un diseño de varias columnas. Los campos como Problema y Descripción conservan la estructura original. Pero se agregaron controles a las filas que anteriormente contenían solo Correo electrónico y Prioridad.

Al activar las líneas de la cuadrícula, observe que la cuadrícula anterior de dos columnas se reemplaza con una cuadrícula de seis columnas. La tercera fila que contiene seis elementos (3 pares de nombre de campo/valor) dicta la estructura. El resto del formulario utilizará la expansión para completar el espacio en blanco.

Hay un poco más de Vgap para ayudar al usuario a seleccionar los controles ComboBox. Como en la versión anterior, los controles se agregan al GridPane con el método add(). Se especifica una columna y una fila. Repasa los índices ya que no es evidente, ya que se espera que se llenen los vacíos mediante el contenido expandido.
Las definiciones de expansión se establecen mediante un método estático en GridPane. Hay un método similar para hacer la expansión de filas. El título ocupará 5 columnas, al igual que el problema y la descripción. El correo electrónico comparte una fila con el contrato, pero ocupará más columnas. La tercera fila de ComboBoxes es un conjunto de tres pares de campo/valor, cada uno de los cuales ocupa una columna.
1 2 3 4 | |
Alternativamente, una variación del método add() tendrá argumentos columnSpan y rowSpan para evitar la subsiguiente llamada al método estático.
Este ejemplo ampliado GridPanedemostró la expansión de columnas. La misma capacidad está disponible para la expansión de filas, lo que permitiría que un control reclame espacio vertical adicional. La expansión mantiene los controles alineados incluso en los casos en que varía el número de elementos en una fila (o columna) determinada.
Código completo¶
El siguiente es el código completo para el ejemplo de GridPane de expansión.
GridPaneAppv2.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 | |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | |
Estructura de la aplicación¶
El patrón MVC¶
Modelo-vista-controlador (MVC) es un patrón de arquitectura de software, que separa los datos y principalmente lo que es la lógica de negocio de una aplicación de su representación y el módulo encargado de gestionar los eventos y las comunicaciones. Para ello MVC propone la construcción de tres componentes distintos que son el modelo, la vista y el controlador, es decir, por un lado define componentes para la representación de la información, y por otro lado para la interacción del usuario. Este patrón de arquitectura de software se basa en las ideas de reutilización de código y la separación de conceptos, características que buscan facilitar la tarea de desarrollo de aplicaciones y su posterior mantenimiento.
De manera genérica, los componentes de MVC se podrían definir como sigue:
- El Modelo: Es la representación de la información con la cual el sistema opera, por lo tanto gestiona todos los accesos a dicha información, tanto consultas como actualizaciones, implementando también los privilegios de acceso que se hayan descrito en las especificaciones de la aplicación (lógica de negocio). Envía a la 'vista' aquella parte de la información que en cada momento se le solicita para que sea mostrada (típicamente a un usuario). Las peticiones de acceso o manipulación de información llegan al 'modelo' a través del 'controlador'.
- El Controlador: Responde a eventos (usualmente acciones del usuario) e invoca peticiones al 'modelo' cuando se hace alguna solicitud sobre la información (por ejemplo, editar un documento o un registro en una base de datos). También puede enviar comandos a su 'vista' asociada si se solicita un cambio en la forma en que se presenta el 'modelo' (por ejemplo, desplazamiento o scroll por un documento o por los diferentes registros de una base de datos), por tanto se podría decir que el 'controlador' hace de intermediario entre la 'vista' y el 'modelo' (véase Middleware).
- La Vista: Presenta el 'modelo' (información y lógica de negocio) en un formato adecuado para interactuar (usualmente la interfaz de usuario), por tanto requiere de dicho 'modelo' la información que debe representar como salida.










