Как сделать диалоговое окно с

Обновлено: 17.05.2024

Как сделать диалоговое окно?

Предположим есть окно в котором в виде таблице отображается некий список, для каждой записи есть некий набор действий, для примера пусть будут "Edit"/"Detail"/"Delete".

При выборе пользователем пункта "Delete" необходимо показать окно с неким предупреждающим текстом, и двумя возможными действиями: "Ok"/"Cancel".

Как бы я это сделал в winforms приложении:

В рамках mvvm, необходимо сделать View, ModelView, т.е. у нас должно быть что то типа Main , MainViewModel , Dialog , DialogViewModel ;

в Main - будут кнопки которые будут прибиндины к командам из ViewModel. т.е. например так могла бы выглядеть команда для "Delete":

Как вариант можно сделать публичное свойство в DialogViewModel с типом boolean и устанавливать его в диалоге, по нажатии на любую из кнопок (Ok/Canсel) менять его значение, в главной форме смотреть значение этого свойства. Вот только меня терзают сомнения в правильности такого подхода.

Как сделать Диалоговое окно в wpf с использованием mvvm?

P.S.: код писал здесь, могут быть ошибки

задан 28 янв '16 в 5:26


6,314 4 4 золотых знака 30 30 серебряных знаков 76 76 бронзовых знаков Постарайтесь писать более развернутые вопросы. Для получения ответа поясните, в чем именно вы видите проблему 28 янв '16 в 5:54 @KromStern попытался написать более развернуто 28 янв '16 в 6:29 Теперь гораздо лучше. Поставил плюсик за развернутость 28 янв '16 в 6:43 Вопрос то в чем? Если у вас простой диалог уточнение - то это может быть на совести вьюшки\вьюмодели целиком. Пилить каждый раз на каждый чих вьюшки и вьюмодели к ним тоже не надо. С другой стороны, если таких диалогов в целом набирается хотя бы штук 5, то наверно стоит вынести куда то в отдельный класс возможность просто во вьюмодели сказать что нужен запрос подтверждения с таким то текстом\иконкой\кнопками. И тут уж ессна надо делать нормальную модель диалога и вьюшку диалога. 28 янв '16 в 7:25 @Monk что бы так тупо написать Вы сначала реализовали свой класс Dialogs (Model), представление (View), логику (ViewModel), теперь это конечно легко и тупо. а я пока не реализовал это для себя и даже не знаю как сделать, наверно придется останавливаться на публичном свойстве в диалоге и проверять его из главного окна. 28 янв '16 в 8:18

Здесь есть два варианта действий:

Более простой способ, но более неудобный в случае, если вы используете TDD: Вам нет необходимости создавать ViewModel и View отдельно для диалогового окна: достаточно перед удалением проверять ответ пользователя в диалоговом окне следующим образом:

Более трудоёмкий способ, но с соблюдением всех канонов MVVM: создаёте ViewModel для вашего диалогового окна. Во ViewModel создаёте событие, например:

Событие нужно декорировать специальным аттрибутом, который позволит транслировать его в другие ViewModel-классы, не нарушая при этом принцип high-cohesion loose-coupling. Для этого используются мессенджеры. Можете попробовать Appcelerate.EventBroker. В своих проектах я использую именно его.

Далее - создаёте команду, которая ссылается на метод, вызывающий вышеупомянутое событие. Привязываете команду к кнопке в вашем диалоговом окне.

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

View в этом случае создавайте, как пару Window.xaml + Window.cs, у которого есть метод ShowDialog(), что автоматически заблокирует вызывающее окно на время открытия диалогового.

PS: первый способ не совсем правильный, потому что будет сложно тестировать результат, выбранный пользователем в MessageBox.

Добавлено Если захотите использовать это окно в разных местах вашего приложения, создайте базовый абстрактный класс, а в унаследованных VM-классах перегрузите нужные вам свойства. Например, в некоторых случаях вам может понадобиться «дернуть» несколько событий, чтобы на подтверждение среагировало несколько ViewModel. Тут всё зависит от сложности проекта.

Диалоговые окна

приложения для Windows часто взаимодействуют с пользователем с помощью диалоговых окон. Класс CDialog предоставляет интерфейс для управления диалоговыми окнами, редактор диалоговых окон Visual C++ упрощает конструирование диалоговых окон и создание ресурсов диалоговых окон, а также мастера кода упрощают процесс инициализации и проверки элементов управления в диалоговом окне и для сбора значений, вводимых пользователем.

