Для справки, вот некоторые из вещей, которые я узнал во время
исследуя этот вопрос. Я получил большинство / все это от
задавать вопросы здесь или с помощью поиска в Интернете. Спасибо всем за
ваша помощь!
Я написал класс для инкапсуляции всего, что обнаружил;
если вы заинтересованы в получении копии, отправьте мне письмо по электронной почте mdorl@wisc.edu.
Передайте 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 попадет в цикл процессора, пытаясь найти страницу свойств и
контролирует в своей винде. Смотри
Для чего нужны WS_EX_CONTROLPARENT и DS_CONTROL?
за довольно хорошее объяснение
Эта проблема. Решение состоит в том, чтобы добавить расширенный WS_EX_CONTROLPARENT
стиль на листе недвижимости. Вы можете найти информацию об этом
в Интернете с помощью поиска WS_EX_CONTROLPARENT. Чего вы не найдете
причинил мне много горя. Если вы используете элемент управления в диалоговом окне в качестве
parent, вы также должны установить его WS_EX_CONTROLPARENT.
Я не знаю, в чем разница между WS_EX_CONTROLPARENT и DS_CONTROL, и я не знаю, можно ли заменить DS_CONTROL на WS_EX_CONTROLPARENT. Из Интернета я понимаю, что 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, используя PSH_NOAPPLYNOW
dwFlags в 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. Но я беспокоюсь о таких вещах, как отключенные и невидимые страницы.