회사에서 뷰 화면에 메뉴를 ‘이쁘게’ 만들어 달라는 요구사항이 들어왔습니다. MFC 화면에 이쁘게라니..
요구 사항이니 CToolBarCtrl 사용하여 아래와 같은 화면을 만들어 보겠습니다.
메시지 정의, 멤버 변수&함수 선언
먼저 뷰나 대화상자를 생성한 뒤 헤더파일에 아래와 같이 메시지들을 정의합니다.
// 클릭 메시지
#define WM_COMMAND1 (WM_USER + 1)
#define WM_COMMAND2 (WM_USER + 2)
#define WM_COMMAND3 (WM_USER + 3)
#define WM_COMMAND4 (WM_USER + 4)
#define WM_COMMAND5 (WM_USER + 5)
#define WM_COMMAND6 (WM_USER + 6)
#define WM_COMMAND7 (WM_USER + 7)
// 메뉴
#define WM_MENU1_1 (WM_USER + 13)
#define WM_MENU1_2 (WM_USER + 14)
#define WM_MENU1_3 (WM_USER + 15)
#define WM_MENU2_1 (WM_USER + 16)
#define WM_MENU2_2 (WM_USER + 17)
#define WM_MENU3 (WM_USER + 18)
멤버 변수도 선언해줍니다.
CToolBarCtrl m_toolbar; // 툴바 컨트롤
CImageList *m_pIconList; // 이미지 리스트
CArray<int, int> m_arrIcons; // 툴바 이미지
CArray<CString, CString> m_arrString; // 툴바 버튼 문자열
CArray<int, int> m_arrCommand; // 툴바 클릭 명령 처리
이 변수들은 생성자와 소멸자에 아래와 같이 코딩해주세요
// 생성자
m_pIconList = new CImageList;
m_arrIcons.RemoveAll();
m_arrIcons.Add(IDI_ICON1);
m_arrIcons.Add(IDI_ICON2);
m_arrIcons.Add(IDI_ICON3);
m_arrIcons.Add(IDI_ICON4);
m_arrIcons.Add(IDI_ICON5);
m_arrIcons.Add(IDI_ICON6);
m_arrIcons.Add(IDI_ICON7);
m_arrString.RemoveAll();
m_arrString.Add(_T("버튼1"));
m_arrString.Add(_T("버튼2"));
m_arrString.Add(_T("버튼3"));
m_arrString.Add(_T("버튼4"));
m_arrString.Add(_T("버튼5"));
m_arrString.Add(_T("버튼6"));
m_arrString.Add(_T("버튼7"));
m_arrCommand.RemoveAll();
m_arrCommand.Add(WM_COMMAND1);
m_arrCommand.Add(WM_COMMAND2);
m_arrCommand.Add(WM_COMMAND3);
m_arrCommand.Add(WM_COMMAND4);
m_arrCommand.Add(WM_COMMAND5);
m_arrCommand.Add(WM_COMMAND6);
m_arrCommand.Add(WM_COMMAND7);
// 소멸자
if (m_pIconList != NULL)
{
m_pIconList->DeleteImageList();
delete m_pIconList;
}
m_pIconList = NULL;
m_arrIcons.RemoveAll();
m_arrString.RemoveAll();
m_arrCommand.RemoveAll();
각 동작에 대한 멤버 함수들도 선언해줍니다.
void CreateToolBarByIcon(void); // 툴바 생성
afx_msg void OnBnClickedByIcon(UINT uiRes); // 버튼 클릭
afx_msg BOOL OnNotifyToolBar(UINT uiID, NMHDR * pNMHDR, LRESULT * pResult); // 마우스 오버시 툴팁
afx_msg BOOL OnToolbarDropDown(UINT uiID, NMHDR * pNMHDR, LRESULT * pResult); // 드롭다운 버튼클릭 메뉴 표시
툴바 생성
우선 툴바를 생성해보겠습니다. CreateToolBar를 아래와 같이 정의해주고, 뷰는 OnInitialUpdate에서 , 대화상자에서는 OnInitDialog에서 호출해주세요.
void CMFCApplication1Dlg::CreateToolBarByIcon(void)
{
// 툴바 생성
CRect rectGw(0, 0, 0, 0);
BOOL bCreate = m_toolbar.Create(TBSTYLE_FLAT | TBSTYLE_TOOLTIPS | TBSTYLE_TRANSPARENT | WS_CHILD | WS_VISIBLE | WS_BORDER | CCS_TOP,
rectGw, this, IDR_TOOLBAR1);
if (!bCreate)
return;
// 드롭다운 화살표 표시를 위한 스타일 변경
DWORD dwStyle = m_toolbar.GetExtendedStyle();
m_toolbar.SetExtendedStyle(dwStyle | TBSTYLE_EX_DRAWDDARROWS);
// 툴바에 사용되는 이미지 설정
int iIconCount = m_arrIcons.GetCount();
m_pIconList->Create(16, 16, ILC_COLOR32 | ILC_MASK, iIconCount, 0); // 이미지리스트 생성
for (int i = 0 ; i < iIconCount ; i++)
m_pIconList->Add(AfxGetApp()->LoadIcon(m_arrIcons.GetAt(i))); // icon 로드
m_toolbar.SetImageList(m_pIconList); // 이미지리스트 툴바에 설정
// 버튼 설정
for (int iIndex = 0; iIndex < iIconCount ; iIndex++)
{
if (iIndex <= 4)
{
// 버튼 추가
TBBUTTON TBButton;
memset(&TBButton, 0, sizeof(TBButton));
TBButton.iString = m_toolbar.AddStrings(m_arrString.GetAt(iIndex));
TBButton.fsState = TBSTATE_ENABLED;
TBButton.fsStyle = TBSTYLE_BUTTON;
TBButton.iBitmap = iIndex;
TBButton.idCommand = m_arrCommand.GetAt(iIndex);
m_toolbar.AddButtons(1, &TBButton);
}
else
{
// 버튼과 드롭다운 분리
if (iIndex == 5)
{
TBBUTTON sepButton;
memset(&sepButton, 0, sizeof(sepButton));
sepButton.fsStyle = TBSTYLE_SEP;
m_toolbar.AddButtons(1, &sepButton);
}
// 드롭다운 버튼 추가
TBBUTTON TBButton;
memset(&TBButton, 0, sizeof(TBButton));
TBButton.iString = m_toolbar.AddStrings(m_arrString.GetAt(iIndex));
TBButton.fsState = TBSTATE_ENABLED;
TBButton.fsStyle = TBSTYLE_BUTTON | TBSTYLE_DROPDOWN;
TBButton.iBitmap = iIndex;
TBButton.idCommand = m_arrCommand.GetAt(iIndex);
m_toolbar.AddButtons(1, &TBButton);
}
}
//Auto Resize Toolbar
m_toolbar.AutoSize();
}
여기까지 만든 후 실행하면 화면에 툴바가 생성되어 있고, 버튼과, 드롭다운 버튼이 생성 되어 있을 겁니다.
버튼 클릭 메시지 처리
툴바의 버튼을 클릭 했을 때 메시지 처리를 위해 OnBnClickedByIcon 함수를 아래와 같이 정의합니다.
void CMFCApplication1Dlg::OnBnClickedByIcon(UINT uiRes)
{
CString strMsg = _T("");
switch (uiRes)
{
case WM_COMMAND1:
strMsg.Format(_T("WM_COMMAND1"));
break;
case WM_COMMAND2:
strMsg.Format(_T("WM_COMMAND2"));
break;
case WM_COMMAND3:
strMsg.Format(_T("WM_COMMAND3"));
break;
case WM_COMMAND4:
strMsg.Format(_T("WM_COMMAND4"));
break;
case WM_COMMAND5:
strMsg.Format(_T("WM_COMMAND5"));
break;
case WM_COMMAND6:
strMsg.Format(_T("WM_COMMAND6"));
break;
case WM_COMMAND7:
strMsg.Format(_T("WM_COMMAND7"));
break;
default:
strMsg = _T("Unknown");
break;
}
AfxMessageBox(strMsg);
}
OnBnClickedByIcon 함수는 아래와 같이 메세지 맵에 등록이 되어있어야합니다.
BEGIN_MESSAGE_MAP(CMFCApplication1Dlg, CDialogEx)
ON_CONTROL_RANGE(BN_CLICKED, WM_COMMAND1, WM_COMMAND7, CMFCApplication1Dlg::OnBnClickedByIcon)
END_MESSAGE_MAP()
마우스 오버 시 툴팁 표시
툴팁 표시를 위해 OnNotifyToolBar 함수 정의를 해줍니다. 마찬가지로 메시지 맵에 등록되어 있어야합니다.
// 메시지맵
BEGIN_MESSAGE_MAP(CMFCApplication1Dlg, CDialogEx)
// ...
ON_NOTIFY_EX(TTN_NEEDTEXT, 0, &CMFCApplication1Dlg::OnNotifyToolBar)
END_MESSAGE_MAP()
BOOL CMFCApplication1Dlg::OnNotifyToolBar(UINT uiID, NMHDR * pNMHDR, LRESULT * pResult)
{
if (pNMHDR->code == TTN_NEEDTEXT)
{
TOOLTIPTEXT *pTTT = (TOOLTIPTEXT*)pNMHDR;
CString strToolTip(_T(""));
switch (pNMHDR->idFrom)
{
case WM_COMMAND1:
strToolTip.Format(_T("WM_COMMAND1"));
break;
case WM_COMMAND2:
strToolTip.Format(_T("WM_COMMAND2"));
break;
case WM_COMMAND3:
strToolTip.Format(_T("WM_COMMAND3"));
break;
case WM_COMMAND4:
strToolTip.Format(_T("WM_COMMAND4"));
break;
case WM_COMMAND5:
strToolTip.Format(_T("WM_COMMAND5"));
break;
case WM_COMMAND6:
strToolTip.Format(_T("WM_COMMAND6"));
break;
case WM_COMMAND7:
strToolTip.Format(_T("WM_COMMAND7"));
break;
default:
strToolTip = _T("");
break;
}
// lpszText
if (!strToolTip.IsEmpty())
pTTT->lpszText = (LPTSTR)(LPCTSTR)strToolTip;
// szText
//mset(pTTT->szText, 0, sizeof(pTTT->szText));
// (!strToolTip.IsEmpty())
//emcpy(pTTT->szText, strToolTip.GetBuffer(), (strToolTip.GetLength() * sizeof(TCHAR)) + 1);
}
*pResult = 0;
return TRUE;
}
상황에 따라 lpszText, szText에 툴팁메시지를 넣어주시면 됩니다. (참고 링크)
드롭다운 클릭시 메뉴 표시
드롭다운 클릭시 메뉴 표시를 위해 아래와 같이 OnToolbarDropDown 함수를 정의해줍니다. 이것 또한 메시지 맵에 등록되어있어야합니다.
// 메시지맵
BEGIN_MESSAGE_MAP(CMFCApplication1Dlg, CDialogEx)
// ...
ON_NOTIFY_EX(TBN_DROPDOWN, IDR_TOOLBAR1, &CMFCApplication1Dlg::OnToolbarDropDown)
END_MESSAGE_MAP()
BOOL CMFCApplication1Dlg::OnToolbarDropDown(UINT uiID, NMHDR * pNMHDR, LRESULT * pResult)
{
CString strMsg = _T("");
NMTOOLBAR *pNMTOOLBAR = (NMTOOLBAR *)pNMHDR;
// 어떤 드롭다운 버튼을 클릭했는지 아이디 체크하려면
if (pNMTOOLBAR->iItem != WM_COMMAND6 && pNMTOOLBAR->iItem != WM_COMMAND7)
return TRUE;
// 선택한 드롭박스 아래에 메뉴 생성
CRect rc = pNMTOOLBAR->rcButton;
ClientToScreen(rc);
CMenu menu, menu1, menu2;
menu.CreatePopupMenu();
menu1.CreatePopupMenu();
menu2.CreatePopupMenu();
menu.AppendMenu(MF_POPUP | MF_STRING, (UINT)menu1.GetSafeHmenu(), _T("메뉴1"));
menu.AppendMenu(MF_POPUP | MF_STRING, (UINT)menu2.GetSafeHmenu(), _T("메뉴2"));
menu.AppendMenu(MF_STRING, WM_MENU3, _T("메뉴3"));
// 메뉴1의 하위 메뉴
menu1.AppendMenu(MF_STRING, WM_MENU1_1, _T("메뉴1_1"));
menu1.AppendMenu(MF_STRING, WM_MENU1_2, _T("메뉴1_2"));
menu1.AppendMenu(MF_STRING, WM_MENU1_3, _T("메뉴1_3"));
// 메뉴2의 하위 메뉴
menu2.AppendMenu(MF_STRING, WM_MENU2_1, _T("메뉴 2_1"));
menu2.AppendMenu(MF_STRING, WM_MENU2_2, _T("메뉴 2_2"));
int id = menu.TrackPopupMenu(TPM_LEFTALIGN | TPM_RETURNCMD, rc.left, rc.bottom, this, &rc);
menu1.DestroyMenu();
menu2.DestroyMenu();
menu.DestroyMenu();
switch (id)
{
case WM_MENU1_1:
AfxMessageBox(_T("메뉴1_1"));
break;
case WM_MENU1_2:
AfxMessageBox(_T("메뉴1_2"));
break;
case WM_MENU1_3:
AfxMessageBox(_T("메뉴1_3"));
break;
case WM_MENU2_1:
AfxMessageBox(_T("메뉴2_1"));
break;
case WM_MENU2_2:
AfxMessageBox(_T("메뉴2_2"));
break;
case WM_MENU3:
AfxMessageBox(_T("메뉴3"));
break;
}
return TRUE;
}
이상으로 툴바에 대해 알아보았습니다.