Диалоговые окна содержат элементы управления, включая:

Windows общие элементы управления, такие как поля ввода, кнопки, списки, поля со списком, элементы управления "дерево", элементы управления "список" и индикаторы хода выполнения.

ActiveX элементы управления.

Рисуемые владельцем элементы управления: элементы управления, которые вы несете для рисования в диалоговом окне.

Большинство диалоговых окон являются модальными, что требует от пользователя закрыть диалоговое окно перед использованием любой другой части программы. Но можно создать немодальные диалоговые окна, которые позволяют пользователям работать с другими окнами, пока диалоговое окно открыто. MFC поддерживает оба вида диалогового окна с классом CDialog . Элементы управления упорядочиваются и управляются с помощью ресурса шаблона диалогового окна, созданного в редакторе диалоговых окон.

Как создать диалоговое окно (C++)

Расположение и размер диалогового окна C++, а также расположение и размер элементов управления в нем измеряются в единицах диалогового окна. значения для отдельных элементов управления и диалогового окна отображаются в правом нижнем углу строки состояния Visual Studio при их выборе.

Если в проекте еще нет RC-файла, см. раздел Создание нового файла описания ресурсов.

Инструкции

Редактор диалоговых окон позволяет:

Создание нового диалогового окна

В представление ресурсовщелкните правой кнопкой мыши RC -файл и выберите Добавить ресурс.

В диалоговом окне Добавление ресурса в списке тип ресурса выберите диалоговое окно , а затем нажмите кнопку создать.

Если + рядом с типом ресурса диалогового окна отображается знак «плюс» (), это означает, что доступны шаблоны диалоговых окон. Щелкните знак «плюс», чтобы развернуть список шаблонов, выберите шаблон и нажмите кнопку создать.

В редакторе диалоговых окон откроется диалоговое окно создать.

Также можно открыть существующие диалоговые окна в редакторе диалоговых окон для редактирования.

Создание диалогового окна, которое пользователь не может выйти

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

В области Свойства диалогового окна задайте для свойства системного меню значение false .

Этот параметр отключает системное меню диалогового окна и кнопку Закрыть .

В форме диалогового окна удалите кнопки Отмена и ОК .

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

Чтобы включить тестирование этого типа диалогового окна, функция тестового диалогового окна обнаруживает, что нажата клавиша ESC . Клавиша ESC также называется виртуальным ключом VK_ESCAPE. Независимо от того, как будет работать диалоговое окно во время выполнения, можно завершить тестовый режим, нажав клавишу ESC.

Для создания диалогового окна, которое пользователи не могут выйти из приложения MFC, необходимо переопределить поведение по умолчанию OnOK и, OnCancel так как даже если удалить связанные кнопки, диалоговое окно по-прежнему может быть закрыто нажатием клавиши Ввод или ESC.

Указание расположения и размера диалогового окна

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

Логическое свойство центра .

Если задать значение true, диалоговое окно всегда будет отображаться в центре экрана. Если для этого свойства задано значение false, можно задать свойства кспос и ИПОС .

Свойства кспос и ИПОС , которые используются для явного определения того, где появится диалоговое окно.

Эти свойства позиции являются значениями смещения в верхнем левом углу области просмотра, которая определена как .

Свойство абсолютного соответствия, которое влияет на положение.

Если значение равно true, координаты задаются относительно экрана. Если значение равно false, координаты задаются относительно окна владельца диалогового окна.

Проверка диалогового окна

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

вводить текст, выбирать пункты в полях со списками, включать и отключать параметры, выбирать команды;

тестировать последовательность табуляции;

проверять группировку элементов управления, например переключателей и флажков;

тестировать сочетания клавиш, используемые для доступа к элементам управления в диалоговом окне.

Подключения к коду диалогового окна, созданному с помощью мастеров, не включаются в имитацию.

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

Когда Редактор диалоговых окон является активным окном, перейдите в > диалоговое окно Проверка формата меню.

Чтобы завершить моделирование, нажмите клавишу ESC или нажмите кнопку Закрыть в тестируемом диалоговом окне.

Редактор диалоговых окон (C++)

Редактор диалоговых окон позволяет создавать и изменять ресурсы диалоговых окон.

  • чтобы открыть редактор, дважды щелкните rc-файл диалогового окна в представление ресурсов окне или выберите пункт меню просмотреть > другие Windows > представление ресурсов.

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

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

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

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

