You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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);
    }
}

问题原因

  1. JavaFX模块加载异常:Spring Boot的类加载机制与JavaFX的模块化要求不匹配,导致JavaFX类被加载到未命名模块,无法正常初始化渲染环境。
  2. 线程冲突:在Web请求线程中直接调用Application.launch(),该方法会阻塞当前线程并启动JavaFX主线程,导致线程调度异常,UI无法正常渲染。
  3. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 18:12:11