简体   繁体   English

仅在Java中没有停靠/任务栏图标的系统托盘中运行

[英]Run only in system tray with no dock/taskbar icon in Java

Is it possible for a Java application, a .jar one to be exact, to run only in the SystemTray without the user seeing anything on his taskbar/dock but having visible components like a JWindow ? 是否有可能Java应用程序(精确的.jar只能在SystemTray运行,而用户不会在任务栏/ Dock上看到任何内容,而是拥有像JWindow这样的可见组件?
An example would be Dropbox's app for MacOS, which has the following window appear from the SystemTray while still having no visible icon at the dock. 一个例子是Dropbox的MacOS应用程序,它在SystemTray显示以下窗口,同时码头上仍然没有可见图标。

If so then how can that be done? 如果是这样,那怎么办呢?

Yes it can be done. 是的,可以做到。 Here is some sample code that adds a menu to a tray icon and adds a listener to a menu item in that menu which creates a dialog with the user clicks the item. 下面是一些示例代码,它将菜单添加到托盘图标,并将监听器添加到该菜单中的菜单项,该菜单项创建了一个用户单击该项目的对话框。 When I create a runnable jar with this code it does not display an icon on the taskbar, it only shows the icon in the system tray. 当我使用此代码创建一个可运行的jar时,它不会在任务栏上显示图标,它只显示系统托盘中的图标。

import java.awt.AWTException;
import java.awt.Image;
import java.awt.SystemTray;
import java.awt.TrayIcon;
import java.awt.Menu;
import java.awt.MenuItem;
import java.awt.PopupMenu;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.net.URL;

import javax.swing.ImageIcon;
import javax.swing.JOptionPane;

public class SystemTrayExample {
    private static final SystemTray tray = SystemTray.getSystemTray();
    private static final PopupMenu popup = new PopupMenu();
    private static TrayIcon trayIcon;

    public static void main(String[] args) {

        if (!SystemTray.isSupported()) {
            // SystemTray is not supported
        }

        trayIcon = new TrayIcon(createImage("icon.jpg", "tray icon"));
        trayIcon.setImageAutoSize(true);

        ActionListener listener = new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                MenuItem item = (MenuItem) e.getSource();

                String s = (String) JOptionPane.showInputDialog(null, "Report "
                        + item.getLabel(), "Create Report",
                        JOptionPane.PLAIN_MESSAGE, null, null, "");

                // Do something with the string...
            }
        };
        MenuItem exitItem = new MenuItem("Exit");
        exitItem.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                tray.remove(trayIcon);
                System.exit(0);
            }
        });


        Menu reportMenu = new Menu("Report");
        MenuItem menuItem = new MenuItem("Item");
        reportMenu.add(menuItem);
        menuItem.addActionListener(listener);
        popup.add(reportMenu);
        popup.add(exitItem);
        trayIcon.setPopupMenu(popup);

        try {
            tray.add(trayIcon);
        } catch (AWTException e) {
            // TrayIcon could not be added
        }

    }

    // Obtain the image URL
    protected static Image createImage(String path, String description) {
        URL imageURL = SystemTrayExample.class.getResource(path);

        if (imageURL == null) {
            System.err.println("Resource not found: " + path);
            return null;
        } else {
            return (new ImageIcon(imageURL, description)).getImage();
        }
    }
}