начиная с Visual Studio 2015, можно использовать редактор диалоговых окон для определения динамических макетов, которые определяют способ перемещения и изменения размеров элементов управления при изменении размера диалогового окна. Для получения дополнительной информации см. Dynamic Layout.

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

Панель инструментов редактора диалоговых окон

Панель инструментов редактора диалоговых окон содержит кнопки для упорядочивания макета элементов управления в диалоговом окне, например размер и выравнивание. Кнопки панели инструментов редактора диалоговых окон соответствуют командам в меню Формат .

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

Переключение между элементами управления диалогового окна и кодом

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

Для классов диалоговых окон на основе ATL всегда выполняется переход к определению конструктора.

Чтобы просмотреть события для элемента управления с выбранным элементом управления, нажмите кнопку контролевентс в окне свойства .

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

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

Сочетания клавиш

Ниже приведены сочетания клавиш по умолчанию для команд редактора диалоговых окон .

Чтобы изменить сочетания клавиш, перейдите в меню Сервис > Параметры и выберите пункт Клавиатура в папке Среда .

чтобы изменить параметры, последовательно выберите пункты меню > импорт и экспорт Параметры.

Параметры, доступные в диалоговых окнах, а также имена и расположения команд меню, которые вы видите, могут отличаться от описанных в справке в зависимости от текущих параметров или выпуска. Дополнительные сведения см. в разделе Персонализация интегрированной среды разработки Visual Studio.

Как сделать диалоговое окно с

Именно он вызывает форму в качестве модального диалога. Если вместо ShowDialog() воспользоваться просто Show(), то форма откроется не модально.

От модальных диалоговых окон можно получить «обратный отклик», задав в свойствах используемых на нем кнопок DialogResult.

DialogResult

У кнопок вроде «OK» и «Cancel» диалоговых окон, рекомендуется это свойство заполнять. Оно очень полезно, когда вызвавшей диалог форме нужно узнать, каким образом завершился диалог. Например, когда нужно применить изменения, если пользователь выбрал «OK».

Как вызвать диалоговое окно по нажатию на кнопку

Помощь в написании контрольных, курсовых и дипломных работ здесь.

94731 / 64177 / 26122 Ответы с готовыми решениями:

При нажатии на кнопку открывается диалоговое окно OpenFileDialog, выбранный файл загружается в RichTextBox
Разработать Windows Forms приложение, содержащее RichTextBox и кнопку. При нажатии на кнопку.


Как вызвать диалоговое окно CommonDialog
Есть ли уже созданное диалоговое окно 'Открыть' или 'Сохранить', на подобии стандпртного, которое.

Как вызвать диалоговое окно загрузки?
Доброе утро. Подскажите как можно вызвать средствами javascript, диалоговое окно загрузки.


Как вызвать диалоговое окно загрузки файла?
Как вызвать диалоговое окно типа загрузить сохранить как? Например для загрузки картинки?

710 / 701 / 168

Что вы подразумеваете под диалоговым окном? MessageBox или отдельную форму?

Создание диалогового окна которое предлагает сохранить изменения

Помощь в написании контрольных, курсовых и дипломных работ здесь.

94731 / 64177 / 26122 Ответы с готовыми решениями:


Использование диалогового окна, которое создается функцией uigetfile
Подскажите, пожалуйста, как с использование диалогового окна, которое создается функцией uigetfile.

При закрытии книга предлагает сохранить изменения, даже если ничего не изменилось
После ввода формулы =ДВССЫЛ(АДРЕС(7;2;;;Сведения!$H$1)) при закрытии рабочая книга требует.

Сохранить катинку без диалогового окна
Как можно и можно ли сохранить без диалогового окна в этом коде? Private Sub btnSave_Click(ByVal.


Как присвоить переменную одного диалогового окна к переменной другого диалогового окна? (ООП)
Вот у меня есть результат вычисления и я его присваиваю переменной в первом диалоговом окне, но я.

707 / 707 / 226 Спасибо, это действительно то. А можно ли изменить текст на кнопках? MessageBox имеет предопределенный набор кнопок.
Если нужно что-то другое можно просто создать класс новой формы (в обозревателе решений правая кнопка мыши на названии проекта -> "Добавить" -> "Форма Windows"). В дизайнере положить нужные надписи, кнопки со своими надписями и т.п. У кнопок есть свойство DialogResult. Если это свойство указано, то при нажатии на кнопку форма закроется и вернет это значение. Если, например, новый класс имеет имя Form2, вызов из основной формы выглядит так:
87844 / 49110 / 22898

Помощь в написании контрольных, курсовых и дипломных работ здесь.

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

Сохранить конечное значение QSpinBox перед закрытием диалогового окна
Как сохранить конечное значение перед закрытием диалогового окна?? При использовании value.

Как сохранить путь диалогового окна открытый в прошлой сессии?
В 1С делаю под собой: 1)"Сервис-дополнительные внешние отчеты и обработки - дополнительные.

Как сохранить созданный файл Word без появления диалогового окна
При сохранении документа вылезает окно выбора названия и места сохранения файла. Можно ли сделать.

Создание диалогового окна
Здравствуйте. Мне необходимо создать диалоговое окно. В программе есть один пункт меню "о.

Создание диалогового окна
мой персонаж проходит всю игру, доходит до конечной точки и далее вылазит окошко, что вы прошли.

Как создать диалоговое окно с одной кнопкой на C++?

нужно создать диалоговое окно с одной единственной кнопкой "ок". как это сделать?

Wataru @wataru Куратор тега C++

Это не столько к С++ относится, сколько к тому, в какой операционной системе вы хотите создать окно?

space2pacman

Ярослав Иванов @space2pacman

loganbaby

logan baby @loganbaby Автор вопроса

Wataru, windows, создать окно надо средствами вин апи судя по всему.

HemulGM

Wataru, не согласен. Если язык кроссплатформенный (не только про срр), то всё будет зависеть от фреймворка

Евгений Шатунов @MarkusD Куратор тега C++

Hemul GM, тебе знакомы некроссплатформенные языки? Перечислишь?

HemulGM

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

Евгений Шатунов @MarkusD Куратор тега C++

Hemul GM, стало быть вопрос, все-таки, относится не столько к языку, сколько к конкретной прослойке перед операционной системой?
И к чему же тогда был твой первый комментарий? С чем конкретно ты не согласен? Особенно приняв во внимание то, что автор вопроса все свои вопросы задает только относительно Win32 API.

HemulGM

Евгений Шатунов, где написано про Win32?
ТС не указал вообще что использует для написания. Может у него Qt? А может Winforms.

Евгений Шатунов @MarkusD Куратор тега C++

Hemul GM, т.е. у тебя не получается разобраться с этим начиная с самого первого вопроса автора? Тебе мало вот этого комментария и ты все еще не можешь определиться с используемым инструментарием и целевой платформой в вопросе автора?
И к чему же тогда был твой первый комментарий? С чем конкретно ты не согласен?

HemulGM

Евгений Шатунов, читайте внимательнее, уважаемый.
Комментарий, с которым я не согласен, был написан до того, как ТС скажет, что нужно для чистого винапи.
И если ты ещё не понял, то я не согласен с тем, что это зависит от платформы. В первую очередь, это зависит от фреймворка, если он используется. Если используется фреймворк, то вызов диалоговых окон не обязательно будет зависеть от платформы, особенно если речь о кроссплатформенном фреймворке.

Евгений Шатунов @MarkusD Куратор тега C++

Hemul GM, и что это меняет? Ты просто не смог прочитать этот самый комментарий и пошел с чем-то там не соглашаться.
Читай внимательнее. Комментарий, с которым ты "не согласен", был написан в последнем вопросе. А у автора этих вопросов уже много и в этих вопросах все уже было объяснено.
Ты просто влез со своим мнением не понимая ни контекста, ни сути. Для чего же ты теперь пытаешься отстоять уже очевидно ошибочное мнение?

HemulGM

Евгений Шатунов, какое ошибочное мнение? В контексте этого вопроса и в рамках комментария, с которым я не согласен, я сказал всё правильно. С какой стати я должен внезапно идти и искать другие вопросы автора вопроса? Я опирался на то, что написано в вопросе.

Евгений Шатунов @MarkusD Куратор тега C++

Hemul GM, В контексте этого вопроса и в рамках своего комментария ты не прав. Ты не прочитал комментарий от автора, не понял контекста вопроса и пошел писать что-то о кроссплатформенных языках. Твой первый комментарий не просто ошибочен, он бесполезен и лишен смысла.

HemulGM

Евгений Шатунов, да с какой стати? Вызов диалоговых окон зависит от фреймворка. Он позволяет штатно вызывать диалоговые окна. И первым делом стоит узнать именно о фреймворке. Почему речь о кроссплатформенности? Потому что кроссплатформенные фреймворки точно будут иметь собственные методы вызова диалоговых окон. Разве это не понятно и не очевидно?

В чем цель твоего "спора"? Твой тред на мой комментарий вот что бесполезно и лишено смысла.

Окна на чистом WinAPI. Или просто о сложном

Казалось бы, что WinAPI уходит в прошлое. Давно уже существует огромное количество кросс-платформенных фреймфорков, Windows не только на десктопах, да и сами Microsoft в свой магазин не жалуют приложения, которые используют этого монстра. Помимо этого статей о том, как создать окошки на WinAPI, не только здесь, но и по всему интернету, исчисляется тысячами по уровню от дошколят и выше. Весь этот процесс разобран уже даже не по атомам, а по субатомным частицам. Что может быть проще и понятнее? А тут я еще…

Но не все так просто, как кажется.

Почему о WinAPI сейчас?

В один прекрасный момент, изучая потроха одной из игр в весьма неплохом эмуляторе NES, я подумал: Вроде неплохой такой эмуль, а в отладчике нет такой простой вещи, как навигация по кнопкам клавиатуры, которая есть в любом нормальном отладчике.

Здесь я не зря дал ссылку на репозиторий, т.к. видно, что ребята столкнулись с проблемой, о которой речь пойдет ниже, но так и не решили ее.

О чем это я? А вот об этом кусочке кода:

Ответ такой: так делать нельзя!

И, возвращаясь, к изначальному вопросу о WinAPI: очень много популярных, и не очень, проектов продолжают его использовать и в настоящее время, т.к. лучше, чем на чистом API многие вещи не сделать (тут можно бесконечно приводить аналогии вроде сравнения высокоуровневых языков и ассемблера, но сейчас не об этом). Да и мало ли почему? Просто используют и все тут.

О проблеме

Обойти такие мелкие неприятности просто. Есть, как минимум, два вполне легальных способа:

Tutorials?


Здесь действительно все просто:

Because the return value can be nonzero, zero, or -1, avoid code like this:

И ниже приводится пример правильного цикла.

Стоит сказать, что в шаблонах VS для Win32 приложений, написан именно такой неправильный цикл. И это очень печально. Ведь мало кто будет вникать в то, что сделали сами авторы, ведь это априори правильно. И неправильный код множится вместе с багами, которые очень сложно отловить.

После этого фрагмента кода, как правило, следует рассказ про акселераторы, и добавляется пара новых строчек (учитывая замечание в MSDN, предлагаю сразу писать правильный цикл):


Этот вариант я видел чаще всего. И он (та-дам) снова неправильный!

Сперва о том, что изменилось (потом о проблемах этого кода):

Ясно, что TranslateAccelerator надо вызывать для нашего созданного окна:


И вроде все хорошо и замечательно теперь: мы разобрали все детально и все должно работать идеально.

И снова нет. :-) Это будет работать правильно, пока у нас ровно одно окно — наше. Как только появится немодальное новое окно (диалог), все клавиши, которые будут в нем нажаты оттранслируются в WM_COMMAND и отправляться куда? И опять же правильно: в наше главное окно.

На этом этапе предлагаю не городить костылей по решению этой тупиковой ситуации, а предлагаю рассмотреть вещи, которые уже реже (или почти не встречаются) в туториалах.

IsDialogMessage

На самом деле, делает она чуть больше, чем следует из названия. А именно:

  • Осуществляет навигацию по дочерним контролам кнопками Tab/Shift+Tab/вверх/вниз/вправо/влево. Плюс еще кое-что, но этого нам достаточно
  • По нажатии на ESC формирует WM_COMMAND( IDCANCEL )
  • По нажатии на Enter формирует WM_COMMAND( IDOK ) или нажатие на текущую кнопку по умолчанию
  • Переключает кнопки по умолчанию (рамочка у таких кнопок чуть ярче остальных)
  • Ну и еще разные штуки, которые облегчают пользователю работу с диалогом

Во-вторых, она нам облегчит жизнь по всем остальным пунктам, перечисленным в списке (и даже немного больше).

Вообще, она используется где-то в недрах Windows для обеспечения работы модальных диалоговых окон, а программистам дана, чтобы вызывать ее для немодальных диалогов. Однако мы ее можем использовать где угодно:

Although the IsDialogMessage function is intended for modeless dialog boxes, you can use it with any window that contains controls, enabling the windows to provide the same keyboard selection as is used in a dialog box.

Т.е. теперь, если мы оформим цикл так:


То наше окошко будет иметь навигацию, как в родном диалоге Windows. Но теперь мы получили два недостатка:

Пора поговорить о том, чего нет в туториалах и ответах.

