11

I'm a beginner of JavaFX. Is there anyway to change the color of title bar. I just want to make the application all black. I have searched the JavaFX API, but I can't find any method to make it.

enter image description here

1

3 Answers 3

13

This is pretty much an OS dependent thing. The operating system gets to decide how titlebars and borders are displayed by default. However, it definitely can be done, if you are willing to venture into making your own title bar.

To start out, you will need to modify the application window's stage to StageStyle.UNDECORATED. Then you will need to set up your own borders and title bar (complete with things like the title, minimize button, close button, etc.). You can then add the border pane as a scene into your application's stage, and that should render your custom titlebar then without the default Windows styling.

You can find an example implementation of that here: https://stackoverflow.com/a/9864496/2694511

Do note that because you are implementing your own titlebar, you will also lose the OS's default window drag behavior, so you will need to implement your own window-drag/window-move code. This answer might be able to help you with that: https://stackoverflow.com/a/11781291/2694511

Sign up to request clarification or add additional context in comments.

3 Comments

setting stage to undecorated removes window 10 support for quick edge resizing
is there a simple way to hack this in JNA.platform.win32? If all I want is SetSysColors?
I doubt that it's only an OS dependent thing. Otherwise the title bar would be dark in my case, since I've set my OS theme to dark and the title bars of all other apps look dark.
3

There is a Windows API allowing you to set the color of the window title bar: DwmSetWindowAttribute and how it can be used.

With JNA you can access this API like this:

import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.platform.win32.WinDef;
import javafx.stage.Stage;
import javafx.stage.Window;
import lombok.val;

public class FXWinUtil {

    public static WinDef.HWND getNativeHandleForStage(Stage stage) {
        try {
            val getPeer = Window.class.getDeclaredMethod("getPeer", null);
            getPeer.setAccessible(true);
            val tkStage = getPeer.invoke(stage);
            val getRawHandle = tkStage.getClass().getMethod("getRawHandle");
            getRawHandle.setAccessible(true);
            val pointer = new Pointer((Long) getRawHandle.invoke(tkStage));
            return new WinDef.HWND(pointer);
        } catch (Exception ex) {
            System.err.println("Unable to determine native handle for window");
            return null;
        }
    }

    public static void setDarkMode(Stage stage, boolean darkMode) {
        val hwnd = FXWinUtil.getNativeHandleForStage(stage);
        val dwmapi = Dwmapi.INSTANCE;
        WinDef.BOOLByReference darkModeRef = new WinDef.BOOLByReference(new WinDef.BOOL(darkMode));

        dwmapi.DwmSetWindowAttribute(hwnd, 20, darkModeRef, Native.getNativeSize(WinDef.BOOLByReference.class));

        forceRedrawOfWindowTitleBar(stage);
    }

    private static void forceRedrawOfWindowTitleBar(Stage stage) {
        val maximized = stage.isMaximized();
        stage.setMaximized(!maximized);
        stage.setMaximized(maximized);
    }

}

Dwmapi.java:

import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.PointerType;
import com.sun.jna.platform.win32.WinDef;

public interface Dwmapi extends Library {

    Dwmapi INSTANCE = Native.load("dwmapi", Dwmapi.class);

    int DwmSetWindowAttribute(WinDef.HWND hwnd, int dwAttribute, PointerType pvAttribute, int cbAttribute);

}

The code allows you to activate the dark mode of the window title bar via:

FXWinUtil.setDarkMode(stage, true);

3 Comments

This is a nice example of how this can be achieved on Windows. However, it would have been nice if you had also included the Dwmapi source :)
@grill2010: Thanks for the hint. I just added the class to my post.
This works, but you need to call this after the stage has been shown, or it won't find the native peer class (TkStage) as it hasn't been created yet. There is also another way to find the HWND of your stage without having to access JavaFX internals (which may not work with modules), if you are willing to give the Stage a specific (searchable) title. See here: stackoverflow.com/a/56614505/1262865
0

Note that Native.getNativeSize(WinDef.BOOLByReference.class) in the sample code is somewhat incorrect. It should be BOOL.SIZE. The example above happens to work because Native.getNativeSize(WinDef.BOOLByReference.class) and BOOL.SIZE happens to be the same. This is not the case when passing a DWORD value:

DwmSetWindowAttribute(hwnd, DWMWA_USE_IMMERSIVE_DARK_MODE, new BOOLByReference(new BOOL(enabled)), BOOL.SIZE);
DwmSetWindowAttribute(hwnd, DWMWA_BORDER_COLOR, new DWORDByReference(new DWORD(color)), DWORD.SIZE);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.