Perfil de Usuario ERP con JavaFX y Tailwind CSS

Construye un panel de perfil de usuario moderno estilo ERP empresarial usando JavaFX, FXML y la librería FxThemeBridge con clases Tailwind. Incluye métricas en tiempo real, tabs de actividad y sistema de permisos.

J

JJ Arroyo

24 de marzo de 2026 15 min de lectura

Perfil de Usuario ERP con JavaFX y Tailwind CSS

En este tutorial vamos a construir desde cero un Panel de Perfil de Usuario tipo ERP empresarial usando JavaFX con FXML y la librería FxThemeBridge en modo Tailwind. El resultado es una interfaz profesional con tarjeta de empleado, métricas de rendimiento operativo, tabla de actividad y panel de permisos.

Descargar Proyecto Completo


¿Qué vamos a construir?

Una interfaz dividida en dos paneles:

  • Panel izquierdo: Tarjeta del empleado con avatar, datos corporativos (ID, departamento, ubicación, turno) y contacto.
  • Panel derecho: Sistema de tabs con tres secciones:
    • Rendimiento Operativo: Métricas en vivo (tasa de recolección, precisión, tareas, incidentes) con barra de progreso.
    • Registro de Actividad: Tabla con el historial de acciones del turno actual.
    • Accesos y Permisos: Badges de módulos autorizados y datos de seguridad.

Requisitos

  • Java 17+ y JavaFX SDK 21+
  • Librería fx-themebridge-library.jar en la carpeta lib/

Estructura del Proyecto

userprofile/
├── run.bat
├── lib/
│   └── fx-themebridge-library.jar
├── src/main/java/com/userprofile/
│   ├── App.java
│   ├── controller/
│   │   └── MainController.java
│   └── model/
│       └── Employee.java
└── src/main/resources/
    ├── css/
    │   └── style.css
    └── fxml/
        └── MainView.fxml

Paso 1: Configurar FxThemeBridge con Tailwind

Lo primero es copiar fx-themebridge-library.jar a la carpeta lib/ del proyecto. Luego, en App.java, inicializamos el tema Tailwind antes de cargar nuestro CSS custom:

package com.userprofile;

import com.fxthemebridge.FxThemeBridge;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;

public class App extends Application {

    @Override
    public void start(Stage primaryStage) throws Exception {
        FXMLLoader loader = new FXMLLoader(getClass().getResource("/fxml/MainView.fxml"));
        Parent root = loader.load();
        Scene scene = new Scene(root, 1100, 650);

        // Cargar Tailwind desde FxThemeBridge
        FxThemeBridge.init(scene, FxThemeBridge.Target.TAILWIND);
        // CSS custom sobre la base Tailwind
        scene.getStylesheets().add(getClass().getResource("/css/style.css").toExternalForm());

        primaryStage.setTitle("Perfil de Usuario - ERP Global Systems v4.2");
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}

Con una sola línea, FxThemeBridge.init(scene, FxThemeBridge.Target.TAILWIND), obtenemos acceso a cientos de clases utilitarias tipo Tailwind: bg-gray-100, text-blue-600, font-bold, p-6, card, badge, btn, y muchas más.

Paso 2: El Modelo — Employee

Usamos JavaFX Properties para que nuestro modelo sea reactivo y listo para binding:

package com.userprofile.model;

import javafx.beans.property.*;

public class Employee {

    private final StringProperty id = new SimpleStringProperty();
    private final StringProperty name = new SimpleStringProperty();
    private final StringProperty role = new SimpleStringProperty();
    private final StringProperty department = new SimpleStringProperty();
    private final StringProperty location = new SimpleStringProperty();
    private final StringProperty shift = new SimpleStringProperty();
    private final StringProperty email = new SimpleStringProperty();
    private final StringProperty phone = new SimpleStringProperty();
    private final BooleanProperty active = new SimpleBooleanProperty(true);

    private final IntegerProperty collectionRate = new SimpleIntegerProperty();
    private final DoubleProperty precision = new SimpleDoubleProperty();
    private final IntegerProperty tasksCompleted = new SimpleIntegerProperty();
    private final IntegerProperty tasksTotal = new SimpleIntegerProperty();
    private final IntegerProperty incidents = new SimpleIntegerProperty();

