Создание мастеров

Мастер — это тип листа свойств, который предоставляет простой и эффективный способ руководства пользователям с помощью процедуры.

Мастера — это один из ключей для упрощения взаимодействия с пользователем. Они позволяют выполнять сложную операцию, например конфигурацию приложения, и разбить ее на ряд простых шагов. В каждой точке процесса можно указать описание необходимых элементов управления и отобразить элементы управления, позволяющие пользователю выбирать и вводить текст.

Мастер на самом деле является типом листа свойств. Лист свойств по сути является контейнером для коллекции страниц, где каждая страница является отдельным диалоговым окном. В то время как обычные листы свойств позволяют пользователю получать доступ к любой странице в любое время, мастера представляют страницы в последовательности. Вместо вкладок кнопки используются для перехода вперед и назад. Порядок отображения страниц контролируется приложением и может быть изменен на основе ввода пользователем.

Существует два основных стиля мастера: старый стиль Wizard97 и стиль Aero, представленный в Windows Vista. Иллюстрации см. в разделе "Сведения о листах свойств". (Третий стиль, использующий только флаг PSH_WIZARD или PSH_WIZARD_LITE, представляет простую последовательность листов свойств без заголовков или подложок.)

Примечание

Подложка в контексте мастера — это растровое изображение, которое отображается в левом поле некоторых страниц.

 

В большинстве этого документа предполагается, что вы реализуете мастер для системы с 5.80 или более поздней версией общих элементов управления. Если вы пытаетесь использовать стиль Wizard97 с более ранними версиями распространенных элементов управления, приложение может скомпилироваться, но оно не будет отображаться должным образом. Дополнительные сведения о создании мастера, совместимого с Wizard97 в более ранних системах, см. в разделе "Мастера обратной совместимости" далее в этом разделе.

Это важно знать

Технологии

Необходимые компоненты

  • C/C++
  • Программирование пользовательского интерфейса Windows

Instructions

Реализация мастера

Реализация мастера аналогична реализации регулярного листа свойств. На самом базовом уровне это вопрос настройки одного из следующих флагов или сочетаний флагов в структуре PROPSHEETHEADER , которая определяет лист свойств.

Флаг Стиль
PSH_WIZARD Простой мастер без заголовков или растровых изображений.
PSH_WIZARD_LITE Как и PSH_WIZARD, с некоторыми незначительными различиями в внешнем виде; Например, разделитель над кнопками имеет полную ширину окна.
PSH_WIZARD97 Мастер мастер97 с заголовками (необязательно), растровыми изображениями заголовков и подложками.
PSH_WIZARD | PSH_AEROWIZARD Мастер Аэро. Мастеры аэро не используют подложки или растровые изображения заголовков. Для них требуется модель однопоточной квартиры (STA).

 

Базовая процедура реализации мастера выглядит следующим образом:

  1. Создайте шаблон диалогового окна для каждой страницы.
  2. Определите страницы, создав структуру PROPSHEETPAGE для каждой страницы. Эта структура определяет страницу и содержит указатели на шаблон диалогового окна и любые растровые изображения или другие ресурсы.
  3. Передайте структуру PROPSHEETPAGE, созданную на предыдущем шаге, функции CreatePropertySheetPage, чтобы создать дескриптор HPROPSHEETPAGE страницы.
  4. Определите мастер, создав для него структуру PROPSHEETHEADER .
  5. Передайте структуру PROPSHEETHEADER функции PropertySheet, чтобы отобразить мастер.
  6. Реализуйте процедуры диалогового окна для каждой страницы для обработки сообщений уведомлений из элементов управления страницы и кнопок мастера и обработки других сообщений Windows.

Создание шаблонов диалогового окна

Существует два основных типа страницы мастера: внешний и внутренний. Внешние страницы — это введение (приветствие) и страницы завершения. Все остальные — внутренние страницы.

Шаблоны диалоговых окон внешней страницы

Базовый макет страниц внедрения и завершения идентичен. На следующем рисунке показан пример страницы внедрения Wizard97 с подложкой заполнителя.

