Class ComponentExtension<C extends JComponent>
- Type Parameters:
C- The type of the component to which this extension is attached as a client property (seeJComponent.putClientProperty(Object, Object)).
-
Method Summary
Modifier and TypeMethodDescriptionvoidaddAnimatedPainter(AnimationStatus status, UI.Layer layer, UI.ComponentArea clipArea, Painter painter) Use this to add aPainterbased animation to the component.voidaddAnimatedStyler(AnimationStatus state, Styler<C> styler) Use this to add aStylerbased animation to the component.voidaddDragAwayConf(Function<Position, DragAwayComponentConf<C>> supplier) Adds a drag away configurator to this component extension.voidAdds aStylerto the component.voidapplyAndInstallStyle(StyleConf styleConf, boolean force) Applies the givenStyleConfto the component after which a newStyleEngineis installed for the component.booleanbelongsToGroup(Enum<?> group) A style group is a tag which is used by the SwingTree style engine to apply styles to things with the same tags making it conceptually similar to CSS classes.booleanbelongsToGroup(String group) A style group is a tag which is used by the SwingTree style engine to apply styles to things with the same tags making it conceptually similar to CSS classes.sprouts.Tuple<BufferedImage> cachedRendering(UI.Layer layer) The fully rendered cache images standing by for the given styleUI.Layerof this component, in the order they are painted.intcacheHitCount(UI.Layer layer) Returns the number of times this component's given styleUI.Layerwas painted entirely from a cached image, i.e.intcacheMissCount(UI.Layer layer) Returns the number of times this component's given styleUI.Layerwas painted without a cache image serving it – either because the style renderer had to be invoked (caching is disabled for that layer, or the cache was not yet populated), or because there was nothing for a cache to hold in the first place, which happens to a layer whose entire style is a noise while it is being resized: the noise is then lifted out and replayed, and nothing is left on either side of it to cache.voidRemoves all animations from the component.voidFrees all bound observables from the extension.static <C extends JComponent>
ComponentExtension<C> from(C comp) Returns theComponentExtensionassociated with the given component.voidgatherApplyAndInstallStyle(boolean force) <P> Optional<P> Looks up an extra-state object of the given type previously attached to this component extension (seegetOrSet(Class, Supplier)), without creating or attaching anything.Allows for the retrieval of a specificShapewhich represents a specific area of the component identified by the givenUI.ComponentArea.getDragAwayConf(Position mousePosition) If it exists, this method invokes the user internal configurator function previously set by theaddDragAwayConf(Function)method and returns an optional of the resultingDragAwayComponentConfobject, which holds the configuration for starting a drag away operation using the AWT nativeDragSource.<P> PAllows for extra state to be attached to the component extension.getStyle()Exposes the currentStyleConfconfiguration of the component, which holds all the SwingTree style information needed to render the component.sprouts.Tuple<String> A component can have multiple group tags, which are used by the SwingTree style engine to apply styles with the same tags, which is conceptually similar to CSS classes.A live snapshot of SwingTree's global rendering caches: one entry per cache with its current number of cached items, in a stable, display-friendly order.static longThe ceilingglobalStyleLayerCacheBytesReserved()is held under: the share of the currentSwingTreeInitConfig.CacheModebudget that style layer renderings may spend.static longHow much memory the cached style layer renderings have reserved, in bytes.booleanChecks if the component has the given id.booleanChecks if the component has the given id.static voidinitializeFor(JComponent comp) Initializes the given component with a newComponentExtension.voidSwingTree overrides the default Swing look and feel to enable custom styling and animation capabilities.sprouts.Viewable<Float> Returns a reactive view of the current UI scale factor as applied to this component.voidpaintBackground(Graphics graphics, Painter lookAndFeelPainting) Primary painting entry point for SwingTree-compatibleComponentUIimplementations to ensure correct SwingTree style installation andUI.Layer.BACKGROUNDrendering.<E extends Enum<E>>
voidsetId(E id) Sets the id of the component based on an enum.voidSets the id of the component.final <E extends Enum<E>>
voidsetStyleGroups(E... groupTags) This method is used byUIForAnySwing.group(String...)to attach so-called group tags to a component.voidsetStyleGroups(String... groupTags) This method is used byUIForAnySwing.group(String...)to attach so called group tags to a component.voidstoreBoundObservable(sprouts.Observable observable) Stores the given observable in the extension in order to ensure that it is not garbage collected before the component is garbage collected.static voidThe single bridge through which theswingtreepackage tells the rendering caches in theswingtree.stylepackage that the library configuration may have changed (seeSwingTree.setCacheMode(swingtree.SwingTreeInitConfig.CacheMode)).intThis method tries to hash everything relevant in the visual appearance of the component and it subcomponents into a single integer value.
-
Method Details
-
from
Returns theComponentExtensionassociated with the given component. If the component does not have an extension, a new one is created and associated with the component.- Type Parameters:
C- The type of the component.- Parameters:
comp- The component for which to get the extension.- Returns:
- The extension associated with the component.
-
initializeFor
Initializes the given component with a newComponentExtension. This method is called by a SwingTree builder node when it receives and builds a new component. The former extension of the component is replaced by a new one.- Parameters:
comp- The component to initialize.
-
localUiScaleFactor
Returns a reactive view of the current UI scale factor as applied to this component. You can use it to register change listeners onto it and react to changes to the factor. The value in the property always reflectsSwingTree.getUiScaleFactor()and it is automatically updated when it changes...- Returns:
- A reactive/read-only
floatbased property which will always reflect the state of the library globalSwingTree.getUiScaleFactor()value.
-
paintBackground
Primary painting entry point for SwingTree-compatible
ComponentUIimplementations to ensure correct SwingTree style installation andUI.Layer.BACKGROUNDrendering.This method is specifically designed to be called from within the
Typical Usage:ComponentUI.paint(Graphics, JComponent)method of anyComponentUIthat implements theSwingTreeStyledComponentUIinterface and returnstruefromSwingTreeStyledComponentUI.canForwardPaintingToSwingTree().
What This Does Generally://Override public void paint(Graphics g, JComponent comp) { ComponentExtension.from(comp).paintBackground(g, g2d -> { super.paint(g2d, comp); // Native look and feel painting }); }- Ensures that the component's
StyleConfis gathered and installed correctly - Renders the
UI.Layer.BACKGROUNDof aStyleConf - Clips the graphics context to the
UI.ComponentArea.BODY - Invokes the supplied look and feel
Painterfor additional native component rendering - Handles buffering for components with parent filters
- Parameters:
graphics- The graphics context to paint intolookAndFeelPainting- Callback that performs native Swing painting (will be clipped to theUI.ComponentArea.BODY, which is based on the current style)- Throws:
ClassCastException- if the providedgraphicsis not aGraphics2Dinstance (should never happen in standard Swing usage)- See Also:
- Ensures that the component's
-
storeBoundObservable
public void storeBoundObservable(sprouts.Observable observable) Stores the given observable in the extension in order to ensure that it is not garbage collected before the component is garbage collected. The Sprouts library is based on the idea of event systems being weakly referenced by theirs event sources, which means that if the observable is not stored in the extension, the binding will be lost when the observable is garbage collected.- Parameters:
observable- The observable to store using a strong reference to ensure it is not garbage collected.
-
freeBoundObservables
public void freeBoundObservables()Frees all bound observables from the extension. This is useful when the component is no longer needed and is about to be garbage collected. -
addDragAwayConf
Adds a drag away configurator to this component extension. The configurator will be invoked to provide drag away configuration based on the mouse position.- Parameters:
supplier- A function that provides a drag away configuration given a mouse position.- Throws:
IllegalStateException- If a drag away configurator has already been set.
-
getDragAwayConf
If it exists, this method invokes the user internal configurator function previously set by theaddDragAwayConf(Function)method and returns an optional of the resultingDragAwayComponentConfobject, which holds the configuration for starting a drag away operation using the AWT nativeDragSource.- Parameters:
mousePosition- The current mouse position.- Returns:
- An optional of the resulting
DragAwayComponentConfobject.
-
getOrSet
Allows for extra state to be attached to the component extension. (Conceptually similar to how Swing components can have client properties.)
If the component already has an object of the given type attached, that object is returned. Otherwise, the given fetcher is used to create a new object of the given type, which is then attached to the component and returned.- Type Parameters:
P- The type of the extra state.- Parameters:
type- The type of the extra state to attach.fetcher- A supplier which is used to create a new object of the given type.- Returns:
- The extra state object of the given type which is attached to the component.
-
get
Looks up an extra-state object of the given type previously attached to this component extension (seegetOrSet(Class, Supplier)), without creating or attaching anything. This is the pure-read companion togetOrSet(Class, Supplier): it never has side effects and simply tells you whether a plugin of the given type is currently present, and what it is. -
setStyleGroups
This method is used byUIForAnySwing.group(String...)to attach so called group tags to a component.
They are used by the SwingTree style engine to apply styles with the same tags, which is conceptually similar to CSS classes.
It is advised to use thesetStyleGroups(Enum[])method instead of this method, as the usage of enums for modelling group tags offers much better compile time type safety!- Parameters:
groupTags- An array of group tags.
-
setStyleGroups
This method is used byUIForAnySwing.group(String...)to attach so-called group tags to a component.
They are used by the SwingTree style engine to apply styles with the same tags, which is conceptually similar to CSS classes.
It is advised to use this method over thesetStyleGroups(String[])method, as the usage of enums for modelling group tags offers much better compile time type safety!- Type Parameters:
E- The type of the enum.- Parameters:
groupTags- An array of group tags.
-
setId
Sets the id of the component. The id is used by the SwingTree style engine to apply styles to components with the same id, which is conceptually similar to CSS ids.
The preferred way to set the id is by using an enum to avoid typos and to get better compile time type safety.- Parameters:
id- The id to set.
-
setId
Sets the id of the component based on an enum. The id is used by the SwingTree style engine to apply styles to components with the same id, which is conceptually similar to CSS ids.
This is the preferred way to set the id, as it offers better compile time type safety. Also check out theUIForAnySwing.id(Enum)to set the id as part of a UI declaration.- Type Parameters:
E- The type of the enum.- Parameters:
id- The id to set.
-
hasId
Checks if the component has the given id.- Parameters:
id- The id to check.- Returns:
trueif the component has the given id.
-
hasId
Checks if the component has the given id.- Parameters:
id- The id to check.- Returns:
trueif the component has the given id.
-
getStyleGroups
A component can have multiple group tags, which are used by the SwingTree style engine to apply styles with the same tags, which is conceptually similar to CSS classes. This method returns the group tags associated with the component.- Returns:
- The group tags associated with the component
in the form of an unmodifiable tuple of
Strings.
-
belongsToGroup
A style group is a tag which is used by the SwingTree style engine to apply styles to things with the same tags making it conceptually similar to CSS classes. This method lets you check if the component belongs to a given String based group.- Parameters:
group- The group to check.- Returns:
trueif the component belongs to the given group.
-
belongsToGroup
A style group is a tag which is used by the SwingTree style engine to apply styles to things with the same tags making it conceptually similar to CSS classes. This method lets you check if the component belongs to a given enum based group.- Parameters:
group- The group to check.- Returns:
trueif the component belongs to the given group.
-
getStyle
Exposes the currentStyleConfconfiguration of the component, which holds all the SwingTree style information needed to render the component. -
cachedRendering
The fully rendered cache images standing by for the given styleUI.Layerof this component, in the order they are painted. When there are any, the next repaint of that layer will be served from them rather than by re-running the style renderer. This is a per-component window into the internalLayerPartitionCachepipeline for tests and tooling, not a hard guarantee about the next paint - cache entries are weakly referenced and may be reclaimed under memory pressure. Caching only kicks in for layers with at least one heavy style ingredient (rounded backgrounds with a base/foundation colour, borders with width and colour, gradients, shadows, noise, painted text, sized icons); other layers permanently report an empty tuple because caching them would not pay for itself.How many images to expect. There is no limit on how much style a single layer may carry, and not all of it caches the same way,
- none - nothing about this layer is currently cached.
- one - the whole layer rasterizes into a single image, which is the ordinary case.
- several - the cache split the layer, because one part of it can be cached in a way another part cannot. Painting the layer then means painting these in order, with the uncached parts rendered in between.
SwingTree.setCacheTilingEnabled(boolean)), while everything else is cached at exactly the component size.The returned images are defensive copies: a cached rendering is shared by all components with an equal style, so callers may examine (or even modify) the copies freely without corrupting anyone's painting.
- Parameters:
layer- The style layer to query (typicallyUI.Layer.BACKGROUNDfor the cases people care about most).- Returns:
- Copies of the rendered cache images currently associated with the given layer of this component, in paint order, or an empty tuple if there are none.
-
cacheHitCount
Returns the number of times this component's given styleUI.Layerwas painted entirely from a cached image, i.e. the style renderer was not invoked. The counter is local to this component instance and increases on every paint that is served from the cache.This counter is cumulative for the lifetime of this component instance. It does not automatically reset when the underlying cache entry is freed, invalidated, or rebuilt; such events only affect whether future paints contribute to this counter or to
cacheMissCount(UI.Layer). Together the two therefore say how often this component painted the layer at all — a paint which put no pixels anywhere, because the layer holds no style worth drawing, is counted by neither, since nothing was painted for a cache to have served.One nuance for layers carrying a noise: while such a component is being resized the noise is lifted out of the cached image and drawn again on every paint (see
cachedRendering(UI.Layer)). Those paints still count as hits, because redrawing a noise is cheap by construction — it is blitted from pre-rendered tiles, or is a single fill — and counting them as renders would hide the saving the split exists to make. A paint which did draw something, but which no cache took part in, is always a miss.- Parameters:
layer- The style layer to query.- Returns:
- Number of paint calls served from the cache, since this component was constructed.
-
cacheMissCount
Returns the number of times this component's given styleUI.Layerwas painted without a cache image serving it – either because the style renderer had to be invoked (caching is disabled for that layer, or the cache was not yet populated), or because there was nothing for a cache to hold in the first place, which happens to a layer whose entire style is a noise while it is being resized: the noise is then lifted out and replayed, and nothing is left on either side of it to cache. The counter is local to this component instance.- Parameters:
layer- The style layer to query.- Returns:
- Number of paint calls that had to render fresh, since this component was constructed.
-
globalRenderCacheEntryCounts
A live snapshot of SwingTree's global rendering caches: one entry per cache with its current number of cached items, in a stable, display-friendly order. The counts react to painting, to garbage collection (the caches are weakly keyed), and to configuration changes likeSwingTree.setCacheMode(swingtree.SwingTreeInitConfig.CacheMode)— which makes this the observation point for monitoring (the dev tool displays it live) and for tests pinning the cache-budget contract.- Returns:
- An ordered association (immutable map) from cache display name to its live entry count.
-
globalStyleLayerCacheBytesReserved
public static long globalStyleLayerCacheBytesReserved()How much memory the cached style layer renderings have reserved, in bytes.
Reserved, not allocated: an entry claims its bytes the moment it exists, whereas a large rendering only allocates its buffer after a warm-up of cache hits has shown it is worth it. The two figures differ for as long as that warm-up lasts, and this is the higher of them - which is the honest one to report, because it is what the budget is enforced against, and because the difference is memory already promised away. What it counts is the pixel memory reserved by each entry's backing images (including any stretch tiles), counted from the moment the entry exists rather than only after the backing buffers are allocated.
This is the observation point for the memory promise aSwingTreeInitConfig.CacheModemakes: style layer images are the only rendering cache big enough for that promise to be about, and it is the one bounded by measuring itself rather than by counting entries, because its entries range from a few kilobytes to tens of megabytes. Counting them (which is whatglobalRenderCacheEntryCounts()reports) therefore says nothing about memory, which is why this exists alongside it.
Call this on the UI thread. Unlike the entry counts, arriving at this figure means walking the cache, and painting writes to it - so a call from another thread races the next repaint.- Returns:
- Bytes currently reserved by the global style layer render cache.
-
globalStyleLayerCacheByteBudget
public static long globalStyleLayerCacheByteBudget()The ceilingglobalStyleLayerCacheBytesReserved()is held under: the share of the currentSwingTreeInitConfig.CacheModebudget that style layer renderings may spend.
Reported next to the figure it bounds because neither number means much alone - the budget scales with the machine's RAM and with the configured mode, so "eleven megabytes cached" is only interpretable against the ceiling in force at the time.- Returns:
- Bytes the global style layer render cache may retain at most, right now.
-
updateAllCachesFromLibraryConfig
public static void updateAllCachesFromLibraryConfig()The single bridge through which theswingtreepackage tells the rendering caches in theswingtree.stylepackage that the library configuration may have changed (seeSwingTree.setCacheMode(swingtree.SwingTreeInitConfig.CacheMode)). It does two things, in this order:- marks the shared
CacheBudgetas needing to re-resolve the currentSwingTreeInitConfig.CacheMode(on the next paint), and - empties every global rendering cache — style layers, rasterised text, noise tiles, shadow gradients and text layouts — so that memory is released immediately rather than only as old entries are evicted.
SwingTree.get()itself (so it is safe to call while theSwingTreesingleton is still being constructed); the budget is only resolved later, lazily, from the painting thread.Call this on the UI thread. It writes the very maps painting reads, and the two library setters which reach it (
SwingTree.setCacheMode(swingtree.SwingTreeInitConfig.CacheMode)andSwingTree.setCacheTilingEnabled(boolean)) marshal onto that thread before they do. Calling it from anywhere else races the next repaint. - marks the shared
-
getComponentArea
Allows for the retrieval of a specificShapewhich represents a specific area of the component identified by the givenUI.ComponentArea. The following areas are available:UI.ComponentArea.ALL- The entire component, which is the union of all other clip areas (INTERIOR + EXTERIOR + BORDER + CONTENT).UI.ComponentArea.INTERIOR- The inner component area, which is defined asALL - EXTERIOR - BORDER.UI.ComponentArea.EXTERIOR- The outer component area, which can be expressed asALL - INTERIOR - BORDER, orALL - CONTENT.UI.ComponentArea.BORDER- The border of the component, which is the area between the inner and outer component area and which can be expressed asALL - INTERIOR - EXTERIOR.UI.ComponentArea.BODY- The body of the component is the inner component area including the border area. It can be expressed asALL - EXTERIOR, orINTERIOR + BORDER.
- Parameters:
area- The area of the component to retrieve.- Returns:
- An optional
Shapewhich represents the given area of the component or an empty optional. If the area is not available, then this means that the style of the component did not lead to the calculation of the given area. This may happen for theEXTERIORin case of there being no margin or corner radius, and theBORDERin case of there being no border width.
-
clearAnimations
public void clearAnimations() -
addAnimatedPainter
public void addAnimatedPainter(AnimationStatus status, UI.Layer layer, UI.ComponentArea clipArea, Painter painter) Use this to add aPainterbased animation to the component.- Parameters:
status- TheAnimationStatuswhich defines when the animation is active.layer- TheUI.Layerwhich defines the layer on which the animation is rendered.clipArea- TheUI.ComponentAreawhich defines the area of the component which is animated.painter- ThePainterwhich defines how the animation is rendered.
-
addAnimatedStyler
Use this to add aStylerbased animation to the component.- Parameters:
state- TheAnimationStatuswhich defines when the animation is active.styler- TheStylerwhich defines how the style of the component is changed during the animation.
-
installCustomUIIfPossible
public void installCustomUIIfPossible()SwingTree overrides the default Swing look and feel to enable custom styling and animation capabilities. This method is used to install the custom look and feel for the component, if possible. -
addStyler
Adds aStylerto the component. The styler will be used to calculate the style of the component.- Parameters:
styler- The styler to add.
-
gatherStyle
- Returns:
- A new immutable
StyleConfconfiguration.
-
gatherApplyAndInstallStyle
public void gatherApplyAndInstallStyle(boolean force) Calculates a newStyleConfobject based on theStylerlambdas associated with the component and then applies it to the component after which a newStyleEngineis installed for the component. If the calculated style is the same as the current style, nothing happens except in case theforceparameter is set totrue.- Parameters:
force- If set totrue, the style will be applied even if it is the same as the current style.
-
applyAndInstallStyle
Applies the givenStyleConfto the component after which a newStyleEngineis installed for the component. If the given style is the same as the current style, nothing happens except in case theforceparameter is set totrue.- Parameters:
styleConf- The style to apply.force- If set totrue, the style will be applied even if it is the same as the current style.
-
viewStateHashCode
public int viewStateHashCode()This method tries to hash everything relevant in the visual appearance of the component and it subcomponents into a single integer value. It is based on the current SwingTree style information as well as more general component information like the current value of a slider, text of a text component, etc.
You may use this for rough cache invalidation purposes. So when you want to render the component into a
BufferedImageand then only rerender it if the state hash changes, you can use this method.
But keep in mind however, it cannot capture look and feel related changes which are not controlled by SwingTree.
So this hash code is not a perfect solution, but it can be useful in some cases. Like visualizing a drag and drop of a component...- Returns:
- The current state hash of the component and all of it subcomponents, which includes SwingTree style information, as well as component specific information.
-