如何在Java中获取原生窗口句柄通过JNI传递给C++ DLL实现JavaFX窗口置底
解决方案
1. 调整JNI方法签名
不要在C侧遍历查找窗口,效率低且容易匹配错误,直接修改JNI方法新增窗口句柄入参,由Java侧获取后传入即可。
修改后的C代码:
#define FLAGS (SWP_NOMOVE | SWP_NOSIZE) // 保留窗口原有位置和尺寸,不需要可删除 #define ALWAYS_ON_BOTTOM HWND_BOTTOM JNIEXPORT void JNICALL Java_libreria_WindowsHandlerWrapper_SetAlwaysOnBottom (JNIEnv* env, jobject obj, jlong hWndValue) { HWND hWnd = (HWND)hWndValue; SetWindowPos( hWnd, ALWAYS_ON_BOTTOM, 0, 0, 0, 0, // 配合SWP_NOMOVE、SWP_NOSIZE参数,这四个值会被自动忽略 FLAGS ); }
同步修改Java侧的native方法声明:
package libreria; public class WindowsHandlerWrapper { public native void SetAlwaysOnBottom(long hWnd); // 原有DLL加载逻辑保留 static { System.loadLibrary("你的DLL文件名"); } }
2. JavaFX侧获取原生窗口句柄
根据你使用的JDK版本选择对应实现,必须在Stage调用show()方法之后再执行获取逻辑,未显示的窗口无法拿到有效句柄:
适用于Java 8
import com.sun.javafx.stage.StageHelper; import javafx.stage.Stage; long hWnd = StageHelper.getStagePeer(stage).getNativeHandle();
适用于Java 9及以上版本
Java 9之后模块化隐藏了内部API,通过反射获取即可:
import javafx.stage.Stage; import java.lang.reflect.Method; public long getHWnd(Stage stage) throws Exception { Method getPeerMethod = Stage.class.getMethod("getPeer"); Object windowPeer = getPeerMethod.invoke(stage); Method getNativeHandleMethod = windowPeer.getClass().getMethod("getNativeHandle"); return (long) getNativeHandleMethod.invoke(windowPeer); }
3. 最终调用
拿到句柄后直接调用JNI方法即可完成窗口置底:
long hWnd = getHWnd(yourStage); new WindowsHandlerWrapper().SetAlwaysOnBottom(hWnd);
注意事项
- 如果需要窗口在大小、位置变化后始终保持置底,可以监听Stage的
xProperty()、yProperty()、widthProperty()、heightProperty()变化,每次变更后重新调用一次置底方法 - 该实现仅适用于Windows平台,跨平台场景需要单独适配其他系统的原生API
内容的提问来源于stack exchange,提问作者DDS
相关产品推荐
相关产品推荐

