Hello, All !
Не сочтите за труд.
Помогите разобраться.
Вопрос 1.
Не могу понять почему нельзя использовать DECLARE_MESSAGE_MAP()
во вложенном классе.
////// пример a.h /////
#if !defined(A_H)
#define A_H
#pragma once
#include "stdafx.h"
class A : public CDialog {
class B : public CButton {
public:
BOOL Create(CWnd* pParentWnd);
protected:
int m_b;
virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);
DECLARE_MESSAGE_MAP()
};
public:
A (CWnd* pParent = NULL); // standard constructor
protected:
int m_a;
virtual BOOL OnInitDialog();
DECLARE_MESSAGE_MAP()
};
#endif
////// пример a.cpp /////
BEGIN_MESSAGE_MAP(A::B, CButton)
ON_WM_DRAWITEM()
END_MESSAGE_MAP()
// <skip>
BEGIN_MESSAGE_MAP(A, CDialog)
// <skip>
END_MESSAGE_MAP()
// <skip>
/////////////////////////
Вобщем синтаксис как-бы позволяет описать для каждого класса свою карту обработки сообщений.
Однако компилятор этого понять не хочет ...
error C2327: 'B::CButton::CWnd::OnDrawItem' : member from enclosing class is not a type name, static, or enumerator
error C2248: 'OnDrawItem' : cannot access protected member declared in class 'CWnd'
Если из описания класса B убрать DECLARE_MESSAGE_MAP() и соответственно BEGIN...END из реализации,
то все чудесным образом начинает работать, и что совершенно непонятно —
кто-то вполне корректно дергает B::DrawItem.
Отсюда вопрос 2.
Кто вызывает B::DrawItem?
И на кой? Если, как говорится никто не просил.
Здравствуйте, Jambo, Вы писали:
1. Если ты написал ON_WM_DRAWITEM(), то ты должен написать реализацию метода OnDrawItem — компилятор тебе об этом и говорит.
2. Ты же описал метод DrawItem, вот компилятор его и дергает

А чтобы он вызывался, никакой карты сообщений не надо. Именно из метода OnDrawItem и дергаются вирутальные методы DrawItem.
А в остальном, насколько я помню, вполне возможно использовать макросы сообщений во вложенных классах.
В общем, смотри исходники MFC
Здравствуйте, Андрей, Вы писали:
А>1. Если ты написал ON_WM_DRAWITEM(), то ты должен написать реализацию метода OnDrawItem — компилятор тебе об этом и говорит.
Спасибо

здесь я немного прорзрел. Я почему-то искренне верил, что в ответ на сообщение WM_DRAWITEM будет дергаться именно мой виртуальный DrawItem. про OnDrawItem я почемуто не подумал. Собственно это твое замечание больше помогло найти ответ на второй вопрос.
Первый все равно пока висит...
Дело в следующем, (забыл сразу об этом написать)
Если вложенный класс B вынуть из A
/// new пример a.h /////
// <skip>
class B : public CButton {
public:
BOOL Create(CWnd* pParentWnd);
protected:
int m_b;
virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);
DECLARE_MESSAGE_MAP()
};
class A : public CDialog {
public:
A (CWnd* pParent = NULL); // standard constructor
protected:
int m_a;
virtual BOOL OnInitDialog();
DECLARE_MESSAGE_MAP()
};
//////////////////////////////
Реализация та же, только поправлены имена классов, я ее здесь опускаю,
то выясняется две вещи.
1. Не надо реализовывать никакой OnDrawItem, — на это ответ уже найден,
перехват WM_DRAWITEM здесь вообще оказался лишним, хотя всетаки кто-то его
обрабатывает, наверное-какой нибудь родитель, вобщем ясно, что дело не в нем.
2. Все лихо компилится и корректно работает.
Вывод: /возможно не правильный/
Нежелание компилятора скушать первый вариант — очень сильно связано именно с вложенностью классов.
А>2. Ты же описал метод DrawItem, вот компилятор его и дергает
А чтобы он вызывался, никакой карты сообщений не надо. Именно из метода OnDrawItem и дергаются вирутальные методы DrawItem.
Совершенно верно для DrawItem, карта действительно не нужна. Например в CButton он сделан специально для кнопарей со стилем
BS_OWNERDRAW
само-рисующиеся кнопочки, если можно так выразится..
Но дело-то не только в нем (простото ради краткости перехват др. сообщений я не описывал), для других WM_* все осталось по преженму — первый пример не компилится
хоть тресни.
А>А в остальном, насколько я помню, вполне возможно использовать макросы сообщений во вложенных классах.

