jairogarcíarincón
03/12/2018
Contenidos
- Introducción a JavaFX y Prerrequisitos
- LibretaDirecciones: Creación del proyecto y configuración
- LibretaDirecciones: Modelo y Lista de personas
- LibretaDirecciones: Interacción con el usuario
- LibretaDirecciones: Hojas de estilo CSS
- LibretaDirecciones: Persistencia de datos con XML
- LibretaDirecciones: Gráficos e Informes
- LibretaDirecciones: Despliegue
- LibretaDirecciones: Persistencia con base de datos con MySQL (local)
- LibretaDirecciones: Persistencia con base de datos con MySQL (remota)
En JavaFX puedes dar estilo al interfaz de usuario utilizando hojas de estilo en cascada (CSS).
En este tutorial vamos a crear un tema oscuro (DarkTheme) inspirado en el diseño de Windows 8 Metro. El código CSS de los botones está basado en el artículo de blog JMetro - Windows 8 Metro controls on Java de Pedro Duque Vieira.
Para información más específica de CSS y JavaFX puedes consultar:
- Skinning JavaFX Applications with CSS - Tutorial by Oracle
- JavaFX CSS Reference - Official Reference
Los estilos por defecto de JavaFX 8 se encuentran en un archivo denominado modena.css. Este archivo CSS se encuentra dentro del archivo jfxrt.jar que se encuentra en tu directorio de instalación de Java, en la ruta /jdk1.8.x/jre/lib/ext/jfxrt.jar.
Dentro de ese archivo, el fichero modena.css se encuentra en el paquete com.sun.javafx.scene.control.skin.modena
Este estilo se aplica siempre a una aplicación JavaFX. Añadiendo un estilo personal podremos reescribir los estilos por defecto.
Crea un nuevo package llamado css y dentro de él un fichero CSS (Other -> New Cascade Stylesheet) fichero denominado DarkTheme.css, con el siguiente contenido:
.root{
-fx-font-family: "Verdana";
}
.background {
-fx-background-color: #1d1d1d;
}
.label {
-fx-font-size: 11pt;
-fx-text-fill: white;
-fx-opacity: 0.6;
}
.label-bright {
-fx-font-size: 11pt;
-fx-text-fill: white;
-fx-opacity: 1;
}
.label-header {
-fx-font-size: 32pt;
-fx-text-fill: white;
-fx-opacity: 1;
}
.table-view {
-fx-base: #1d1d1d;
-fx-control-inner-background: #1d1d1d;
-fx-background-color: #1d1d1d;
-fx-table-cell-border-color: transparent;
-fx-table-header-border-color: transparent;
-fx-padding: 5;
}
.table-view .column-header-background {
-fx-background-color: transparent;
}
.table-view .column-header, .table-view .filler {
-fx-size: 35;
-fx-border-width: 0 0 1 0;
-fx-background-color: transparent;
-fx-border-color:
transparent
transparent
derive(-fx-base, 80%)
transparent;
-fx-border-insets: 0 10 1 0;
}
.table-view .column-header .label {
-fx-font-size: 20pt;
-fx-text-fill: white;
-fx-alignment: center-left;
-fx-opacity: 1;
-fx-font-weight: normal;
}
.table-view:focused .table-row-cell:filled:focused:selected {
-fx-background-color: -fx-focus-color;
}
.split-pane:horizontal > .split-pane-divider {
-fx-border-color: transparent #1d1d1d transparent #1d1d1d;
-fx-background-color: transparent, derive(#1d1d1d,20%);
}
.split-pane {
-fx-padding: 1 0 0 0;
}
.menu-bar {
-fx-background-color: derive(#1d1d1d,20%);
}
.context-menu {
-fx-background-color: derive(#1d1d1d,50%);
}
.menu-bar .label {
-fx-font-size: 14pt;
-fx-text-fill: white;
-fx-opacity: 0.9;
}
.menu .left-container {
-fx-background-color: black;
}
.text-field {
-fx-font-size: 12pt;
}
.button {
-fx-padding: 5 22 5 22;
-fx-border-color: #e2e2e2;
-fx-border-width: 2;
-fx-background-radius: 0;
-fx-background-color: #1d1d1d;
-fx-font-size: 11pt;
-fx-text-fill: #d8d8d8;
-fx-background-insets: 0 0 0 0, 0, 1, 2;
}
.button:hover {
-fx-background-color: #3a3a3a;
}
.button:pressed, .button:default:hover:pressed {
-fx-background-color: white;
-fx-text-fill: #1d1d1d;
}
.button:focused {
-fx-border-color: white, white;
-fx-border-width: 1, 1;
-fx-border-style: solid, segments(1, 1);
-fx-border-radius: 0, 0;
-fx-border-insets: 1 1 1 1, 0;
}
.button:disabled, .button:default:disabled {
-fx-opacity: 0.4;
-fx-background-color: #1d1d1d;
-fx-text-fill: white;
}
.button:default {
-fx-background-color: -fx-focus-color;
-fx-text-fill: #ffffff;
}
.button:default:hover {
-fx-background-color: derive(-fx-focus-color,30%);
}
Para vincular y el archivo CSS y asociar la clases correspondientes podríamos utilizar Java, si bien en este primer tutorial vamos a hacerlo mediante Scene Builder para que sea más visual:
- Abrimos el archivo VistaPrincipal.fxml y seleccionamos el BorderPane raíz.
- En la sección Properties (derecha) añadimos la ruta de nuestro Stylesheet.
- Abrimos el archivo EditarPersona.fxml y seleccionamos el AnchorPane raíz.
- En la sección Properties (derecha) añadimos la ruta de nuestro Stylesheet.
- Como el fondo aún es blanco, añadimos la clase background al AnchorPane raíz mediante la propiedad Style Class.
- Selecciona el botón Guardar y elige Default Button en la vista Properties. Eso cambiará su color y lo convertirá en el botón "por defecto", el que se ejecutará si el usuario aprieta la tecla Enter.
- Selecciona el botón Cancelar y elige Cancel Button en la vista Properties.
- Posiblemente tengas que ajustar el tamaño de algunos botones y paneles para que se muestre todo el texto.
- Abrimos el archivo VistaPersona.fxml y seleccionamos el AnchorPane raíz.
- En la sección Properties (derecha) añadimos la ruta de nuestro Stylesheet.
- Selecciona el panel AnchorPane de la derecha, dentro del SplitPane.
- En Properties, slecciona background como clase de estilo. El fondo debería volverse negro.
- Selecciona la etiqueta (Label) Detalles y añade label-header como clase de estilo.
- Para cada etiqueta en la columna de la derecha (donde se muestran los detalles de una persona), añade la clase de estilo label-bright.
- Posiblemente tengas que ajustar el tamaño de algunos botones y paneles para que se muestre todo el texto.
Ahora mismo nuestra aplicación utiliza el icono por defecto para la barra de título y la barra de tareas, pero quedaría mucho mejor con un icono personalizado.
Un posible sitio para obtener iconos gratuitos es Icon Finder. Yo por ejemplo descargué este icono de libreta de direcciones.
Una vez descargado el icono, crea un nuevo package img y añade el archivo descargado, en mi caso libretaDirecciones.png , redimensionado a 32px de altura.
Ahora modifica el método start() de LibretaDirecciones.java para que quede como sigue:
@Override
public void start(Stage escenarioPrincipal) {
//Debo hacerlo para que luego me funcione en l carga de escenas
this.escenarioPrincipal = escenarioPrincipal;
//Establezco el título
this.escenarioPrincipal.setTitle("Libreta de direcciones");
//Establezco el icono de aplicación
this.escenarioPrincipal.getIcons().add(new Image("file:img/libretaDirecciones.png"));
//Inicializo el layout principal
initLayoutPrincipal();
//Muestro la vista persona
muestraVistaPersona();
}
Por supuesto, podrías hacer lo mismo para el método muestraEditarPersona y asignarle su propio icono de edición.
El resultado final de este capítulo debería ser similar a la captura mostrada al inicio del presente capítulo.
Publicado el 30 de Enero de 2025
xmlinterfacesjavafx