Here, you'll learn about using Swing components in the Compose Multiplatform application and vice versa, the limitations and advantages of this interoperability, and when you should or shouldn't use this approach.
The interoperability between Compose Multiplatform and Swing aims to help you:
Simplify and smooth the migration process of Swing applications to Compose Multiplatform.
Enhance Compose Multiplatform applications using Swing components when no Compose analogues are available.
In many cases, it's more effective to implement a missing component directly in Compose Multiplatform (and contribute it to the community) rather than using a Swing component within a Compose Multiplatform application.
Swing interop use cases and limitations
Compose Multiplatform component in a Swing app
The first use case involves adding a Compose Multiplatform component to a Swing application. You can achieve it using the ComposePanel Swing component to render the Compose Multiplatform part of the application. From Swing's perspective, ComposePanel is another Swing component, and handles it accordingly.
Note that all Compose Multiplatform components, including popups, tooltips, and context menus, are rendered within Swing's ComposePanel and positioned and resized inside it. Therefore, consider replacing these components with Swing-based implementations, or try two new experimental features:
Popups are no longer limited by the initial composable canvas or the app window.
Here are several scenarios for using ComposePanel:
Embed animated objects or a whole panel of animated objects into your application (for example, selection of emoticons or a toolbar with animated reactions to events).
Implement an interactive rendering area such as graphics or infographics in your application, which is easier and more convenient to accomplish using Compose Multiplatform.
Integrate a complex rendering area (potentially even animated) into your application, which is simpler with Compose Multiplatform.
Replace complex parts of the user interface in your Swing-based application, as Compose Multiplatform provides a convenient component layout system and a wide range of built-in components and options for quickly creating custom components.
Swing component in a Compose Multiplatform app
Another use case is when you need to use a component that exists in Swing but has no analog in Compose Multiplatform. If creating its new implementation from scratch is too time-consuming, try SwingPanel. The SwingPanel function serves as a wrapper that manages the size, position, and rendering of a Swing component placed on top of a Compose Multiplatform component.
Note that the Swing component within SwingPanel will always be layered above the Compose Multiplatform component, so anything positioned underneath your SwingPanel will be clipped by the Swing component. To avoid clipping and overlapping issues, try experimental interop blending. If there is still a risk of incorrect rendering, you can redesign the UI accordingly or avoid using SwingPanel and try implementing the missing component, contributing to technology development.
Here are scenarios for using SwingPanel:
Your application does not require popups, tooltips, or context menus, or at least they are not inside your SwingPanel.
SwingPanel remains in a fixed position. In this case, you reduce the risk of glitches and artifacts when the Swing component's position changes. However, this condition is not mandatory and should be tested for each particular case.
Compose Multiplatform and Swing can be combined in both ways, allowing for flexible UI design. You can place a SwingPanel inside a ComposePanel, which can also be inside another SwingPanel. However, before using such nested combinations, consider potential rendering glitches. Refer to Layout with nested SwingPanel and ComposePanel for a code sample.
Use Compose Multiplatform in a Swing application
ComposePanel allows you to create a UI with Compose Multiplatform within a Swing-based application. Add an instance of ComposePanel to your Swing layout and define the composition inside setContent:
An experimental mode allows rendering compose panels directly on Swing components. This prevents transitional rendering issues when panels are shown, hidden, or resized. It also enables proper layering when combining Swing components and compose panels: a Swing component can be shown above or beneath a ComposePanel.
To enable off-screen rendering, use the compose.swing.render.on.graphics system property. The property must be set before executing any Compose code in your application, so it is recommended to enable it using the -D command-line JVM argument at startup:
-Dcompose.swing.render.on.graphics=true
Alternatively, use System.setProperty() at the entry point:
fun main() {
System.setProperty("compose.swing.render.on.graphics", "true")
...
}
Experimental separate views for popups
It can be important that popup elements such as tooltips and dropdown menus are not limited by the initial composable canvas or the app window. For example, when the composable view does not occupy the full screen but needs to spawn an alert dialog.
To create separate views or windows for popups on desktop, set the compose.layers.type system property. Supported values:
WINDOW creates Popup and Dialog components as separate undecorated windows.
COMPONENT creates Popup or Dialog as a separate Swing component in the same window. Note that the setting requires enabled off-screen rendering (see the Experimental off-screen rendering section), and off-screen rendering only works for ComposePanel components, not full window applications.
Note that popups and dialogs are still unable to draw anything outside their own bounds (for example, the shadow of the topmost container).
Here is an example of the code that uses the COMPONENT property:
SwingPanel allows you to create a UI with Swing within a Compose Multiplatform application. Use the factory parameter of SwingPanel to create a Swing JPanel:
Update Swing components when Compose state changes
To keep a Swing component up to date, provide an update: (T) -> Unit callback, which is invoked whenever the composable state changes or the layout is inflated. The following code sample demonstrates how to update a Swing component within a SwingPanel whenever the composable state changes:
By default, the interop view implemented using the SwingPanel wrapper is rectangular and in the foreground, on top of any Compose Multiplatform components. To make popup elements easier to use, we introduced experimental support for interop blending.
To enable this experimental feature, set the compose.interop.blending system property to true. The property must be enabled before executing any Compose code in your application, so set it via the -Dcompose.interop.blending=true command-line JVM argument or use System.setProperty() at the entry point:
fun main() {
System.setProperty("compose.interop.blending", "true")
...
}
With interop blending enabled, you can rely on Swing in the following use cases:
Clipping. You're no longer limited by a rectangular shape: the clip and shadow modifiers work correctly with SwingPanel.
Overlapping. It is possible to draw any Compose Multiplatform content on top of a SwingPanel and interact with it as usual.
Layout with nested Swing and Compose Multiplatform components
With interoperability, you can combine Swing and Compose Multiplatform in both ways: adding Swing components to a Compose Multiplatform application and adding Compose Multiplatform components to a Swing application. If you want to nest several components and freely combine approaches, this scenario is also supported.
The following code sample demonstrates how to add a SwingPanel to a ComposePanel, which is already inside another SwingPanel, creating a Swing-Compose Multiplatform-Swing structure: