Deprecated API
Contents
-
Deprecated InterfacesInterfaceDescriptionThis contract is inherently unfriendly to both composition and thread safety, which is why it is replaced by the tuple based binding:
- It forces an inheritance style contract onto your view models: every entry model must expose two mutable properties it usually does not care about, just to be displayable.
-
It is incompatible with the decoupled threading mode (see
EventProcessor.DECOUPLED), by design: the UI thread writes into your view model while building an entry view and the view supplier immediately reads that state back. Since your view model belongs to the application thread, this mid-construction write/read handshake cannot be handed over to the application event queue without breaking it. Change listeners onEntryViewModel.isSelected()andEntryViewModel.position()will consequently run on the UI thread.
The recommended alternative: tuple based binding
Model your entries as aVarproperty holding an immutableTupleof plain value objects which implementHasId(so that entry views can be recycled efficiently when the tuple changes). Any state an entry view needs, including its selection flag, is simply data in the value object:
This dissolves the threading problem instead of merely patching it: there is no UI owned selection state to synchronize at all. The selection is owned by the application thread like any other view model state, exclusivity ("selecting one deselects the others") is one atomic tuple update, multi-selection and "no selection" fall out naturally, and because the entries are identified throughpublic record Entry(String id, String text, boolean selected) implements HasId<String> { public Entry withSelected( boolean selected ) { return new Entry(id, text, selected); } } Var<Tuple<Entry>> entries = Var.of(Tuple.of( new Entry("a", "Alpha", false), new Entry("b", "Beta", true ) )); UI.scrollPanels() .addAll(entries, entry -> // <- every entry is exposed as a Var<Entry> lens UI.label(entry.viewAsString( e -> (e.selected() ? "> " : "") + e.text() )) .onMouseClick( it -> // Selecting one entry and deselecting all others is a single, // atomic tuple update, executed safely on the application thread: entries.update( tuple -> tuple.map( e -> e.withSelected(e.id().equals(entry.get().id())) ) ) ) )HasId.id(), flipping a flag on an entry recycles its existing sub-view and channels the new state into it through its item property.The position of an entry is intentionally absent from this pattern: you assemble the tuple, so you already know where each entry sits, and you may store an index in your value objects if a view needs to display it.
Note that this legacy interface remains functional in the coupled threading modes, but binding
EntryViewModels in a UI declaration which uses theEventProcessor.DECOUPLEDevent processor will log a loud warning, because thread safety cannot be guaranteed for it.
-
Deprecated Classes
-
Deprecated MethodsMethodDescriptionUse
AbstractDelegate.setMaxSize(Size)instead!UseAbstractDelegate.setMinSize(Size)instead!UseAbstractDelegate.setPrefSize(Size)instead of this method.UseAbstractDelegate.setSize(Size)instead of this method!This is part of theEntryViewModelbased selection machinery, which is deprecated in favour of modelling the selection as plain data in tuple bound entries. SeeEntryViewModelfor the migration pattern.This is part of theEntryViewModelbased selection machinery, which is deprecated in favour of modelling the selection as plain data in tuple bound entries. SeeEntryViewModelfor the migration pattern.This is part of theEntryViewModelbased selection machinery, which is deprecated in favour of modelling the selection as plain data in tuple bound entries. SeeEntryViewModelfor the migration pattern.This is part of theEntryViewModelbased selection machinery, which is deprecated in favour of modelling the selection as plain data in tuple bound entries. SeeEntryViewModelfor the migration pattern.because it introduces the following two issues:
-
SwingTree styles are expected to be side effect free functions.
The
JComponenthowever is mutable and very sensitive to repaints. Mutating a component in a styler can lead to things like endless repaints and other bugs which are extremely hard to track... -
A developer may want to access the dimensions of a component to perform
rendering in a custom
Painter. Unfortunately, the dimensions of a component are not in "developer pixels"! Instead, they are already scaled to the currentUI.scale(). To prevent scaling issues, useComponentStyleDelegate.componentWidth()andComponentStyleDelegate.componentHeight()for the current size, orComponentStyleDelegate.componentPrefWidth()andComponentStyleDelegate.componentPrefHeight()for the preferred size. These are all scaled down to "developer pixel". This matters in particular when the size you read here is fed back into the styling API (e.g.ComponentStyleDelegate.minHeight(double)orComponentStyleDelegate.maxHeight(double)), because those methods scale their inputs up again. Readingcomponent().getPreferredSize()directly and passing it back in would scale the value twice.
because it introduces the following two issues:
-
SwingTree styles are expected to be side effect free functions.
The parent of a
JComponenthowever is mutable and very sensitive to repaints. Mutating a component in a styler can lead to things like endless repaints and other bugs which are extremely hard to track... -
A developer may want to access the dimensions of a component to perform
rendering in a custom
Painter. Unfortunately, the dimensions of a parent component are not in "developer pixels"! Instead, they are already scaled to the currentUI.scale().
because it introduces the following two issues:
-
SwingTree styles are expected to be side effect free functions.
The parent of a
JComponenthowever is mutable and very sensitive to repaints. Mutating a component in a styler can lead to things like endless repaints and other bugs which are extremely hard to track... -
A developer may want to access the dimensions of a component to perform
rendering in a custom
Painter. Unfortunately, the dimensions of a parent component are not in "developer pixels"! Instead, they are already scaled to the currentUI.scale().
-
SwingTree styles are expected to be side effect free functions.
The