Как я могу получить дескриптор окна (hWnd) для сцены в JavaFX?

Мы создаем приложение JavaFX в Windows и хотим иметь возможность управлять тем, как наше приложение отображается на панели задач Windows 7/8. Для этого необходимо изменить переменную Windows с именем "Идентификатор модели пользователя приложения".

Нам уже удалось сделать в Swing именно то, что мы хотели, используя JNA, и мы хотели бы повторить наше решение в JavaFX. К сожалению, для этого нам нужно получить hWnd (дескриптор окна) для каждого окна в нашем приложении. Это можно сделать в Swing/AWT через JNA Native.getWindowPointer(), который работает с java.awt.Window, но я не могу найти хороший способ сделать это с javafx.stage.Window.

Кто-нибудь знает, как получить hWnd за Stage?


person Xanatos    schedule 22.02.2013    source источник
comment
Не могли бы вы посмотреть на этот запрос функции и сказать, есть ли в нем вещи, которые вам интересны? javafx-jira.kenai.com/browse/RT-24249   -  person Alexander Kirov    schedule 23.02.2013
comment
@Alexander: кажется, это правильная идея, хотя я сомневаюсь, что они реализуют что-либо, что позволит нам делать то, что нам нужно, с панелью задач (у нас есть одно приложение, которое должно отображаться с несколькими разными значками на панели задач.) Думаю, нам действительно нужен hWnd. Спасибо за ссылку, я добавил комментарий к этому RFE.   -  person Xanatos    schedule 23.02.2013
comment
Вы можете проголосовать за эту функцию, если хотите повысить вероятность ее исправления.   -  person Alexander Kirov    schedule 23.02.2013


Ответы (4)


Вот версия JavaFX2 (использует Stage, а не Window):

private static Pointer getWindowPointer(Stage stage) {
    try {
        TKStage tkStage = stage.impl_getPeer();
        Method getPlatformWindow = tkStage.getClass().getDeclaredMethod("getPlatformWindow" );
        getPlatformWindow.setAccessible(true);
        Object platformWindow = getPlatformWindow.invoke(tkStage);
        Method getNativeHandle = platformWindow.getClass().getMethod( "getNativeHandle" );
        getNativeHandle.setAccessible(true);
        Object nativeHandle = getNativeHandle.invoke(platformWindow);
        return new Pointer((Long) nativeHandle);
    } catch (Throwable e) {
        System.err.println("Error getting Window Pointer");
        return null;
    }
}
person Craig Day    schedule 28.05.2014
comment
Я не думаю, что это больше работает, по крайней мере, с 1.8_66. getPlatformWindow больше не существует в TKStage. - person robross0606; 25.03.2017
comment
Похоже, он был перемещен в класс WindowStage. Кто-нибудь знает, как туда добраться? - person robross0606; 25.03.2017
comment
Да, WindowStage является подклассом TKStage. Метод найден через отражение, но я получаю InvocationException при вызове метода. - person robross0606; 25.03.2017

Следующий метод показывает, как можно получить собственный дескриптор окна (hWnd) для сцены JavaFX (или окно), а затем сохраните его в JNA Указатель объект:

private static Pointer getWindowPointer(javafx.stage.Window window) {
    Pointer retval = null;
    try {
        Method getPeer = window.getClass().getMethod("impl_getPeer");
        final Object tkStage = getPeer.invoke(window);
        Method getPlatformWindow = tkStage.getClass().getDeclaredMethod("getPlatformWindow");
        getPlatformWindow.setAccessible(true);
        final Object platformWindow = getPlatformWindow.invoke(tkStage);
        Method getNativeHandle = platformWindow.getClass().getMethod("getNativeHandle");
        retval = new Pointer((Long) getNativeHandle.invoke(platformWindow));
    } catch (Throwable t) {
        System.err.println("Error getting Window Pointer");
        t.printStackTrace();
    }
    return retval;
}

Это решение является хрупким и, как правило, нежелательным, поскольку оно использует отражение для доступа к множеству приватных методов. Но это делает работу. Будем надеяться, что Oracle в конечном итоге предоставит нам прямой доступ к собственным дескрипторам окон, чтобы нам не пришлось этого делать.

Конечно, этот код работает только тогда, когда вы работаете в MS Windows. Кроме того, я пробовал это только с ранними версиями JavaFX 8 (но я подозреваю, что он будет хорошо работать и на JavaFX 2. РЕДАКТИРОВАТЬ: похоже, он не работает в JavaFX 2.)

person Xanatos    schedule 01.11.2013
comment
Пользователь JavaFX 2 здесь. Windows 7, jdk1.7.0_21. m.invoke( window ) возвращает null. Решение не работает. - person mre; 15.01.2014
comment
Добавлена ​​версия JavaFX2 в качестве отдельного ответа. ПОМОЩЬ. - person Craig Day; 28.05.2014
comment
Собственно, это уже версия JavaFX2. Window является надклассом Stage. - person Xanatos; 26.09.2014

Добавьте зависимость от JNA:

<dependency>
  <groupId>net.java.dev.jna</groupId>
  <artifactId>jna-platform</artifactId>
  <version>5.3.1</version>
</dependency>

Затем дайте вашему Stage отдельный заголовок ("MyStage" в этом примере), а затем получите идентификатор окна следующим образом:

WinDef.HWND hwnd = User32.INSTANCE.FindWindow(null, "MyStage");

long wid = Pointer.nativeValue(hwnd.getPointer());

Это будет работать в Windows независимо от версии JavaFX.

person john16384    schedule 15.06.2019

person    schedule
comment
Это сработало для меня. Никаких отражений, никаких дополнительных зависимостей, просто вызов простого метода. - person Nohus; 04.09.2020