gpt4 book ai didi

JavaFX 最小化未修饰阶段

转载 作者:太空狗 更新时间:2023-10-29 22:47:30 25 4
gpt4 key购买 nike

我有一个未修饰的 JavaFX 舞台,以及我自己的最小化、最大化和关闭按钮。但不幸的是,与装饰行为相比,在 Windows 7 中单击任务栏图标不会自动最小化舞台。

有没有一种方法可以通过单击任务栏图标来使用纯 Java 代码最小化未修饰的阶段?如果不是,我如何使用 JNA 来做到这一点?

编辑:好的,我一直在尝试用 JNA 解决这个问题,但是几乎没有完成任何 C/C++/JNA,我在设置它时遇到了一些麻烦。如果有人帮我把这些碎片拼在一起,我将不胜感激。

到目前为止,这是我的代码:

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: 我最终在这方面取得了进一步的进展,但是一旦我重新设置 WNDPROC,我未装饰的窗口就没有响应任何事件。我提供了一个具有工作解决方案的独立示例悬赏 100 声望。仅 Windows (7+) 可以,我什至不知道它在其他平台上的表现如何。

编辑 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);
}
}
}

最佳答案

您可以设置合适的窗口样式。它在 XP 中工作,但在 windows 7 32 位中应该没问题。我认为(但无法测试)如果你使用 64 位然后更改为 Ptr Windows 功能,即。 GetWindowLongPtr.

import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.platform.win32.User32;
import com.sun.jna.platform.win32.WinDef.HWND;
import com.sun.jna.platform.win32.WinUser;
import static com.sun.jna.platform.win32.WinUser.GWL_STYLE;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.TextArea;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class JNATest extends Application {
public static void main(String[] args) { launch(args); }

@Override
public void start(Stage stage) {
TextArea ta = new TextArea("output\n");
VBox root = new VBox(5,ta);
Scene scene = new Scene(root,800,200);
stage.setTitle("Find this window");
stage.setScene(scene);
stage.show();
//gets this window (stage)
long lhwnd = com.sun.glass.ui.Window.getWindows().get(0).getNativeWindow();
Pointer lpVoid = new Pointer(lhwnd);
//gets the foreground (focused) window
final User32 user32 = User32.INSTANCE;
char[] windowText = new char[512];
HWND hwnd = user32.GetForegroundWindow();
//see what the title is
user32.GetWindowText(hwnd, windowText, 512);
//user32.GetWindowText(new HWND(lpVoid), windowText, 512);//to use the hwnd from stage
String text=(Native.toString(windowText));
//see if it's the same pointer
ta.appendText("HWND java:" + lpVoid + " HWND user32:"+hwnd+" text:"+text+"\n");
//change the window style if it's the right title
if (text.equals(stage.getTitle())){
//the style to change
int WS_DLGFRAME = 0x00400000;//s/b long I think
//not the same constant here??
ta.appendText("windows api:"+WS_DLGFRAME+" JNA: "+WinUser.SM_CXDLGFRAME);
int oldStyle = user32.GetWindowLong(hwnd, GWL_STYLE);
int newStyle = oldStyle & ~0x00400000; //bitwise not WS_DLGFRAME means remove the style
newStyle = newStyle & ~0x00040000;//WS_THICKFRAME
user32.SetWindowLong(hwnd, GWL_STYLE, newStyle);
}
}

}

我的猜测是你将最后 3 行替换为

            long oldStyleLong = user32.GetWindowLongPtr(hwnd, GWL_STYLE).longValue();
long newStyleLong = oldStyleLong & ~ 0x00400000l;
user32.SetWindowLongPtr(hwnd, GWL_STYLE, new BaseTSD.LONG_PTR(newStyleLong));

64 位。我想我的 User32.dll 中没有这些函数,所以我无法对其进行测试。里面有很多无关代码,主要用于测试或者教学。确定要执行的操作后,请删除未使用的行。

附言。不要添加 newStyle = newStyle & ~0x00020000;//WS_MINIMIZEBOX。这是 JavaFX 不用于未修饰的样式标志之一。这就是最小化不可用的原因。也许如果您尝试将舞台设置为未修饰并添加(使用 |,而不是 &~)最小化框标志,您将得到相同的结果。有一些工具可以从任何窗口中查找所有样式标志。

下面是最简单的代码量,仅使用舞台的 HWND 更改未修饰的舞台。

    public void start(Stage stage) {
Scene scene = new Scene(new Pane(new Label("Hello World")));
stage.initStyle(StageStyle.UNDECORATED);
stage.setTitle("Find this window");
stage.setScene(scene);
stage.show();
long lhwnd = com.sun.glass.ui.Window.getWindows().get(0).getNativeWindow();
Pointer lpVoid = new Pointer(lhwnd);
HWND hwnd = new HWND(lpVoid);
final User32 user32 = User32.INSTANCE;
int oldStyle = user32.GetWindowLong(hwnd, GWL_STYLE);
System.out.println(Integer.toBinaryString(oldStyle));
int newStyle = oldStyle | 0x00020000;//WS_MINIMIZEBOX
System.out.println(Integer.toBinaryString(newStyle));
user32.SetWindowLong(hwnd, GWL_STYLE, newStyle);
}

它打印出之前和之后的样式标志,以便您可以查看设置了哪些样式。

关于JavaFX 最小化未修饰阶段,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26972683/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com