Нарисованный владельцем CTabCtrl в WTL

WTL/WIN32 новичок здесь, изо всех сил пытаясь понять, как сообщения передаются.

Я пытаюсь написать нарисованный владельцем CTabCtrl в WTL. По какой-то (по крайней мере для меня) непонятной причине WM_DRAWITEM отправляется в родительское окно, а не в окно, которое на самом деле нужно знать. Что затрудняет создание хорошего, автономного графического интерфейса для простой замены CTabCtrl. Я всегда мог захватить сообщение в родительском и передать его элементу управления вкладками, но это было бы плохим дизайном ОО. Есть ли способ перехватить сообщение, не требуя дополнительного кода перенаправления в классе владельца / родителя?

РЕДАКТИРОВАТЬ: После небольшого поиска в Google, у меня теперь есть

class CQueryTabCtrl : 
    public CWindowImpl<CQueryTabCtrl, CTabCtrl>, 
    public COwnerDraw<CQueryTabCtrl>
{
public:
    DECLARE_WND_SUPERCLASS(NULL, CTabCtrl::GetWndClassName())
    BEGIN_MSG_MAP(CQueryTabCtrl)
        CHAIN_MSG_MAP(COwnerDraw<CQueryTabCtrl>)
        DEFAULT_REFLECTION_HANDLER()
    END_MSG_MAP()

    BOOL PreTranslateMessage(MSG* pMsg)
    {
        pMsg;
        return FALSE;
    }

    void DeleteItem(LPDELETEITEMSTRUCT /*lpDeleteItemStruct*/)
    {
    }

    void DrawItem ( LPDRAWITEMSTRUCT lpdis )
    {
        CDCHandle dc = lpdis->hDC;
        CDC dcMem;

        dcMem.CreateCompatibleDC ( dc );
        dc.SaveDC();
        dcMem.SaveDC();

        dc.FillSolidRect ( &lpdis->rcItem, RGB(255,0,0) );

        dcMem.RestoreDC(-1);
        dc.RestoreDC(-1);
    }
};

Что, очевидно, совершенно неверно, поскольку DrawItem() никогда не вызывается.

2 ответа

Этот ответ немного запоздал на вечеринку, но может помочь другим...

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

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

1) согласиться на отражение

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

// Just a made-up dialog class for outlining message reflection installed on the parent window
class SomeDialog : public CDialogImpl<SomeDialog, CWindow>
{
public:
    BEGIN_MSG_MAP_EX(SomeDialog)
        REFLECT_NOTIFICATIONS()
    END_MSG_MAP()
};

2) Обрабатывать отраженные (владелец-рисовать) сообщения

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

class CQueryTabCtrl : 
    public CWindowImpl<CQueryTabCtrl, CTabCtrl>, 
    public COwnerDraw<CQueryTabCtrl>
{
public:
    DECLARE_WND_SUPERCLASS(NULL, CTabCtrl::GetWndClassName())

    BEGIN_MSG_MAP(CQueryTabCtrl)
        CHAIN_MSG_MAP_ALT(COwnerDraw<CQueryTabCtrl>, 1)
    END_MSG_MAP()

    void DrawItem(LPDRAWITEMSTRUCT)
    {
        // ...
    }
};

Также посмотрите полный нарисованный владельцем элемент управления tablist из репозитория wtlext, который может служить примером (Отказ от ответственности: я связан с автором FireDaemon Technologies Ltd).

WM_DRAWITEM отправляется родителю по замыслу.

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

Вы обрабатываете это в окне хостинга, и с WTL вы можете использовать COwnerDraw класс на него и / или отражать сообщения там, чтобы они отправлялись обратно в окно, где ваш подкласс WindowProc будет обращаться с ними, как вы, возможно, изначально планировали.

Другие вопросы по тегам