5

我们正在 Windows 中构建 JavaFX 应用程序,我们希望能够做一些事情来控制我们的应用程序在 Windows 7/8 任务栏中的显示方式。这需要修改一个名为“应用程序用户模型 ID ”的 Windows 变量。

我们已经通过使用JNA成功地在 Swing 中完成了我们想要的,并且我们想在 JavaFX 中重复我们的解决方案。不幸的是,要做到这一点,我们需要能够检索hWnd应用程序中每个窗口的(窗口句柄)。这可以通过 JNA Native.getWindowPointer()方法在 Swing/AWT 中完成,该方法java.awt.Windowjavafx.stage.Window.

有谁知道有什么办法可以得到hWnd一个Stage

4

6 回答 6

3

这是一个 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;
    }
}
于 2014-05-28T01:40:23.803 回答
2

添加对 JNA 的依赖:

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

然后给你Stage一个独特的标题(在这个例子中是“MyStage”),然后像这样获取窗口 ID:

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

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

无论 JavaFX 版本如何,这都适用于 Windows。

于 2019-06-15T22:05:31.423 回答
1

以下方法显示了如何获取 JavaFX Stage(或Window)的本机窗口句柄 (hWnd),然后将其存储在 JNA Pointer对象中:

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 中不起作用。)

于 2013-11-01T21:48:50.630 回答
1
com.sun.glass.ui.Window.getWindows.get(0).getNativeWindow

//

com.sun.glass.ui.Window.getFocusedWindow.getNativeWindow
于 2014-07-12T05:01:02.763 回答
1

以下代码适用于 Windows 上的 JavaFX 11(我只需要它)。我没有在任何其他版本中测试过它。

它非常脆弱,但在我的情况下是可以管理的,因为我将 Java 运行时与应用程序捆绑在一起,所以我总是知道下面是什么。

如果您使用 Java 9 模块,您还需要打开调用模块的包:

--add-opens javafx.graphics/javafx.stage=com.example--add-opens javafx.graphics/com.sun.javafx.tk.quantum=com.example

package com.example;

import com.sun.jna.Pointer;
import com.sun.jna.platform.win32.WinDef;
import javafx.stage.Stage;
import javafx.stage.Window;
import java.lang.reflect.Method;

public class FXWinUtil {

    public static WinDef.HWND getNativeHandleForStage(Stage stage) {
        try {
            final Method getPeer = Window.class.getDeclaredMethod("getPeer", null);
            getPeer.setAccessible(true);
            final Object tkStage = getPeer.invoke(stage);
            final Method getRawHandle = tkStage.getClass().getMethod("getRawHandle");
            getRawHandle.setAccessible(true);
            final Pointer 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;
        }
    }
}

如果您使用的是 JNA(如果您正在做类似这样的骇人听闻的事情,这很可能),您也可以从WinDef.HWND.

于 2021-08-18T19:06:28.440 回答
0

JavaFX 16 的解决方案,用 Kotlin 编写(仅反射)

fun getPointer(scene: Scene): Long {
    val tkStage = SceneHelper.getPeer(scene)

    val windowStage = tkStage.javaClass.getDeclaredMethod("getWindowStage")
        .apply { isAccessible = true }
        .invoke(tkStage)

    val platformWindow = windowStage.javaClass.getDeclaredMethod("getPlatformWindow")
        .apply { isAccessible = true }
        .invoke(windowStage)
    
    // Use fields 'ptr' and 'delegatePtr' instead of getNativeHandle() to avoid Platform.runLater
    val ptr = Window::class.java.getDeclaredField("ptr")
        .apply { isAccessible = true }[platformWindow] as Long

    val delegatePtr = Window::class.java.getDeclaredField("delegatePtr")
        .apply { isAccessible = true }[platformWindow] as Long

    return if (delegatePtr != 0L) delegatePtr else ptr
}

于 2021-12-17T04:45:53.900 回答