screen shot showing a wizard page with a graphic on the left, title and body text on the right, and back, next and cancel buttons at the bottom

Для внешних страниц Wizard97 шаблон диалогового окна — 317x193. Он заполняет все мастера, за исключением подпись и полосы в нижней части, содержащей кнопки "Назад", "Далее" и "Отмена". Левая часть шаблона, зарезервированная для растрового изображения "водяного знака", не должна содержать элементов управления. Подложка указывается в структуре PROPSHEETHEADER мастера и автоматически добавляется на страницу. При разработке шаблона ресурса необходимо разрешить пространство.

При создании растрового изображения водяного знака следует помнить, что диалоговое окно может увеличить размер, если, например, пользователь выбирает большой системный шрифт. Разные языки также обычно имеют разные метрики шрифта. Когда страница растет, область, зарезервированная для подложки, получает пропорционально больше. Однако вы не можете изменить растровое изображение водяного знака и не растянуто растровое изображение, чтобы заполнить большую область. Вместо этого растровое изображение остается в исходном размере в левой верхней части зарезервированной области. Часть большей зарезервированной области, которая не охватывается подложкой, автоматически заполняется цветом верхнего левого пикселя растрового изображения.

Если у вас должны быть точечные изображения разных размеров подложки для разных метрик шрифтов, возможны два возможных решения.

  • Получите метрики шрифта перед созданием мастера и укажите соответствующее размер растровое изображение водяного знака.
  • Не указывайте растровое изображение водяного знака при создании мастера. Мастер97 останется пустой областью водяного знака. Затем нарисуйте растровое изображение соответствующего размера в области, зарезервированной для подложки.

Элементы управления можно поместить в область справа от водяного знака, как и для обычного диалогового окна. Цвет фона этой области определяется системой и не требует никаких действий в вашей части. Обычно в этой области помещают два статических элемента управления. Верхняя часть содержит заголовок и использует большой полужирный шрифт (12 точек Verdana Полужирный для Wizard97). Другой, который предназначен для пояснительных текста, использует стандартный шрифт диалогового окна.

Основное различие между страницами внедрения и завершения — это кнопки мастера и текст в статических элементах управления. Страницы введение обычно имеют кнопку "Далее " и "Назад " с включенным только кнопкой "Далее ". Страницы завершения включают кнопку "Назад ", а кнопка "Далее " заменена кнопкой "Готово ".

Примечание

В мастерах Аэро кнопка "Назад" заменяется кнопкой со стрелкой на панели подпись.

 

Вы можете изменить текст на кнопке "Готово ", отправив мастеру сообщение PSM_SETFINISHTEXT . По умолчанию кнопка "Готово" не включает акселератор клавиатуры. Чтобы определить акселератор клавиатуры, включите амперсанд в текстовую строку, передаваемую в PSM_SETFINISHTEXT. Например, "&Finish" определяет "F" в качестве акселератора клавиатуры.

Шаблоны диалоговых окон внутренней страницы

Внутренние страницы имеют несколько отличается от внешнего вида страниц. На следующем рисунке показана пример страницы интерьера Wizard97 с растровым изображением заголовка заполнителя.

screen shot of a wizard page with title and subtitle text and a graphic at the top, text in the middle, and buttons on the bottom

Область заголовка в верхней части страницы обрабатывается листом свойств, поэтому он не включен в шаблон. Содержимое заголовка указывается в структуре PROPSHEETPAGE страницы и структуре PROPSHEETHEADER мастера. Так как внутренняя страница должна соответствовать заголовку и кнопкам, шаблон диалогового окна Wizard97 составляет 317x143, что несколько меньше шаблона для внешних страниц.

На следующем рисунке показан мастер Аэро, созданный на основе того же шаблона.

screen shot that differs from the previous one by having a title area at the top, and only next and cancel buttons at the bottom

Определение страниц мастера

После создания шаблонов диалоговых окон и связанных ресурсов, таких как растровые изображения и строковые таблицы, можно создать страницы листа свойств. Процедура аналогична процедуре для стандартных листов свойств. Сначала заполните соответствующие элементы структуры PROPSHEETPAGE. (Некоторые члены относятся к мастерам.) Затем вызовите функцию CreatePropertySheetPage, чтобы создать дескриптор HPROPSHEETPAGE страницы.

