io.github.dinamo541.corefx.navigation

Controller

Abstract classClase abstracta JavaFX optionalopcional since 1.3.0desde 1.3.0

An optional base class for your FXML controllers. Extend it and FlowController starts wiring your controller automatically: it injects the Stage the view is showing on, records the viewName it was loaded from, and — the important part — calls initialize() again every time a cached view is shown, so screens can refresh themselves without any manual plumbing. Una clase base opcional para tus controladores FXML. Extiéndela y FlowController empieza a conectar tu controlador automáticamente: inyecta el Stage en el que se muestra la vista, registra el viewName desde el que se cargó y — lo importante — llama a initialize() otra vez cada vez que se muestra una vista cacheada, para que las pantallas puedan refrescarse solas sin ningún cableado manual.

The problem it solvesEl problema que resuelve

FlowController caches one FXMLLoader per view, which is what makes navigation fast and keeps controllers reachable. But caching has a catch: JavaFX only calls a controller's initialize() once, when the FXML is first loaded. Navigate away and come back, and the screen still shows whatever it held before — stale totals, an old selection, a form that was never cleared. FlowController cachea un FXMLLoader por vista, que es lo que hace la navegación rápida y mantiene los controladores accesibles. Pero el caché tiene una trampa: JavaFX solo llama al initialize() de un controlador una vez, cuando el FXML se carga por primera vez. Navegas a otro lado y vuelves, y la pantalla sigue mostrando lo que tenía antes — totales obsoletos, una selección vieja, un formulario que nunca se limpió.

Extending Controller closes that gap. CoreFx detects the base class with a pattern match and re-invokes initialize() on every reuse, so "runs when the view is shown" becomes the contract — not "runs once, ever". Extender Controller cierra esa brecha. CoreFx detecta la clase base con un pattern match y vuelve a invocar initialize() en cada reutilización, así que "se ejecuta cuando la vista se muestra" pasa a ser el contrato — no "se ejecuta una sola vez, para siempre".

Quick startInicio rápido

public class DashboardController extends Controller {

    @FXML private Label totalLabel;
    @FXML private TableView<Order> table;

    // Called by JavaFX on first load, and by CoreFx on every
    // navigation back to this cached view.
    @Override
    public void initialize() {
        totalLabel.setText(orderService.currentTotal());
        TableUtils.setItems(table, orderService.findAll());
    }

    @FXML
    private void onClose() {
        getStage().close();          // injected by FlowController
    }
}
🔁
Who calls initialize(), and whenQuién llama a initialize(), y cuándo

On the first load JavaFX itself calls the no-arg initialize(), as it does for any FXML controller. On every later navigation to that view, FlowController.getLoader(...) finds the cached loader and calls initialize() again. Same method, two callers — so write it to be safely re-runnable.En la primera carga es el propio JavaFX quien llama al initialize() sin argumentos, como hace con cualquier controlador FXML. En cada navegación posterior a esa vista, FlowController.getLoader(...) encuentra el loader cacheado y vuelve a llamar a initialize(). El mismo método, dos llamantes — así que escríbelo para que se pueda re-ejecutar sin problemas.

API referenceReferencia de API

abstract void initialize()

The one method you must implement. Put here whatever the screen needs each time it becomes visible: reload data, reset filters, clear a form. Called once by JavaFX at load time and again by CoreFx on every reuse of the cached loader.El único método que debes implementar. Pon aquí lo que la pantalla necesite cada vez que se hace visible: recargar datos, resetear filtros, limpiar un formulario. Lo llama una vez JavaFX al cargar y otra vez CoreFx en cada reutilización del loader cacheado.

Stage getStage()  ·  void setStage(Stage stage)

The window this view is currently showing on. Injected (and re-injected) by FlowController on every navigation call, so it always points at the right stage — the main stage, a secondary window, or a modal. Use it to close, resize or title the window from inside the controller.La ventana en la que se muestra esta vista actualmente. FlowController lo inyecta (y reinyecta) en cada llamada de navegación, así que siempre apunta al stage correcto — el principal, una ventana secundaria o un modal. Úsalo para cerrar, redimensionar o titular la ventana desde el propio controlador.

String getViewName()  ·  void setViewName(String viewName)

The name the view was loaded under (the FXML file name, without extension). Set by CoreFx the moment the loader is created, so a controller always knows its own identity — handy for logging or for asking FlowController about itself.El nombre con el que se cargó la vista (el nombre del archivo FXML, sin extensión). CoreFx lo asigna en el momento en que se crea el loader, así un controlador siempre conoce su propia identidad — útil para logs o para preguntarle a FlowController por sí mismo.

String getAction()  ·  void setAction(String action)

A free-form slot for the intent behind the navigation — "create" vs "edit", for instance — so one view can serve several modes. CoreFx never writes to it; it is yours to set before navigating and read inside initialize().Un espacio libre para la intención detrás de la navegación — "create" frente a "edit", por ejemplo — para que una misma vista sirva varios modos. CoreFx nunca lo escribe; es tuyo para asignarlo antes de navegar y leerlo dentro de initialize().

void sendTabEvent(KeyEvent event)

Consumes the given key event and fires a synthetic TAB at its source — the usual trick for making Enter advance focus like a data-entry form. The source must be a Control.Consume el evento de teclado dado y dispara un TAB sintético sobre su origen — el truco habitual para que Enter avance el foco como en un formulario de captura. El origen debe ser un Control.

toString(), equals and hashCode are overridden over the three fields (stage, action, viewName).toString(), equals y hashCode están sobrescritos sobre los tres campos (stage, action, viewName).

What FlowController injects, and whereQué inyecta FlowController, y dónde

Every one of these methods checks whether the loaded controller extends Controller and, if so, injects the stage it is navigating to. Controllers that don't extend it are simply left alone — the base class is entirely opt-in.Cada uno de estos métodos comprueba si el controlador cargado extiende Controller y, en tal caso, le inyecta el stage al que está navegando. Los controladores que no la extienden simplemente se dejan intactos — la clase base es totalmente opcional.

HookPunto de engancheWhat CoreFx setsQué asigna CoreFx
createLoaderInstance(name)viewName, once, as the loader is built.viewName, una vez, al construir el loader.
getLoader(viewName)Calls initialize() when a cached loader is reused.Llama a initialize() cuando se reutiliza un loader cacheado.
goViewMain · changeViewInMainstage ← the main stage.stage ← el stage principal.
goViewInWindowstage ← the new window.stage ← la ventana nueva.
goViewInModal · goViewInModalAndWaitstage ← the modal stage.stage ← el stage del modal.
changeViewInStage · changeViewInScenestage ← the target stage.stage ← el stage de destino.
changeViewInBorderPanestage ← the stage owning the pane.stage ← el stage dueño del panel.
⚠️
initialize() must be re-runnableinitialize() debe poder re-ejecutarse

Because it fires on every visit, treat it as "refresh this screen", not "build this screen once". Adding a listener or a menu item there will add it again on the next visit — do that kind of one-time setup in the controller's constructor, or guard it with a flag. Reloading data, resetting fields and re-binding text is exactly what belongs here.Como se dispara en cada visita, trátalo como "refresca esta pantalla", no como "construye esta pantalla una vez". Añadir ahí un listener o un ítem de menú lo añadirá otra vez en la siguiente visita — haz ese tipo de configuración única en el constructor del controlador, o protégela con un flag. Recargar datos, resetear campos y re-enlazar textos es exactamente lo que corresponde aquí.

RecommendationsRecomendaciones

Do extend Controller for any screen that shows data which can change while the user is elsewhere — lists, dashboards, anything with a total.Extiende Controller en cualquier pantalla que muestre datos que puedan cambiar mientras el usuario está en otro lado — listas, dashboards, cualquier cosa con un total.

Do use getStage() instead of digging a window out of a node (node.getScene().getWindow()) — it is already the right stage, and it stays right across modals.Usa getStage() en vez de sacar la ventana desde un nodo (node.getScene().getWindow()) — ya es el stage correcto, y sigue siéndolo a través de los modales.

Do pair setAction("edit") with FlowController's typed transfer value when one view serves both create and edit modes.Combina setAction("edit") con el valor de transferencia tipado de FlowController cuando una misma vista sirve para crear y editar.