Skip to content

FAQ

General

What engines does Strata support?

The Swing (Java2D) adapter, in the Strata-Swing repository, runs on any desktop JVM. The Vulkan adapter, in Strata-Vulkan, draws into the Vulkan frames of any application on LWJGL. Platforms lists the adapters. Other engines need an adapter, which is a small amount of code; see Writing an adapter.

Is it ready for production?

Not yet. Strata is at 0.1.0, unreleased, and the API will change. See Status and limitations.

Is it a port of MalisisCore?

No. Strata takes ideas from MalisisCore (a retained component tree, anchors, cancelable events) and from Wintergreen (measure-and-arrange layout, click and drag handling, focus, typed events, the text box), but it is new code with no engine dependency.

What license?

The Apache License, Version 2.0. You can use Strata in any project, open or closed, and change it without publishing your changes. Strata's own files keep its license and notices, and changed files must say they were changed.

Writing screens

How do I open a screen?

Strata.screens().open(screen) opens it wherever the platform shows screens, on every engine. On Swing, first mark the panel that shows them with StrataPanel.setDefault(). From inside an open screen, handle.open(other) opens another screen above it. See Screens.

Why can't I write new Button()?

Components are interfaces with a hidden implementation. You get them from the ComponentFactory the host passes to your screen, so every component belongs to the host that shows it. See Core concepts.

Why is there no static way to get a factory?

Plugin systems often give each plugin its own class loader, and one application can show several hosts at once. Passing the factory keeps every tree tied to the host that shows it, and leaves no global state behind when a screen closes.

Can I implement Component or Button myself?

No. A class that implements a component interface directly is rejected with IllegalArgumentException. Extend CustomComponent, CustomComposite or CustomContainer. See Extending Strata.

Can I subclass the built-in controls?

No, their implementations are hidden. Change them through their events, compose them, or write your own component. See Extending Strata.

Do I need to call layout or repaint?

Not for anything Strata's own controls do. Setters that affect size schedule a layout, and the host draws the next frame. A component you write calls repaint() when a change only its paint reads, such as a gauge's needle, and repaintAfter(millis) for a change the clock brings. Forgetting them shows only on adapters that draw when asked, not on every frame. See Asking for frames.

Why does parent() return an Optional?

A component has no parent before it is added to one, and a screen's root and an overlay's content have none. Getters of values that can be absent return Optional: parent(), tooltip(), cursor(), the sprite of an image, the content of an expander. A setter with a single form takes null to clear. A setter with overloads never takes null and has a clearX() beside it, such as clearTooltip() and clearPadding(). See Javadoc.

Why is bounds() zero or out of date?

Layout runs before the next frame, not when you call a setter. Before the first layout, bounds are Rect.ZERO. Read bounds in an event handler or a later frame.

How do I make something fill the rest of a column?

Give the child a weight in its StackPanel and stretch it, or use a weighted row or column in a GridPanel. See Filling the remaining space.

How do I center a dialog?

Put it in a root AnchorPanel anchored with Anchor.FILL, and give the dialog Anchor.CENTER. A modal dialog opened with factory.overlays().dialog(window) is laid out in the whole host, so a centered window stays centered there too.

How do I show a popup, a dialog or a short notice?

Through factory.overlays(): popup(content, area) next to a component, dialog(content) for a modal dialog, and toast(text) for a notice that closes itself. See Overlays and tooltips.

How do I bring a panel to the front?

Call raise(child) on its container, or give it a higher z index with setZIndex. Neither moves it in the layout. See Drawing order.

Why doesn't my label wrap?

It has no width to wrap to. Give it a fixed or maximum width, or stretch it in a parent that has one. See Wrapping text.

How do I update the screen when my data changes?

For small changes, call setters: label.setText(...), button.setEnabled(...). For structural changes, call handle.invalidate() to rebuild the tree, or add and remove children directly. See Screens.

Is there a scroll panel, list or dropdown?

Yes. ScrollPanel scrolls anything larger than itself; ListView, TableView, TreeView and GridView show collections; ComboBox picks one item from a drop-down list; and DropDownButton opens a menu or a flyout. The controls guide covers every built-in control. To write your own, the extending guide builds a switch as a complete example.

