лист свойств в диалоговом окне на примере WINAPI (без использования MFC)

Может ли кто-нибудь указать мне пример WINAPI для встраивания листа свойств в диалоговое окно с использованием WINAPI (не MFC)?


person Mike D    schedule 11.07.2011    source источник


Ответы (1)


Для справки, вот некоторые вещи, которые я узнал, исследуя этот вопрос. Я получил большую часть / все это, задавая вопросы здесь или выполняя поиск в Интернете. Спасибо всем за вашу помощь!

Я написал класс, чтобы инкапсулировать все, что я обнаружил; если вы заинтересованы в получении копии, отправьте мне электронное письмо по адресу [email protected].

Передайте HWND родительского окна для вашего листа свойств в .hwndParent PROPSHEETHEADER при создании листа свойств с помощью функции страницы PropertySheet.

Я использовал элемент управления изображением в диалоговом окне в качестве родителя листа свойств, так что это HWND, который я использовал в качестве hwndParent.

Измените стиль страницы свойств, используя поле обратного вызова pfnCallback в заголовке, не забудьте включить PSH_USECALLBACK в dwFlags. См. Функция PropSheetProc в MSDN. В обработчике обратного вызова PSCB_PRECREATE настройте стиль окна листа свойств, удалив WS_POPUP и добавив WS_CHILD. Мне не нужна рамка или строка заголовка на странице свойств, поэтому я также удалил WS_CAPTION, WS_SYSEMNU и DS_MODALFRAME.

LONG L = ((LPDLGTEMPLATE)lParam)->style;
L &= ~WS_POPUP; 
L &= ~WS_CAPTION;       // gets rid of title bar
L &= ~WS_SYSMENU;       
L &= ~DS_MODALFRAME;        // gets rid of border
L |=  WS_CHILD;         // 40000000
((LPDLGTEMPLATE)lParam)->style = L;

Использование дочернего окна вместо всплывающего аккуратно решает некоторые проблемы, такие как перемещение листа свойств при перемещении родительского окна, сохранение правильного синего/серого состояния родительского окна и проблемы отсечения. т.е. вам не нужно беспокоиться об этих вещах.

Если вы остановитесь здесь, вы столкнетесь с другой проблемой. Код поддержки диалога в WIN32 попадал в цикл процессора, пытаясь найти лист свойств и элементы управления в его Windows. Видеть

Для чего нужны WS_EX_CONTROLPARENT и DS_CONTROL?

за довольно хорошее объяснение этой проблемы. Решение состоит в том, чтобы добавить расширенный стиль WS_EX_CONTROLPARENT в список свойств. Вы можете найти информацию об этом в Интернете, выполнив поиск WS_EX_CONTROLPARENT. То, что вы не найдете, причинило мне много горя. Если вы используете элемент управления в диалоговом окне в качестве родителя, вы также должны установить его WS_EX_CONTROLPARENT.

Я не знаю, в чем разница между WS_EX_CONTROLPARENT и DS_CONTROL, и не знаю, можно ли заменить WS_EX_CONTROLPARENT на DS_CONTROL. Из Интернета я понял, что DS_CONTROL как-то связан с вкладками. Мое тестовое приложение работает одинаково в отношении вкладок с DS_CONTROL или без него.

Я позаботился о бизнесе WS_EX_CONTROLPARENT после вызова функции PropertySheet для создания листа свойств. Я не знаю, можете ли вы сделать это в процедуре обратного вызова или нет. Я полагаю, вы могли бы использовать GetParent в обратном вызове, чтобы получить HWND элемента управления.

LONG S;

S = GetWindowLong (hwndPS, GWL_EXSTYLE) | WS_EX_CONTROLPARENT;
SetWindowLong (hwndPS, GWL_EXSTYLE, S);

S = GetWindowLong (hwndPS_Area, GWL_EXSTYLE) | WS_EX_CONTROLPARENT;
SetWindowLong (hwndPS_Area, GWL_EXSTYLE, S);

После создания листа свойств с помощью функции PropertySheet его необходимо правильно расположить:

