Class MainWindowRoute
- All Implemented Interfaces:
com.vaadin.flow.component.AttachNotifier, com.vaadin.flow.component.ClickNotifier<com.vaadin.flow.component.html.Div>, com.vaadin.flow.component.DetachNotifier, com.vaadin.flow.component.HasComponents, com.vaadin.flow.component.HasComponentsOfType<com.vaadin.flow.component.Component>, com.vaadin.flow.component.HasElement, com.vaadin.flow.component.HasEnabled, com.vaadin.flow.component.HasOrderedComponents, com.vaadin.flow.component.HasSize, com.vaadin.flow.component.HasStyle, com.vaadin.flow.component.HasText, Serializable
JFrame. Migrators paste a one-class scaffold
extending this base into their app, owning @Route /
@PreserveOnRefresh / the bootstrap call:
@Route("") @PreserveOnRefresh
public class AppRoute extends MainWindowRoute {
@Override protected void bootstrap() { MyApp.mainUI(); }
}
Attaching throws IllegalStateException when SwingBridgeEmulatorsBootstrap never ran for the
attaching UI — the app forgot the one SPI line, and the route is the earliest place that is
knowable (M1D_bootstrap_canonical).
bootstrap() runs at most once per instance.
On every attach (initial + @PreserveOnRefresh re-bind to a fresh
UI), the route registers itself as the current MainWindowRoute
on the attaching UI via ComponentUtil.setData(Component, SerializableTriConsumer, T, U), so the
@MainWindow-annotated JFrame constructed
inside (or transitively, via SwingUtilities.invokeLater +
EHelper.callSwing) captures the route as its inline-render
target. Subsequent onAttach calls on the same instance skip
bootstrap(); the user's preserved component subtree (including
the @MainWindow JFrame's peer) is reused.
UI-scoped data, not ThreadLocal
The route→UI binding lives on UI.getCurrent()
(ComponentUtil.setData(Component, SerializableTriConsumer, T, U)), not a ThreadLocal around
bootstrap(), because the canonical Swing entry wraps frame
construction in SwingUtilities.invokeLater(...): that runs through
EHelper.callSwing's virtual-thread executor, so the frame ctor fires
on a VT continuation after bootstrap() has returned (a
bootstrap-scoped ThreadLocal would already be cleared) and on a fresh
thread with its own thread-local table (so it'd read null anyway).
UI-scoped data survives both the synchronous and VT-deferred hop because
callSwing guarantees UI.getCurrent() is the calling thread's
UI (R_callswing_envelope / D_callswing_loom).
Why an instance flag and not AttachEvent#isInitialAttach
Flow's isInitialAttach() returns true on every
@PreserveOnRefresh re-bind (the detached node's id resets to
-1, so the rebind reads as initial), so gating bootstrap()
on it would construct a fresh @MainWindow frame on every browser
refresh and stack it under the preserved Div. The bootstrapped
instance flag is the reliable gate — @PreserveOnRefresh preserves the
instance, so an instance field is exactly once-per-instance.
App-tab identity & multi-tab (option 1)
onAttach maintains the session's AppTab — the one UI
(and browser tab) the app lives in — via AppTab.markAppUI(UI).
The same bootstrapped flag that gates bootstrap()
doubles as the F5-vs-new-tab discriminator: a preserved-instance
re-attach (F5) re-binds the fresh UI to the app tab; a fresh instance
while the app is already live in another UI is a second tab,
which renders onAppAlreadyActive() instead of running a second
copy (one app per session). EHelper.singleLiveUI(VaadinSession)
resolves the AppTab first. See
D_active_ui_pointer.
Per
D_mainwindow_route:
lifecycle plumbing (once-per-instance bootstrap gating, UI-scoped
route registration, eventual session-destroy → WINDOW_CLOSING
listener) lives here so we can evolve it without touching every
migrated app.
- See Also:
-
Nested Class Summary
Nested classes/interfaces inherited from interface com.vaadin.flow.component.HasText
com.vaadin.flow.component.HasText.WhiteSpace -
Constructor Summary
Constructors -
Method Summary
Modifier and TypeMethodDescriptionprotected abstract voidInvoked once per route instance, on first attach.static MainWindowRoutecurrent()Read byJFrame's ctor to bind a@MainWindowframe to the route registered on the current UI.protected voidRendered instead of the app when this UI is a second tab and the app is already active in another UI (multi-tab option 1: one app per session, non-active tabs don't run it).protected voidonAttach(com.vaadin.flow.component.AttachEvent attachEvent) protected voidonDetach(com.vaadin.flow.component.DetachEvent detachEvent) Methods inherited from class com.vaadin.flow.component.HtmlComponent
getTitle, setTitleMethods inherited from class com.vaadin.flow.component.Component
addListener, bindVisible, findAncestor, fireEvent, from, get, getChildren, getElement, getEventBus, getId, getListeners, getLocale, getParent, getTestId, getTranslation, getTranslation, getTranslation, getTranslation, getTranslation, getTranslation, getUI, hasListener, isAttached, isTemplateMapped, isVisible, onEnabledStateChanged, removeFromParent, scrollIntoView, scrollIntoView, set, setElement, setId, setTestId, setVisible, whenAttachedMethods inherited from class Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, waitMethods inherited from interface com.vaadin.flow.component.AttachNotifier
addAttachListenerMethods inherited from interface com.vaadin.flow.component.ClickNotifier
addClickListener, addClickShortcut, addDoubleClickListener, addSingleClickListenerMethods inherited from interface com.vaadin.flow.component.DetachNotifier
addDetachListenerMethods inherited from interface com.vaadin.flow.component.HasComponents
addMethods inherited from interface com.vaadin.flow.component.HasComponentsOfType
add, add, addComponentAsFirst, addComponentAtIndex, bindChildren, getChildren, getComponentAt, getComponentCount, indexOf, remove, remove, removeAll, replaceMethods inherited from interface com.vaadin.flow.component.HasElement
getElementMethods inherited from interface com.vaadin.flow.component.HasEnabled
bindEnabled, isEnabled, setEnabledMethods inherited from interface com.vaadin.flow.component.HasSize
bindHeight, bindWidth, getHeight, getHeightUnit, getMaxHeight, getMaxWidth, getMinHeight, getMinWidth, getWidth, getWidthUnit, setHeight, setHeight, setHeightFull, setMaxHeight, setMaxHeight, setMaxWidth, setMaxWidth, setMinHeight, setMinHeight, setMinWidth, setMinWidth, setSizeFull, setSizeUndefined, setWidth, setWidth, setWidthFullMethods inherited from interface com.vaadin.flow.component.HasStyle
addClassName, addClassNames, bindClassName, bindClassNames, getClassName, getClassNames, getStyle, hasClassName, removeClassName, removeClassNames, setClassName, setClassNameMethods inherited from interface com.vaadin.flow.component.HasText
bindText, getText, getWhiteSpace, setText, setWhiteSpace
-
Constructor Details
-
MainWindowRoute
public MainWindowRoute()Default sizing: fill the browser viewport. Per D_inline_route_sizing, a@MainWindowJFrame's route fills the viewport unless the user callspack()— main windows occupy as much space as possible, opposed to dialogs that wrap their children. The ctor setssetSizeFull()so the default-fill mode lights up before any JFrame ctor runs; height-stretchable children (Vaadin Grid inside SJScrollPane, future TabPane / SplitPane) get a real height to expand into.JFrame.pack()on InlineStrategy clears this — seeInlineStrategy.applyInlineSizingOnPack.
-
-
Method Details
-
current
Read byJFrame's ctor to bind a@MainWindowframe to the route registered on the current UI. Returnsnullif there is no current UI or noMainWindowRouteis mounted on it. -
onAttach
protected void onAttach(com.vaadin.flow.component.AttachEvent attachEvent) - Overrides:
onAttachin classcom.vaadin.flow.component.Component
-
onAppAlreadyActive
protected void onAppAlreadyActive()Rendered instead of the app when this UI is a second tab and the app is already active in another UI (multi-tab option 1: one app per session, non-active tabs don't run it). Default shows a plain message; override to customise (e.g. a "reload to take over here" action once the active tab is gone — a future option-2/3 upgrade). Runs under the session lock on the attaching UI. -
onDetach
protected void onDetach(com.vaadin.flow.component.DetachEvent detachEvent) - Overrides:
onDetachin classcom.vaadin.flow.component.Component
-
bootstrap
protected abstract void bootstrap()Invoked once per route instance, on first attach. Implementations typically call the migrated app'smainUI()method, which instantiates the@MainWindowJFrame and callssetVisible(true). Wrapping construction inSwingUtilities.invokeLater(...)is supported — the route's registration on the current UI survives the VT hop.
-