2008年4月23日水曜日

OnPaint on wxWidgets/wxPython その7 M$ windows

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
これは完全におまけですが、ついでなので調べることにしました。

src/msw/windows.cpp
まあ、もはやお決まり。まず、src/[platform]/window.cppをみる、のだ。これであなたも俺様window systemにwxWidgetをportできますねw。

  • OnPaint
    WM_PAINT
    しかしまぁごてごてしているなぁ。

    // Can be called from an application's OnPaint handler
    void wxWindowMSW::OnPaint(wxPaintEvent& event)
    {
    #ifdef __WXUNIVERSAL__
    event.Skip();
    #else
    HDC hDC = (HDC) wxPaintDCImpl::FindDCInCache((wxWindow*) event.GetEventObject());
    if (hDC != 0)
    {
    MSWDefWindowProc(WM_PAINT, (WPARAM) hDC, 0);
    }
    #endif
    }

  • EraseBackground
    一見入り組んでいるが、
    • HandleEraseBkgndがM$ windows側から呼ばれるEventHandler。

    • OnEraseBackgroundがwxのデフォルトのPaintEventHandler


    bool wxWindowMSW::HandleEraseBkgnd(WXHDC hdc)
    {
    wxDCTemp dc(hdc, GetClientSize());
    wxDCTempImpl *impl = (wxDCTempImpl*) dc.GetImpl();

    impl->SetHDC(hdc);
    impl->SetWindow((wxWindow *)this);

    wxEraseEvent event(m_windowId, &dc);
    event.SetEventObject(this);
    bool rc = HandleWindowEvent(event);

    // must be called manually as ~wxDC doesn't do anything for wxDCTemp
    impl->SelectOldObjects(hdc);

    return rc;
    }

    void wxWindowMSW::OnEraseBackground(wxEraseEvent& event)
    {
    // standard non top level controls (i.e. except the dialogs) always erase
    // their background themselves in HandleCtlColor() or have some control-
    // specific ways to set the colours (common controls)
    if ( IsOfStandardClass() && !IsTopLevel() )
    {
    event.Skip();
    return;
    }

    if ( GetBackgroundStyle() == wxBG_STYLE_CUSTOM )
    {
    // don't skip the event here, custom background means that the app
    // is drawing it itself in its OnPaint(), so don't draw it at all
    // now to avoid flicker
    return;
    }

    wxDC *dc = event.GetDC();
    if (!dc) return;
    wxMSWDCImpl *impl = (wxMSWDCImpl*) dc->GetImpl();

    // do default background painting
    if ( !DoEraseBackground(GetHdcOf(*impl)) )
    {
    // let the system paint the background
    event.Skip();
    }
    }

    bool wxWindowMSW::DoEraseBackground(WXHDC hDC)
    {
    HBRUSH hbr = (HBRUSH)MSWGetBgBrush(hDC);
    if ( !hbr )
    return false;

    wxFillRect(GetHwnd(), (HDC)hDC, hbr);

    return true;
    }

  • wxWindow::Refresh
    • RedrawWindowウィンドウのクライアント領域にある、指定された長方形またはリージョンを更新します

    • InvalidateRect指定されたウィンドウの更新リージョンに 1 個の長方形を追加します。更新リージョンとは、ウィンドウのクライアント領域のうち、再描画しなければならない部分のことです。

    う~~ん。ほかのプラットフォームは1つの関数なのに。M$は混乱しているなぁ。わけわからん。しかもフラグがすごくいっぱいあるし。こんなAPIを使わないといけないプログラマは気の毒だ。まあ歴史があるともいうが。

    void wxWindowMSW::Refresh(bool eraseBack, const wxRect *rect)
    {
    HWND hWnd = GetHwnd();
    if ( hWnd )
    {
    RECT mswRect;
    const RECT *pRect;
    if ( rect )
    {
    wxCopyRectToRECT(*rect, mswRect);
    pRect = &mswRect;
    }
    else
    {
    pRect = NULL;
    }

    // RedrawWindow not available on SmartPhone or eVC++ 3
    #if !defined(__SMARTPHONE__) && !(defined(_WIN32_WCE) && _WIN32_WCE < 400)
    UINT flags = RDW_INVALIDATE | RDW_ALLCHILDREN;
    if ( eraseBack )
    flags |= RDW_ERASE;

    ::RedrawWindow(hWnd, pRect, NULL, flags);
    #else
    ::InvalidateRect(hWnd, pRect, eraseBack);
    #endif
    }
    }

  • Update
    UpdateWindow
    ですね。

    void wxWindowMSW::Update()
    {
    if ( !::UpdateWindow(GetHwnd()) )
    {
    wxLogLastError(_T("UpdateWindow"));
    }

    #if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
    // just calling UpdateWindow() is not enough, what we did in our WM_PAINT
    // handler needs to be really drawn right now
    (void)::GdiFlush();
    #endif // __WIN32__
    }
  • 0 件のコメント: