JFrame去掉任务栏图标

11

我有一个JFrame窗口,我使用以下代码将其最小化到托盘:

这是展示的代码:

Frame.this.Minimized = false;
Frame.this.setVisible(true);
systemTray.remove(systemTrayIcon);
Frame.this.setExtendedState(JFrame.NORMAL);

并且这是用于隐藏的:

if (SystemTray.isSupported()) {
    systemTray.add(systemTrayIcon);
    Frame.this.setVisible(false);
    Frame.this.Minimized = true;
}
Frame.this.setExtendedState(JFrame.ICONIFIED);

然而,我不想将框架设置为不可见。当我将它设置为不可见时,它会删除我喜欢的任务栏图标。有没有一种方法可以在不将可见性设置为false的情况下删除框架的任务栏图标?

原因是当我最小化我的应用程序时,我可以发送命令并执行它们,但是在将其可见性设置为false后,它停止执行来自外部应用程序的任何命令。我所需的只是在最小化时从任务栏中删除图标,在正常时显示图标。

有什么想法吗?


这篇关于如何将JFrame隐藏到任务栏的系统托盘中的帖子,似乎就是你所指的,或者我应该说可能是那个主题的重复? :-) - nIcE cOw
不行,因为那使用了setVisible(false);而第二个答案是等价的。我只想随意从任务栏中移除图标并随时将其添加回去。 - Brandon
我放弃了...我无法相信在Java中这样的事情会如此困难..说实话,这相当荒谬..我猜这就是C++和Java之间的区别。:l - Brandon
2个回答

8

我知道这已经很晚了,但是我花了一个小时的时间试图自己解决这个问题。你只需要将你的JFrame改为JWindow就可以了。我有一个相当复杂的JFrame,我只需要删除setUndecorated()setDefaultCloseOperation()即可。其他的都可以正常工作。


6

叹气 嗯,考虑到已经有相当长时间没有回复了...我决定使用C++/JNI和反射来解决它,如下所示:

在Java方面:

package apptotray;

import java.awt.*;
import java.io.File;
import java.nio.file.Paths;
import javax.swing.*;

public class AppToTray {

    public static void main(String[] args) {
        JFrame frame = new JFrame("Some Window");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLayout(new BorderLayout());
        frame.add(new JPanel(), BorderLayout.CENTER);
        frame.setPreferredSize(new Dimension(500, 500));
        frame.pack();
        frame.setVisible(true);
        
        System.load(new File("JNI.dll").getAbsolutePath());
        try {
            System.out.println("Icon is showing..");
            Thread.sleep(3000);
        } catch (Exception Ex) {
            Ex.printStackTrace();
        }
        
        removeFromTaskBar(getWindowHandle(frame));
        
        try {
            System.out.println("Icon is not showing..");
            Thread.sleep(3000);
        } catch (Exception Ex) {
            Ex.printStackTrace();
        }
        
        addToTaskBar(getWindowHandle(frame));
        System.out.println("Icon is showing again..");
    }
    
    public static native void addToTaskBar(long WindowHandle);
    
    public static native void removeFromTaskBar(long WindowHandle);

    public static long getWindowHandle(java.awt.Frame frame) {
        return (Long)invokeMethod(invokeMethod(frame, "getPeer"), "getHWnd");
    }

    protected static Object invokeMethod(Object o, String methodName) {
        Class c = o.getClass();
        for (java.lang.reflect.Method m : c.getMethods()) {
            if (m.getName().equals(methodName)) {
                try {
                    return m.invoke(o);
                } catch (IllegalAccessException | IllegalArgumentException | java.lang.reflect.InvocationTargetException Ex) {
                    Ex.printStackTrace();
                    break;
                }
            }
        }
        return null;
    }
}

在JNI/C++方面(Main.cpp):
#include <windows.h>
#include <shobjidl.h>
#include "jni.h"

