SpringBoot运行JavaFX应用遇透明窗口及配置警告问题求助
Spring Boot + JavaFX 悬浮窗渲染问题解决
问题背景
我有一个Spring Boot应用,类位于src/main/java/in/javacoder/overlayapp包下,需求是收到带xCoordinate、yCoordinate、zCoordinate参数的POST请求时,在屏幕上渲染一个显示坐标的透明悬浮窗。但实际发送请求后,只出现完全透明的窗口,控制台抛出警告:
2023-01-27T15:01:27.384+05:30 WARN 13060 --- [JavaFX-Launcher] javafx: Unsupported JavaFX configuration: classes were loaded from 'unnamed module @1ec4c0e8'
现有代码
build.gradle
plugins { id 'java' id 'org.springframework.boot' version '3.0.2' id 'io.spring.dependency-management' version '1.1.0' id 'application' id 'org.openjfx.javafxplugin' version '0.0.13' } javafx { version = "17" modules = [ 'javafx.controls' ] } group = 'in.techpro424' version = '0.0.1-SNAPSHOT' sourceCompatibility = '17' configurations { compileOnly { extendsFrom annotationProcessor } } repositories { mavenCentral() } dependencies { implementation 'org.springframework.boot:spring-boot-starter-web' developmentOnly 'org.springframework.boot:spring-boot-devtools' annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor' testImplementation 'org.springframework.boot:spring-boot-starter-test' } tasks.named('test') { useJUnitPlatform() }
CoordinateOverlayAppApplication.java
package in.techpro424.coordinateoverlayapp; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class CoordinateOverlayAppApplication { public static void main(String[] args) { SpringApplication.run(CoordinateOverlayAppApplication.class, args); } }
CoordinateRestController.java
package in.techpro424.coordinateoverlayapp; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @RestController public class CoordinateRestController { public static double xCoord; public static double yCoord; public static double zCoord; @PostMapping(value = "/coordinateOverlay") public int receiveCoordinates(@RequestParam(name = "xCoordinate") Double xCoordinate, @RequestParam(name = "yCoordinate") Double yCoordinate, @RequestParam(name = "zCoordinate") Double zCoordinate) { CoordinateRestController.xCoord = xCoordinate; System.out.println(CoordinateRestController.xCoord); CoordinateRestController.yCoord = yCoordinate; System.out.println(CoordinateRestController.yCoord); CoordinateRestController.zCoord = zCoordinate; System.out.println(CoordinateRestController.zCoord); javafx.application.Application.launch(RenderCoordinateOverlay.class); return 1; } }
RenderCoordinateOverlay.java
package in.techpro424.coordinateoverlayapp; import javafx.application.Application; import javafx.scene.Group; import javafx.scene.Scene; import javafx.scene.paint.Color; import javafx.scene.text.Text; import javafx.stage.Stage; import javafx.stage.StageStyle; public class RenderCoordinateOverlay extends Application { double radius = 50; @Override public void start(Stage primaryStage) { Group root = new Group(); Text coordinates = new Text(); coordinates.setText("X:" + CoordinateRestController.xCoord + ", Y:" + CoordinateRestController.yCoord + ", Z:" + CoordinateRestController.zCoord); root.getChildren().add(coordinates); Scene scene = new Scene(root, Color.TRANSPARENT); scene.getRoot().setStyle("-fx-background-color: transparent"); primaryStage.initStyle(StageStyle.TRANSPARENT); primaryStage.setScene(scene); primaryStage.show(); primaryStage.setAlwaysOnTop(true); } public static void main(String[] args) { launch(args); } }
问题原因
- JavaFX模块加载异常:Spring Boot的类加载机制与JavaFX的模块化要求不匹配,导致JavaFX类被加载到未命名模块,无法正常初始化渲染环境。
- 线程冲突:在Web请求线程中直接调用
Application.launch(),该方法会阻塞当前线程并启动JavaFX主线程,导致线程调度异常,UI无法正常渲染。 - UI元素配置缺失:Text控件未设置位置、字体大小和颜色,即使窗口正常显示,文本也可能处于不可见状态。
解决方案
1. 调整Gradle配置,确保JavaFX模块正确加载
修改build.gradle,添加JavaFX依赖配置和Spring Boot打包时的模块路径支持:
plugins { id 'java' id 'org.springframework.boot' version '3.0.2' id 'io.spring.dependency-management' version '1.1.0' id 'application' id 'org.openjfx.javafxplugin' version '0.0.13' } javafx { version = "17" modules = [ 'javafx.controls' ] configuration = 'implementation' // 确保JavaFX依赖加入implementation配置 } group = 'in.techpro424' version = '0.0.1-SNAPSHOT' sourceCompatibility = '17' configurations { compileOnly { extendsFrom annotationProcessor } } repositories { mavenCentral() } dependencies { implementation 'org.springframework.boot:spring-boot-starter-web' developmentOnly 'org.springframework.boot:spring-boot-devtools' annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor' testImplementation 'org.springframework.boot:spring-boot-starter-test' } tasks.named('test') { useJUnitPlatform() } // 配置Spring Boot打包时的模块信息 tasks.named('bootJar') { manifest { attributes 'Main-Class': 'in.techpro424.coordinateoverlayapp.CoordinateOverlayAppApplication', 'Module-Classpath': configurations.runtimeClasspath.files.collect { it.name }.join(' ') } }
2. 重构Controller,避免线程阻塞
修改CoordinateRestController.java,改用线程安全的方式初始化JavaFX,并用Platform.runLater()在JavaFX主线程更新UI:
package in.techpro424.coordinateoverlayapp; import javafx.application.Platform; import javafx.stage.Stage; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import java.util.concurrent.atomic.AtomicBoolean; @RestController public class CoordinateRestController { private static final AtomicBoolean javafxInitialized = new AtomicBoolean(false); private static Stage overlayStage; @PostMapping(value = "/coordinateOverlay") public int receiveCoordinates(@RequestParam(name = "xCoordinate") Double xCoordinate, @RequestParam(name = "yCoordinate") Double yCoordinate, @RequestParam(name = "zCoordinate") Double zCoordinate) { // 仅初始化一次JavaFX运行时 if (javafxInitialized.compareAndSet(false, true)) { new Thread(() -> RenderCoordinateOverlay.launch(RenderCoordinateOverlay.class)).start(); // 等待JavaFX初始化完成 try { Thread.sleep(500); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } // 在JavaFX主线程更新UI Platform.runLater(() -> { if (overlayStage != null) { RenderCoordinateOverlay.updateCoordinates(xCoordinate, yCoordinate, zCoordinate); overlayStage.show(); } }); return 1; } public static void setOverlayStage(Stage stage) { overlayStage = stage; } }
3. 优化JavaFX UI,支持动态更新
修改RenderCoordinateOverlay.java,添加坐标更新方法,配置UI元素的可见性:
package in.techpro424.coordinateoverlayapp; import javafx.application.Application; import javafx.scene.Group; import javafx.scene.Scene; import javafx.scene.paint.Color; import javafx.scene.text.Font; import javafx.scene.text.Text; import javafx.stage.Stage; import javafx.stage.StageStyle; public class RenderCoordinateOverlay extends Application { private static Text coordinatesText; @Override public void start(Stage primaryStage) { Group root = new Group(); // 设置文本位置、字体和颜色 coordinatesText = new Text(20, 40, ""); coordinatesText.setFont(Font.font(20)); coordinatesText.setFill(Color.WHITE); root.getChildren().add(coordinatesText); // 设置窗口大小 Scene scene = new Scene(root, 300, 60, Color.TRANSPARENT); scene.getRoot().setStyle("-fx-background-color: transparent"); primaryStage.initStyle(StageStyle.TRANSPARENT); primaryStage.setScene(scene); primaryStage.setAlwaysOnTop(true); // 将Stage引用传递给Controller CoordinateRestController.setOverlayStage(primaryStage); } // 动态更新坐标的方法 public static void updateCoordinates(double x, double y, double z) { coordinatesText.setText(String.format("X: %.2f, Y: %.2f, Z: %.2f", x, y, z)); } public static void main(String[] args) { launch(args); } }
4. 运行应用
使用Gradle的run任务启动应用,确保JavaFX模块路径正确配置:
./gradlew run
发送POST请求到http://localhost:8080/coordinateOverlay,携带参数xCoordinate、yCoordinate、zCoordinate,即可看到屏幕上显示坐标的透明悬浮窗。
内容的提问来源于stack exchange,提问作者JavaCoder10
相关产品推荐
相关产品推荐

