Use JNA
to call the native API of Mac
, Windows
or Linux
to hide the title bar, and the following demo
shows how to hide the title-bar on Windows and keep all Windows localized window decorations. There is no custom title-bar implementation provided here, you need to design it yourself.
The pom.xml:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>demo</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<maven.compiler.release>17</maven.compiler.release>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.26</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.12.0</version>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-controls</artifactId>
<version>19.0.2.1</version>
</dependency>
<dependency>
<groupId>net.java.dev.jna</groupId>
<artifactId>jna-platform</artifactId>
<version>5.13.0</version>
</dependency>
<!-- This dependency is required when using FX-BorderlessScene -->
<dependency>
<groupId>uk.co.bithatch</groupId>
<artifactId>FX-BorderlessScene</artifactId>
<version>5.0.0</version>
</dependency>
</dependencies>
</project>
package org.example;
import javafx.application.Application;
public class Main {
public static void main(String[] args) {
Application.launch(MyApp.class);
}
}
package org.example;
import com.goxr3plus.fxborderlessscene.borderless.BorderlessScene;
import javafx.application.Application;
import javafx.scene.*;
import javafx.scene.layout.*;
import javafx.scene.paint.*;
import javafx.stage.*;
import org.apache.commons.lang3.SystemUtils;
public class MyApp extends Application {
private static final String TITLE = "Test GUI";
private static final Color PRIMARY_COLOR = Color.rgb(60, 60, 60);
private static final boolean USE_BORDERLESS_WRAPPER = true;
private static Scene getScene(Stage stage, Parent root) {
if (!USE_BORDERLESS_WRAPPER) return new Scene(root);
BorderlessScene borderlessScene = new BorderlessScene(stage, StageStyle.DECORATED, root);
// Pass your custom title-bar element
borderlessScene.setMoveControl(root);
return borderlessScene;
}
@Override
public void start(Stage primaryStage) {
// Init window
primaryStage.setTitle(TITLE);
primaryStage.setWidth(1024);
primaryStage.setHeight(768);
Pane pane = new Pane();
pane.setBackground(Background.fill(PRIMARY_COLOR));
primaryStage.setScene(getScene(primaryStage, pane));
primaryStage.show();
// Only for Windows system
if (SystemUtils.IS_OS_WINDOWS) {
// Remove caption
WindowsUtils.removeCaption(null, TITLE);
// Redraw window
WindowsUtils.refreshWindow(null, TITLE);
} else if (SystemUtils.IS_OS_MAC) {
throw new RuntimeException("Please write a window custom implementation suitable for this platform.");
} else if (SystemUtils.IS_OS_LINUX) {
throw new RuntimeException("Please write a window custom implementation suitable for this platform.");
} else {
throw new RuntimeException("Please write a window custom implementation suitable for this platform.");
}
}
}
package org.example;
import com.sun.jna.Pointer;
import com.sun.jna.platform.win32.*;
import org.apache.commons.lang3.SystemUtils;
/** Windows OS utils */
public class WindowsUtils {
public static void removeCaption(String className, String windowName) {
requireWindowsOS();
// Find window by class name and/or window name
WinDef.HWND window = findWindow(className, windowName);
// Get current style of window
int presentStyle = User32.INSTANCE.GetWindowLongPtr(window, WinUser.GWL_STYLE).intValue();
// Remove title-bar of window: current style minus caption
int newStyle = presentStyle ^ WinUser.WS_CAPTION;
// Update window style
User32.INSTANCE.SetWindowLongPtr(window, WinUser.GWL_STYLE, new Pointer(newStyle));
}
public static void refreshWindow(String className, String windowName) {
requireWindowsOS();
// Find window by class name and/or window name
WinDef.HWND window = findWindow(className, windowName);
int uFlags =
WinUser.SWP_FRAMECHANGED |
// 保留当前位置(忽略X和Y参数)
WinUser.SWP_NOMOVE |
// 保留当前大小(忽略cx和cy参数)
WinUser.SWP_NOSIZE |
// 不更改所有者窗口在 Z 顺序中的位置
WinUser.SWP_NOREPOSITION |
// 保留当前的 Z 顺序(忽略 hWndInsertAfter 参数)
WinUser.SWP_NOZORDER;
// 更新SetWindowLong函数设置的样式
User32.INSTANCE.SetWindowPos(window, null, 0, 0, 0, 0, uFlags);
}
public static WinDef.HWND findWindow(String className, String windowName) {
requireWindowsOS();
return User32.INSTANCE.FindWindow(className, windowName);
}
protected static void requireWindowsOS() {
if (SystemUtils.IS_OS_WINDOWS) return;
throw new IllegalStateException("unsupported operation");
}
}
Demo: https://videos.ximinghui.org/230303_demo_running_on_win10.mp4
Note: The top 6px white bar question redirects Create window without titlebar, with resizable border and without bogus 6px white stripe