Can I use Strata from Kotlin or another JVM language?

Nothing prevents it. The API is plain Java interfaces and records. The examples are all Java.

Can I change the screen from another thread?

Not through components: a component that a host shows belongs to the host's UI thread, and calling a setter from another thread throws IllegalStateException. Hand the work over with Strata.uiThread().execute(...), or set a State that the screen is bound to, which works from any thread. Opening a screen from another thread is also handed over for you. See The UI thread.

How do I animate something?

Animate a property with the factory's animator(), or turn on the theme's motion metrics for the built-in controls, such as toggle.animation. See Animation.

How do I test a screen?

Core's test kit opens a screen without a window, finds components, clicks and types, and advances the clock. See Testing your screens.

How do I support Arabic or Hebrew?

Set the translator's language. Screens mirror by themselves, text mixing both directions is ordered, and plurals and numbers follow the language. See Internationalization.

Can users drag things around?

Yes. A drag that carries data starts with startTransfer, targets accept it, and a list with a drag transfer lets its rows be reordered or dropped elsewhere. Files dragged from the desktop arrive as a drop where the adapter supports it. See Drag and drop.

Events

What is the difference between target() and current()?

target() is the component the event was fired at and never changes. current() is the component whose handlers are running, which moves up as the event bubbles. A handler on a container uses target() to see which child was involved. See Target and current.

Why doesn't a handler on my screen hear events from a dialog or menu?

An overlay's content is outside the screen's tree, so its events stop at the overlay's content. Register the handler on the dialog, the menu or the control inside it. See How overlays are layered.

Why doesn't my panel's click handler see clicks on its buttons?

Buttons consume the clicks that press them, and consuming stops bubbling. Handle Button.PRESSED on the panel instead, since control events bubble, or put the handler on the button. See the warning in Events.

What's the difference between cancel, stopPropagation and consume?

cancel skips default behavior, stopPropagation stops bubbling, and consume does both. See Canceling and stopping.

A handler ran even though I canceled the event. Is that a bug?

No. Canceling skips the default behavior, or for a control's request the change itself. The other handlers on the path still run, so a handler that should not act on a canceled event checks isCancelled().

How do I tell a double click from a single click?

Read clicks() on the CLICK event. Strata delivers every click immediately with its count, so a double click arrives as a click with count 1 followed by one with count 2. See Click counting.

How do I make a keyboard shortcut?

For an action that a button, a menu item or a toolbar also offers, make a Command with a shortcut and share it; the shortcut works everywhere the screen does, and the menu shows it. See Commands and shortcuts. For a one-off key, register a KEY handler on the screen's root and use event.is(key, modifiers, policy). See Shortcuts.

Why does event.snapshot() throw?

Only input events and a control's requests have snapshots, since they are the SnapshotEvents. A Post event such as TextInput.EDITED fires after its change and has no snapshot() method at all; read previous() instead. Paint and measure events have none either. See When there is no snapshot.

Does a snapshot include a panel's children?

No. Snapshots are shallow. A child has its own snapshot only if it was captured.

Can I fire my own events?

Yes. Declare event types with EventType.request, valueRequest, report and valueReport, and fire them from your CustomComponent with request and report. See Events for your own control.

Do I need to remove handlers when a screen closes?

No. A closed screen's tree is dropped, along with its handlers. Remove handlers only from components you keep and reuse.

Swing

What does the scale argument of StrataPanel mean?

Pixels per UI unit. At 2, a 100-unit button is 200 pixels wide. On a high density display Strata also knows the device's pixels, so charts can draw one-pixel lines and sprites with @2x files are chosen; see Swing.

Why does text look different from other adapters?

Swing draws with an AWT font, Dialog 9 by default, while other adapters use their engine's font. Widths differ too, so leave slack around text. See Platform differences.

My sprite draws as a magenta square.

The image was not found on the classpath at assets/<namespace>/sprites/<path>.png (or where your SpriteResolver points), or could not be read. See Sprites.

Can I render a screen without a window?

Yes, with SwingSnapshot.render, which works headless. See Rendering without a display.