compose-multiplatform: Crash when I use JFXPanel
I want to use JavaFX in Compose-jb, but Compose-jb only support swing, so I use JFXPanel
But, kotlin.UninitializedPropertyAccessException: lateinit property layout has not been initialized
when I use JFXPanel
My Code
@Composable
private fun createMainSwingScreen() {
SwingPanel(
background = Color.White,
modifier = Modifier.fillMaxSize(),
factory = {
JFXPanel().also { jfxPanel ->
PlatformImpl.startup {
}
}
}
)
}
Error log
Exception in thread "AWT-EventQueue-0 @coroutine#5" kotlin.UninitializedPropertyAccessException: lateinit property layout has not been initialized
at androidx.compose.desktop.ComponentInfo.getLayout(SwingPanel.desktop.kt:113)
at androidx.compose.desktop.SwingPanel_desktopKt$SwingPanel-euL9pac$$inlined$onGloballyPositioned$1.onGloballyPositioned(OnGloballyPositionedModifier.kt:60)
at androidx.compose.ui.node.LayoutNode.dispatchOnPositionedCallbacks$ui(LayoutNode.kt:1095)
at androidx.compose.ui.node.OnPositionedDispatcher.dispatchHierarchy(OnPositionedDispatcher.kt:51)
at androidx.compose.ui.node.OnPositionedDispatcher.dispatchHierarchy(OnPositionedDispatcher.kt:55)
at androidx.compose.ui.node.OnPositionedDispatcher.dispatch(OnPositionedDispatcher.kt:44)
at androidx.compose.ui.node.MeasureAndLayoutDelegate.dispatchOnPositionedCallbacks(MeasureAndLayoutDelegate.kt:253)
at androidx.compose.ui.node.MeasureAndLayoutDelegate.dispatchOnPositionedCallbacks$default(MeasureAndLayoutDelegate.kt:249)
at androidx.compose.ui.platform.DesktopOwner.measureAndLayout(DesktopOwner.desktop.kt:227)
at androidx.compose.ui.platform.DesktopOwner.render(DesktopOwner.desktop.kt:207)
at androidx.compose.ui.platform.DesktopOwners.onFrame(DesktopOwners.desktop.kt:121)
at androidx.compose.desktop.ComposeLayer$1.onRender(ComposeLayer.desktop.kt:123)
at org.jetbrains.skiko.SkiaLayer.update$skiko(SkiaLayer.kt:117)
at org.jetbrains.skiko.redrawer.Direct3DRedrawer.update(Direct3DRedrawer.kt:42)
at org.jetbrains.skiko.redrawer.Direct3DRedrawer.redrawImmediately(Direct3DRedrawer.kt:37)
at org.jetbrains.skiko.SkiaLayer$redraw$1.run(SkiaLayer.kt:82)
at java.desktop/java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:316)
at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:770)
at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:721)
at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:715)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:391)
at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85)
at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:740)
at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113)
at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109)
at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
at java.desktop/java.awt.WaitDispatchSupport$2.run(WaitDispatchSupport.java:188)
at java.desktop/java.awt.WaitDispatchSupport$4.run(WaitDispatchSupport.java:235)
at java.desktop/java.awt.WaitDispatchSupport$4.run(WaitDispatchSupport.java:233)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:312)
at java.desktop/java.awt.WaitDispatchSupport.enter(WaitDispatchSupport.java:233)
at javafx.embed.swing.JFXPanel.initFx(JFXPanel.java:241)
at javafx.embed.swing.JFXPanel.<init>(JFXPanel.java:267)
at top.gtf35.nekohelper.ui.file_manager.FileManagerScreen$createMainSwingScreen$1.invoke(FileManagerScreen.kt:92)
at top.gtf35.nekohelper.ui.file_manager.FileManagerScreen$createMainSwingScreen$1.invoke(FileManagerScreen.kt:91)
at androidx.compose.desktop.SwingPanel_desktopKt$SwingPanel$4.invoke(SwingPanel.desktop.kt:84)
at androidx.compose.desktop.SwingPanel_desktopKt$SwingPanel$4.invoke(SwingPanel.desktop.kt:83)
at androidx.compose.runtime.DisposableEffectImpl.onRemembered(Effects.kt:81)
at androidx.compose.runtime.ComposerImpl$RememberEventDispatcher.dispatchRememberObservers(Composer.kt:1344)
at androidx.compose.runtime.ComposerImpl.applyChanges$runtime(Composer.kt:1409)
at androidx.compose.runtime.CompositionImpl.applyChanges(Composition.kt:414)
at androidx.compose.runtime.Recomposer.composeInitial$runtime(Recomposer.kt:699)
at androidx.compose.runtime.CompositionImpl.setContent(Composition.kt:304)
at androidx.compose.ui.platform.Wrapper_desktopKt.setContent(Wrapper.desktop.kt:39)
at androidx.compose.desktop.ComposeLayer.initOwner(ComposeLayer.desktop.kt:257)
at androidx.compose.desktop.ComposeLayer.access$initOwner(ComposeLayer.desktop.kt:50)
at androidx.compose.desktop.ComposeLayer$Wrapped.init(ComposeLayer.desktop.kt:83)
at org.jetbrains.skiko.HardwareLayer.checkIsShowing(HardwareLayer.kt:30)
at org.jetbrains.skiko.HardwareLayer.access$checkIsShowing(HardwareLayer.kt:7)
at org.jetbrains.skiko.HardwareLayer$1.hierarchyChanged(HardwareLayer.kt:22)
at java.desktop/java.awt.Component.processHierarchyEvent(Component.java:6781)
at java.desktop/java.awt.Component.processEvent(Component.java:6400)
at java.desktop/java.awt.Component.dispatchEventImpl(Component.java:4990)
at java.desktop/java.awt.Component.dispatchEvent(Component.java:4822)
at java.desktop/java.awt.Component.createHierarchyEvents(Component.java:5628)
at java.desktop/java.awt.Container.createHierarchyEvents(Container.java:1466)
at java.desktop/java.awt.Container.createHierarchyEvents(Container.java:1466)
at java.desktop/java.awt.Container.createHierarchyEvents(Container.java:1466)
at java.desktop/java.awt.Container.createHierarchyEvents(Container.java:1466)
at java.desktop/java.awt.Container.createHierarchyEvents(Container.java:1466)
at java.desktop/java.awt.Component.show(Component.java:1680)
at java.desktop/java.awt.Window.show(Window.java:1056)
at java.desktop/java.awt.Component.show(Component.java:1717)
at java.desktop/java.awt.Component.setVisible(Component.java:1664)
at java.desktop/java.awt.Window.setVisible(Window.java:1028)
at androidx.compose.desktop.ComposeWindow.setVisible(ComposeWindow.desktop.kt:85)
at androidx.compose.desktop.AppWindow.show(AppWindow.desktop.kt:446)
at androidx.compose.desktop.AppWindow.show$default(AppWindow.desktop.kt:432)
at top.gtf35.nekohelper.ui.file_manager.FileManagerScreen.dispatch(FileManagerScreen.kt:78)
at top.gtf35.nekohelper.ui.file_manager.FileManagerScreen$dispatch$3.invoke(FileManagerScreen.kt)
at top.gtf35.nekohelper.ui.file_manager.FileManagerScreen$dispatch$3.invoke(FileManagerScreen.kt)
at androidx.compose.runtime.RecomposeScopeImpl.compose(RecomposeScopeImpl.kt:91)
at androidx.compose.runtime.ComposerImpl.recomposeToGroupEnd(Composer.kt:2252)
at androidx.compose.runtime.ComposerImpl.skipCurrentGroup(Composer.kt:2499)
at androidx.compose.runtime.ComposerImpl.recompose$runtime(Composer.kt:2625)
at androidx.compose.runtime.CompositionImpl.recompose(Composition.kt:406)
at androidx.compose.runtime.Recomposer.performRecompose(Recomposer.kt:724)
at androidx.compose.runtime.Recomposer.access$performRecompose(Recomposer.kt:100)
at androidx.compose.runtime.Recomposer$runRecomposeAndApplyChanges$2$2.invoke(Recomposer.kt:437)
at androidx.compose.runtime.Recomposer$runRecomposeAndApplyChanges$2$2.invoke(Recomposer.kt:411)
at androidx.compose.runtime.BroadcastFrameClock$FrameAwaiter.resume(BroadcastFrameClock.kt:41)
at androidx.compose.runtime.BroadcastFrameClock.sendFrame(BroadcastFrameClock.kt:62)
at androidx.compose.ui.platform.DesktopOwners.onFrame(DesktopOwners.desktop.kt:116)
at androidx.compose.desktop.ComposeLayer$1.onRender(ComposeLayer.desktop.kt:123)
at org.jetbrains.skiko.SkiaLayer.update$skiko(SkiaLayer.kt:117)
at org.jetbrains.skiko.redrawer.Direct3DRedrawer.update(Direct3DRedrawer.kt:42)
at org.jetbrains.skiko.redrawer.Direct3DRedrawer.access$update(Direct3DRedrawer.kt:11)
at org.jetbrains.skiko.redrawer.Direct3DRedrawer$frameDispatcher$1.invokeSuspend(Direct3DRedrawer.kt:20)
at org.jetbrains.skiko.redrawer.Direct3DRedrawer$frameDispatcher$1.invoke(Direct3DRedrawer.kt)
at org.jetbrains.skiko.FrameDispatcher$job$1.invokeSuspend(FrameDispatcher.kt:32)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
at java.desktop/java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:316)
at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:770)
at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:721)
at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:715)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:391)
at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85)
at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:740)
at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113)
at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109)
at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90)
About this issue
- Original URL
- State: closed
- Created 3 years ago
- Reactions: 3
- Comments: 15 (2 by maintainers)
Hello! It looks like the initialization of the JFXPanel happens before the initialization of the SwingPanel, because both Swing and JavaFX have their own thread to dispatch events. So, if you try the following approach, it should solve your problem:
Hi @aro311 @theone55
It seems that the problem was some
ClassNotFoundException
. However, Compose simply swallows any exception, which is why your app won’t crash and it would simply appear that theWebView
didn’t load.To fix that, I followed the tutorial at, Configuring included JDK modules | Native distributions & local execution | JetBrains/compose-jb, and as suggested by that tutorial, I ran the
suggestModules
gradle task on my project. It suggested that I addmodules("java.instrument", "java.net.http", "jdk.jfr", "jdk.jsobject", "jdk.unsupported", "jdk.unsupported.desktop", "jdk.xml.dom")
undercompose.desktop.application.nativeDistributions
.Demo
Using the provided desktop-template, I made the following modifications to
./build.gradle.kts
and./src/main/kotlin/main.kt
, and then I added a new file./src/main/kotlin/JFXWebView.kt
(sources below):For
./build.gradle.kts
:For
./src/main/kotlin/main.kt
:For
./src/main/kotlin/JFXWebView.kt
:Then run
./gradlew packageDistributionForCurrentOS
, install the resulting native distribution, and upon running, you should get something like:P.S. Not sure if we should also worry about firewall settings, which may prevent the JavaFX
WebView
from also working, but then other parts of your app that connects to the internet might also stop working.Edit: The simplified
JFXWebView
class is not my original idea. Credits goes to Luke Quinane.