Электронная библиотека книг Александра Фролова и Григория Фролова.
Shop2You.ru Создайте свой интернет-магазин
Библиотека
Братьев
Фроловых

Операционная система Windows 95 для программиста

© Александр Фролов, Григорий Фролов
Том 22, М.: Диалог-МИФИ, 1993, 271 стр.

[Назад] [Содеожание] [Дальше]

6.1. Создание органа управления Property Sheet

Орган управления Property Sheet - это системная немодальная диалоговая панель, состоящая из нескольких страниц. Перед тем как продолжить чтение, мы рекомендуем вам обратиться к главе "Диалоговые панели", расположенной в 12 томе "Библиотеки системного программиста", и вспомнить, как работают обычные диалоговые панели.

Для создания органа управления Property Sheet вы должны сделать следующее:

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

Сразу отметим, что для создания органа управления Wizard необходимо использовать точно такую же процедуру. Отличия заключаются в заполнении структур и обработке сообщений в функциях диалога.

Рассмотрим перечисленные выше шаги подробнее.

Подготовка шаблонов диалоговых панелей

Шаблон диалоговой панели готовится обычным способом с помощью интегрированной среды разработки приложений Microsoft Visual C++. Единственное, на что нам хотелось бы обратить внимание: на страницах блокнота и органа управления Wizard нет кнопок OK, Cancel и Help, так как эти кнопки относятся ко всему блокноту и располагаются в нижней части его окна. В остальном шаблоны страниц блокнота ничем не отличаются от шаблонов обычных диалоговых панелей.

Функция диалога страницы блокнота

Функция диалога страницы блокнота обычно обрабатывает сообщения WM_INITDIALOG , WM_COMMAND и WM_NOTIFY . Первое из них передается функции диалога при его инициализации, второе поступает от органов управления, расположенных на странице блокнота. Сообщение WM_NOTIFY генерируется в том случае, когда пользователь нажимает кнопки OK, Cancel, Help, Apply (а также кнопки Back, Next и Finish в органе управления Wizard) или переходит к просмотру другой страницы блокнота. Ниже мы рассмотрим эти сообщения подробнее.

В отличие от обычной функции диалога, функция диалога для страницы блокнота или органа управления Wizard не вызывает функцию EndDialog , так как это привело бы к уничтожению органа управления. Вот пример функции диалога для страницы блокнота, взятый из приложения Property Sheet Demo, полные исходные тексты которого вы найдете ниже в разделе "Приложение Property Sheet Demo":

BOOL APIENTRY
DlgProc1(HWND hdlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
  switch(msg)
  {
    HANDLE_MSG(hdlg, WM_INITDIALOG, DlgProc1_OnInitDialog);
    HANDLE_MSG(hdlg, WM_COMMAND,    DlgProc1_OnCommand);
    HANDLE_MSG(hdlg, WM_NOTIFY,     DlgProc1_OnNotify);
    default:
      break;
  }
  return FALSE;
}

Так же как и в функции главного окна приложений, в функции диалога для организации обработки сообщений мы воспользовались удобной макрокомандой HANDLE_MSG .

Подготовка массива структур PROPSHEETPAGE

Для каждой страницы блокнота или органа управления Wizard вы должны подготовить структуру PROPSHEETPAGE , записав в нее описание страницы. Структура PROPSHEETPAGE определена следующим образом:

typedef struct _PROPSHEETPAGE 
{
  DWORD     dwSize;             // размер структуры  
  DWORD     dwFlags;            // флаги
  HINSTANCE hInstance;          // идентификатор приложения
  union 
  { 
    LPCTSTR pszTemplate; // идентификатор ресурса 
                         // диалоговой панели
    LPCDLGTEMPLATE pResource;   // шаблон диалоговой панели
  };
  union 
  { 
    HICON  hIcon;               // идентификатор пиктограммы
    LPCTSTR pszIcon; // идентификатор ресурса пиктограммы
  }; 
  LPCTSTR pszTitle;             // заголовок страницы
  DLGPROC pfnDlgProc;           // адрес функции диалога
  LPARAM  lParam;               // дополнительный параметр
 LPFNPSPCALLBACK pfnCallback;// адрес функции обратного вызова
 UINT FAR  * pcRefParent;// указатель на счетчик использования       
} PROPSHEETPAGE, FAR  *LPPROPSHEETPAGE; 
typedef const PROPSHEETPAGE FAR  *LPCPROPSHEETPAGE; 

Возможно, эта структура выглядит несколько громоздко, однако ее заполнение не вызовет у вас никаких затруднений.

В поле dwSize необходимо записать размер структуры, т. е. значение sizeof(PROPSHEETPAGE).

В поле dwFlags следует записать флаги, отмечающие задействованные поля структуры и определяющие внешний вид органа управления. Здесь можно использовать следующие значения:

Флаг Описание
PSP_DEFAULT Используются все поля структуры, имеющие назначение, принятое по умолчанию
PSP_DLGINDIRECT Поле pResource используется вместо поля pszTemplate. Этот флаг следует указать в том случае, если вы создаете шаблон диалоговой панели для страницы динамически в памяти, а не загружаете его из ресурсов приложения
PSP_HASHELP Если указан этот флаг, для данной страницы отображается кнопка Help
PSP_RTLREADING Заголовок, определенный в поле pszTitle, отображается справа налево. Используется только в арабских версиях Microsoft Windows 95
PSP_USECALLBACK При создании или уничтожении страницы управление получает функция обратного вызова, адрес которой определен в поле pfnCallback
PSP_USEHICON Поле hIcon содержит идентификатор пиктограммы уменьшенного размера, которая будет отображаться в левой части закладки страницы
PSP_USEICONID Поле pszIcon содержит идентификатор ресурса пиктограммы уменьшенного размера, которая будет отображаться в левой части закладки страницы
PSP_USEREFPARENT Используется поле pcRefParent
PSP_USETITLE В качестве заголовка страницы следует использовать строку, адрес которой задан в поле pszTitle, а не ту строку, что определена в шаблоне диалоговой панели

В нашем приложении мы использовали флаги PSP_USETITLE и PSP_USEICONID.

Поле hInstance должно содержать идентификатор приложения, который передается через соответствующий параметр функции WinMain.

Поля pszTemplate и pResource объединены, поэтому вы можете использовать только одно из них. По умолчанию вы должны записать в поле pszTemplate идентификатор ресурса, содержащего шаблон диалоговой панели. Однако указав флаг PSP_DLGINDIRECT, вы вместо этого можете создать шаблон диалоговой панели динамически в оперативной памяти и записать указатель на этот шаблон в поле pResource.

Аналогичным образом объединены поля hIcon и pszIcon. Если в поле pszIcon вы собираетесь записать идентификатор пиктограммы, которая будет отображаться в закладке, следует указать флаг PSP_USEHICON. Если же пиктограмма определена в ресурсах приложения, вы должны записать соответствующий идентификатор ресурса в поле pszIcon и указать флаг PSP_USEICONID.

В том случае, когда вам не нужно отображать пиктограмму на закладке, не указывайте флаги PSP_USEHICON и PSP_USEICONID, а в поле pszIcon (или hIcon, что одно и то же) запишите значение NULL.

При создании шаблона диалоговой панели вы можете указать ее заголовок. Однако вместо этого можно использовать поле pszTitle и флаг PSP_USEICONID.

В поле pfnDlgProc необходимо записать адрес функции диалога, подготовленной с учетом приведенных выше замечаний.

Вот как мы заполнили поля структуры PROPSHEETPAGE для трех страниц блокнота в приложении Property Sheet Demo:

PROPSHEETPAGE   psheetPage[3];

psheetPage[0].dwSize = sizeof(PROPSHEETPAGE);
psheetPage[0].hInstance = hInst;
psheetPage[0].pszIcon = MAKEINTRESOURCE(IDI_EFFECTS);
psheetPage[0].dwFlags = PSP_USETITLE | PSP_USEICONID;
psheetPage[0].pszTemplate = 
  MAKEINTRESOURCE(IDD_DIALOG1);
psheetPage[0].pfnDlgProc = DlgProc1;
psheetPage[0].pszTitle = "Set Effects";
psheetPage[0].lParam = 0;

psheetPage[1].dwSize = sizeof(PROPSHEETPAGE);
psheetPage[1].hInstance = hInst;
psheetPage[1].pszIcon = MAKEINTRESOURCE(IDI_TAB);
psheetPage[1].dwFlags = PSP_USETITLE | PSP_USEICONID;
psheetPage[1].pszTemplate = 
  MAKEINTRESOURCE(IDD_DIALOG2);
psheetPage[1].pfnDlgProc = DlgProc2;
psheetPage[1].pszTitle = "Using Tabs";
psheetPage[1].lParam = 0;

psheetPage[2].dwSize = sizeof(PROPSHEETPAGE);
psheetPage[2].hInstance = hInst;
psheetPage[2].pszIcon = MAKEINTRESOURCE(IDI_KEYWORD);
psheetPage[2].dwFlags = PSP_USETITLE | PSP_USEICONID;
psheetPage[2].pszTemplate = 
  MAKEINTRESOURCE(IDD_DIALOG3);
psheetPage[2].pfnDlgProc = DlgProc3;
psheetPage[2].pszTitle = "Keyword";
psheetPage[2].lParam = 0;

Заполнение структуры PROPSHEETHEADER и создание блокнота

Структура PROPSHEETHEADER , как это видно из ее названия, описывает заголовок блокнота. Она имеет следующий формат:

typedef struct _PROPSHEETHEADER 
{
  DWORD      dwSize;     // размер структуры    
  DWORD      dwFlags;    // флаги
  HWND       hwndParent; // идентификатор родительского окна
  HINSTANCE  hInstance;  // идентификатор приложения
  union 
  { 
    HICON  hIcon;        // идентификатор пиктограммы
    LPCTSTR pszIcon;     // идентификатор ресурса пиктограммы
  }; 
  LPCTSTR  pszCaption;   // заголовок блокнота
  UINT     nPages;       // количество страниц в блокноте
  union 
  { 
    UINT  nStartPage;     // номер первой страницы 
    LPCTSTR pStartPage;   // имя первой страницы
  }; 
  union 
  { 
    LPCPROPSHEETPAGE ppsp; // адрес массива структур 
                           // PROPSHEETPAGE
    HPROPSHEETPAGE FAR  *phpage; // адрес массива
  };            // идентификаторов страниц блокнота
  PFNPROPSHEETCALLBACK pfnCallback; // адрес функции 
                                 // обратного вызова
} PROPSHEETHEADER, FAR  *LPPROPSHEETHEADER; 
typedef const PROPSHEETHEADER FAR  *LPCPROPSHEETHEADER;

В поле dwSize нужно записать размер структуры.

Поле dwFlags может содержать логическую комбинацию следующих значений:

Флаг Описание
PSH_DEFAULT Используются все поля структуры, имеющие назначение, принятое по умолчанию
PSH_MULTILINETABS Закладки страниц могут располагаться в несколько рядов
PSH_NOAPPLYNOW Не отображается кнопка Apply
PSH_PROPSHEETPAGE При создании органа управления вместо поля phpage используется поле ppsp
PSH_PROPTITLE К заголовку, определенному в поле pszCaption, добавляется строка Properties for
PSH_USECALLBACK При инициализации органа управления используется функция обратного вызова, адрес которой указан в поле pfnCallback
PSH_USEHICON Поле hIcon содержит идентификатор пиктограммы уменьшенного размера, которая отображается в заголовке блокнота. Эта пиктограмма не нужна для органа управления Wizard
PSH_USEICONID Поле pszIcon содержит идентификатор htcehcf пиктограммы уменьшенного размера, которая отображается в заголовке блокнота. Эта пиктограмма не нужна для органа управления Wizard
PSH_USEPSTARTPAGE Вместо поля nStartPage используется поле pStartPage
PSH_WIZARD Создается орган управления Wizard, а не блокнот Property Sheet

В приложении Property Sheet Demo мы заполнили структуру PROPSHEETHEADER следующим образом:

PROPSHEETHEADER psheetHeader;
psheetHeader.dwSize     = sizeof(PROPSHEETHEADER);
psheetHeader.hInstance  = hInst;
psheetHeader.pszIcon    = MAKEINTRESOURCE(IDI_APPICONSM);
psheetHeader.dwFlags    = PSH_USEICONID;
psheetHeader.hwndParent = hWnd;
psheetHeader.pszCaption = "Property Sheet Sample";
psheetHeader.nPages = 
  sizeof(psheetPage) / sizeof(PROPSHEETPAGE);
psheetHeader.phpage     = (HPROPSHEETPAGE FAR  *)&hPage[0];

Обратите внимание на поле phpage. В него мы записали адрес массива идентификаторов страниц HPROPSHEETPAGE. Этот массив заполняется функцией CreatePropertySheetPage, которой в качестве параметра передается адрес предварительно заполненной структуры PROPSHEETPAGE:

HPROPSHEETPAGE  hPage[3];
hPage[0] = CreatePropertySheetPage(&psheetPage[0]);
hPage[1] = CreatePropertySheetPage(&psheetPage[1]);
hPage[2] = CreatePropertySheetPage(&psheetPage[2]);

После заполнения заголовка блокнота можно создать блокнот (или орган управления Wizard, если указан флаг PSH_WIZARD ) при помощи функции PropertySheet :

PropertySheet(&psheetHeader);

Есть еще один способ создания блокнота или органа управления Wizard без использования функции CreatePropertySheetPage. Мы применили этот способ в приложении Wizard Demo:

psheetHeader.dwSize = sizeof(PROPSHEETHEADER);
psheetHeader.hInstance = hInst;
psheetHeader.pszIcon = NULL;
psheetHeader.dwFlags = PSH_PROPSHEETPAGE | PSH_WIZARD;
psheetHeader.hwndParent = hWnd;
psheetHeader.pszCaption = "Property Sheet Sample";
psheetHeader.nPages = 
  sizeof(psheetPage) / sizeof(PROPSHEETPAGE);
psheetHeader.ppsp = (LPCPROPSHEETPAGE)&psheetPage;
PropertySheet(&psheetHeader);

Здесь мы не используем пиктограмму, так как она все равно не отображается, поэтому в поле pszIcon записано значение NULL. Кроме того, указаны флаги PSH_PROPSHEETPAGE и PSH_WIZARD.

Так как указан флаг PSH_PROPSHEETPAGE, то в поле ppsp мы записываем адрес массива структур PROPSHEETPAGE, описывающих отдельные страницы органа управления Wizard. При этом нам не нужен массив идентификаторов страниц и, соответственно, функция CreatePropertySheetPage, которая его заполняет.

[Назад] [Содеожание] [Дальше]