JavaFX如何移除标题栏但保留原生窗口边框?
在JavaFX中移除标题栏但保留Windows原生边框的方案
JavaFX原生的StageStyle枚举确实没有直接提供“保留系统边框但移除标题栏”的选项,不过我们可以通过调用Windows平台API实现这个需求,同时还能自定义顶部区域添加返回按钮。以下是具体实现步骤:
1. 依赖准备(JNA)
要调用Win32 API,需引入JNA库,Maven依赖如下:
<dependency> <groupId>net.java.dev.jna</groupId> <artifactId>jna</artifactId> <version>5.13.0</version> </dependency> <dependency> <groupId>net.java.dev.jna</groupId> <artifactId>jna-platform</artifactId> <version>5.13.0</version> </dependency>
2. 获取窗口句柄并修改样式
通过JavaFX内部API获取Stage对应的Windows窗口句柄,再调用Win32 API移除标题栏样式:
import com.sun.glass.ui.Window; import com.sun.jna.Pointer; import com.sun.jna.platform.win32.User32; import com.sun.jna.platform.win32.WinDef; import com.sun.jna.platform.win32.WinUser; import javafx.stage.Stage; public class WindowUtils { public static void removeTitleBar(Stage stage) { // 获取JavaFX窗口的原生句柄 Window glassWindow = stage.getPeer(); long hwnd = glassWindow.getNativeWindow(); User32 user32 = User32.INSTANCE; WinDef.HWND hWnd = new WinDef.HWND(new Pointer(hwnd)); // 获取当前窗口样式 long style = user32.GetWindowLongPtr(hWnd, WinUser.GWL_STYLE).longValue(); // 移除标题栏样式,同时保留边框和可调整大小的属性 long newStyle = style & ~WinUser.WS_CAPTION; newStyle |= WinUser.WS_BORDER | WinUser.WS_THICKFRAME; // 应用新样式并刷新窗口 user32.SetWindowLongPtr(hWnd, WinUser.GWL_STYLE, new WinDef.LONG(newStyle)); user32.SetWindowPos(hWnd, null, 0, 0, 0, 0, WinUser.SWP_NOMOVE | WinUser.SWP_NOSIZE | WinUser.SWP_FRAMECHANGED); } }
注意:
com.sun.glass.ui.Window是JavaFX内部API,JavaFX 11+需添加VM参数--add-exports javafx.graphics/com.sun.glass.ui=ALL-UNNAMED才能访问。
3. 自定义顶部区域并添加返回按钮
移除标题栏后,可在Scene顶部添加自定义面板,放置返回按钮并实现窗口拖动:
import javafx.application.Application; import javafx.scene.Scene; import javafx.scene.control.Button; import javafx.scene.control.Label; import javafx.scene.layout.BorderPane; import javafx.scene.layout.HBox; import javafx.stage.Stage; import javafx.stage.StageStyle; public class CustomTitleBarApp extends Application { @Override public void start(Stage primaryStage) { primaryStage.setTitle("自定义标题栏示例"); primaryStage.initStyle(StageStyle.DECORATED); // 自定义顶部栏 HBox titleBar = new HBox(); titleBar.setStyle("-fx-background-color: #f0f0f0; -fx-padding: 8px;"); Button backBtn = new Button("返回"); backBtn.setOnAction(e -> { // 替换为你的返回逻辑 System.out.println("触发返回操作"); }); titleBar.getChildren().add(backBtn); // 主内容布局 BorderPane root = new BorderPane(); root.setTop(titleBar); root.setCenter(new Label("应用主内容区域")); Scene scene = new Scene(root, 800, 600); primaryStage.setScene(scene); // 必须在窗口显示后修改样式,确保句柄已生成 primaryStage.show(); WindowUtils.removeTitleBar(primaryStage); // 实现窗口拖动功能 double[] dragDelta = new double[2]; titleBar.setOnMousePressed(e -> { dragDelta[0] = primaryStage.getX() - e.getScreenX(); dragDelta[1] = primaryStage.getY() - e.getScreenY(); }); titleBar.setOnMouseDragged(e -> { primaryStage.setX(e.getScreenX() + dragDelta[0]); primaryStage.setY(e.getScreenY() + dragDelta[1]); }); } public static void main(String[] args) { launch(args); } }
4. 注意事项
- 该方案仅适用于Windows平台,跨平台需针对Linux(GTK)、macOS(Cocoa)编写对应平台代码。
- 内部API存在版本兼容性风险,升级JavaFX时需测试验证。
- 移除标题栏后系统默认的最小化/最大化/关闭按钮会消失,需在自定义标题栏中添加对应按钮,通过
primaryStage.setIconified(true)、primaryStage.setMaximized(true)、primaryStage.close()实现功能。
内容的提问来源于stack exchange,提问作者Shiedix
相关产品推荐
相关产品推荐