SetWindowPos(hwndPS, HWND_TOP, 2, 2, -1, -1,
             SWP_NOSIZE | SWP_NOACTIVATE); 

Я оставил пару пикселей для границы.

Если вы хотите избавиться от всех кнопок листа свойств и места, которое они занимают:

RECT rectWnd;
RECT rectButton;

GetWindowRect(hwndPS, &rectWnd);
HWND hWnd = ::GetDlgItem(hwndPS, IDOK);

if(!hWnd)
{
    DebugBreak();
}

GetWindowRect(hWnd, &rectButton);

SetWindowPos (hwndPS, NULL, 0, 0,
          rectWnd.right - rectWnd.left, rectButton.top - rectWnd.top,
          SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_SHOWWINDOW);

Отдельные кнопки можно исключить:

hwndOk = GetDlgItem (hwndPS,IDOK);              // Hide the OK button
ShowWindow (hwndOk, SW_HIDE);
EnableWindow (hwndOk, FALSE);

Вы можете избавиться от кнопки APPLY, используя dwFlags PSH_NOAPPLYNOW в PROPERTYSHEETHEADER при создании листа свойств.

Страницы листа свойств НЕ будут созданы до тех пор, пока пользователь не активирует их. Я хотел, чтобы все они были созданы при создании листа свойств.

unsigned int iP;
for (iP=0; iP<Header.nPages; iP++)
{
    if (iP != Header.nStartPage)
        SendMessage (hwndPS, PSM_SETCURSEL,iP,NULL);
}
SendMessage (hwndPS, PSM_SETCURSEL,Header.nStartPage,NULL);

Есть флаг PROPSHEETPAGE, который делает то же самое (из MSDN)

PSP_PREMATURE версии 4.71. Заставляет страницу создаваться при создании листа свойств. Если этот флаг не указан, страница не будет создана, пока она не будет выбрана в первый раз.

Но я беспокоился о бизнесе версии 4.71, поэтому сделал это сам.

Вы можете изменить текст на любой из кнопок:

SetDlgItemText (hwndPS,ButtonID,Text);

где ButtonID является одним из IDOK IDCANCEL IDHELP IDAPPLYNOW

IDAPPLYNOW не определен в моей системе, поэтому

#define IDAPPLYNOW     0x3021   

Вот как я собираюсь использовать свой лист свойств. Я собираюсь поместить весь код инициализации и завершения в диалоговое окно, содержащее лист свойств, и убрать все кнопки листа свойств. Я могу установить там все начальные значения и получить там все окончательные значения, когда пользователь нажимает кнопку DO IT. Я заметил, что действие установки, например, текстового поля приводит к тому, что диалоговое окно содержащей страницы получает WM_COMMAND/EN_CHANGE. Если вы используете это сообщение, чтобы активировать кнопку ПРИМЕНИТЬ, вам может потребоваться отключить флаг изменения для страницы после установки каких-либо списков. Я решил эту проблему, очистив все измененные флаги после установки начального значения. (Я подозреваю, что лист свойств очищает измененный флаг после отправки всех сообщений INITDIALOG. В любом случае APPLY не включен, если текстовые поля установлены в обработчиках страницы INITDIALOG.) Если я обнаружу ошибку, я выберу этот лист свойств. страницу и поместите красный текст в родительский диалог, описывающий ошибку. Единственное, что должны делать диалоговые процедуры листа свойств, — это манипулировать их элементами управления.

Меня озадачивает один вопрос: как определить, все ли страницы вернули PSNRET_NOERROR из своих сообщений WS_NOTIFY/PSN_APPLY. Мне удалось подсчитать количество последовательных ответов PSNRET_NOERROR, установив счетчик на ноль, когда сообщается PSNRET_INVALID или получен PSN_KILLACTIVE. Если счетчик достигает количества страниц в заголовке листа свойств, я предполагаю, что все страницы вернули PSNRET_NOERROR. Но меня беспокоят такие вещи, как отключенные и невидимые страницы.

person Mike D    schedule 24.07.2011