    public Employee(String id, String name, String role, String department,
                    String location, String shift, String email, String phone) {
        this.id.set(id);
        this.name.set(name);
        this.role.set(role);
        this.department.set(department);
        this.location.set(location);
        this.shift.set(shift);
        this.email.set(email);
        this.phone.set(phone);
    }

    // Property accessors
    public StringProperty idProperty() { return id; }
    public StringProperty nameProperty() { return name; }
    public StringProperty roleProperty() { return role; }
    // ... getters, setters y demás properties
}

Paso 3: El Layout FXML — Dos Paneles con Tailwind

El archivo FXML utiliza directamente las clases de FxThemeBridge Tailwind. Nada de CSS inline, todo con clases utilitarias:

<HBox styleClass="bg-gray-100" xmlns:fx="http://javafx.com/fxml/1"
      fx:controller="com.userprofile.controller.MainController"
      prefWidth="1100" prefHeight="650" spacing="0">
    <padding>
        <Insets top="24" right="24" bottom="24" left="24"/>
    </padding>

    <!-- Panel izquierdo: Tarjeta del empleado -->
    <VBox styleClass="card-elevated" spacing="0" prefWidth="300"
          alignment="TOP_CENTER">

        <!-- Avatar con iniciales -->
        <StackPane prefWidth="100" prefHeight="100">
            <Region styleClass="avatar-circle"/>
            <Label fx:id="avatarInitials" text="CM" styleClass="avatar-text"/>
            <Region styleClass="online-dot" StackPane.alignment="BOTTOM_RIGHT"/>
        </StackPane>

        <Label fx:id="nameLabel" text="Carlos Mendoza" styleClass="h4"/>
        <Label fx:id="roleLabel" text="Supervisor" styleClass="text-blue-600, text-sm"/>

        <!-- Badge activo -->
        <HBox styleClass="badge-active">
            <Label text="●" styleClass="text-green-500"/>
            <Label text="Activo" styleClass="text-green-700, font-medium"/>
        </HBox>

        <!-- Info corporativa con clases Tailwind -->
        <Label text="INFORMACIÓN CORPORATIVA" styleClass="section-header"/>
        <Label fx:id="departmentLabel" styleClass="text-primary, text-sm, font-semibold"/>
        <!-- ... más campos -->
    </VBox>

