Что не так?
От: Jambo  
Дата: 09.01.04 04:54
Оценка:
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?
И на кой? Если, как говорится никто не просил.
Re: Что не так?
От: Андрей Россия  
Дата: 09.01.04 08:55
Оценка:
Здравствуйте, Jambo, Вы писали:

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

А в остальном, насколько я помню, вполне возможно использовать макросы сообщений во вложенных классах.

В общем, смотри исходники MFC
Re[2]: Что не так?
От: Jambo  
Дата: 09.01.04 22:40
Оценка:
Здравствуйте, Андрей, Вы писали:

А>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


Пытаюсь, там вроде все логично...
Re[3]: Что не так?
От: Андрей Россия  
Дата: 12.01.04 05:17
Оценка:
Здравствуйте, Jambo, Вы писали:

skip

Ну, не знаю, что сказать
Я специально сделал тестовый пример. Создал диалог, в нем описал класс кнопки, повесил пару обработчиков — и все компиляется и работает без проблем.
Да и в моих рабочих проектах такие вещи используются.

Похоже, проблема в твоем коде.
Re[4]: Что не так?
От: Jambo  
Дата: 12.01.04 22:34
Оценка:
Здравствуйте, Андрей, Вы писали:

А>skip


А>Ну, не знаю, что сказать

А>Я специально сделал тестовый пример. Создал диалог, в нем описал класс кнопки, повесил пару обработчиков — и все компиляется и работает без проблем.
А>Да и в моих рабочих проектах такие вещи используются.

Это радует...
Наверное мне тоже следует посмотреть на это с другой стороны.

А>Похоже, проблема в твоем коде.


Надеюсь, что ты прав...
Спасибо за помощь. Дальше я сам.
Re: Что не так?
От: Аноним  
Дата: 18.01.05 17:45
Оценка:
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()
Re[2]: Что не так?
От: Андрей Россия  
Дата: 19.01.05 05:08
Оценка:
Здравствуйте, Аноним, Вы писали:

skip

Я тут подумал на досуге:

1. А на кой хрен вообще использовать макрос ON_WM_DRAWITEM во вложенном классе? Если можно просто определить свою реализацию виртуальной функции DrawItem?

2. Сколько ни пробовал, а у меня во вложенных классах все прекрасно работает, в том числе и ON_WM_DRAWITEM. Так что проблемы в вашем коде, как я уже и писал.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.