wxWeights Demo学习(四)bombs

核心类分析

wxApp继承关系

在这里插入图片描述

在这里插入图片描述

wxFrame继承关系

在这里插入图片描述

在这里插入图片描述

wxPanel的继承关系

在这里插入图片描述
在这里插入图片描述
类图还是有点复杂的,超出预期。那我们从关系的视角入手分析吧。

消息是怎么分发的

OnPaint 打个断点断下来
在这里插入图片描述

从栈底部往上看,WinMainwxEntryReal 之前是有分析的。
wxEntryReal 的最后 return wxTheApp->OnRun();启动了消息循环

int wxAppBase::OnRun()
{
	……
    return wxAppConsole::OnRun();
}
int wxAppConsoleBase::OnRun()
{
    return MainLoop();
}
int wxAppConsoleBase::MainLoop()
{
    wxEventLoopBaseTiedPtr mainLoop(&m_mainLoop, CreateMainLoop());

    if (wxTheApp)
        wxTheApp->OnLaunched();

    return m_mainLoop ? m_mainLoop->Run() : -1;
}

实质上调到了wxAppConsoleBase::MainLoop()
很明显是 wxEventLoopBaseTiedPtr mainLoop(&m_mainLoop, CreateMainLoop()); 这一句创建了消息循环。mainLoop 是个指针,m_mainLoop 是负责消息循环的对象。打个断点调一下试试。

wxEventLoopBase *wxAppConsoleBase::CreateMainLoop()
{
    return GetTraits()->CreateEventLoop();
}
wxEventLoopBase* wxGUIAppTraits::CreateEventLoop()
{
    return new wxEventLoop;
}

看上去像是这里在这里创建的。其实 wxEventLoop 在Windows平台被定义为了 wxGUIEventLoop
wxGUIEventLoop 继承自 wxMSWEventLoopBase 继承自 wxEventLoopManual 继承自 wxEventLoopBase

这里启动消息循环 return m_mainLoop ? m_mainLoop->Run() : -1;

int wxEventLoopManual::DoRun()
{
	……
            // this is the event loop itself
            for ( ;; )
            {
                while ( !m_shouldExit
                            && !Pending()
                                && !(wxTheApp && wxTheApp->HasPendingEvents())
                                    && ProcessIdle() );
                                                
                if ( m_shouldExit )
                    break;
                    
                if ( !ProcessEvents() || m_shouldExit )
                    break;
            }

    return m_exitcode;
}
bool wxMSWEventLoopBase::Pending() const
{
    MSG msg;
    return ::PeekMessage(&msg, 0, 0, 0, PM_NOREMOVE) != 0;
}

这里就是我们熟悉的PeekMessage了。消息经过系统处理以后,发回给我们注册的 WndProc 函数
实际上是 注册的是 ……\wxWidgets\src\msw\window.cpp 中的 wxWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) 函数,注册过程我们后续分析。

LRESULT WXDLLEXPORT APIENTRY
wxWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	……
    wxWindowMSW *wnd = wxFindWinFromHandle(hWnd);

    LRESULT rc;
    
    wxSEH_TRY
    {
        if ( wnd && wxGUIEventLoop::AllowProcessing(wnd) )
            rc = wnd->MSWWindowProc(message, wParam, lParam);
        else
            rc = ::DefWindowProc(hWnd, message, wParam, lParam);
    }
    wxSEH_HANDLE(0)

    return rc;
}

找到消息对应的 wxWindowMSW 对象,然后调用 MSWWindowProc

WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam)
{
    WXLRESULT result;
    if ( !MSWHandleMessage(&result, message, wParam, lParam) )
    {
#if wxDEBUG_LEVEL >= 2
        wxLogTrace("winmsg", wxT("Forwarding %s to DefWindowProc."),
                   wxGetMessageName(message));
#endif // wxDEBUG_LEVEL >= 2
        result = MSWDefWindowProc(message, wParam, lParam);
    }

    return result;
}
bool
wxWindowMSW::MSWHandleMessage(WXLRESULT *result,
                              WXUINT message,
                              WXWPARAM wParam,
                              WXLPARAM lParam)
{
    // did we process the message?
    bool processed = false;

    // the return value
    union
    {
        bool        allow;
        WXLRESULT   result;
        WXHBRUSH    hBrush;
    } rc;

    // for most messages we should return 0 when we do process the message
    rc.result = 0;

    switch ( message )
    {
        case WM_PAINT:
            {
                processed = HandlePaint();
            }
            break;
            
        default:
            // try a custom message handler
    }

    if ( !processed )
        return false;

    *result = rc.result;

    return true;
}
bool wxWindowMSW::HandlePaint()
{
    wxPaintEvent event(this);

    bool processed = HandleWindowEvent(event);


    return createdPaintDC;
}

这里构造出了 wxPaintEvent 事件对象

bool wxWindowBase::HandleWindowEvent(wxEvent& event) const
{
    // SafelyProcessEvent() will handle exceptions nicely
    return GetEventHandler()->SafelyProcessEvent(event);
}

