Вопросы базовой структуры МФЦ - PullRequest
2 голосов
/ 24 декабря 2009

Есть несколько вещей, в которых я не уверен:

Когда вы создаете базовый SDI с помощью мастера приложений MFC (назовем его TestMfc), вы получаете:

4 основных класса:

CTestMfcApp
CTestMfcView
CTestMfcDoc
CMainFrame

Что я заметил, так это то, что у CTestMfcApp есть эти объявления

ON_COMMAND(ID_APP_ABOUT, &CTestMfcApp::OnAppAbout)
    // Standard file based document commands
    ON_COMMAND(ID_FILE_NEW, &CWinApp::OnFileNew)
    ON_COMMAND(ID_FILE_OPEN, &CWinApp::OnFileOpen)
    // Standard print setup command
    ON_COMMAND(ID_FILE_PRINT_SETUP, &CWinApp::OnFilePrintSetup)

while CTestMfcView has those :
BEGIN_MESSAGE_MAP(CTestMfcView, CEditView)
    // Standard printing commands
    ON_COMMAND(ID_FILE_PRINT, &CEditView::OnFilePrint)
    ON_COMMAND(ID_FILE_PRINT_DIRECT, &CEditView::OnFilePrint)
    ON_COMMAND(ID_FILE_PRINT_PREVIEW, &CEditView::OnFilePrintPreview)
END_MESSAGE_MAP()

Чего я не понимаю, так это почему MFC создает такое разделение? Я не могу понять, почему класс приложения должен объявлять функции для обработки событий ... разве это не работа представления? Если, например, мало окон, это становится еще яснее.

Во-вторых, как эти события называются? Я знаю, что должна быть функция WINPROC, которая должна получить MSG и вызвать правильный обработчик. это ON_COMMAND макрос, который устанавливает какую-то функцию указателя, которая позже становится доступной для функции WINPROC. И почему ON_COMMAND не получает дескриптор WINDOWS ... если, например, в программе есть еще одно WINDOW с таким же идентификатором?

Третий и последний, скажем, я хочу изменить потоки некоторых окон в состояние оповещения. Для этого я хочу изменить основной цикл (который продолжает вызывать getmessage / dispatchmessage и т.д .. и вставьте функцию waitformultibleonject. где функция winmain? Я не могу найти его, когда мастер приложений выполняет всю работу за меня.

Спасибо !!

Ответы [ 3 ]

2 голосов
/ 24 декабря 2009

В MFC сообщения «всплывают», пока не найдут обработчик. IIRC это Просмотр -> Документ -> Шаблон документа -> MainFrame -> Приложение. Это позволяет обрабатывать специфичные для вида события в представлении, специфичные для документа события в документе и т. Д.

Обычно глобальные обработчики попадают в класс мэйнфреймов. Однако вы можете использовать несколько окон мэйнфреймов - даже с разным поведением - там, где различие между «MainFrame» и «App class» становится важным.

Тем не менее, специфичные для управления обработчики принадлежат классу представления. Я бы поместил только обработчики WM_COMMAND в старшие классы.


на ваш третий вопрос: я бы так не поступил. Хотя MFC избегает нескольких распространенных модальных циклов, вы не можете избежать их всех. OnIdle - хорошее место для реализации отложенных обновлений.


[обновление] MFC использует один глобальный WNDPROC для обработки всех сообщений. Он использует отображение HWND в CWnd для определения местоположения объекта MFC. Когда WNDPROC видит сообщение WM_COMMAND, он сначала проверит карту сообщений окна получателя, если он содержит обработчик для этого сообщения. Если его нет, он будет выполнять различные проверки, например, «Это не просто CWnd, но CView?» Да -> получить документ и посмотреть, есть ли на карте сообщений документов обработчик для этой конкретной команды.

0 голосов
/ 20 мая 2015

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

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

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

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

Мое мнение таково, что обработка диалогового окна About и Help была добавлена ​​в класс приложения, так как это было самое простое место для размещения. Обычно About - это диалоговое окно с базовым описанием приложения. И «Справка», и «О программе» могут быть теми вещами, к которым вы хотите получить доступ без необходимости сначала запускать документ или просматривать.

Эти сообщения являются стандартными сообщениями Windows, использующими PostMessage() или SendMessage() со стандартным форматом Windows дескриптора целевого окна, идентификатором сообщения и двумя параметрами, которые используются для предоставления дополнительной информации. Инфраструктура MFC имеет множество различных определений препроцессора C для различных идентификаторов сообщений. Если вы будете следовать иерархии деривации классов, то обнаружите, что классы документов CDocument в конечном итоге являются производными от CCmdTarget классов так же, как классы представлений CView или производные CView. CCmdTarget в свою очередь происходит от самого основного класса MFC, CObject.

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

Из-за возраста платформы MFC, довольно много открытых частей используют препроцессор C и макросы. Вы можете проверить макросы, чтобы увидеть, что они делают и как они реализованы с помощью Visual Studio IDE. И те части инфраструктуры MFC, которые реализованы в виде шаблонов, также легко доступны для чтения через Visual Studio IDE. И макросы, и шаблоны находятся в MFC-файлах. Однако, чтобы прочитать код в реальных классах, вам нужно будет найти копию исходного текста MFC. Использование исходных файлов MFC с веб-сайта Microsoft предоставляет отправную точку, включая информацию о том, где можно найти источник из вашей установки Visual Studio.

Библиотека Microsoft Foundation Class (MFC) предоставляет полный исходный код код. Заголовочные файлы (.h) находятся в каталоге \ atlmfc \ include;файлы реализации (.cpp) находятся в каталоге \ atlmfc \ src \ mfc.

Я бы не советовал разветвлять это с вашими собственными изменениями.

Третий вопрос касается потоков, а описанный вами подход не имеет смысла в рамках MFC. С MFC вы обычно создаете поток, используя функции AfxBeginThread() или AfxBeginThreadEx(). Существует два вида потоков: один с пользовательским интерфейсом и один без. Не имеет смысла, что многопоточное приложение должно было бы модифицировать насос сообщений. Вместо этого вы бы отправляли сообщения в ветку после того, как создали ее, используя что-то вроде PostThreadMessage().

Эта статья, Потоки с MFC , в проекте кода содержит обзор и исходный пример.

0 голосов
/ 24 декабря 2009

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

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

...