도구 모음을 사용자 지정하는 방법
대부분의 Windows 기반 애플리케이션은 도구 모음 컨트롤을 사용하여 사용자에게 프로그램 기능에 대한 편리한 액세스를 제공합니다. 그러나 정적 도구 모음에는 사용 가능한 모든 도구를 효과적으로 표시할 공간이 너무 적다는 점 등 몇 가지 단점이 있습니다. 이 문제의 해결 방법은 애플리케이션의 도구 모음을 사용자 지정 가능하게 만드는 것입니다. 그러면 사용자가 필요한 도구만 표시하도록 선택할 수 있으며 개인 작업 스타일에 맞는 방식으로 구성할 수 있습니다.
참고
대화 상자의 도구 모음은 사용자 지정할 수 없습니다.
사용자 지정을 사용하도록 설정하려면 도구 모음 컨트롤을 만들 때 CCS_ADJUSTABLE 공통 컨트롤 스타일 플래그를 포함합니다. 사용자 지정에는 두 가지 기본 접근 방법이 있습니다.
- 사용자 지정 대화 상자. 이 시스템 제공 대화 상자는 가장 간단한 방법입니다. 사용자에게 아이콘을 추가, 삭제 또는 이동할 수 있는 그래픽 사용자 인터페이스를 제공합니다.
- 끌어서 놓기 도구. 끌어서 놓기 기능을 구현하면 사용자가 도구 모음의 다른 위치로 도구를 이동하거나 도구 모음에서 끌어서 삭제할 수 있습니다. 사용자에게 도구 모음을 빠르고 쉽게 구성할 수 있는 방법을 제공하지만 도구를 추가할 수는 없습니다.
애플리케이션의 요구 사항에 따라 접근 방식 또는 둘 다를 구현할 수 있습니다. 이러한 두 가지 사용자 지정 방법 중 어느 것도 도구 모음을 이전 상태로 되돌리기 위해 취소 또는 실행 취소 단추와 같은 기본 제공 메커니즘을 제공하지 않습니다. 도구 모음 컨트롤 API를 명시적으로 사용하여 도구 모음의 사전 사용자 지정 상태를 저장해야 합니다. 필요한 경우 나중에 이 저장된 정보를 사용하여 도구 모음을 원래 상태로 복원할 수 있습니다.
알아야 하는 작업
기술
필수 구성 요소
- C/C++
- Windows 사용자 인터페이스 프로그래밍
지침
사용자 지정 대화 상자
사용자 지정 대화 상자는 도구 모음 컨트롤을 통해 사용자에게 도구를 추가, 이동 또는 삭제하는 간단한 방법을 제공합니다. 사용자는 도구 모음을 두 번 클릭하여 시작할 수 있습니다. 애플리케이션은 도구 모음 컨트롤에 TB_CUSTOMIZE 메시지를 보내 프로그래밍 방식으로 사용자 지정 대화 상자를 시작할 수 있습니다.
다음 그림에서는 도구 모음 사용자 지정 대화 상자의 예를 보여 줍니다.
오른쪽 목록 상자의 도구는 현재 도구 모음에 있는 도구입니다. 처음에 이 목록에는 도구 모음을 만들 때 지정한 도구가 포함됩니다. 왼쪽의 목록 상자에는 도구 모음에 추가할 수 있는 도구가 포함되어 있습니다. 애플리케이션은 해당 목록을 채우는 작업을 담당합니다(자동으로 표시되는 구분 기호 제외).
도구 모음 컨트롤은 부모 창에 TBN_BEGINADJUST 알림 코드와 뒤이어서 TBN_INITCUSTOMIZE 알림 코드를 전송하여 사용자 지정 대화 상자를 시작하고 있음을 애플리케이션에 알립니다. 대부분의 경우 애플리케이션은 이러한 알림 코드에 응답할 필요가 없습니다. 그러나 도구 모음 사용자 지정 대화 상자에서 도움말 단추를 표시하지 않으려면 TBNRF_HIDEHELP를 반환하여 TBN_INITCUSTOMIZE를 처리하세요.
그런 다음 도구 모음 컨트롤은 다음 순서대로 세 가지 일련의 알림 코드를 전송하여 대화 상자를 초기화하는 데 필요한 정보를 수집합니다.
- 단추를 삽입할 수 있는 위치를 결정하기 위한 도구 모음의 각 단추의 TBN_QUERYINSERT 알림 코드. 알림 메시지에 지정된 단추의 왼쪽에 단추가 삽입되지 않도록 하려면 FALSE를 반환합니다. 모든 TBN_QUERYINSERT 알림 코드에 FALSE 를 반환하면 대화 상자가 표시되지 않습니다.
- 현재 도구 모음에 있는 각 도구에 대한 TBN_QUERYDELETE 알림 코드. 도구를 삭제할 수 있으면 TRUE를 반환하고, 그렇지 않으면 FALSE를 반환합니다.
- 사용 가능한 단추 목록을 채우는 일련의 TBN_GETBUTTONINFO 알림 코드. 목록에 단추를 추가하려면 알림 코드와 함께 전달되는 NMTOOLBAR 구조체를 입력하고 TRUE를 반환합니다. 더 이상 추가할 도구가 없으면 FALSE를 반환합니다. 도구 모음에 이미 있는 단추에 대한 정보를 반환할 수 있습니다. 이러한 단추는 목록에 추가되지 않습니다.
그런 다음 대화 상자가 표시되고 사용자가 도구 모음을 사용자 지정하기 시작할 수 있습니다.
대화 상자가 열려 있으면 애플리케이션은 사용자의 작업에 따라 다양한 알림 코드를 받을 수 있습니다.
- TBN_QUERYINSERT. 사용자가 도구 모음에서 도구의 위치를 변경하거나 도구를 추가했습니다. 도구가 해당 위치에 삽입되지 않도록 하려면 FALSE를 반환합니다.
- TBN_DELETINGBUTTON. 사용자가 도구 모음에서 도구를 제거하려고 합니다.
- TBN_CUSTHELP. 사용자가 도움말 단추를 클릭했습니다.
- TBN_TOOLBARCHANGE. 사용자가 도구를 추가, 이동 또는 삭제했습니다.
- TBN_RESET. 사용자가 다시 설정 단추를 클릭했습니다.
대화 상자가 제거되면 애플리케이션에 TBN_ENDADJUST 알림 코드가 표시됩니다.
다음 코드 예제에서는 이 도구 모음 사용자 지정을 구현하는 한 가지 방법을 보여 줍니다.
// The buttons are stored in an array of TBBUTTON structures.
//
// Constants such as STD_FILENEW are identifiers for the
// built-in bitmaps that have already been assigned as the toolbar's
// image list.
//
// Constants such as IDM_NEW are application-defined command identifiers.
TBBUTTON allButtons[] =
{
{ MAKELONG(STD_FILENEW, ImageListID), IDM_NEW, TBSTATE_ENABLED, 0, {0}, 0, (INT_PTR)L"New" },
{ MAKELONG(STD_FILEOPEN, ImageListID), IDM_OPEN, TBSTATE_ENABLED, 0, {0}, 0, (INT_PTR)L"Open"},
{ MAKELONG(STD_FILESAVE, ImageListID), IDM_SAVE, TBSTATE_ENABLED, 0, {0}, 0, (INT_PTR)L"Save"},
{ MAKELONG(STD_CUT, ImageListID), IDM_CUT, TBSTATE_ENABLED, 0, {0}, 0, (INT_PTR)L"Cut" },
{ MAKELONG(STD_COPY, ImageListID), IDM_COPY, TBSTATE_ENABLED, 0, {0}, 0, (INT_PTR)L"Copy"},
{ MAKELONG(STD_PASTE, ImageListID), IDM_PASTE, TBSTATE_ENABLED, 0, {0}, 0, (INT_PTR)L"Paste"}
};
// The following appears in the window's message handler.
case WM_NOTIFY:
{
switch (((LPNMHDR)lParam)->code)
{
case TBN_GETBUTTONINFO:
{
LPTBNOTIFY lpTbNotify = (LPTBNOTIFY)lParam;
// Pass the next button from the array. There is no need to filter out buttons
// that are already used—they will be ignored.
int buttonCount = sizeof(allButtons) / sizeof(TBBUTTON);
if (lpTbNotify->iItem < buttonCount)
{
lpTbNotify->tbButton = allButtons[lpTbNotify->iItem];
return TRUE;
}
else
{
return FALSE; // No more buttons.
}
}
break;
case TBN_QUERYINSERT:
case TBN_QUERYDELETE:
return TRUE;
}
}
끌어서 놓기 도구
Shift 키를 누르고 단추를 다른 위치로 끌어서 도구 모음의 단추를 다시 정렬할 수도 있습니다. 끌어서 놓기 프로세스는 도구 모음 컨트롤에 의해 자동으로 처리됩니다. 끌어서 놓으면 단추의 고스트 이미지가 표시되고 도구 모음이 삭제된 후 다시 정렬됩니다. 사용자는 이러한 방식으로 단추를 추가할 수는 없지만 도구 모음에서 단추를 삭제하여 단추를 삭제할 수 있습니다.
도구 모음 컨트롤은 일반적으로 이 작업을 자동으로 수행하지만 애플리케이션에 두 개의 알림 코드, 즉 TBN_QUERYDELETE 및 TBN_QUERYINSERT도 보냅니다. 끌어서 놓기 프로세스를 제어하려면 다음과 같이 이러한 알림 코드를 처리합니다.
- TBN_QUERYDELETE 알림 코드는 고스트 단추가 표시되기 전에 사용자가 단추를 이동하려고 시도하는 즉시 전송됩니다. FALSE를 반환하여 단추가 이동되지 않도록 합니다. TRUE를 반환하면 사용자가 도구를 이동하거나 도구 모음 밖에 놓아서 삭제할 수 있습니다. 도구를 이동할 수 있으면 삭제할 수 있습니다. 그러나 사용자가 도구를 삭제하는 경우 도구 모음 컨트롤은 애플리케이션에 TBN_DELETINGBUTTON 알림 코드를 보내며, 이때 원래 위치에 단추를 다시 삽입하여 삭제를 취소할 수 있습니다.
- 사용자가 도구 모음에서 단추를 놓으려고 하면 TBN_QUERYINSERT 알림 코드가 전송됩니다. 이동 중인 단추가 알림에 지정된 단추의 왼쪽으로 삭제되지 않도록 하려면 FALSE를 반환합니다. 사용자가 도구 모음에서 도구를 삭제하면 이 알림 코드가 전송되지 않습니다.
사용자가 SHIFT 키를 누르지 않고 단추를 끌려고 하면 도구 모음 컨트롤이 끌어서 놓기 작업을 처리하지 않습니다. 그러나 끌어서 놓기 작업의 시작을 나타내는 TBN_BEGINDRAG 알림 코드와 끝을 나타내는 TBN_ENDDRAG 알림 코드를 애플리케이션에 보냅니다. 이 형태의 끌어서 놓기를 사용하려면 애플리케이션에서 이러한 알림 코드를 처리하고, 필요한 사용자 인터페이스를 제공하고, 변경 내용을 반영하도록 도구 모음을 수정해야 합니다.
도구 모음 저장 및 복원
도구 모음을 사용자 지정하는 과정에서 애플리케이션은 도구 모음을 원래 상태로 복원할 수 있도록 정보를 저장해야 할 수 있습니다. 도구 모음 상태 저장 또는 복원을 시작하려면 도구 모음 컨트롤에 lParam이 TRUE로 설정된 TB_SAVERESTORE 메시지를 보냅니다. 이 메시지의 lParam 값은 저장 또는 복원 작업을 요청하는지 여부를 지정합니다. 메시지를 보낸 후에는 저장/복원 작업을 처리하는 데 두 가지 방법이 있습니다.
- 일반적인 컨트롤 버전 4.72 이하에서는 TBN_GETBUTTONINFO 처리기를 구현해야 합니다. 도구 모음 컨트롤은 복원될 때 각 단추에 대한 정보를 요청하기 위해 이 알림 코드를 보냅니다.
- 버전 5.80에는 저장/복원 옵션이 포함되어 있습니다. 프로세스 시작 시, 각 단추가 저장되거나 복원될 때 애플리케이션은 TBN_SAVE 또는 TBN_RESTORE 알림 코드를 받습니다. 이 옵션을 사용하려면 알림 처리기를 구현하여 도구 모음 상태를 성공적으로 저장하거나 복원하는 데 필요한 비트맵 및 상태 정보를 제공해야 합니다.
도구 모음 상태는 애플리케이션 정의 데이터 블록과 번갈아 가며 셸 정의 데이터 블록으로 구성된 데이터 스트림에 저장됩니다. 애플리케이션이 스트림의 시작 부분에 배치할 수 있는 전역 데이터의 선택적 블록과 함께 각 형식의 데이터 블록 하나가 각 단추에 대해 저장됩니다. 저장 프로세스 중에 TBN_SAVE 처리기는 데이터 스트림에 애플리케이션 정의 블록을 추가합니다. 복원 프로세스 중에 TBN_RESTORE 처리기는 각 블록을 읽고 셸에 도구 모음을 재구성하는 데 필요한 정보를 제공합니다.
TBN_SAVE 알림을 처리하는 방법
첫 번째 TBN_SAVE 알림 코드는 저장 프로세스의 시작 시 전송됩니다. 단추를 저장하기 전에 NMTBSAVE 구조체의 멤버는 다음 표와 같이 설정됩니다.
멤버 | 설정 |
---|---|
iItem | –1 |
cbData | 셸 정의 데이터에 필요한 메모리의 양입니다. |
cButtons | 단추의 수입니다. |
pData | 애플리케이션 정의 데이터에 필요한 것으로 계산된 메모리의 양입니다. 일반적으로 일부 전역 데이터와 각 단추에 대한 데이터가 포함됩니다. cbData에 해당 값을 추가하고 모두 저장하기에 충분한 메모리를 pData에 할당합니다. |
pCurrent | 데이터 스트림에서 사용되지 않는 첫 번째 바이트입니다. 전역 도구 모음 정보가 필요하지 않은 경우 pCurrent = pData를 설정하여 데이터 스트림의 시작을 가리킵니다. 전역 도구 모음 정보가 필요한 경우 pData에 저장한 다음, 반환하기 전에 pCurrent를 데이터 스트림의 사용되지 않는 부분의 시작으로 설정합니다. |
전역 도구 모음 정보를 추가하려면 데이터 스트림의 시작에 배치합니다. pCurrent를 전역 데이터의 끝으로 이동하여 데이터 스트림의 사용되지 않는 부분의 시작을 가리키고 반환합니다.
반환한 후 셸은 단추 정보 저장을 시작합니다. pCurrent의 첫 번째 단추에 대한 셸 정의 데이터를 추가한 다음 pCurrent를 사용하지 않는 부분의 시작으로 진행합니다.
각 단추가 저장되면 TBN_SAVE 알림 코드가 전송되고 다음과 같이 이러한 멤버가 설정된 NMTBSAVE가 반환됩니다.
멤버 | 설정 |
---|---|
iItem | 단추 번호의 인덱스(0부터 시작)입니다. |
pCurrent | 데이터 스트림에서 사용되지 않는 첫 번째 바이트에 대한 포인터입니다. 단추에 대한 추가 정보를 저장하려는 경우 pCurrent가 가리키는 위치에 저장하고 그 후 데이터 스트림의 사용되지 않는 첫 번째 부분을 가리키도록 pCurrent를 업데이트합니다. |
TBBUTTON | 저장되는 단추를 설명하는 TBBUTTON 구조체입니다. |
알림 코드를 받으면 필요한 단추별 정보를 TBBUTTON에서 추출해야 합니다. 단추를 추가할 때 TBBUTTON의 dwData 멤버를 사용하여 애플리케이션별 데이터를 저장할 수 있습니다. pCurrent의 데이터 스트림에 데이터를 로드합니다. pCurrent를 데이터의 끝으로 이동하여 다시 스트림의 사용되지 않는 부분의 시작을 가리키고 돌아옵니다.
그런 다음 셸은 다음 단추로 이동하고, pData에 정보를 추가하고, pCurrent를 진행시키고, TBBUTTON을 로드하고, 다른 TBN_SAVE 알림 코드를 보냅니다. 이 프로세스는 모든 단추가 저장될 때까지 계속됩니다.
저장된 도구 모음 복원
복원 프로세스는 기본적으로 저장 프로세스를 반대로 합니다. 처음에 애플리케이션은 NMTBRESTORE 구조체의 iItem 멤버가 –1로 설정된 TBN_RESTORE 알림 코드를 받게 됩니다. cbData 멤버는 pData의 크기로 설정되고 cButtons는 단추의 수로 설정됩니다.
알림 처리기는 저장 중에 pData의 시작에 배치된 전역 정보를 추출하고 pCurrent를 셸 정의 데이터의 첫 번째 블록의 시작으로 진행해야 합니다. cBytesPerRecord를 단추 데이터를 저장하는 데 사용한 데이터 블록의 크기로 설정합니다. cButtons를 단추의 수로 설정하고 돌아옵니다.
다음 NMTBRESTORE는 첫 번째 단추에 대한 것입니다. pCurrent 멤버는 단추 데이터의 첫 번째 블록의 시작을 가리키고 iItem은 단추 인덱스로 설정됩니다. 해당 데이터를 추출하고 pCurrent를 진행합니다. TBBUTTON에 데이터를 로드하고 돌아옵니다. 복원된 도구 모음에서 단추를 생략하려면 TBBUTTON의 idCommand 멤버를 0으로 설정합니다. 셸은 나머지 단추에 대한 프로세스를 반복합니다. NMTBSAVE 및 NMTBRESTORE 메시지 외에도 TBN_RESET과 같은 메시지를 사용하여 도구 모음을 저장하고 복원할 수도 있습니다.
다음 코드 예제에서는 도구 모음을 사용자 지정하기 전에 저장하고 애플리케이션이 TBN_RESET 메시지를 받으면 복원합니다.
int i;
LPNMHDR lpnmhdr;
static int nResetCount;
static LPTBBUTTON lpSaveButtons;
LPARAM lParam;
switch( lpnmhdr->code)
{
case TBN_BEGINADJUST: // Begin customizing the toolbar.
{
LPTBNOTIFY lpTB = (LPTBNOTIFY)lparam;
// Allocate memory for the button information.
nResetCount = SendMessage(lpTB->hdr.hwndFrom, TB_BUTTONCOUNT, 0, 0);
lpSaveButtons = (LPTBBUTTON)GlobalAlloc(GPTR, sizeof(TBBUTTON) * nResetCount);
// In case the user presses reset, save the current configuration
// so the original toolbar can be restored.
for(i = 0; i < nResetCount; i++)
{
SendMessage(lpTB->hdr.hwndFrom,
TB_GETBUTTON, i,
(LPARAM)(lpSaveButtons + i));
}
}
return TRUE;
case TBN_RESET:
{
LPTBNOTIFY lpTB = (LPTBNOTIFY)lparam;
int nCount, i;
// Remove all of the existing buttons, starting with the last one.
nCount = SendMessage(lpTB->hdr.hwndFrom, TB_BUTTONCOUNT, 0, 0);
for(i = nCount - 1; i >= 0; i--)
{
SendMessage(lpTB->hdr.hwndFrom, TB_DELETEBUTTON, i, 0);
}
SendMessage(lpTB->hdr.hwndFrom, // Restore the saved buttons.
TB_ADDBUTTONS,
(WPARAM)nResetCount,
(LPARAM)lpSaveButtons);
}
return TRUE;
case TBN_ENDADJUST: // Free up the memory you allocated.
GlobalFree((HGLOBAL)lpSaveButtons);
return TRUE;
}
관련 항목