[WinAPI] Tray Icon, 트레이아이콘

오늘은 트레이아이콘에 대해 알아보겠습니다.

아래 그림과 같이 작업표시줄 우측에 조그만 그림으로 표시된 것을 트레이 아이콘이라 합니다.

트레이 아이콘은 아이콘 표시 뿐만 아니라, 알람과 메뉴를 만들수 있어서 사용 편의성을 위해서 많이 사용 됩니다.

이번 글에서는 트레이 아이콘을 생성변경삭제알람 표시메뉴 표시까지 해보겠습니다.

1. 트레이 아이콘 만들기전 세팅

우선 MFC 대화상자로 프로젝트 생성해주시고 아래와 같이 생성, 작제 변경, 알람 버튼 4개를 만들어 줍니다.

Make 버튼: IDC_BTN_MAKE, Delete 버튼: IDC_BTN_DEL, Modify 버튼: IDC_BTN_MOD, Alarm 버튼: IDC_BTN_ALARM

그리고 아래 파일을 받으셔서 트레이 아이콘 두개를 ‘프로젝트 폴더 -> res’ 위치에 복사 해 줍니다.

그리고 난 뒤 아래 그림처럼 우클릭 -> 리소스 추가를 하여 아이콘을 추가합니다.

2. 트레이 아이콘 생성

헤더파일에 아래와 같이 트레이 아이콘 메시지와 트레이 아이콘 고유 아이디를 선언합니다.

#define TRAY_ICON_ID		1000
#define WM_TRAYICON_MSG		WM_USER + 1

생성 버튼을 더블 클릭 하시고 아래와 같이 코딩합니다.

void CTrayIconDlg::OnBnClickedBtnMake()
{
	// TODO: Add your control notification handler code here
	NOTIFYICONDATA  nid;
	TCHAR atcModuleName[_MAX_PATH];
	CString sModuleName;

	nid.cbSize = sizeof( nid );
	nid.hWnd = this->m_hWnd; // 메인 윈도우 핸들
	nid.uID = TRAY_ICON_ID;  // 아이콘 ID
	nid.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP; // 플래그 설정
	nid.uCallbackMessage = WM_TRAYICON_MSG; // 콜백메시지 설정
	nid.hIcon = AfxGetApp()->LoadIcon( IDI_ICON1 ); // 아이콘 로드  
	nid.uTimeout = 1000;

	::GetModuleFileName( ::AfxGetInstanceHandle(), atcModuleName, _MAX_PATH );
	sModuleName = PathFindFileName( atcModuleName );
	_tcscpy_s( atcModuleName, sModuleName.GetLength() + 1, sModuleName );
	lstrcpy( nid.szTip, atcModuleName );

	Shell_NotifyIcon( NIM_ADD, &nid );
}
3. 트레이 아이콘 삭제

삭제 버튼을 더블 클릭한 뒤 아래와 같이 코딩합니다.

void CTrayIconDlg::OnBnClickedBtnDel()
{
	// TODO: Add your control notification handler code here
	NOTIFYICONDATA  nid;
	nid.cbSize = sizeof( nid );
	nid.hWnd = this->m_hWnd; // 메인 윈도우 핸들
	nid.uID = TRAY_ICON_ID;

	// 작업 표시줄(TaskBar)의 상태 영역에 아이콘을 삭제한다.
	Shell_NotifyIcon( NIM_DELETE, &nid );
}
4. 트레이 아이콘 변경

변경 버튼을 더블 클릭한 뒤 아래와 같이 코딩합니다.

void CTrayIconDlg::OnBnClickedBtnDel()
{
	// TODO: Add your control notification handler code here
	NOTIFYICONDATA  nid;
	nid.cbSize = sizeof( nid );
	nid.hWnd = this->m_hWnd; // 메인 윈도우 핸들
	nid.uID = TRAY_ICON_ID;

	// 작업 표시줄(TaskBar)의 상태 영역에 아이콘을 삭제한다.
	Shell_NotifyIcon( NIM_DELETE, &nid );
}
5. 알람 표시

알람 버튼을 더블 클릭한 뒤 아래와 같이 코딩합니다.

void CTrayIconDlg::OnBnClickedBtnDel()
{
	// TODO: Add your control notification handler code here
	NOTIFYICONDATA  nid;
	nid.cbSize = sizeof( nid );
	nid.hWnd = this->m_hWnd; // 메인 윈도우 핸들
	nid.uID = TRAY_ICON_ID;

	// 작업 표시줄(TaskBar)의 상태 영역에 아이콘을 삭제한다.
	Shell_NotifyIcon( NIM_DELETE, &nid );
}
6. 메뉴 표시

클래스 뷰에서 대화상자 선택 후 재정의 함수 중에 WindowProc 함수를 선택합니다.

WindowProc 함수에 아래와 같이 코딩합니다.

LRESULT CTrayIconDlg::WindowProc( UINT message, WPARAM wParam, LPARAM lParam )
{
	// TODO: 여기에 특수화된 코드를 추가 및/또는 기본 클래스를 호출합니다.
	switch ( message )
	{
		// 콜백 메시지
	case WM_TRAYICON_MSG:
		{
			// 트레이 아이콘 ID
			if ( TRAY_ICON_ID == wParam )
			{
				// 동작
				switch ( lParam )
				{
				case WM_RBUTTONUP:	// 우클릭
					CPoint pntCursor;
					HMENU hMenu = CreatePopupMenu();

					AppendMenu( hMenu, MF_STRING, WM_DLG_CLOSE, _T( "종료" ) );

					SetForegroundWindow();			// 생성된 팝업 메뉴 밖을 클릭할 때 팝업 닫기

					// 팝업 메뉴 띄우기
					GetCursorPos( &pntCursor );
					TrackPopupMenu( hMenu, TPM_LEFTALIGN | TPM_RIGHTBUTTON, pntCursor.x, pntCursor.y, 0, this->m_hWnd, NULL );
					break;
				}
			}
		}
		break;
        
	case WM_COMMAND:
		{
			if ( WM_DLG_CLOSE == wParam )
			{
				OnBnClickedCancel();
			}
		}
		break;
	}

	return CDialogEx::WindowProc( message, wParam, lParam );
}

헤더파일에 아래 메시지를 정의합니다.

#define WM_DLG_CLOSE		WM_USER + 2

트레이 아이콘을 우클릭 하면 종료 메뉴가 나오게 했고 그 메뉴를 선택하면 대화 상자가 종료되는 코드입니다.
끝으로 트레이 아이콘은 작업표시줄에 종속적이다보니 작업표시줄이 생성되지 않으면 트레이 아이콘도 표시되지 않습니다.
그럴때엔 taskbarcreated 메시지를 수신하여 작업표시줄이 생성 될 때 트레이 아이콘을 생성하시면 됩니다.
자세한건 구글 검색으로 taskbarcreated 하시면 많은 자료가 나옵니다.

이상으로 트레이 아이콘에 대해 알아보았습니다.