В начале я тоже в этом не сомневался...
А>В общем, смотри исходники MFC
Пытаюсь, там вроде все логично...
Здравствуйте, Jambo, Вы писали:
skip
Ну, не знаю, что сказать
Я специально сделал тестовый пример. Создал диалог, в нем описал класс кнопки, повесил пару обработчиков — и все компиляется и работает без проблем.
Да и в моих рабочих проектах такие вещи используются.
Похоже, проблема в твоем коде.
Здравствуйте, Андрей, Вы писали:
А>skip
А>Ну, не знаю, что сказать
А>Я специально сделал тестовый пример. Создал диалог, в нем описал класс кнопки, повесил пару обработчиков — и все компиляется и работает без проблем.
А>Да и в моих рабочих проектах такие вещи используются.
Это радует...
Наверное мне тоже следует посмотреть на это с другой стороны.
А>Похоже, проблема в твоем коде.
Надеюсь, что ты прав...
Спасибо за помощь. Дальше я сам.
J>Вопрос 1.
J>Не могу понять почему нельзя использовать DECLARE_MESSAGE_MAP()
J>во вложенном классе.
J>J>////// пример a.h /////
J>#if !defined(A_H)
J>#define A_H
J>#pragma once
J>#include "stdafx.h"
J>class A : public CDialog {
J> class B : public CButton {
J> public:
J> BOOL Create(CWnd* pParentWnd);
J> protected:
J> int m_b;
J> virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);
J> DECLARE_MESSAGE_MAP()
J> };
J> public:
J> A (CWnd* pParent = NULL); // standard constructor
J> protected:
J> int m_a;
J> virtual BOOL OnInitDialog();
J> DECLARE_MESSAGE_MAP()
J>};
J>#endif
J>////// пример a.cpp /////
J>BEGIN_MESSAGE_MAP(A::B, CButton)
J> ON_WM_DRAWITEM()
J>END_MESSAGE_MAP()
J>// <skip>
J>BEGIN_MESSAGE_MAP(A, CDialog)
J>// <skip>
J>END_MESSAGE_MAP()
J>// <skip>
J>/////////////////////////
J>
J>Вобщем синтаксис как-бы позволяет описать для каждого класса свою карту обработки сообщений.
J>Однако компилятор этого понять не хочет ...
J>J>error C2327: 'B::CButton::CWnd::OnDrawItem' : member from enclosing class is not a type name, static, or enumerator
J>error C2248: 'OnDrawItem' : cannot access protected member declared in class 'CWnd'
J>
J>Если из описания класса B убрать DECLARE_MESSAGE_MAP() и соответственно BEGIN...END из реализации,
J>то все чудесным образом начинает работать, и что совершенно непонятно —
J>кто-то вполне корректно дергает B::DrawItem.
Знаю, что поздно. Но сам только что столкнулся с этой проблемой. Ответа готового не нашёл, пришлось копать самому.
Ошибка возникает при разворачивании BEGIN_MESSAGE_MAP() с последующими макросами, что для случая с ON_WM_DRAWITEM выливается в вызов OnDrawItem(). Не B::OnDrawItem() а именно DrawItem()! Решение я использовал для этого случая такое:
BEGIN_MESSAGE_MAP(A::B, CButton)
ON_MESSAGE(WM_DRAWITEM,B::DrawItem())
END_MESSAGE_MAP()