- Published on
Java로 트레이 아이콘 등록하기
- Authors
- Name
- Hyesung Lee
- GitHub
- @silentsoft
 
 
Java에서 기본적으로 제공하는 SystemTray 클래스를 이용하면 아이콘을 등록거나,
메뉴를 등록하거나, 메세지를 띄우는건 의외로 간단하다.
void java.awt.SystemTray.add(TrayIcon trayIcon) throws AWTException
SystemTray.add() 메소드는 시스템 트레이에 트레이 아이콘을 등록해주는 메소드이다. 이 메소드를 사용해서 트레이 아이콘을 추가해보도록 하자.
우선, 한번 만들고 범용적으로 쓸 수 있도록 TrayIconHandler 클래스를 만들고,
아래와 같이 trayIcon 선언과 registerTrayIcon() 메소드를 작성하자.
private static TrayIcon trayIcon;
public static void registerTrayIcon(Image image, String toolTip, ActionListener action) {
	if (SystemTray.isSupported()) {
		if (trayIcon != null) {
			trayIcon = null;
		}
		trayIcon = new TrayIcon(image);
		trayIcon.setImageAutoSize(true);
		if (toolTip != null) {
			trayIcon.setToolTip(toolTip);
		}
		if (action != null) {
			trayIcon.addActionListener(action);
		}
		try {
			for (TrayIcon registeredTrayIcon : SystemTray.getSystemTray()
					.getTrayIcons()) {
				SystemTray.getSystemTray().remove(registeredTrayIcon);
			}
			SystemTray.getSystemTray().add(trayIcon);
		} catch (AWTException e) {
			LOGGER.error("I got catch an error during add system tray !", e);
		}
	} else {
		LOGGER.error("System tray is not supported !");
	}
}
Parameters
- image : 시스템 트레이에 등록될 아이콘 이미지.
- toolTip : 아이콘에 마우스를 올렸을 때 보여질 메세지.
- action : 아이콘을 더블 클릭했을 때 실행 할 행동을 정의한 ActionListener.
사용 예는 아래와 같다.
public static void main(String[] args) {
	TrayIconHandler.registerTrayIcon(
		Toolkit.getDefaultToolkit().getImage("src/main/resources/icon/computer.png"),
		"Example",
		new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				System.exit(0);
			}
		}
	);
}
src/main/resources/icon 폴더 밑에 computer.png 아이콘 파일을 넘겨주고, 마우스로 올려질 때 보여질 "Example", 그리고 더블 클릭했을 때 종료되는 코드이다.
이제 오른쪽 클릭했을 때 보여질 아이템을 추가하고, 아이템에 대한 액션을 정의해보자.
getPopupMenu(), add(), isRegistered(), isNotRegistered(), addItem() 총 4개의 메소드를 TrayIconHandler 클래스에 아래와 같이 정의한다.
private static PopupMenu getPopupMenu() {
	PopupMenu popupMenu = trayIcon.getPopupMenu();
	if (popupMenu == null) {
		popupMenu = new PopupMenu();
	}
	return popupMenu;
}
private static void add(MenuItem item) {
	if (isNotRegistered()) {
		return;
	}
	PopupMenu popupMenu = getPopupMenu();
	popupMenu.add(item);
	trayIcon.setPopupMenu(popupMenu);
}
public static boolean isRegistered() {
	return (trayIcon != null && getPopupMenu() != null) ? true : false;
}
public static boolean isNotRegistered() {
	return !isRegistered();
}
public static void addItem(String label, ActionListener action) {
	MenuItem menuItem = new MenuItem(label);
	menuItem.addActionListener(action);
	add(menuItem);
}
그리고 아래와 같이 addItem() 메소드를 호출하자.
public static void main(String[] args) {
	TrayIconHandler.registerTrayIcon(
		Toolkit.getDefaultToolkit().getImage("src/main/resources/icon/computer.png"),
		"Example",
		new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				// Open your application here.
			}
		}
	);
	TrayIconHandler.addItem("Exit", new ActionListener() {
		@Override
		public void actionPerformed(ActionEvent e) {
			System.exit(0);
		}
	});
}
앞서 더블 클릭했을 때 수행하던 프로그램 종료 코드를 삭제하고, Exit 아이템을 클릭했을 때 종료하도록 변경했다.
트레이 아이콘 근처에 팝업 메세지를 띄우는 것도 가능하다.
아래와 같이 displayMessage() 메소드를 TrayIconHandler 클래스에 정의하자.
public static void displayMessage(String caption, String text, MessageType messageType) {
	if (isNotRegistered()) {
		return;
	}
	trayIcon.displayMessage(caption, text, messageType);
}
프로그램이 시작될 때 팝업 메세지를 보여주도록 displayMessage() 메소드를 호출하자.
public static void main(String[] args) {
	TrayIconHandler.registerTrayIcon(
		Toolkit.getDefaultToolkit().getImage("src/main/resources/icon/computer.png"),
		"Example",
		new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				// Open your application here.
			}
		}
	);
	TrayIconHandler.addItem("Exit", new ActionListener() {
		@Override
		public void actionPerformed(ActionEvent e) {
			System.exit(0);
		}
	});
	TrayIconHandler.displayMessage("Silentsoft", "Benefit the world !", MessageType.INFO);
}
이제 프로그램이 시작될 때 팝업 메세지가 보여진다.
MessageType은 INFO 이외에도 WARNING, ERROR, NONE을 사용할 수 있다.
package org.silentsoft.core.tray;
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.TrayIcon.MessageType;
import java.awt.event.ActionListener;
import java.awt.event.ItemListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public final class TrayIconHandler {
	private static Logger LOGGER = LoggerFactory
			.getLogger(TrayIconHandler.class);
	private static TrayIcon trayIcon;
	private static PopupMenu getPopupMenu() {
		PopupMenu popupMenu = trayIcon.getPopupMenu();
		if (popupMenu == null) {
			popupMenu = new PopupMenu();
		}
		return popupMenu;
	}
	private static void add(MenuItem item) {
		if (isNotRegistered()) {
			return;
		}
		PopupMenu popupMenu = getPopupMenu();
		popupMenu.add(item);
		trayIcon.setPopupMenu(popupMenu);
	}
	private static void addToMenu(String menu, MenuItem item) {
		if (isNotRegistered()) {
			return;
		}
		if (isNotExistsMenu(menu)) {
			addMenu(menu);
		}
		for (int i = 0, j = getPopupMenu().getItemCount(); i < j; i++) {
			if (getPopupMenu().getItem(i) instanceof Menu) {
				Menu menuitem = (Menu) getPopupMenu().getItem(i);
				if (menuitem.getLabel().equals(menu)) {
					menuitem.add(item);
					getPopupMenu().insert(menuitem, i);
					break;
				}
			}
		}
	}
	public static boolean isRegistered() {
		return (trayIcon != null && getPopupMenu() != null) ? true : false;
	}
	public static boolean isNotRegistered() {
		return !isRegistered();
	}
	public static boolean isExistsMenu(String menu) {
		if (isNotRegistered()) {
			return false;
		}
		for (int i = 0, j = getPopupMenu().getItemCount(); i < j; i++) {
			if (getPopupMenu().getItem(i) instanceof Menu) {
				Menu item = (Menu) getPopupMenu().getItem(i);
				if (item.getLabel().equals(menu)) {
					return true;
				}
			}
		}
		return false;
	}
	public static boolean isNotExistsMenu(String menu) {
		return !isExistsMenu(menu);
	}
	public static void registerTrayIcon(Image image) {
		registerTrayIcon(image, null, null);
	}
	public static void registerTrayIcon(Image image, String toolTip) {
		registerTrayIcon(image, toolTip, null);
	}
	public static void registerTrayIcon(Image image, String toolTip,
			ActionListener action) {
		if (SystemTray.isSupported()) {
			if (trayIcon != null) {
				trayIcon = null;
			}
			trayIcon = new TrayIcon(image);
			trayIcon.setImageAutoSize(true);
			if (toolTip != null) {
				trayIcon.setToolTip(toolTip);
			}
			if (action != null) {
				trayIcon.addActionListener(action);
			}
			try {
				for (TrayIcon registeredTrayIcon : SystemTray.getSystemTray()
						.getTrayIcons()) {
					SystemTray.getSystemTray().remove(registeredTrayIcon);
				}
				SystemTray.getSystemTray().add(trayIcon);
			} catch (AWTException e) {
				LOGGER.error("I got catch an error during add system tray !", e);
			}
		} else {
			LOGGER.error("System tray is not supported !");
		}
	}
	public static void setToolTip(String toolTip) {
		if (isNotRegistered()) {
			return;
		}
		trayIcon.setToolTip(toolTip);
	}
	public static void setImage(Image image) {
		if (isNotRegistered()) {
			return;
		}
		trayIcon.setImage(image);
	}
	public static void displayMessage(String caption, String text,
			MessageType messageType) {
		if (isNotRegistered()) {
			return;
		}
		trayIcon.displayMessage(caption, text, messageType);
	}
	public static void addSeparator() {
		if (isNotRegistered()) {
			return;
		}
		getPopupMenu().addSeparator();
	}
	public static void addSeparator(String menu) {
		if (isNotRegistered()) {
			return;
		}
		for (int i = 0, j = getPopupMenu().getItemCount(); i < j; i++) {
			if (getPopupMenu().getItem(i) instanceof Menu) {
				Menu item = (Menu) getPopupMenu().getItem(i);
				if (item.getLabel().equals(menu)) {
					item.addSeparator();
					getPopupMenu().insert(item, i);
					break;
				}
			}
		}
	}
	public static void addMenu(String menu) {
		add(new Menu(menu));
	}
	public static void addItem(String label, ActionListener action) {
		MenuItem menuItem = new MenuItem(label);
		menuItem.addActionListener(action);
		add(menuItem);
	}
	public static void addCheckBox(String label, ItemListener action) {
		addCheckBox(label, false, action);
	}
	public static void addCheckBox(String label, boolean state,
			ItemListener action) {
		CheckboxMenuItem checkboxMenuItem = new CheckboxMenuItem(label, state);
		checkboxMenuItem.addItemListener(action);
		add(checkboxMenuItem);
	}
	public static void addItemToMenu(String menu, String label,
			ActionListener action) {
		MenuItem menuItem = new MenuItem(label);
		menuItem.addActionListener(action);
		addToMenu(menu, menuItem);
	}
	public static void addCheckBoxToMenu(String menu, String label,
			ItemListener action) {
		addCheckBoxToMenu(menu, label, false, action);
	}
	public static void addCheckBoxToMenu(String menu, String label,
			boolean state, ItemListener action) {
		CheckboxMenuItem checkboxMenuItem = new CheckboxMenuItem(label, state);
		checkboxMenuItem.addItemListener(action);
		addToMenu(menu, checkboxMenuItem);
	}
}
포스트에는 소개하지 않았지만, 위 TrayIconHandler 클래스에 구분선 추가, 메뉴 추가, 메뉴 안에 메뉴 혹은 아이템 추가, 체크박스를 추가할 수 있도록 구현해 놓았다.
코드가 너무 간단해서 별도의 주석은 없다.