Sure it can be done (for Windows anyways). 当然可以做到(对于Windows无论如何)。 Here is a runnable example with a popup menu. 这是一个带弹出菜单的可运行示例。 The icon displayed in the tray is retrieved from a URL (use whatever Icon you want: 托盘中显示的图标是从URL中检索的(使用您想要的任何图标:

import java.awt.AWTException;
import java.awt.CheckboxMenuItem;
import java.awt.Image;
import java.awt.Menu;
import java.awt.MenuItem;
import java.awt.PopupMenu;
import java.awt.SystemTray;
import java.awt.TrayIcon;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;


public class TrayIconDemo2 {

    public TrayIconDemo2() throws Exception {
        initComponents();
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    new TrayIconDemo2();
                } catch (Exception ex) { System.out.println("Error - " + ex.getMessage()); }
            }
        });
    }

    private void initComponents() throws Exception {
        createAndShowTray();
    }

    private void createAndShowTray() throws Exception {
        //Check the SystemTray is supported
        if (!SystemTray.isSupported()) {
            System.out.println("SystemTray is not supported");
            return;
        }

        PopupMenu popup = new PopupMenu();
        //retrieve icon form url and scale it to 32 x 32
        final TrayIcon trayIcon = new TrayIcon(ImageIO.read(
                new URL("http://www.optical-illusions.com/thumb/ec665b8dfcc248da272224972e9eaf92.jpg"))
                .getScaledInstance(32, 32, Image.SCALE_SMOOTH), null);

        //get the system tray
        final SystemTray tray = SystemTray.getSystemTray();

        // Create a pop-up menu components
        MenuItem aboutItem = new MenuItem("About");
        aboutItem.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent ae) {
                JOptionPane.showMessageDialog(null, "About");
            }
        });

        final  CheckboxMenuItem cb1 = new CheckboxMenuItem("Show Tooltip");
        cb1.addItemListener(new ItemListener() {
            @Override
            public void itemStateChanged(ItemEvent ie) {
                if(cb1.getState()==true) {
                trayIcon.setToolTip("Hello, world");
                }else {
                trayIcon.setToolTip("");
                }
            }
        });

        Menu displayMenu = new Menu("Display");

        MenuItem infoItem = new MenuItem("Info");
        //add actionlistner to Info menu item
        infoItem.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent ae) {
                JOptionPane.showMessageDialog(null, "Display Info of some sort :D");
            }
        });

        MenuItem exitItem = new MenuItem("Exit");
        //add actionlistner to Exit menu item
        exitItem.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent ae) {
                System.exit(0);
            }
        });

        //Add components to pop-up menu
        popup.add(aboutItem);
        popup.addSeparator();
        popup.add(cb1);
        popup.addSeparator();
        popup.add(displayMenu);
        displayMenu.add(infoItem);
        popup.add(exitItem);

        trayIcon.setPopupMenu(popup);

        try {
            tray.add(trayIcon);
        } catch (AWTException e) {
            System.out.println("TrayIcon could not be added.");
        }
    }
}

You can display whatever you like from your system tray icon but you should do it via a popup menu. 您可以从系统托盘图标中显示任何您喜欢的内容,但您应该通过弹出菜单进行显示。

Put this line: 把这一行:

System.setProperty("apple.awt.UIElement", "true");

as first statement in your main: 作为主要内容的第一个陈述:

public static void main(String[] args) {
    System.setProperty("apple.awt.UIElement", "true");
    // Your stuff...
}

I have succesfully tried it with "TrayIconDemo2" example by @DevilsHnd that you can find as another answer in this page. 我已成功通过@DevilsHnd的“TrayIconDemo2”示例尝试了它,您可以在此页面中找到另一个答案。


By the way I'll add something more giving credits to this answer by @Muhammad Usman. 顺便说一句,我会添加更多东西给@Muhammad Usman的答案 I have pasted all the answer that I have checked as correct below: 我已经粘贴了我在下面检查过的所有答案:

According to JavaFX you cannot hide dock icon in JavaFX application. 根据JavaFX,您无法在JavaFX应用程序中隐藏停靠图标。 Please view this link . 请查看此链接

There are two ways to hide dock icon. 隐藏停靠图标有两种方法。

  • Apple standard way, just modify *.app/Contents/Info.plist and add <key>LSUIElement</key> <string>1</string> . Apple标准方式,只需修改* .app / Contents / Info.plist并添加<key>LSUIElement</key> <string>1</string>
  • Start your application as AWT application and hide dock icon using system property. 以AWT应用程序启动应用程序并使用系统属性隐藏停靠图标。 After setting system property call the JavaFX main method and JavaFX application will take over now with no dock icon. 设置系统属性调用后,JavaFX主方法和JavaFX应用程序将立即接管,没有停靠图标。 Please see the sample code snippet below. 请参阅下面的示例代码段。

 /** - This class is intended to start application as AWT application before initializing - JavaFX application. JavaFX does not support dock-icon-less application so we are - creating JavaFX application from AWT application so that we can achieve the desired - functionality. - */ public class AWTMain { public static void main(String[] args) { // This is awt property which enables dock-icon-less // applications System.setProperty("apple.awt.UIElement", "true"); java.awt.Toolkit.getDefaultToolkit(); // This is a call to JavaFX application main method. // From now on we are transferring control to FX application. FXMain.main(args); } } 

Here FXMain is referred as previous class with main method. 这里FXMain被称为主类方法的前一类。

You will also need to modify your .pom file if you are using maven and other places too where you have mentioned main class for application. 如果你正在使用maven和其他地方,你也需要修改.pom文件,你提到应用程序的主类。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM