마법사를 만드는 방법
마법사는 프로시저를 통해 사용자를 안내하는 간단하고 강력한 방법을 제공하는 속성 시트의 유형입니다.
마법사는 사용자 환경을 간소화하기 위한 키 중 하나입니다. 애플리케이션 구성과 같은 복잡한 작업을 수행하고 일련의 간단한 단계로 분할할 수 있습니다. 프로세스의 각 지점에서 필요한 항목에 대한 설명을 제공하고 사용자가 선택하고 텍스트를 입력할 수 있도록 하는 컨트롤을 표시할 수 있습니다.
마법사는 실제로 속성 시트의 유형입니다. 속성 시트는 기본적으로 각 페이지가 별도의 대화 상자인 페이지 컬렉션의 컨테이너입니다. 일반 속성 시트를 사용하면 언제든지 모든 페이지에 액세스할 수 있지만 마법사는 페이지를 순서대로 표시합니다. 단추는 탭 대신 앞뒤로 이동하는 데 사용됩니다. 페이지가 표시되는 순서는 애플리케이션에 의해 제어되며 사용자 입력에 따라 수정할 수 있습니다.
마법사에는 이전 Wizard97 스타일과 Windows Vista에서 도입된 에어로 스타일의 두 가지 기본 스타일이 있습니다. 속성 시트에 대한 삽화는 을 참조하세요. (세 번째 스타일은 PSH_WIZARD 또는 PSH_WIZARD_LITE 플래그만 사용하여 머리글이나 워터마크가 없는 간단한 속성 시트 시퀀스를 제공합니다.)
메모
마법사 컨텍스트의 "워터마크"는 일부 페이지의 왼쪽 여백에 나타나는 비트맵입니다.
이 문서의 대부분 설명에서는 버전 5.80 이상의 공용 컨트롤이 있는 시스템에 대한 마법사를 구현한다고 가정합니다. 이전 버전의 공용 컨트롤에서 Wizard97 스타일을 사용하려고 하면 애플리케이션이 컴파일될 수 있지만 제대로 표시되지는 않습니다. 이전 시스템에서 Wizard97 호환 마법사를 만드는 방법에 대한 자세한 내용은 이 항목의 뒷부분에 있는 이전 버전 호환 마법사를 참조하세요.
알아야 할 사항
기술
필수 구성 요소
- C/C++
- Windows 사용자 인터페이스 프로그래밍
지시
마법사 구현
마법사 구현은 일반 속성 시트를 구현하는 것과 유사합니다. 가장 기본적인 수준에서 속성 시트를 정의하는 PROPSHEETHEADER 구조에서 다음 플래그 또는 플래그 조합 중 하나를 설정하는 것이 중요합니다.
깃발 | 스타일 |
---|---|
PSH_WIZARD | 헤더 또는 비트맵이 없는 간단한 마법사입니다. |
PSH_WIZARD_LITE | PSH_WIZARD 유사하며 모양에 약간의 차이가 있습니다. 예를 들어 단추 위의 구분선은 창의 전체 너비로 설정됩니다. |
PSH_WIZARD97 | (선택 사항) 헤더, 헤더 비트맵 및 워터마크가 있는 Wizard97 마법사입니다. |
PSH_WIZARD | PSH_AEROWIZARD | 에어로 마법사. 에어로 마법사는 워터마크 또는 헤더 비트맵을 사용하지 않습니다. STA(단일 스레드 아파트) 모델이 필요합니다. |
마법사를 구현하기 위한 기본 절차는 다음과 같습니다.
- 각 페이지에 대한 대화 상자 템플릿을 만듭니다.
- 각 페이지에 대한 PROPSHEETPAGE 구조를 만들어 페이지를 정의합니다. 이 구조는 페이지를 정의하고 대화 상자 템플릿 및 비트맵 또는 기타 리소스에 대한 포인터를 포함합니다.
- 이전 단계에서 만든 PROPSHEETPAGE 구조를 CreatePropertySheetPage 함수에 전달하여 페이지의 HPROPSHEETPAGE 핸들을 만듭니다.
- PROPSHEETHEADER 구조를 만들어 마법사를 정의합니다.
- PROPSHEETHEADER 구조를 PropertySheet 함수에 전달하여 마법사를 표시합니다.
- 페이지 컨트롤과 마법사 단추의 알림 메시지를 처리하고 다른 Windows 메시징을 처리하기 위해 각 페이지에 대한 대화 상자 프로시저를 구현합니다.
대화 상자 템플릿 만들기
마법사 페이지에는 외부 및 내부라는 두 가지 기본 유형이 있습니다. 외부 페이지는 소개(시작) 및 완성 페이지입니다. 다른 모든 페이지는 내부 페이지입니다.
외부 페이지 대화 상자 서식 파일
소개 및 완성 페이지의 기본 레이아웃은 동일합니다. 다음 그림에서는 자리 표시자 워터마크가 있는 샘플 Wizard97 소개 페이지를 보여 줍니다.
Wizard97 외부 페이지의 경우 대화 상자 템플릿은 317x193 대화 상자 단위입니다. 마법사의 모든 부분을 채우지만, 하단에 있는 캡션과 뒤로, 다음, 취소 단추가 포함된 밴드는 제외합니다. "워터마크" 비트맵용으로 예약된 템플릿의 왼쪽에는 컨트롤이 포함되어서는 안 됩니다. 워터마크는 마법사의 PROPSHEETHEADER 구조에 지정되고 페이지에 자동으로 추가됩니다. 리소스 템플릿을 디자인할 때 공간을 허용해야 합니다.
워터마크 비트맵을 만들 때 사용자가 큰 시스템 글꼴을 선택하는 경우 대화 상자의 크기가 증가할 수 있습니다. 언어도 글꼴 메트릭이 다른 경향이 있습니다. 페이지가 커지면 워터마크에 예약된 영역이 비례적으로 커집니다. 그러나 워터마크 비트맵을 변경할 수 없으며 더 큰 영역을 채우기 위해 비트맵이 늘어나지도 않습니다. 대신 비트맵은 예약 영역의 왼쪽 위 부분에 원래 크기로 남아 있습니다. 워터마크가 적용되지 않는 더 큰 예약 영역의 부분은 비트맵의 왼쪽 위 픽셀 색으로 자동으로 채워집니다.
다른 글꼴 메트릭에 대해 서로 다른 크기의 워터마크 비트맵이 필요한 경우 두 가지 가능한 해결 방법은 다음과 같습니다.
- 마법사를 만들기 전에 글꼴 메트릭을 가져와 적절한 크기의 워터마크 비트맵을 지정합니다.
- 마법사를 만들 때 워터마크 비트맵을 지정하지 마세요. Wizard97은 워터마크 영역을 비워 둡니다. 그런 다음 워터마크용으로 예약된 영역에 적절한 크기의 비트맵을 그립니다.
일반 대화 상자와 마찬가지로 워터마크 오른쪽 영역에 컨트롤을 배치할 수 있습니다. 이 영역의 배경색은 시스템에 의해 결정되며 해당 부분에 대한 작업이 필요하지 않습니다. 일반적으로 이 영역에 두 개의 정적 컨트롤을 배치합니다. 위쪽은 제목을 유지하고 큰 굵은 글꼴을 사용합니다(Wizard97의 경우 12포인트 Verdana Bold). 다른 하나는 설명 텍스트용으로 표준 대화 상자 글꼴을 사용합니다.
소개 페이지와 완성 페이지의 주요 차이점은 마법사 단추와 정적 컨트롤의 텍스트입니다. 소개 페이지에는 일반적으로 다음뒤로 단추가 있으며 다음 단추만 사용하도록 설정되어 있습니다. 완료 페이지에서는 뒤로 단추를 사용하도록 설정하고 다음 단추는 마침 단추로 바뀝니다.
메모
에어로 마법사에서 뒤로 단추는 캡션 표시줄의 화살표 단추로 바뀝니다.
마법사에 PSM_SETFINISHTEXT 메시지를 보내 마침 단추의 텍스트를 수정할 수 있습니다. 기본적으로 마침 단추에는 키보드 가속기가 포함되어 있지 않습니다. 키보드 가속기를 정의하려면 PSM_SETFINISHTEXT 전달하는 텍스트 문자열에 앰퍼샌드를 포함합니다. 예를 들어, "&마침"에서 'F'는 키보드 단축키로 정의됩니다.
내부 페이지 대화 상자 서식 파일
내부 페이지는 외부 페이지와 모양이 약간 다릅니다. 다음 그림에서는 자리 표시자 헤더 비트맵이 있는 샘플 Wizard97 내부 페이지를 보여 줍니다.
제목 및 부제목 텍스트와 맨 위에 그래픽, 가운데에 텍스트, 아래쪽에 단추가 있는 마법사 페이지의 스크린샷을
페이지 맨 위에 있는 머리글 영역은 속성 시트에서 처리되므로 템플릿에 포함되지 않습니다. 머리글의 내용은 페이지의 PROPSHEETPAGE 구조 및 마법사의 PROPSHEETHEADER 구조에 지정됩니다. 내부 페이지는 머리글과 단추 사이에 맞아야 하므로 Wizard97 대화 상자 템플릿은 317x143 대화 상자 단위로 외부 페이지의 템플릿보다 약간 작습니다.
다음 그림에서는 동일한 템플릿에서 만든 Aero 마법사를 보여 줍니다.
마법사 페이지 정의
대화 상자 템플릿 및 비트맵 및 문자열 테이블과 같은 관련 리소스를 만든 후에는 속성 시트 페이지를 만들 수 있습니다. 이 프로시저는 표준 속성 시트의 경우와 비슷합니다. 먼저 PROPSHEETPAGE 구조체의 적절한 멤버를 채웁니다. (일부 멤버는 마법사와 관련이 있습니다.) 그런 다음 CreatePropertySheetPage 함수를 호출하여 페이지의 HPROPSHEETPAGE 핸들을 만듭니다.
다음 마법사 관련 플래그는 PROPSHEETPAGE 구조체의 dwFlags 멤버에서 설정할 수 있습니다.
깃발 | 묘사 |
---|---|
PSP_HIDEHEADER | Wizard97의 외부 페이지에 대해 이 플래그를 설정합니다. 머리글이 표시되지 않으며 워터마크를 표시할 수 있습니다. |
PSP_USEHEADERTITLE | 마법사97의 머리글 영역이나 에어로 마법사의 클라이언트 영역 맨 위에 제목을 넣도록 내부 페이지에 대해 이 플래그를 설정합니다. |
PSP_USEHEADERSUBTITLE | 위저드97의 머리글 영역에 자막을 넣도록 내부 페이지에 대해 이 플래그를 설정합니다. |
PSP_USEHEADERTITLE 또는 PSP_USEHEADERSUBTITLE 설정한 경우 제목 및 부제목 텍스트를 pszHeaderTitle 및 pszHeaderSubtitle 멤버에 각각 할당합니다. PROPSHEETPAGE 및 PROPSHEETHEADER 구조체의 멤버에 텍스트 문자열을 할당할 때, 문자열 포인터를 할당하거나 MAKEINTRESOURCE 매크로를 사용하여 문자열 리소스에서 값을 할당할 수 있습니다. 문자열 리소스는 마법사의 PROPSHEETHEADER 구조체의 hInstance 멤버에 지정된 모듈에서 로드됩니다.
CreatePropertySheetPage 호출하여 페이지를 만들 때 HPROPSHEETPAGE 핸들 배열의 요소에 결과를 할당합니다. 이 배열은 속성 시트를 만들 때 사용됩니다. 페이지 핸들의 배열 인덱스는 페이지가 표시되는 기본 순서를 결정합니다. 페이지의 HPROPSHEETPAGE 핸들을 만든 후에는 동일한 PROPSHEETPAGE 구조를 다시 사용하여 관련 멤버에게 새 값을 할당하여 다음 페이지를 만들 수 있습니다.
페이지를 만드는 또 다른 방법은 각 페이지에 대해 별도의 PROPSHEETPAGE 구조를 사용하고 구조체 배열을 만드는 것입니다. 이 배열은 속성 시트를 만들 때 HPROPSHEETPAGE 핸들의 배열 대신 사용됩니다. 별도의 PROPSHEETPAGE 구조를 사용하면 CreatePropertySheetPage 호출할 필요가 없지만 더 많은 메모리를 사용합니다. 그렇지 않으면 두 방법 사이에 큰 차이가 없습니다.
다음 예제에서는 PROPSHEETPAGE 구조에 값을 할당하여 내부 Wizard97 페이지를 정의합니다. 이 예제에서는 페이지의 제목, 부제목 및 대화 상자 템플릿이 모두 해당 리소스 ID로 식별됩니다. 그런 다음 CreatePropertySheetPage 함수를 호출하여 페이지의 HPROPSHEETPAGE 핸들을 만듭니다. 두 번째 페이지가 표시되기 때문에 핸들은 ahpsp 핸들 배열에 할당되고 인덱스는 1입니다.
// g_hInstance is the global HINSTANCE of the application.
// IntPage1DlgProc is the dialog procedure for this page.
// ahpsp is an array of HPROPSHEETPAGE handles.
PROPSHEETPAGE psp = { sizeof(psp) };
psp.hInstance = g_hInstance;
psp.dwFlags = PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE;
psp.lParam = (LPARAM) &wizdata;
psp.pszHeaderTitle = MAKEINTRESOURCE(IDS_TITLE1);
psp.pszHeaderSubTitle = MAKEINTRESOURCE(IDS_SUBTITLE1);
psp.pszTemplate = MAKEINTRESOURCE(IDD_INTERIOR1);
psp.pfnDlgProc = IntPage1DlgProc;
ahpsp[1] = CreatePropertySheetPage(&psp);
사용자 지정 페이지 데이터
페이지를 생성할 때 PROPSHEETPAGE 구조체의 lParam 멤버를 사용하여 사용자 정의 데이터를 할당할 수 있습니다. 일반적으로 사용자 정의 구조체에 포인터를 할당함으로써 이러한 작업을 수행합니다.
페이지를 처음 선택하면 해당 대화 상자 프로시저에서 WM_INITDIALOG 메시지를 받습니다. 메시지의 lParam 값은 사용자 지정 데이터를 검색할 수 있는 페이지의 PROPSHEETPAGE 구조의 복사본을 가리킵니다. 그런 다음 GWL_USERDATA 인덱스 매개 변수로 SetWindowLongPtr 사용하여 후속 메시지에 사용하기 위해 이 데이터를 저장할 수 있습니다. 여러 페이지에 동일한 데이터에 대한 포인터가 있을 수 있으며, 한 페이지가 변경한 데이터는 대화 상자 절차의 다른 페이지에서 사용할 수 있습니다.
마법사 속성 시트 정의
일반 속성 시트와 마찬가지로 PROPSHEETHEADER 구조체의 멤버를 입력하여 마법사의 속성 시트를 정의합니다. 이 구조를 사용하면 마법사를 구성하는 페이지와 표시되는 기본 순서를 여러 관련 매개 변수와 함께 지정할 수 있습니다. 그런 다음 PropertySheet 함수를 호출하여 마법사를 시작합니다.
Wizard97 스타일에서 PROPSHEETHEADER 구조체의 pszCaption 멤버는 무시됩니다. 대신 마법사는 현재 페이지의 대화 상자 템플릿에 지정된 캡션을 표시합니다. 서식 파일에 캡션이 없으면 이전 페이지의 캡션이 표시됩니다. 따라서 모든 페이지에 동일한 캡션을 표시하려면 템플릿에서 소개 페이지의 캡션을 지정합니다.
Aero 마법사 스타일에서는 대화 상자 캡션이 pszCaption에서 취해집니다.
페이지에 대한 HPROPSHEETPAGE 핸들 배열을 만든 경우 phpage 멤버에 배열을 할당합니다. 대신 PROPSHEETPAGE 구조의 배열을 만든 경우 배열을 ppsp 멤버에 할당하고 dwFlags 멤버에서 PSH_PROPSHEETPAGE 플래그를 설정합니다.
다음 예제에서는 PROPSHEETHEADER 구조인 psh값을 할당하고 PropertySheet 함수를 호출하여 마법사를 시작합니다. Wizard97 스타일 마법사에는 리소스 ID로 지정된 워터마크 및 헤더 그래픽이 모두 있습니다. ahpsp 배열은 HPROPSHEETPAGE 핸들을 모두 포함하고 표시되는 기본 순서를 정의합니다.
// g_hInstance is the global HINSTANCE of the application.
// ahpsp is an array of HPROPSHEETPAGE handles.
PROPSHEETHEADER psh = { sizeof(psh) };
psh.hInstance = g_hInstance;
psh.hwndParent = NULL;
psh.phpage = ahpsp;
psh.dwFlags = PSH_WIZARD97 | PSH_WATERMARK | PSH_HEADER;
psh.pszbmWatermark = MAKEINTRESOURCE(IDB_WATERMARK);
psh.pszbmHeader = MAKEINTRESOURCE(IDB_BANNER);
psh.nStartPage = 0;
psh.nPages = 4;
PropertySheet(&psh);
대화 상자 프로시저
마법사의 각 페이지에는 Windows 메시지, 특히 컨트롤 및 마법사의 알림을 처리하는 대화 상자 프로시저가 필요합니다. 거의 모든 마법사에서 처리할 수 있어야 하는 세 가지 메시지는 WM_INITDIALOG, WM_DESTROY및 WM_NOTIFY.
페이지가 표시되기 전과 마법사의 단추를 클릭할 때 WM_NOTIFY 메시지가 수신됩니다. 메시지의 lParam 매개 변수는 NMHDR 헤더 구조에 대한 포인터입니다. 알림의 ID는 구조체의 코드 멤버에 포함됩니다. 대부분의 마법사에서 처리해야 하는 네 가지 알림은 다음과 같습니다.
코드 | 묘사 |
---|---|
PSN_SETACTIVE | 페이지가 표시되기 전에 전송됩니다. |
PSN_WIZBACK | 뒤로 단추를 클릭하면 전송됩니다. |
PSN_WIZNEXT | 다음 단추를 클릭하면 전송됩니다. |
PSN_WIZFINISH | 마침 단추를 클릭하면 전송됩니다. |
WM_INITDIALOG 처리 및 WM_DESTROY
페이지가 처음으로 표시될 때 해당 대화 상자 프로시저는 WM_INITDIALOG 메시지를 받습니다. 이 메시지를 처리하면 마법사에서 사용자 지정 데이터 저장 또는 글꼴 설정과 같은 필요한 초기화 작업을 수행할 수 있습니다.
속성 시트가 제거되면 WM_DESTROY 메시지가 표시됩니다. 마법사는 시스템에 의해 자동으로 제거되지만 이 메시지를 처리하면 필요한 정리를 수행할 수 있습니다.
PSN_SETACTIVE 작업 처리
페이지가 표시될 때마다 PSN_SETACTIVE 알림 코드가 전송됩니다. 페이지를 처음 방문할 때 PSN_SETACTIVE WM_INITDIALOG 메시지를 따릅니다. 이후에 페이지를 다시 방문하면 PSN_SETACTIVE 알림만 받습니다. 이 알림은 일반적으로 페이지의 데이터를 초기화하고 적절한 단추를 사용하도록 설정하기 위해 처리됩니다.
마법사는 기본적으로 모든 버튼이 활성화된 상태에서 뒤로, 다음및 취소 버튼을 표시합니다. 버튼을 사용하지 않도록 설정하거나 다음대신 마침을 표시하려면 PSM_SETWIZBUTTONS 메시지를 보내야 합니다. 이 메시지를 보낸 후 단추의 상태는 새 페이지를 선택한 경우에도 다른 PSM_SETWIZBUTTONS 메시지에 의해 수정될 때까지 유지됩니다. 일반적으로 모든 PSN_SETACTIVE 처리기는 각 페이지에 올바른 단추 상태가 있는지 확인하기 위해 이 메시지를 보냅니다.
언제든지 이 메시지를 사용하여 단추 상태를 변경할 수 있습니다. 예를 들어 다음 단추를 처음에 사용하지 않도록 설정할 수 있습니다. 사용자가 필요한 모든 정보를 입력한 후 다른 PSM_SETWIZBUTTONS 메시지를 보내 다음 단추를 사용하도록 설정하고 사용자가 다음 페이지로 진행하도록 할 수 있습니다.
다음 코드 조각은 PropSheet_SetWizButtons 매크로를 사용하여 내부 페이지가 표시되기 전에 뒤로 버튼과 다음 버튼을 활성화합니다.
case WM_NOTIFY :
{
LPNMHDR pnmh = (LPNMHDR)lParam;
switch(pnmh->code)
{
...
case PSN_SETACTIVE :
...
// This is an interior page.
PropSheet_SetWizButtons(hwnd, PSWIZB_NEXT | PSWIZB_BACK);
...
}
...
}
PSN_WIZNEXT, PSNWIZBACK 및 PSN_WIZFINISH 처리
다음 또는 뒤로 단추를 클릭하면 PSN_WIZNEXT 또는 PSN_WIZBACK 알림 코드가 표시됩니다. 기본적으로 마법사는 속성 시트를 만들 때 정의된 순서대로 다음 또는 이전 페이지로 자동으로 이동합니다. 이러한 알림을 처리하는 일반적인 이유는 사용자가 페이지를 전환하지 못하게 하거나 기본 페이지 순서를 재정의하기 위해서입니다.
사용자가 페이지를 전환하지 못하도록 하려면 단추 알림을 처리하고 DWL_MSGRESULT 값이 -1로 설정된 SetWindowLong 함수를 호출하고 TRUE반환합니다. 예를 들어:
case PSN_WIZNEXT :
...
// Do not go to the next page yet.
SetWindowLong(hwnd, DWL_MSGRESULT, -1);
return TRUE;
...
표준 순서를 재정의하고 특정 페이지로 이동하려면 DWL_MSGRESULT 값이 페이지의 대화 상자 리소스 ID로 설정된 SetWindowLong 호출하고 TRUE반환합니다. 예를 들어:
case PSN_WIZNEXT :
...
// Go straight to the completion page.
SetWindowLong(hwnd, DWL_MSGRESULT, IDD_FINISH);
return TRUE;
...
마침 또는 취소 단추를 클릭하면 각각 PSN_WIZFINISH 또는 PSN_RESET 알림 코드가 표시됩니다. 이러한 단추 중 하나를 클릭하면 마법사가 시스템에 의해 자동으로 제거됩니다. 그러나 마법사가 제거되기 전에 정리 작업을 수행해야 하는 경우 이러한 알림을 처리할 수 있습니다. PSN_WIZFINISH 알림을 받을 때 마법사가 제거되지 않도록 하려면 DWL_MSGRESULT 값이 TRUE설정된 SetWindowLong 호출하고 TRUE반환합니다. 예를 들어:
case PSN_WIZFINISH :
...
// Not finished yet.
SetWindowLong(hwnd, DWL_MSGRESULT, TRUE);
return TRUE;
...
이전 버전과 호환되는 마법사
이전 섹션에서는 버전 5 이상의 공용 컨트롤이 있는 시스템에 대한 마법사를 구현한다고 가정합니다.
이전 버전의 공용 컨트롤이 있는 시스템에 대한 마법사를 작성하는 경우 이전 섹션에서 설명한 많은 기능을 사용할 수 없습니다. Wizard97 스타일에서 사용되는 PROPSHEETHEADER 및 PROPSHEETPAGE 구조체의 여러 멤버는 일반 컨트롤 버전 5 이상에서만 지원됩니다. 그러나 Wizard97 스타일과 유사한 모양으로 이전 버전과 호환되는 마법사를 구현할 수 있습니다. 이렇게 하려면 다음을 명시적으로 구현해야 합니다.
- 소개 및 완성 페이지의 대화 상자 템플릿에 워터마크 그래픽을 추가합니다.
- 모든 템플릿을 동일한 크기로 만듭니다. 내부 페이지에 대한 별도의 시스템 정의 헤더 영역이 없습니다.
- 템플릿에서 내부 페이지의 머리글 영역을 명시적으로 만듭니다.
- 마법사의 크기가 변경되면 제목이나 부제목과 충돌할 수 있으므로 머리글 그래픽을 사용하지 마세요.
이전 버전과 호환되는 마법사에 대한 자세한 내용은 이전 버전 호환 마법사 97참조하세요.
발언
Wizard97의 디자인 문제에 대한 자세한 내용은 Windows SDK의 Wizard97 사양참조하세요. 이 문서에는 대화 상자의 차원, 비트맵 차원 및 색, 컨트롤 배치와 같은 항목에 대한 지침이 있습니다.
관련 항목