我有一个未经修饰的JavaFX Stage,还有我自己的最小化,最大化和关闭按钮。但是不幸的是,与经过修饰的行为相比,在Windows 7中单击任务栏图标不会自动最小化该阶段。
是否可以通过单击任务栏图标来最小化纯Java代码的未修饰阶段?如果没有,我该如何使用JNA?
编辑:好的,我一直在尝试使用JNA解决此问题,但是几乎没有C / C ++ / JNA完成,因此设置起来有些麻烦。如果有人帮助我把这些拼凑在一起,我将不胜感激。
到目前为止是我的代码:
我最终对此进行了进一步的研究,但是当我重新设置WNDPROC时,我未修饰的窗口没有响应任何事件。.我提供了100个声誉的赏金一个包含解决方案的独立示例。仅Windows(7+)可以,我什至不知道它在其他平台上的表现。public final class Utils { static { if (PlatformUtil.isWin7OrLater()) { Native.register("shell32"); Native.register("user32"); } } // Apparently, this is the event I am after public static final int WM_ACTIVATEAPP = 0x1C; public static void registerMinimizeHandler(Stage stage) { // Hacky way to get a pointer to JavaFX Window Pointer pointer = getWindowPointer(stage); WinDef.HWND hwnd = new WinDef.HWND(pointer); // Here's my minimize/activate handler WinUser.WindowProc windowProc = new MinimizeHandler(stage); Pointer magicPointer = ... set this to point to windowProc? // This.. apparently, re-sets the WndProc? But how do I get the "magicPointer" that is "attached" to the windowProc? User32.INSTANCE.SetWindowLong(hwnd, User32.GWL_WNDPROC, magicPointer); } } private static class MinimizeHandler implements WinUser.WindowProc { private Stage stage; private MinimizeHandler(Stage stage) { this.stage = stage; } @Override public WinDef.LRESULT callback(WinDef.HWND hWnd, int uMsg, WinDef.WPARAM wParam, WinDef.LPARAM lParam) { if (uMsg == WM_ACTIVATEAPP) { System.out.println("ACTIVATE"); } return User32.INSTANCE.DefWindowProc(hWnd, uMsg, wParam, lParam); } } 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; } }
编辑2:
编辑3:
好吧,我有点放弃了这一点..我正确地设置了所有内容,并接收了事件,但是在确定正确的事件以侦听时遇到了问题。由于这个问题引起了人们的兴趣,如果有人想继续进行下去,这是我的最终代码(希望它可以开箱即用地工作):
public final class Utils {
static interface ExtUser32 extends StdCallLibrary, User32 {
ExtUser32 INSTANCE = (ExtUser32) Native.loadLibrary(
"user32",
ExtUser32.class,
W32APIOptions.DEFAULT_OPTIONS);
WinDef.LRESULT CallWindowProcW(
Pointer lpWndProc,
Pointer hWnd,
int msg,
WinDef.WPARAM wParam,
WinDef.LPARAM lParam);
int SetWindowLong(HWND hWnd, int nIndex, com.sun.jna.Callback wndProc) throws LastErrorException;
}
// Some possible event types
public static final int WM_ACTIVATE = 0x0006;
public static final int WM_ACTIVATEAPP = 0x1C;
public static final int WM_NCACTIVATE = 0x0086;
public static void registerMinimizeHandler(Stage stage) {
Pointer pointer = getWindowPointer(stage);
WinDef.HWND hwnd = new WinDef.HWND(pointer);
long old = ExtUser32.INSTANCE.GetWindowLong(hwnd, User32.GWL_WNDPROC);
MinimizeHandler handler = new MinimizeHandler(stage, old);
ExtUser32.INSTANCE.SetWindowLong(hwnd, User32.GWL_WNDPROC, handler);
}
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;
}
}
private static class MinimizeHandler implements WinUser.WindowProc, StdCallLibrary.StdCallCallback {
private Pointer mPrevWndProc32;
private Stage stage;
private MinimizeHandler(Stage stage, long oldPtr) {
this.stage = stage;
mPrevWndProc32 = new Pointer(oldPtr);
// Set up an event pump to deliver messages for JavaFX to handle
Thread thread = new Thread() {
@Override
public void run() {
int result;
WinUser.MSG msg = new WinUser.MSG();
while ((result = User32.INSTANCE.GetMessage(msg, null, 0, 0)) != 0) {
if (result == -1) {
System.err.println("error in get message");
break;
}
else {
System.out.println("got message: " + result);
User32.INSTANCE.TranslateMessage(msg);
User32.INSTANCE.DispatchMessage(msg);
}
}
}
};
thread.start();
}
@Override
public WinDef.LRESULT callback(WinDef.HWND hWnd, int uMsg, WinDef.WPARAM wParam, WinDef.LPARAM lParam) {
if (uMsg == WM_ACTIVATEAPP) {
// Window deactivated (wParam == 0)... Here's where I got stuck and gave up,
// this is probably not the best event to listen to.. the app
// does indeed get iconified now by pressing the task-bar button, but it
// instantly restores afterwards..
if (wParam.intValue() == 0) {
stage.setIconified(true);
}
return new WinDef.LRESULT(0);
}
// Let JavaFX handle other events
return ExtUser32.INSTANCE.CallWindowProcW(
mPrevWndProc32,
hWnd.getPointer(),
uMsg,
wParam,
lParam);
}
}
}
我有一个未经修饰的JavaFX Stage,还有我自己的最小化,最大化和关闭按钮。但是不幸的是,在Windows 7中单击任务栏图标不会自动最小化阶段-与...
您可以只设置适当的窗口样式。它可以在XP中使用,但在Windows 7 32位环境中应该可以。我认为(但无法测试)是否使用64位,然后更改为Ptr Windows函数,即。 GetWindowLongPtr。
这里有两点要注意。
没有正确回答您的问题。但是这是解决方法