这里进入了 wxEvtHandler 的分发逻辑,一路调用到

bool wxEvtHandler::TryHereOnly(wxEvent& event)
{
    // Then static per-class event tables
    if ( GetEventHashTable().HandleEvent(event, this) )
        return true;

GetEventHashTable() 继续分发

bool wxEventHashTable::HandleEvent(wxEvent &event, wxEvtHandler *self)
{
    // Find all entries for the given event type.
    wxEventType eventType = event.GetEventType();
    const EventTypeTablePointer eTTnode = m_eventTypeTable[eventType % m_size];
    if (eTTnode && eTTnode->eventType == eventType)
    {
        // Now start the search for an event handler
        // that can handle an event with the given ID.
        const wxEventTableEntryPointerArray&
            eventEntryTable = eTTnode->eventEntryTable;

        const size_t count = eventEntryTable.GetCount();
        for (size_t n = 0; n < count; n++)
        {
            const wxEventTableEntry& entry = *eventEntryTable[n];
            if ( wxEvtHandler::ProcessEventIfMatchesId(entry, self, event) )
                return true;
        }
    }

    return false;
}          

这里遍历 wxEventTableEntry

bool wxEvtHandler::ProcessEventIfMatchesId(const wxEventTableEntryBase& entry,
                                           wxEvtHandler *handler,
                                           wxEvent& event)
{
    int tableId1 = entry.m_id,
        tableId2 = entry.m_lastId;

    if ((tableId1 == wxID_ANY) ||
        (tableId2 == wxID_ANY && tableId1 == event.GetId()) ||
        (tableId2 != wxID_ANY &&
         (event.GetId() >= tableId1 && event.GetId() <= tableId2)))
    {
        event.Skip(false);
        event.m_callbackUserData = entry.m_callbackUserData;

            wxTheApp->CallEventHandler(handler, *entry.m_fn, event);
    }

    return false;
}

这里匹配到entry也就找到了处理函数,又经过曲折的几部,最终调到了

BombCanvas::OnPaint(wxPaintEvent& WXUNUSED(event))

消息机制总结

窗口创建过程

在这里插入图片描述

消息分发过程

待补充

其他待整理的信息

RTTI 实现

wxIMPLEMENT_DYNAMIC_CLASS(wxApp, wxEvtHandler); 展开如下

wxClassInfo wxApp::ms_classInfo(L"wxApp", &wxEvtHandler::ms_classInfo, 0, (int)sizeof(wxApp), wxApp::wxCreateObject);
wxClassInfo* wxApp::GetClassInfo() const { return &wxApp::ms_classInfo; }
wxObject* wxApp::wxCreateObject() { return new wxApp; };

生成一个 wxClassInfo 静态成员变量

event机制

const wxEventTable wxApp::sm_eventTable = { &wxEvtHandler::sm_eventTable, &wxApp::sm_eventTableEntries[0] };
const wxEventTable* wxApp::GetEventTable() const { return &wxApp::sm_eventTable; }
wxEventHashTable wxApp::sm_eventHashTable(wxApp::sm_eventTable);
wxEventHashTable& wxApp::GetEventHashTable() const { return wxApp::sm_eventHashTable; }
const wxEventTableEntry wxApp::sm_eventTableEntries[] = {
    wxEventTableEntry(wxEVT_IDLE, wxID_ANY, wxID_ANY, wxNewEventTableFunctor(wxEVT_IDLE, wxEventFunctionCast(static_cast<wxIdleEventFunction>(&wxApp::OnIdle))), 0),
    wxEventTableEntry(wxEVT_END_SESSION, wxID_ANY, wxID_ANY, wxNewEventTableFunctor(wxEVT_END_SESSION, wxEventFunctionCast(static_cast<wxCloseEventFunction>(&wxApp::OnEndSession))), 0),
    wxEventTableEntry(wxEVT_QUERY_END_SESSION, wxID_ANY, wxID_ANY, wxNewEventTableFunctor(wxEVT_QUERY_END_SESSION, wxEventFunctionCast(static_cast<wxCloseEventFunction>(&wxApp::OnQueryEndSession))), 0),
    wxEventTableEntry(wxEVT_NULL, 0, 0, 0, 0) };
struct WXDLLIMPEXP_BASE wxEventTable
{
    const wxEventTable *baseTable;    // base event table (next in chain)
    const wxEventTableEntry *entries; // bottom of entry array
};
const wxEventTable wxApp::sm_eventTable = { &wxEvtHandler::sm_eventTable, &wxApp::sm_eventTableEntries[0] };

一个wxEventTable 静态常量成员,wxApp::sm_eventTable
wxApp::sm_eventTable.baseTable 指向自己 wxEvtHandler::sm_eventTable 基类同名成员
wxApp::sm_eventTable.entries 指向自己 wxApp::sm_eventTableEntries[0]
一个wxEventHashTable 静态成员 wxApp::sm_eventHashTable
一个 wxEventTableEntry 静态常量数组 wxApp::sm_eventTableEntries[]保存ID和成员函数的对应关系

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值