    <!-- Panel derecho: Tabs -->
    <VBox HBox.hgrow="ALWAYS">
        <TabPane fx:id="tabPane" styleClass="tab-pane">
            <Tab text="Rendimiento Operativo" closable="false">
                <!-- Métricas en cards -->
            </Tab>
            <Tab text="Registro de Actividad" closable="false">
                <!-- Tabla de actividad -->
            </Tab>
            <Tab text="Accesos y Permisos" closable="false">
                <!-- Badges y seguridad -->
            </Tab>
        </TabPane>
    </VBox>
</HBox>

Clases Tailwind usadas en el FXML

ClaseFunción
bg-gray-100Fondo gris claro del root
card-elevatedTarjeta con sombra elevada
text-blue-600Texto azul para el rol
text-mutedTexto gris secundario
text-green-500Indicador verde
font-semiboldPeso semibold
h4Heading nivel 4
badge, badge-primaryBadges de permisos
card-colored-greenCard con fondo verde para el mensaje de objetivo
btn, btn-outlineBotón con borde

Paso 4: Las Métricas — Cards con Datos en Vivo

Cada métrica vive en su propia card con el valor numérico grande y una etiqueta descriptiva:

<VBox styleClass="card, metric-card" HBox.hgrow="ALWAYS" alignment="CENTER">
    <HBox spacing="6" alignment="CENTER">
        <Label text="📦"/>
        <Label text="Tasa de Recolección" styleClass="text-muted, text-xs"/>
    </HBox>
    <Label fx:id="collectionRateLabel" text="185" styleClass="metric-value"/>
    <Label text="und/hr" styleClass="text-muted, text-sm"/>
</VBox>

La barra de progreso de tareas se estiliza con la clase progress-primary definida en nuestro CSS custom:

.progress-primary .bar {
    -fx-background-color: #3b82f6;
    -fx-background-radius: 4px;
}
.progress-primary .track {
    -fx-background-color: #e5e7eb;
    -fx-background-radius: 4px;
}

Paso 5: El Controlador — Binding y Tabla

El controlador crea el Employee con datos demo y los enlaza con los Labels del FXML. La tabla de actividad usa TableView<String[]> para mantener el ejemplo simple:

@FXML
public void initialize() {
    employee = new Employee(
        "EMP-8472", "Carlos Mendoza", "Supervisor de Almacén",
        "Logística y Distribución", "Bodega Central - Zona A",
        "Turno Mañana (06:00 - 14:00)",
        "carlos.mendoza@empresa.com", "+57 300 123 4567"
    );

    employee.setCollectionRate(185);
    employee.setPrecision(99.8);
    employee.setTasksCompleted(145);
    employee.setTasksTotal(150);
    employee.setIncidents(1);

    bindEmployeeData();
    setupActivityTable();
}

private void setupActivityTable() {
    timeColumn.setCellValueFactory(
        data -> new SimpleStringProperty(data.getValue()[0])
    );
    actionColumn.setCellValueFactory(
        data -> new SimpleStringProperty(data.getValue()[1])
    );
    // ... zona y estado

    activityTable.setItems(FXCollections.observableArrayList(
        new String[]{"06:05", "Inicio de turno", "Acceso Principal", "Completado"},
        new String[]{"07:30", "Despacho #ORD-4521", "Zona Despacho", "Completado"},
        new String[]{"09:20", "Incidente - Caja dañada", "Zona A", "Reportado"}
    ));
}

Paso 6: CSS Custom — Solo lo que Tailwind no cubre

La magia de FxThemeBridge es que nuestro style.css es mínimo. Solo definimos lo específico de esta app:

/* Avatar circular con gradiente */
.avatar-circle {
    -fx-background-color: linear-gradient(to bottom right, #e0e7ff, #c7d2fe);
    -fx-background-radius: 9999px;
    -fx-pref-width: 100px;
    -fx-pref-height: 100px;
}

/* Indicador verde de "en línea" */
.online-dot {
    -fx-background-color: #22c55e;
    -fx-background-radius: 9999px;
    -fx-border-color: white;
    -fx-border-width: 3px;
}

/* Valor grande de las métricas */
.metric-value {
    -fx-font-size: 32px;
    -fx-font-weight: bold;
    -fx-text-fill: #111827;
}

/* Encabezado de sección */
.section-header {
    -fx-font-size: 11px;
    -fx-font-weight: bold;
    -fx-text-fill: #6366f1;
}

Todo lo demás — colores de texto, backgrounds, bordes, paddings, badges, cards, botones, tabs, tablas — viene gratis de FxThemeBridge Tailwind.

Resultado Final

La aplicación muestra una interfaz idéntica a un dashboard web moderno:

  • Tarjeta lateral con avatar, estado activo, datos corporativos y contacto
  • Métricas operativas con cards individuales y barra de progreso
  • Tabla de actividad con el historial del turno completo
  • Panel de permisos con badges de colores por módulo

Puntos Clave

  1. FxThemeBridge simplifica todo: Con FxThemeBridge.init(scene, "tailwind") obtienes un sistema de diseño completo.
  2. FXML + Tailwind = Productivo: Las clases utilitarias directamente en styleClass del FXML eliminan la necesidad de escribir CSS extenso.
  3. CSS custom mínimo: Solo ~100 líneas para los componentes específicos del perfil.
  4. Datos reactivos: El modelo usa Property de JavaFX, listo para binding bidireccional si necesitas editabilidad.

Requisitos: Java 17+, JavaFX 21+, tener configurada la variable JAVAFX_PATH en run.bat.

forumComentarios

Deja tu comentario

progress_activityCargando comentarios...