Как правило (как правило! Если кому-то захочется большего, то можно регистрировать свой класс для диалогов и работать так. И, если же, кому-то это интересно, я могу дополнить этим статью) WM_KEYDOWN хотят тогда, когда хотят обработать нажатие на клавишу, которая выполнит функцию в независимости от выбранного контрола в окне — т.е. некая общая функция для всего данного конкретного диалога. А раз так, то почему бы не воспользоваться богатыми возможностями, которые нам сама WinAPI и предлагает: TranslateAccelerator.

Везде используют ровно одну таблицу акселераторов, и только для главного окна. Ну действительно: цикл GetMessage-loop один, значит и таблица одна. Куда еще их девать?

На самом деле, циклы GetMessage-loop могут быть вложенными. Давайте еще раз посмотрим описание PostQuitMessage:

The PostQuitMessage function posts a WM_QUIT message to the thread's message queue and returns immediately; the function simply indicates to the system that the thread is requesting to quit at some time in the future.
И GetMessage:
If the function retrieves the WM_QUIT message, the return value is zero.

Таким образом, выход из GetMessage-loop осуществится, если мы вызовем PostQuitMessage в процедуре окна. Что это значит?

Мы можем для каждого немодального окна в нашей программе создавать свой собственный подобный цикл. В данном случае DialogBoxParam нам не подходит, т.к. оно крутит свой собственный цикл и повлиять мы на него не можем. Однако если создадим диалог через CreateDialogBoxParam или окно через CreateWindow, то можно закрутить еще один цикл. При этом в каждом таком окне и диалоге мы должны вызывать PostQuitMessage:


Обратите внимание: теперь для каждого нового окна в нашей программе мы можем добавить в обработку собственную таблицу акселераторов. WM_QUIT будет выхватывать GetMessage из цикла для диалога, а внешний цикл его даже не увидит. Почему так происходит?

Дело в том, что внешний цикл «встал» на вызове DispatchMessage, который вызвал нашу процедуру, которая крутит свой собственный внутренний цикл GetMessage с таким же DispatchMessage. Классический вложенный вызов (в данном случае DispatchMessage). Посему внешний цикл не получит WM_QUIT и не завершится на этом этапе. Все будет работать стройно.

Делаем красиво

Т.к. правильная постановка задачи является половиной решения, то сперва надо эту самую задачу правильно же и поставить.

Создадим простой std::map, который будет мапить дескриптор окна в дескриптор таблицы акселераторов. Вот так:


И по мере создания окон будем в него добавлять новые окна с дескриптором на свою любимую таблицу (или нуль, если такая обработка не требуется).


Ну и после закрытия окна удалять. Вот так:


Теперь, как создаем новый диалог/окно, вызываем AddAccelerators( hNewDialog, IDR_MY_ACCEL_TABLE ). Как закрываем: DelAccel( hNewDialog ).


Значительно лучше! Что же там в HandleAccelArray и зачем там GetActiveWindow()?

Есть две функции, возвращающих дескриптор активного окна GetForegroundWindow и GetActiveWindow. Отличие первой от второй вполне доходчиво описано в описании второй:

The return value is the handle to the active window attached to the calling thread's message queue. Otherwise, the return value is NULL.


Теперь каждое дочернее окно вправе добавить себе любимую таблицу акселераторов и спокойно ловить и обрабатывать WM_COMMAND с нужным кодом.

А что там еще об одной строчке в коде обработчика WM_COMMAND?

Описание в TranslateAccelerator гласит:
To differentiate the message that this function sends from messages sent by menus or controls, the high-order word of the wParam parameter of the WM_COMMAND or WM_SYSCOMMAND message contains the value 1.

Обычно код обработки WM_COMMAND выглядит так:


Теперь можно написать так:

P.S.: Мало кто знает, но можно создавать свою собственную таблицу акселераторов, а теперь и применять ее прямо налету.

P.P.S.: Т.к. DialogBox/DialogBoxParam крутит собственный цикл, то от при вызове диалога через них акселераторы работать не будут и наш цикл (или циклы) будет «простаивать».

P.P.P.S.: После вызова HandleAccelWindow мап l_mAccelTable может измениться, т.к. TranslateAccelerator или IsDialogMessage вызывают DispatchMessage, а там может встретиться AddAccelerators или DelAccel в наших обработчиках! Поэтому лучше его после этой функции не трогать.

Пощупать код можно здесь. За основу был взят код, генерируемый из стандартного шаблона MS VS 2017.

Читайте также: