Я создаю окно с CreateWindow()
и покажу его с ShowWindow()
. Но родительское окно, на котором оно было создано, должно быть отключено до тех пор, пока пользователь не вернется из этого окна, то есть он должен имитировать модальное диалоговое окно.
Создание модального окна win32 с помощью CreateWindow
Ответ 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 класса, и он устанавливается, если в диалоговом окне доступны или кнопки "ОК" или "Отмена", и в некоторых других условиях, которые находятся вне области фрагмента кода здесь.