Следующие флаги, связанные с мастером, можно задать в элементе dwFlags структуры PROPSHEETPAGE.

Флаг Description
PSP_HIDEHEADER Задайте этот флаг для внешних страниц в Мастер97. Заголовок не отображается, и можно показать подложку.
PSP_USEHEADERTITLE Задайте этот флаг для внутренних страниц, чтобы поместить заголовок в область заголовка в Wizard97 или в верхней части клиентской области в мастере Аэро.
PSP_USEHEADERSUBTITLE Задайте этот флаг для внутренних страниц, чтобы поместить подзаголовок в область заголовка в Мастер97.

 

Если вы установили PSP_USEHEADERTITLE или PSP_USEHEADERSUBTITLE, назначьте текст заголовка и субтитра членам pszHeaderTitle и pszHeaderSubtitle соответственно. При назначении текстовых строк членам структур PROPSHEETPAGE и PROPSHEETHEADER можно назначить указатель строки или использовать макрос MAKEINTRESOURCE для назначения значения из строкового ресурса. Строковый ресурс загружается из модуля, указанного в элементе hInstance структуры PROPSHEETHEADER мастера.

При вызове CreatePropertySheetPage для создания страницы назначьте результат элементу массива дескрипторов HPROPSHEETPAGE . Этот массив используется при создании листа свойств. Индекс массива дескриптора страницы определяет порядок по умолчанию, в котором он отображается. После создания дескриптора HPROPSHEETPAGE страницы можно повторно использовать ту же структуру PROPSHEETPAGE , чтобы создать следующую страницу, назначив новые значения соответствующим членам.

Альтернативным способом создания страниц является использование отдельных структур PROPSHEETPAGE для каждой страницы и создание массива структур. Этот массив используется вместо массива дескрипторов HPROPSHEETPAGE при создании листа свойств. Использование отдельных структур PROPSHEETPAGE устраняет необходимость вызова CreatePropertySheetPage, но использует больше памяти. В противном случае нет существенной разницы между двумя подходами.

В следующем примере определяется страница "Внутренний мастер97", назначая значения структуре PROPSHEETPAGE. В этом примере заголовок, подзаголовок и шаблон диалогового окна страницы определяются идентификаторами ресурсов. Затем вызывается функция 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);

Пользовательские данные страницы

При создании страницы можно назначить пользовательские данные с помощью элемента lParam структуры PROPSHEETPAGE, обычно назначая ему указатель на определяемую пользователем структуру.

При первом выборе страницы процедура диалогового окна получает сообщение WM_INITDIALOG . Значение lParam сообщения указывает на копию структуры PROPSHEETPAGE страницы, из которой можно получить пользовательские данные. Затем эти данные можно хранить в последующих сообщениях с помощью SetWindowLongPtr с GWL_USERDATA в качестве параметра индекса. Несколько страниц могут иметь указатель на одни и те же данные, и любые изменения данных, сделанные одной страницей, доступны другим страницам в их процедурах диалога.

Определение листа свойств мастера

Как и в обычных листах свойств, вы определяете лист свойств мастера, заполняя элементы структуры PROPSHEETHEADER. Эта структура позволяет указать страницы, составляющие мастер и порядок по умолчанию, в котором они отображаются, а также несколько связанных параметров. Затем вы запустите мастер, вызвав функцию PropertySheet .

В стиле Wizard97 член pszCaption структуры PROPSHEETHEADER игнорируется. Вместо этого мастер отображает подпись, указанные в шаблоне диалогового окна текущей страницы. Если шаблон отсутствует подпись, отображается подпись из предыдущей страницы. Таким образом, чтобы отобразить одинаковые подпись на всех страницах, укажите подпись в шаблоне для вводной страницы.

В стиле "Мастер аэро" диалоговое окно подпись взято из pszCaption.

