wxWidgets的DC为何不用明示的拷贝就能完成对clientDC的内容的改变?

本来是没有这一篇记录的,因为之前猜是肯定用了C++的析构函数做拷贝,因此很多dc看起来只要是对dc画东西,然后出了栈后,内容就自然而然的到了画面上(clientDC上)。今天无意中撞到了wxBufferedDC的代码,索性就这个猜测证实了一下。


wxBufferedDC,一般我们用的时候,会用某个clientDC作为参数传入,这样,其实在内部被m_dc记录下来,


dcbuffer.h中,可以看到如下声明,成员变量m_dc是个指针,记住了进来的dc的地址(一般就是我们传的ClientDC)。另外一个地方就是析构函数,如果m_dc不为空的话,会调用UnMask()方法。


class WXDLLIMPEXP_CORE wxBufferedDC : public wxMemoryDC
{
public:
    // Default ctor, must subsequently call Init for two stage construction.
    wxBufferedDC()
        : m_dc(NULL),
          m_buffer(NULL),
          m_style(0)
    {
    }

    // Construct a wxBufferedDC using a user supplied buffer.
    wxBufferedDC(wxDC *dc,
                 wxBitmap& buffer = wxNullBitmap,
                 int style = wxBUFFER_CLIENT_AREA)
        : m_dc(NULL), m_buffer(NULL)
    {
        Init(dc, buffer, style);
    }

    // Construct a wxBufferedDC with an internal buffer of 'area'
    // (where area is usually something like the size of the window
    // being buffered)
    wxBufferedDC(wxDC *dc, const wxSize& area, int style = wxBUFFER_CLIENT_AREA)
        : m_dc(NULL), m_buffer(NULL)
    {
        Init(dc, area, style);
    }

    // The usually desired  action in the dtor is to blit the buffer.
    virtual ~wxBufferedDC()
    {
        if ( m_dc )
            UnMask();
    }

    // These reimplement the actions of the ctors for two stage creation
    void Init(wxDC *dc,
              wxBitmap& buffer = wxNullBitmap,
              int style = wxBUFFER_CLIENT_AREA)
    {
        InitCommon(dc, style);

        m_buffer = &buffer;

        UseBuffer();
    }

    void Init(wxDC *dc, const wxSize &area, int style = wxBUFFER_CLIENT_AREA)
    {
        InitCommon(dc, style);

        UseBuffer(area.x, area.y);
    }

    // Blits the buffer to the dc, and detaches the dc from the buffer (so it
    // can be effectively used once only).
    //
    // Usually called in the dtor or by the dtor of derived classes if the
    // BufferedDC must blit before the derived class (which may own the dc it's
    // blitting to) is destroyed.
    void UnMask();

    // Set and get the style
    void SetStyle(int style) { m_style = style; }
    int GetStyle() const { return m_style & ~wxBUFFER_USES_SHARED_BUFFER; }

private:
    // common part of Init()s
    void InitCommon(wxDC *dc, int style)
    {
        wxASSERT_MSG( !m_dc, wxT("wxBufferedDC already initialised") );

        m_dc = dc;
        m_style = style;
    }

    // check that the bitmap is valid and use it
    void UseBuffer(wxCoord w = -1, wxCoord h = -1);

    // the underlying DC to which we copy everything drawn on this one in
    // UnMask()
    //
    // NB: Without the existence of a wxNullDC, this must be a pointer, else it
    //     could probably be a reference.
    wxDC *m_dc;

    // the buffer (selected in this DC), initially invalid
    wxBitmap *m_buffer;

    // the buffering style
    int m_style;

    wxSize m_area;
    
    DECLARE_DYNAMIC_CLASS(wxBufferedDC)
    wxDECLARE_NO_COPY_CLASS(wxBufferedDC);
};

下面是UnMask的内容:


void wxBufferedDC::UnMask()
{
    wxCHECK_RET( m_dc, wxT("no underlying wxDC?") );
    wxASSERT_MSG( m_buffer && m_buffer->IsOk(), wxT("invalid backing store") );

    wxCoord x = 0,
            y = 0;

    // Ensure the scale matches the device
    SetUserScale(1.0, 1.0);

    if ( m_style & wxBUFFER_CLIENT_AREA )
        GetDeviceOrigin(&x, &y);

    // It's possible that the buffer may be bigger than the area that needs to
    // be drawn (the client size of the window is smaller than the bitmap, or
    // a shared bitmap has been reused for a smaller area, etc.) so avoid
    // blitting too much if possible, but only use the real DC size if the
    // wxBUFFER_VIRTUAL_AREA style is not set.
    int width = m_area.GetWidth(),
        height = m_area.GetHeight();

    if (! m_style & wxBUFFER_VIRTUAL_AREA)
    {
        int widthDC,
            heightDC;
        m_dc->GetSize(&widthDC, &heightDC);
        width = wxMin(width, widthDC);
        height = wxMin(height, heightDC);
    }

    m_dc->Blit(0, 0, width, height, this, -x, -y);
    m_dc = NULL;

    if ( m_style & wxBUFFER_USES_SHARED_BUFFER )
        wxSharedDCBufferManager::ReleaseBuffer(m_buffer);
}

可以看到,析构函数会利用m_dc->Blit()把这个memdc的内容拷贝到送进来的dc中(一般就是我们的clientDC)。这也就是我们看到的dc都是

1、栈上创建,然后

2、在这个dc中绘图,然后

3、就没有任何跟dc相关的代码


的缘故。



你可能感兴趣的:(wxWidgets的DC为何不用明示的拷贝就能完成对clientDC的内容的改变?)