Qué es
jdashboard_WindowsStyle es la base de ventana moderna de jdashboardUI para B4J. Convierte un Form normal en una ventana sin marco nativo y crea la estructura sobre la que después pueden montarse Ribbon, menús laterales, dashboards, tablas, editores, visores PDF y cualquier otro contenido.
No es un tema cerrado ni obliga a que todas las aplicaciones se vean iguales. Precisamente por eso aplicaciones tan distintas como Licensr Pro, LibX Template Studio, B4X Antivirus Pro o DataFlow pueden usar la misma base de ventana y tener diseños completamente diferentes.
WindowsStyle administra principalmente:
- barra superior personalizada;
- icono y título;
- botones de minimizar, maximizar / restaurar, cerrar y pantalla completa;
- botones propios con iconos o imágenes;
- área central para controles personalizados;
- RootPane para el contenido de la aplicación;
- arrastre de la ventana;
- redimensionamiento;
- bordes y esquinas redondeadas;
- sombras;
- Always On Top;
- animación al maximizar / restaurar;
- límites mínimos y máximos;
- tamaño por porcentaje de pantalla;
- adaptación multi-monitor;
- reserva de espacio para menús laterales mediante MenuType.
La implementación real utiliza un Form transparente, carga internamente jCustomWindow.fxml y agrega fluent-light.css.
Por qué es una pieza central de jdashboardUI
WindowsStyle no dibuja por sí solo un dashboard completo. Su trabajo es proporcionar el shell moderno de la aplicación.
Una forma sencilla de entenderlo es:
jdashboard_WindowsStyle
↓
ventana + barra superior + acciones + RootPane
↓
tu diseño
↓
Ribbon / menú lateral / tablas / gráficos / editores / formularios
Esto permite separar dos responsabilidades:
- WindowsStyle controla la ventana.
- El desarrollador controla el contenido y la identidad visual.
Por eso una misma clase puede servir para una aplicación oscura de licencias, un editor con degradados, una aplicación de seguridad o un dashboard claro.
Anatomía real de la ventana
La estructura interna principal es:
Form transparente
├── apWindowTop
│ ├── icono
│ ├── Title
│ ├── BarPanel
│ └── hbWindowTopButtons
├── apWindowLeft
├── apWindowRight
├── apWindowBottom
└── RootPane / pbase
└── contenido de tu aplicación
El RootPane público no es el RootPane nativo del Form. Devuelve pbase, que es el área preparada para colocar el contenido real.
Ejemplo:
ui.RootPane.LoadLayout("Main")
Cuando usas Ribbon, una tabla, un editor o un visor, normalmente debes cargarlo dentro de ui.RootPane.
Inicialización
Firma real:
Initialize( _
moduleParent As Object, _
parentForm As Form, _
eventName As String, _
color As Paint)
Ejemplo básico:
Sub Process_Globals
Private fx As JFX
Private xui As XUI
Private MainForm As Form
Private ui As jdashboard_WindowsStyle
End Sub
Sub AppStart(Form1 As Form, Args() As String)
MainForm = Form1
ui.Initialize( _
Me, _
MainForm, _
"ui", _
fx.Colors.RGB(30, 30, 46))
ui.Title.Text = "My Application"
ui.Title.TextColor = fx.Colors.White
ui.AddIconButton( _
"close", _
Chr(0xE14C), _
fx.Colors.White, _
fx.CreateMaterialIcons(22), _
ui.ACTION_EXIT, _
"Close")
ui.AddIconButton( _
"maximize", _
Chr(0xE3E0), _
fx.Colors.White, _
fx.CreateMaterialIcons(22), _
ui.ACTION_MAXIMIZE, _
"Maximize")
ui.AddIconButton( _
"minimize", _
Chr(0xE15B), _
fx.Colors.White, _
fx.CreateMaterialIcons(22), _
ui.ACTION_MINIMIZE, _
"Minimize")
ui.RootPane.LoadLayout("Main")
MainForm.Show
End Sub
Durante Initialize, la clase:
- pone el Form en estilo TRANSPARENT;
- hace transparente la escena JavaFX;
- elimina el borde nativo;
- aplica radio al RootPane exterior;
- carga jCustomWindow.fxml;
- prepara pbase;
- centra la ventana;
- configura el resize;
- inicia el Timer de animación;
- registra listeners X/Y del Stage para multi-monitor;
- crea BarPanel;
- aplica Always On Top con su valor actual;
- agrega fluent-light.css.
Ejemplo real de uso
Un patrón usado en aplicaciones construidas con jdashboardUI es:
ui.Initialize(Me, MainForm, "ui", fx.Colors.RGB(30, 30, 46))
ui.SetSizeByPercentage(75, 86)
ui.Title.Text = "Ribbon UI Studio Pro"
ui.Title.TextColor = fx.Colors.White
ui.Title.Font = xui.CreateDefaultBoldFont(12)
ui.SetIcon(fx.LoadImage(File.DirAssets, "app.png"))
ui.titlestyle(xui.Color_RGB(67, 67, 77))
ui.AnimationsActivated = False
ui.AlwaysOnTop = False
ui.AddIconButton("close", Chr(0xE14C), fx.Colors.White, _
fx.CreateMaterialIcons(22), ui.ACTION_EXIT, "Cerrar")
ui.AddIconButton("maximize", Chr(0xE3E0), fx.Colors.White, _
fx.CreateMaterialIcons(22), ui.ACTION_MAXIMIZE, "Maximizar")
ui.AddIconButton("minimize", Chr(0xE15B), fx.Colors.White, _
fx.CreateMaterialIcons(22), ui.ACTION_MINIMIZE, "Minimizar")
MainForm.Show
ui.RootPane.LoadLayout("Layout1")
La idea importante es que WindowsStyle prepara la ventana primero y el contenido se carga después dentro de RootPane.
Title
Title devuelve el Label real de la barra superior.
ui.Title.Text = "Licensr Pro"
ui.Title.TextColor = fx.Colors.White
ui.Title.Font = xui.CreateDefaultBoldFont(12)
Puedes modificarlo igual que cualquier Label B4J.
titlestyle
ui.titlestyle(xui.Color_RGB(67, 67, 77))
La implementación aplica al título:
- fondo degradado;
- esquinas suaves;
- sombra;
- texto en negrita.
Si se utiliza xui.Color_Transparent, el fondo del título queda transparente.
Icono de la aplicación
ui.SetIcon(fx.LoadImage(File.DirAssets, "app.png"))
SetIcon actualiza:
- el icono visible de la barra personalizada;
- Form.Icon.
La imagen se adapta al ImageView manteniendo proporción.
Botones de la barra superior
Los botones superiores se agregan dinámicamente a hbWindowTopButtons.
AddIconButton
ui.AddIconButton( _
"settings", _
Chr(0xE8B8), _
fx.Colors.White, _
fx.CreateMaterialIcons(22), _
ui.ACTION_NONE, _
"Settings")
Firma:
AddIconButton( _
EventName As String, _
IconChar As String, _
IconColor As Paint, _
IconFont As Font, _
Action As Int, _
ToolTipMsg As String) As Button
El icono se normaliza internamente a un tamaño cercano a 22.
AddImageButton
ui.AddImageButton( _
"profile", _
File.DirAssets, _
"user.png", _
ui.ACTION_NONE, _
"Profile")
La imagen se prepara aproximadamente a 22 px.
Acciones incorporadas
| Constante | Valor | Acción |
|---|---|---|
| ACTION_NONE | -1 | No ejecuta una acción de ventana |
| ACTION_EXIT | 2 | Finaliza la aplicación |
| ACTION_MAXIMIZE | 4 | Maximiza o restaura |
| ACTION_MINIMIZE | 8 | Minimiza |
| ACTION_FULLSCREEN | 16 | Entra en pantalla completa |
Ejemplo:
ui.AddIconButton( _
"fullscreen", _
Chr(0xE5D0), _
fx.Colors.White, _
fx.CreateMaterialIcons(22), _
ui.ACTION_FULLSCREEN, _
"Full screen")
ACTION_EXIT
ACTION_EXIT ejecuta el evento Exiting y después ExitApplication.
No equivale a cerrar únicamente un Form secundario.
Para una ventana secundaria usa ACTION_NONE y desde EventName_Click llama al cierre que necesites.
Eventos de ventana
Si el EventName es ui:
Private Sub ui_Maximizing
End Sub
Private Sub ui_Maximized
End Sub
Private Sub ui_Minimizing
End Sub
Private Sub ui_Minimized
End Sub
Private Sub ui_EnteringFullScreen
End Sub
Private Sub ui_FullScreen
End Sub
Private Sub ui_Exiting
End Sub
También existen los eventos generales de los botones:
Private Sub ui_MouseClicked(ButtonSender As Button, EventData As MouseEvent)
End Sub
Private Sub ui_MouseEntered(ButtonSender As Button, EventData As MouseEvent)
End Sub
Private Sub ui_MouseExited(ButtonSender As Button, EventData As MouseEvent)
End Sub
Y cada botón dinámico puede utilizar su propio:
EventName_Click
Ejemplo:
Private Sub settings_Click
Log("Settings")
End Sub
Orden visual de los botones
Los botones se insertan en la posición 0 del contenedor.
Si agregas:
close
maximize
minimize
el orden visual habitual termina como:
minimize | maximize | close
Esto permite construir fácilmente la disposición clásica de controles de ventana.
GetButton
Dim Btn As Button = ui.GetButton("settings")
If Btn.IsInitialized Then
Btn.Disable = True
End If
El Map interno utiliza el EventName entregado al crear el botón.
BarPanel
WindowsStyle crea un panel superior central que puede obtenerse así:
Dim TopArea As B4XView = ui.panelbar
Su altura base es 45 y su ancho se recalcula aproximadamente como un tercio del ancho de la ventana.
Este panel puede usarse para:
- switch claro / oscuro;
- selector de modo;
- estado;
- búsqueda;
- acciones rápidas;
- cualquier B4XView personalizado.
Ejemplo:
Dim TopArea As B4XView = ui.panelbar
TopArea.AddView(MySwitch, 0, 0, 100dip, 35dip)
PanelBarAllowDragging
ui.PanelBarAllowDragging = True
Cuando está activo, el BarPanel también funciona como zona de arrastre de la ventana.
Arrastrar la ventana
apWindowTop permite mover el Form utilizando coordenadas globales del mouse.
El arrastre se bloquea mientras:
- la ventana está maximizada;
- se ejecuta una animación.
Resizable
ui.Resizable = True
La implementación actual usa principalmente:
- borde derecho;
- borde inferior;
- esquina inferior derecha.
Mientras la ventana está maximizada, el resize manual queda desactivado.
Límites de tamaño
ui.SetWindowSizeLimits(700, 500, 1800, 1200)
La clase guarda:
- ancho mínimo;
- alto mínimo;
- ancho máximo;
- alto máximo.
También corrige inmediatamente el Form si ya está fuera del rango.
BorderWidth
Valor inicial interno: 7.
ui.BorderWidth = 8
Log(ui.BorderWidth)
Este valor participa en la geometría de los bordes y del área de contenido.
BorderRadius
Valor inicial interno: 10.
ui.BorderRadius(14)
Se aplica a border-radius y background-radius del RootPane exterior.
Dropshadow
ui.Dropshadow = fx.Colors.Black
Aplica una sombra gaussiana al marco exterior.
La implementación también reduce pbase con un margen interno para que la sombra y las esquinas sean visibles.
Por eso, después de aplicar Dropshadow, una aplicación con layouts muy ajustados debe comprobar el espacio disponible.
Inershadow
El nombre real de la propiedad pública es Inershadow.
ui.Inershadow = fx.Colors.Gray
Aplica un efecto CSS innershadow al RootPane exterior.
ColorUI
ui.ColorUI = fx.Colors.RGB(30, 30, 46)
Cambia el fondo exterior de WindowsStyle.
No debe confundirse con el color del layout que cargues dentro de ui.RootPane.
AlwaysOnTop
ui.AlwaysOnTop = False
En el código actual el valor interno inicial es True y Initialize lo aplica al Stage.
Por tanto, para una ventana de escritorio normal conviene establecer explícitamente:
ui.AlwaysOnTop = False
Animaciones
ui.AnimationsActivated = True
ui.AnimationSpeedMultiplier = 5
WindowsStyle usa un Timer para interpolar:
- X;
- Y;
- ancho;
- alto;
- geometría de borde.
La animación se usa principalmente al maximizar y restaurar.
RegisterOnMaximizeComplete
ui.RegisterOnMaximizeComplete(Me)
Public Sub OnMaximizeComplete
Log("Maximize terminado")
End Sub
Esta notificación ocurre al finalizar la transición hacia maximizado.
Es útil cuando un menú, tabla, editor o layout necesita recalcularse después de que termine físicamente la animación.
Full Screen
ui.AddIconButton( _
"fullscreen", _
Chr(0xE5D0), _
fx.Colors.White, _
fx.CreateMaterialIcons(22), _
ui.ACTION_FULLSCREEN, _
"Full screen")
Flujo:
ui_EnteringFullScreen
→ Stage.setFullScreen(True)
→ ui_FullScreen
MenuType
WindowsStyle puede reservar automáticamente espacio lateral para un menú.
| Constante | Valor | Reserva lateral |
|---|---|---|
| No_menu | 0 | 0 |
| Menu_type_1 | 1 | 261 |
| Menu_type_2 | 2 | 140 |
| Menu_type_3 | 3 | 261 |
Ejemplo:
ui.MenuType = ui.Menu_type_1
La llamada recalcula RootPane y BarPanel.
Esto permite integrar WindowsStyle con JWindowsMenuStyle sin tener que calcular manualmente el ancho del contenido.
Relación con JWindowsMenuStyle
JWindowsMenuStyle recibe una instancia de jdashboard_WindowsStyle y utiliza MenuType para reservar el espacio correcto.
En otras palabras:
jdashboard_WindowsStyle = ventana y shell
JWindowsMenuStyle = navegación lateral opcional
Son módulos complementarios, pero WindowsStyle puede usarse sin menú.
AdjustRootPanel
Firma:
AdjustRootPanel(Width As Double, Height As Double, MenuWidth As Int)
Considera:
- barra superior de 45;
- margen interno;
- BorderWidth;
- ancho reservado por menú.
Normalmente no necesitas llamarlo a mano porque MenuType, resize y SetSizeByPercentage ya actualizan la geometría.
AdjustBarPanel
ui.AdjustBarPanel(MainForm.Width)
Mantiene BarPanel centrado, con aproximadamente un tercio del ancho disponible y 45 de alto.
SetSizeByPercentage
ui.SetSizeByPercentage(75, 86)
Significa:
75 % del ancho de la pantalla
86 % del alto de la pantalla
La ventana se centra automáticamente en la pantalla detectada.
Multi-monitor
La clase registra listeners sobre X y Y del Stage.
Si la ventana fue configurada con SetSizeByPercentage y se mueve a otro monitor, WindowsStyle vuelve a calcular su tamaño usando el mismo porcentaje en la nueva pantalla.
Esto es especialmente útil con monitores de resoluciones distintas.
GetPercentX y GetPercentY
Se basan en TargetWidth y TargetHeight del Form completo.
Dim W As Double = ui.GetPercentX(50)
Dim H As Double = ui.GetPercentY(25)
GetRootPanelPercentX y GetRootPanelPercentY
Se basan en el área visible real de pbase.
Dim W As Double = ui.GetRootPanelPercentX(80)
Dim H As Double = ui.GetRootPanelPercentY(50)
Úsalos cuando haya:
- barra superior;
- BorderWidth;
- MenuType;
- márgenes internos.
Focused
If ui.Focused Then
Log("Hay una vista con foco")
End If
La implementación recorre de forma recursiva las vistas del RootPane y comprueba isFocused de JavaFX.
Dispose
ui.Dispose
Libera:
- Timer;
- listeners X/Y;
- Stylesheets;
- nodos del RootPane;
- Maps de botones;
- callbacks de maximize.
Dispose es idempotente.
Es especialmente importante para Forms secundarios que se crean y destruyen sin cerrar toda la aplicación.
TopBarStyle y BorderStyle
La API pública incluye:
Log(ui.TopBarStyle)
Log(ui.BorderStyle)
En la implementación actual las variables internas asociadas se declaran pero no reciben un valor posterior. Por tanto, actualmente estos getters pueden devolver una cadena vacía.
Se documentan porque forman parte de la API pública, pero no deben considerarse una fuente fiable del CSS aplicado.
Lo que WindowsStyle NO hace automáticamente
Para evitar confusiones:
- no crea un Ribbon;
- no crea un menú lateral;
- no crea un dashboard;
- no crea tablas ni gráficos;
- no incluye un conjunto cerrado de temas de aplicación;
- no decide el diseño interior.
Lo que sí hace es proporcionar la ventana moderna sobre la que todos esos componentes pueden montarse.
Los ejemplos visuales de Licensr Pro, LibX Template Studio, B4X Antivirus Pro y DataFlow muestran precisamente esa flexibilidad: misma base de ventana, diseños internos completamente distintos.
API pública completa
Métodos
| API | Función |
|---|---|
| Initialize | Inicializa WindowsStyle |
| Dispose | Libera recursos |
| BorderRadius | Cambia radio de esquinas |
| panelbar | Devuelve BarPanel |
| AddIconButton | Agrega botón superior con icono |
| AddImageButton | Agrega botón superior con imagen |
| GetButton | Recupera botón por EventName |
| Focused | Busca una vista con foco |
| SetIcon | Define icono de ventana |
| RegisterOnMaximizeComplete | Registra callback al terminar maximize |
| Title | Devuelve Label del título |
| titlestyle | Aplica estilo al título |
| SetWindowSizeLimits | Define límites min/max |
| AdjustBarPanel | Recalcula BarPanel |
| AdjustRootPanel | Recalcula área de contenido |
| SetSizeByPercentage | Tamaño relativo a la pantalla |
| GetRootPanelPercentX | Porcentaje de pbase |
| GetRootPanelPercentY | Porcentaje de pbase |
| GetPercentX | Porcentaje de TargetWidth |
| GetPercentY | Porcentaje de TargetHeight |
Propiedades
| Propiedad | Función |
|---|---|
| AlwaysOnTop | Mantiene el Stage sobre otras ventanas |
| ColorUI | Fondo exterior |
| PanelBarAllowDragging | Permite drag desde BarPanel |
| Dropshadow | Sombra exterior |
| Inershadow | Sombra interior |
| Resizable | Activa resize manual |
| TopBarStyle | Getter de estilo |
| BorderStyle | Getter de estilo |
| BorderWidth | Ancho del marco |
| AnimationSpeedMultiplier | Velocidad de animación |
| AnimationsActivated | Activa / desactiva animaciones |
| RootPane | Área de contenido pbase |
| MenuType | Reserva lateral de menú |
Campos públicos
ACTION_EXIT
ACTION_MAXIMIZE
ACTION_MINIMIZE
ACTION_FULLSCREEN
ACTION_NONE
Menu_type_1
Menu_type_2
Menu_type_3
No_menu
hbWindowTopButtons
TargetWidth
TargetHeight
Ejemplo completo recomendado
Sub Process_Globals
Private fx As JFX
Private xui As XUI
Private MainForm As Form
Private ui As jdashboard_WindowsStyle
End Sub
Sub AppStart(Form1 As Form, Args() As String)
MainForm = Form1
ui.Initialize(Me, MainForm, "ui", fx.Colors.RGB(30, 30, 46))
ui.SetSizeByPercentage(75, 86)
ui.SetWindowSizeLimits(700, 500, 1800, 1200)
ui.Title.Text = "My Application"
ui.Title.TextColor = fx.Colors.White
ui.Title.Font = xui.CreateDefaultBoldFont(12)
ui.SetIcon(fx.LoadImage(File.DirAssets, "app.png"))
ui.titlestyle(xui.Color_RGB(67, 67, 77))
ui.BorderRadius(10)
ui.BorderWidth = 7
ui.Resizable = True
ui.AnimationsActivated = True
ui.AnimationSpeedMultiplier = 5
ui.AlwaysOnTop = False
ui.MenuType = ui.No_menu
ui.AddIconButton("close", Chr(0xE14C), fx.Colors.White, _
fx.CreateMaterialIcons(22), ui.ACTION_EXIT, "Close")
ui.AddIconButton("maximize", Chr(0xE3E0), fx.Colors.White, _
fx.CreateMaterialIcons(22), ui.ACTION_MAXIMIZE, "Maximize")
ui.AddIconButton("minimize", Chr(0xE15B), fx.Colors.White, _
fx.CreateMaterialIcons(22), ui.ACTION_MINIMIZE, "Minimize")
ui.AddIconButton("settings", Chr(0xE8B8), fx.Colors.White, _
fx.CreateMaterialIcons(22), ui.ACTION_NONE, "Settings")
ui.RegisterOnMaximizeComplete(Me)
ui.RootPane.LoadLayout("Main")
MainForm.Show
End Sub
Private Sub settings_Click
Log("Settings")
End Sub
Private Sub ui_Maximizing
Log("Maximize / restore requested")
End Sub
Private Sub ui_Minimizing
Log("Minimize requested")
End Sub
Private Sub ui_Exiting
Log("Application closing")
End Sub
Public Sub OnMaximizeComplete
Log("Maximize animation finished")
End Sub
Recomendaciones
- Inicializa WindowsStyle antes de cargar el layout principal.
- Carga el contenido en ui.RootPane.
- Establece AlwaysOnTop = False para ventanas normales.
- Usa ACTION_* para controles del sistema.
- Usa ACTION_NONE para botones propios.
- Mantén EventName consistentes para GetButton.
- Usa SetSizeByPercentage en entornos multi-monitor.
- Usa GetRootPanelPercentX/Y cuando el layout deba basarse en el área visible real.
- Configura MenuType al usar navegación lateral.
- Llama Dispose cuando destruyas Forms secundarios.