Создание модального окна win32 с помощью CreateWindow
Я создаю окно с CreateWindow()
и покажу его с ShowWindow()
. Но родительское окно, на котором оно было создано, должно быть отключено до тех пор, пока пользователь не вернется из этого окна, то есть он должен имитировать модальное диалоговое окно.
Ответы
Ответ 1
Убедитесь, что вы установите hwndParent
в CreateWindow
и используйте EnableWindow(hwndParent, FALSE)
, чтобы отключить родителя после отображения всплывающего окна. Затем включите родительский элемент с EnableWindow(hwndParent, TRUE)
после закрытия всплывающего окна.
Ответ 2
Модальность, часть 1: Модальность пользовательского интерфейса против модальности кода объясняет, как это сделать, и почему вы этого не захотите.
Ответ 3
Вам нужно подумать о том, что значит быть модальным окном - в основном, родитель окна отключен. Единственный автоматический способ сделать это (что я знаю) - вызвать DialogBox()
для создания модального диалогового окна. Однако, поскольку вы хотите использовать CreateWindow()
, тогда все, что вам нужно сделать, это вручную отключить родительское окно самостоятельно.
В идеале было бы лучше идти по маршруту диалога (так как ОС точно знает, что нужно сделать для создания модального окна), но я полагаю, что этот параметр есть, если вы должны его использовать.
Ответ 4
Вы также можете запустить "вторичный цикл сообщений", который не даст родительскому окну неактивно, пока ваша работа с "модальным" диалогом не будет завершена.
Ответ 5
Хорошо, я сам боролся с этой проблемой. Мне нужен был быстрый диалог, который бы вел себя так, как если бы я использовал DialogBox(), но я не хотел создавать шаблон для конкретного проекта, который я использовал.
Я обнаружил, что если вы отключите родительское окно диалога, вы также отключите диалог. И вы не можете включить этот диалог без повторного включения родительского диалога. Таким образом, этот метод не будет работать.
Я также обнаружил, что вы не можете использовать SetCapture()/ReleaseCapture(), потому что дочерние окна диалога не получат сообщения.
Я нашел решение, которое работает: Используйте локальный насос сообщений, управляемый либо PeekMessage(), либо GetMessage(). Вот код, который работал у меня:
while (!m_bFinished)
{
BOOL bEat;
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
if (msg.message == WM_CHAR)
{
if (msg.wParam == VK_ESCAPE)
{
m_bFinished = TRUE;
continue;
}
}
bEat = FALSE;
if (msg.message >= WM_MOUSEFIRST &&
msg.message <= WM_MOUSELAST)
{
RECT rectMe;
pcMe->GetWindowRect(&rectMe);
if (!::PtInRect(&rectMe, msg.pt))
bEat = TRUE;
}
if (!bEat)
{
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
}
}
То, что это эффективно делает, - "есть" любые сообщения мыши, которые находятся за пределами клиентской области окна, для всех сообщений, доставляемых в это приложение. Он не запрещает выходить за пределы приложения, просто щелкая в любом месте приложения, которое не находится в клиентской области "модального" окна. Если вы добавите MessageBeep(), когда будете есть сообщение, вы получите то же самое поведение, что и настоящий модальный диалог.
m_bFinished является членом BOOL класса, и он устанавливается, если в диалоговом окне доступны или кнопки "ОК" или "Отмена", и в некоторых других условиях, которые находятся вне области фрагмента кода здесь.