11

I have a JFrame that I minimize to the tray using:

This for showing:

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

And this for hiding:

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

However, I do NOT want to set the frame invisible.. When I set it invisible, it removes the taskbar icon which I like. Is there a way to remove the taskbar icon of the frame without setting the visibility to false?

The reason is because when I minimize my application, I can send it commands and it executes them but the second that I set its visibility to false, it stops executing any commands from an external application. All I need to do is remove the icon from the taskbar when minimized and show the icon when normal.

Any ideas?

Brandon
  • 22,723
  • 11
  • 93
  • 186
  • This post regarding how to [hide Jframe to SystemTray of Taskbar](http://stackoverflow.com/q/7461477/1057230), seems like what you exactly referring to, or SHALL I say possible duplicate of that thread ? :-) – nIcE cOw Jun 21 '13 at 06:57
  • No because that uses setVisible(false); And the second answer is the equivalent. All I want to do is remove the icon from the taskbar at will and add it back at will. – Brandon Jun 21 '13 at 07:19
  • I give up.. I can't believe something like this is so difficult in Java.. Quite ridiculous tbh.. Guess that's the difference between C++ and Java. :l – Brandon Jun 21 '13 at 07:56

2 Answers2

8

I know this is VERY late, but I spent a good hour trying to figure this out myself. All you have to do is change your JFrame to a JWindow and you're done. I had a fairly complex JFrame and the only things I had to remove were setUndecorated() and setDefaultCloseOperation(). everything else worked just fine.

Chris
  • 2,435
  • 6
  • 26
  • 49
6

sigh well seeing as there have been no replies for quite some time.. I decided to solve it using C++/JNI, and reflection as follows:

On the Java side:

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;
    }
}

On the JNI/C++ side (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
}

Compile the DLL with:

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

Or just use codeblocks to do it.

If anyone else has better ideas, feel free to add them or comment or anything.. I still can't believe I had to use C++/JNI, and reflection to do this.. Ridiculous.. It's the year 2013, Java needs to get with the program.

Community
  • 1
  • 1
Brandon
  • 22,723
  • 11
  • 93
  • 186
  • May you provide a complete workaround, a small example program, if its really not a heap of code to deal with. +1 on both sides for the effort though :-) – nIcE cOw Jun 21 '13 at 14:03
  • 1
    There.. Added a working example. I used codeblocks to compile the dll. It's one file aka main.cpp and the java app is one file as well. From there, adding it to the system tray is the same as in the OP except you don't need to set the frame invisible.. Just minimize it, add tray icon and call removeFromTaskbar. – Brandon Jun 21 '13 at 14:45