Как изменить цвет панели управления окном JavaFX
Возможно ли изменить цвет стандартной панели управления окном Windows на JavaFX
Буду благодарен за ответ
Ответы (1 шт):
Вы можете использовать WinAPI для изменения цвета заголовка окна.
В Windows 10 его можно сделать черного цвета через DwmSetWindowAttribute
с помощью атрибута DWMWA_USE_IMMERSIVE_DARK_MODE
(20)
https://learn.microsoft.com/en-us/windows/win32/api/dwmapi/ne-dwmapi-dwmwindowattribute https://learn.microsoft.com/en-us/windows/win32/api/dwmapi/nf-dwmapi-dwmsetwindowattribute
Пример использования этой функции на java 21 (аргументы jvm для запуска --enable-preview --enable-native-access=ALL-UNNAMED
) с javafx 23:
import com.sun.javafx.tk.TKStage;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;
import java.lang.foreign.Arena;
import java.lang.foreign.FunctionDescriptor;
import java.lang.foreign.Linker;
import java.lang.foreign.SymbolLookup;
import java.lang.invoke.MethodHandle;
import static java.lang.foreign.ValueLayout.*;
public class App extends Application {
void run() {
launch();
}
@Override
public void start(Stage stage) {
stage.setScene(new Scene(new Pane()));
useImmersiveDarkMode(stage);
}
void useImmersiveDarkMode(Stage stage) {
final int DWMWA_USE_IMMERSIVE_DARK_MODE = 20;
Arena arena = Arena.ofConfined();
Linker linker = Linker.nativeLinker();
MethodHandle dwmSetWindowAttribute = linker.downcallHandle(
SymbolLookup
.libraryLookup("Dwmapi", arena)
.find("DwmSetWindowAttribute")
.orElseThrow(),
FunctionDescriptor.of(JAVA_LONG, JAVA_LONG, JAVA_INT, ADDRESS, JAVA_INT));
stage.setWidth(499);
stage.setHeight(499);
stage.show();
try {
// Получение дескриптора окна
var getPeer = stage.getClass().getSuperclass().getDeclaredMethod("getPeer");
getPeer.setAccessible(true);
var hwnd = ((TKStage) getPeer.invoke(stage)).getRawHandle();
dwmSetWindowAttribute.invoke(
hwnd,
DWMWA_USE_IMMERSIVE_DARK_MODE,
arena.allocate(JAVA_INT, 1),
4
);
} catch (Throwable _) {
}
arena.close();
//обновления размеров окна чтобы изменения стали видимыми
stage.setWidth(500);
stage.setHeight(500);
}
}
void main() {
new App().run();
}
на более старых версиях foreign functions api может отличаться или можно вызвать DwmSetWindowAttribute
через JNI:
native void useImmersiveDarkMode(long hwnd, boolean value);
#include <jni.h>
#include "Dwmapi.h"
JNIEXPORT void JNICALL Java_App_useImmersiveDarkMode(JNIEnv* env, jobject obj, jlong hwnd, jint value) {
DwmSetWindowAttribute((HWND)hwnd, DWMWA_USE_IMMERSIVE_DARK_MODE, &value, sizeof(int));
}
Команда компиляции через clang:
clang -shared -I"C:\Program Files\Java\jdk-21\include" -I"C:\Program Files\Java\jdk-21\include\win32" -lDwmapi -o lib.dll lib.c
import com.sun.javafx.tk.TKStage;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;
import java.io.File;
public class App extends Application {
void run() {
System.load(new File("./lib.dll").getAbsolutePath());
launch();
}
native void useImmersiveDarkMode(long hwnd, boolean value);
@Override
public void start(Stage stage) throws Exception {
stage.setScene(new Scene(new Pane()));
stage.setWidth(499);
stage.setHeight(499);
stage.show();
var getPeer = stage.getClass().getSuperclass().getDeclaredMethod("getPeer");
getPeer.setAccessible(true);
var hwnd = ((TKStage) getPeer.invoke(stage)).getRawHandle();
useImmersiveDarkMode(hwnd, true);
stage.setWidth(500);
stage.setHeight(500);
}
}
В Windows 11 добавили возможность установить любой цвет для фона и цвет шрифта заголовка через атрибуты
DWMWA_BORDER_COLOR
(34)
DWMWA_CAPTION_COLOR
(35)
DWMWA_TEXT_COLOR
(36)