Tôi có một giai đoạn JavaFX chưa được đặt trước và mức tối thiểu của riêng tôi, tối đa hóa các nút đóng &. Nhưng tiếc là nhấp vào biểu tượng thanh tác vụ trong Windows 7 không tự động giảm thiểu giai đoạn - so với hành vi được trang trí.JavaFX tối thiểu hóa giai đoạn chưa được trang trí
Có cách nào để giảm thiểu giai đoạn chưa được trang trí bằng mã Java thuần túy không, bằng cách nhấp vào biểu tượng thanh tác vụ? Nếu không, làm thế nào tôi có thể làm điều này với, nói, JNA?
EDIT: OK, tôi đã cố gắng để giải quyết việc này với JNA, nhưng đã thực hiện bên cạnh không có C/C++/JNA, tôi có một rắc rối chút thiết lập này. Tôi muốn được biết ơn nếu ai đó giúp tôi để đưa các mảnh lại với nhau ..
Dưới đây là mã của tôi cho đến nay:
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;
}
}
EDIT 2: tôi cuối cùng đã thêm vào với thế này, nhưng trong thời gian sớm khi tôi thiết lập lại WNDPROC, cửa sổ chưa được trang trí của tôi không trả lời bất kỳ sự kiện nào. Tôi đang cung cấp một khoản tiền thưởng 100 danh tiếng cho một ví dụ độc lập với một giải pháp làm việc. Windows (7+) chỉ là OK, tôi thậm chí không biết làm thế nào điều này cư xử trên các nền tảng khác.
EDIT 3: Vâng, tôi loại bỏ với một này .. Tôi đã thiết lập mọi thứ một cách chính xác, và nhận được các sự kiện, nhưng có vấn đề tìm ra các sự kiện chính xác để lắng nghe ..
Vì có được một số lợi ích trong câu hỏi, nếu có ai muốn cố gắng để tiếp tục với điều này, đây là mã cuối cùng của tôi (nó hy vọng sẽ "làm việc" out-of-box):
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);
}
}
}
Có thể bạn cần khởi động máy bơm sự kiện. Nhìn vào vòng lặp 'GetMessage()' trong [mã ví dụ này] (https://github.com/twall/jna/blob/master/contrib/w32keyhook/com/sun/jna/contrib/demo/KeyHook.java) . Khi mã Java của bạn đang chạy máy bơm sự kiện, cửa sổ và móc sự kiện của bạn sẽ bắt đầu nhận tin nhắn đúng cách. – technomage
Bạn cũng có thể tận dụng 'Native.getWindowHandle()' của JNA để có được cửa sổ gốc xử lý, thay vì tra cứu dựa trên sự phản chiếu mà bạn đang sử dụng. Tùy thuộc vào cách các công cụ JavaFX xử lý các đồng nghiệp bản địa của nó, mặc dù. – technomage
@technomage Cảm ơn nhận xét của bạn. Tôi tạo ra một Chủ đề mới và bắt đầu bơm sự kiện này trong đó, và cửa sổ giờ đây thực sự đáp ứng với các sự kiện! Tuy nhiên, khi tôi nhấp vào biểu tượng thanh tác vụ của ứng dụng của tôi, CallWindowProcW không bao giờ được gọi. Nhưng, nó được gọi trên nhiều sự kiện khác: ví dụ: khi tôi tối đa hóa ứng dụng từ nút tối đa của riêng mình, tôi sẽ nhận được tin nhắn được in qua một cuộc gọi lại. Làm cách nào để tôi thực sự nắm bắt "sự kiện nhấp vào thanh tác vụ"? – user2499946