Если вы создали массив дескрипторов HPROPSHEETPAGE для страниц, назначьте массив элементу phpage . Если вместо этого вы создали массив структур PROPSHEETPAGE, назначьте массив члену ppsp и задайте флаг PSH_PROPSHEETPAGE в элементе dwFlags.

В следующем примере присваивается значения psh, структуре PROPSHEETHEADER и вызывается функция PropertySheet для запуска мастера. Мастер стилей Wizard97 содержит как подложку, так и графические заголовки, указанные идентификаторами ресурсов. Массив 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. Идентификатор уведомления содержится в элементе кода структуры. Четыре уведомления, которые большинство мастеров должны обрабатывать, приведены ниже.

Код Описание
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. По умолчанию мастер автоматически переходит на следующую или предыдущую страницу в том порядке, который определяется при создании листа свойств. Распространенной причиной обработки этих уведомлений является предотвращение переключения страниц пользователем или переопределение порядка страниц по умолчанию.

Чтобы предотвратить переключение страниц пользователем, обработайте уведомление кнопки, вызовите функцию SetWindowLong со значением DWL_MSGRESULT значением –1 и возвращайте ЗНАЧЕНИЕ TRUE. Например:

case PSN_WIZNEXT :

        ...
        
        // Do not go to the next page yet.
        SetWindowLong(hwnd, DWL_MSGRESULT, -1);
        
        return TRUE;
        
        ...

Чтобы переопределить стандартный порядок и перейти на определенную страницу, вызовите SetWindowLong со значением DWL_MSGRESULT, заданным для идентификатора ресурса диалогового окна страницы, и верните значение TRUE. Например:

case PSN_WIZNEXT :

        ...
        
        // Go straight to the completion page.
        SetWindowLong(hwnd, DWL_MSGRESULT, IDD_FINISH);
        
        return TRUE;
        
        ...

После нажатия кнопки "Готово" или "Отмена" вы получаете код уведомления PSN_WIZFINISH или PSN_RESET соответственно. При нажатии любой из этих кнопок мастер автоматически уничтожается системой. Однако эти уведомления можно обрабатывать, если необходимо выполнить задачи очистки перед уничтожением мастера. Чтобы предотвратить уничтожение мастера при получении уведомления PSN_WIZFINISH, вызовите SetWindowLong со значением DWL_MSGRESULT значение TRUE и возвращает значение TRUE. Например:

case PSN_WIZFINISH :

        ...
        
        // Not finished yet.
        SetWindowLong(hwnd, DWL_MSGRESULT, TRUE);
        
        return TRUE;
        
        ...

Мастера обратной совместимости

В предыдущем разделе предполагается, что вы реализуете мастер для системы с версией 5 или более поздними общими элементами управления.

Если вы пишете мастер для систем с более ранними версиями общих элементов управления, многие функции, описанные в предыдущем разделе, не будут доступны. Ряд членов структур PROPSHEETHEADER и PROPSHEETPAGE, используемых стилем Wizard97, поддерживаются только общими элементами управления версии 5 и более поздних версий. Однако по-прежнему можно реализовать мастер обратной совместимости с внешним видом, похожим на стиль Wizard97. Для этого необходимо явно реализовать следующее:

  • Добавьте рисунок водяного знака в шаблон диалогового окна для страниц внедрения и завершения.
  • Сделайте все шаблоны одинаковым размером. Для внутренних страниц нет отдельной системной области заголовков.
  • Явным образом создайте область заголовка внутренней страницы в шаблонах.
  • Не используйте рисунок заголовка, так как он может конфликтуть с заголовком или подзаголовоком, если мастер изменяет размер.

Дополнительные сведения о мастерах с обратной совместимостью см. в разделе "Мастер обратной совместимости 97".

Замечания

Полное обсуждение вопросов разработки для Wizard97 см . в спецификации Wizard97 в другом месте пакета SDK для Windows. В этом документе приведены рекомендации по таким аспектам, как измерения для диалоговых окон, размеров растровых изображений и цветов, а также размещение элементов управления.

Использование таблиц свойств

Демонстрация общих элементов управления Windows (CppWindowsCommonControls)