#if defined _WIN32 || defined _WIN64
extern "C"
{
    const GUID CLSID_TaskbarList = {0x56FDF344, 0xFD6D, 0x11D0, {0x95, 0x8A, 0x00, 0x60, 0x97, 0xC9, 0xA0, 0x90}};

    const GUID IID_ITaskbarList = {0x56FDF342, 0xFD6D, 0x11D0, {0x95, 0x8A, 0x00, 0x60, 0x97, 0xC9, 0xA0, 0x90}};

    const GUID IID_ITaskbarList2 = {0x602D4995, 0xB13A, 0x429b, {0xA6, 0x6E, 0x19, 0x35, 0xE4, 0x4F, 0x43, 0x17}};

    const GUID IID_ITaskList3 = {0xEA1AFB91, 0x9E28, 0x4B86, {0x90, 0xE9, 0x9E, 0x9F, 0x8A, 0x5E, 0xEF, 0xAF}};
}
#endif

extern "C" JNIEXPORT void JNICALL Java_apptotray_AppToTray_addToTaskBar(JNIEnv *, jclass, jlong WindowHandle)
{
    #if defined _WIN32 || defined _WIN64
    ITaskbarList* TaskListPtr;
    CoInitialize(nullptr);
    long Result = !CoCreateInstance(CLSID_TaskbarList, nullptr, CLSCTX_SERVER, IID_ITaskbarList, reinterpret_cast<void**>(&TaskListPtr));
    if (Result) TaskListPtr->AddTab(reinterpret_cast<HWND>(WindowHandle));
    TaskListPtr->Release();
    CoUninitialize();
    #endif
}

extern "C" JNIEXPORT void JNICALL Java_apptotray_AppToTray_removeFromTaskBar(JNIEnv *, jclass, jlong WindowHandle)
{
    #if defined _WIN32 || defined _WIN64
    ITaskbarList* TaskListPtr;
    CoInitialize(nullptr);
    long Result = !CoCreateInstance(CLSID_TaskbarList, nullptr, CLSCTX_SERVER, IID_ITaskbarList, reinterpret_cast<void**>(&TaskListPtr));
    if (Result) TaskListPtr->DeleteTab(reinterpret_cast<HWND>(WindowHandle));
    TaskListPtr->Release();
    CoUninitialize();
    #endif
}

extern "C" bool __stdcall DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
    switch (fdwReason)
    {
        case DLL_PROCESS_ATTACH:
            // attach to process
            // return FALSE to fail DLL load
            break;

        case DLL_PROCESS_DETACH:
            // detach from process
            break;

        case DLL_THREAD_ATTACH:
            // attach to thread
            break;

        case DLL_THREAD_DETACH:
            // detach from thread
            break;
    }
    return TRUE; // succesful
}

使用以下命令编译DLL:
x86_64-w64-mingw32-g++.exe -O2 -Wall -DBUILD_DLL -std=c++11 -c C:\Users\Brandon\Desktop\JNI\main.cpp -o obj\Release\main.o x86_64-w64-mingw32-g++.exe -shared -Wl,--output-def=bin\Release\libJNI.def -Wl,--out-implib=bin\Release\libJNI.a -Wl,--dll obj\Release\main.o -o bin\Release\JNI.dll -s -static -static-libgcc -static-libstdc++ -lole32 -lshell32 -luser32
或者使用codeblocks来完成。如果有更好的想法,请随意添加或评论。我还是无法相信我不得不使用C++ / JNI和反射来完成这个任务。荒谬。现在已经是2013年了,Java需要跟上时代。

你能提供一个完整的解决方案吗?如果可以,请提供一个小型的示例程序,以便于处理,但不要太多代码。感谢你的努力,双方加1分 :-) - nIcE cOw
1
这里..添加了一个可工作的例子。我使用CodeBlocks编译dll。它只有一个文件即main.cpp,Java应用程序也只有一个文件。从那里开始,将其添加到系统托盘与OP中一样,除了您不需要设置框架不可见..只需将其最小化,添加托盘图标并调用removeFromTaskbar。 - Brandon

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接