天天看點

基于對話框的簡單雙緩沖繪圖架構

   基于文檔視圖結構程式的雙緩沖繪圖架構比較多,那麼如何在對話框上繪圖呢?以前通常的做法是拖一個靜态文本控件或其它控件當作繪圖區域或者在這個區域上建立一個視圖出來。看了微軟的一個示例程式DrawCli(一個繪圖的單文檔程式),産生了一些靈感,決心把它移植到對話框繪圖上,摸索了一下,搞了一個基于對話框的簡單雙緩沖繪圖架構。

     具體代碼如下,對話框頭檔案代碼:

#include <vector>  

//@brief 直線結構體  

struct stLine  

{  

    stLine(CPoint &Begin,CPoint &End)  

    {  

        m_Begin = Begin;  

        m_End = End;  

    }  

    //@brief 起點  

    CPoint m_Begin;  

    //@brief 終點  

    CPoint m_End;  

};  

class CDoubleBufDrawDlg : public CDialog  

    DECLARE_DYNAMIC(CDoubleBufDrawDlg)  

public:  

    CDoubleBufDrawDlg(CWnd* pParent = NULL);   // 标準構造函數  

    virtual ~CDoubleBufDrawDlg();  

// 對話框資料  

    enum { IDD = IDD_DIALOG_GDIPLUS };  

protected:  

    virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支援  

    DECLARE_MESSAGE_MAP()  

    virtual BOOL OnInitDialog();  

    afx_msg void OnBnClickedDrawPoint();  

    afx_msg void OnBnClickedDrawLine();  

    afx_msg void OnSize(UINT nType, int cx, int cy);  

    void AdjustControls();  

    afx_msg void OnPaint();  

    //   

    void InitDrawPara();  

    //@brief 上一個點  

    CPoint m_PrePt;  

    //@brief 滑鼠按下點  

    CPoint m_DownPt;  

    //@brief 直線結構體數組  

    std::vector<stLine> m_Lines;  

    afx_msg void OnLButtonDown(UINT nFlags, CPoint point);  

    afx_msg void OnMouseMove(UINT nFlags, CPoint point);  

    afx_msg void OnLButtonUp(UINT nFlags, CPoint point);  

};   

    Cpp檔案源碼(這裡隻列出主要函數):

//@brief 初始化繪圖參數  

void CDoubleBufDrawDlg::InitDrawPara()  

    m_PrePt = CPoint(-1,-1);  

    m_DownPt = CPoint(-1,-1);  

}  

CDoubleBufDrawDlg::CDoubleBufDrawDlg(CWnd* pParent /*=NULL*/)  

: CDialog(CDoubleBufDrawDlg::IDD, pParent)  

    InitDrawPara();  

void CDoubleBufDrawDlg::OnLButtonDown(UINT nFlags, CPoint point)  

    // TODO: 在此添加消息處理程式代碼和/或調用預設值  

    // 記錄滑鼠按下點  

    m_DownPt = point;  

    CDialog::OnLButtonDown(nFlags, point);  

void CDoubleBufDrawDlg::OnMouseMove(UINT nFlags, CPoint point)  

    // 假如在移動滑鼠的同時按下左鍵  

    if (MK_LBUTTON&nFlags)  

        CDC *pDC = GetDC();  

        pDC->SetROP2(R2_NOTXORPEN);  

    // 将繪圖區域限制在對話框的客戶區上面的/4區域  

CRect rtDraw(rtClient.top,rtClient.left,rtClient.Width(),3*(rtClient.Height()/4));  

    CRgn DrawRgn;  

    DrawRgn.CreateRectRgn(rtDraw.left,rtDraw.top,rtDraw.right,rtDraw.bottom);  

    pDC->SelectClipRgn(&DrawRgn);  

        if (m_PrePt.x!=-1)  

        {  

            // 擦除上一條線  

            pDC->MoveTo(m_DownPt);  

            pDC->LineTo(m_PrePt);  

        }  

        // 畫線  

        pDC->MoveTo(m_DownPt);  

        pDC->LineTo(point);  

        ReleaseDC(pDC);  

        m_PrePt = point;  

    CDialog::OnMouseMove(nFlags, point);  

void CDoubleBufDrawDlg::OnLButtonUp(UINT nFlags, CPoint point)  

    // 将繪制的直線加入到直線數組  

    m_Lines.push_back(stLine(m_DownPt,point));  

    // 初始化繪圖參數  

    CDialog::OnLButtonUp(nFlags, point);  

void CDoubleBufDrawDlg::OnPaint()  

    // 最小時繪制菜單圖示,因為我是在一個單文檔程式中彈出該對話框的,故不需要繪制圖示  

    // 如果是基于對話框的程式則需要繪制圖示  

    if (IsIconic())  

        CPaintDC dc(this); // device context for painting  

        SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);  

        // Center icon in client rectangle  

        //int cxIcon = GetSystemMetrics(SM_CXICON);  

        //int cyIcon = GetSystemMetrics(SM_CYICON);  

        //CRect rect;  

        //GetClientRect(&rect);  

        //int x = (rect.Width() - cxIcon + 1) / 2;  

        //int y = (rect.Height() - cyIcon + 1) / 2;  

        //// Draw the icon  

        //dc.DrawIcon(x, y, m_hIcon);  

    else  

        CPaintDC dc(this);  

        // 定義一個相容DC  

        CDC CompaDC;  

        // 初始化繪圖DC指針  

        CDC* pDrawDC = &dc;  

        CBitmap bitmap;  

        CBitmap* pOldBitmap = 0;  

        CRect rtClient;  

        GetClientRect(&rtClient);  

        // 将對話框的客戶區上面的/4區域設為繪圖區域  

        CRect rtDraw(rtClient.top,rtClient.left,rtClient.Width(),3*(rtClient.Height()/4));  

        // 假如不是列印機DC  

        if (!dc.IsPrinting())  

            // 建立相容DC,建立相容位圖,将相容位圖選進相容DC  

            if (CompaDC.CreateCompatibleDC(&dc))  

            {  

                if (bitmap.CreateCompatibleBitmap(&dc,rtDraw.Width(),rtDraw.Height()))  

                {  

                    pDrawDC = &CompaDC;  

                    pOldBitmap = CompaDC.SelectObject(&bitmap);  

                }  

            }  

        // 定義一個白色畫刷,将背景色設為白色  

        CBrush brush;  

        if (!brush.CreateSolidBrush(RGB(255,255,255)))  

            return;  

        brush.UnrealizeObject();  

        pDrawDC->FillRect(rtDraw,&brush);  

        // 繪制直線  

        for (size_t i = 0;i<m_Lines.size();i++)  

            pDrawDC->MoveTo(m_Lines[i].m_Begin);  

            pDrawDC->LineTo(m_Lines[i].m_End);  

        // 使用GDI+繪制一個線性漸變畫刷  

        Gdiplus::Graphics graphics(pDrawDC->m_hDC);  

        LinearGradientBrush linGrBrush(Point(100,0),Point(100,100),Color(255,255,0,0),Color(255,0,255,0));  

        Color colors[] = {  

            Color(255, 255, 0, 0),   // red  

            Color(255, 255, 255, 0), //yellow  

            Color(255, 0, 0, 255),   // blue  

            Color(255, 0, 255, 0)};  // green  

            REAL positions[] = {  

                0.0f,     

                0.33f,     

                0.66f,  

                1.0f};    

                linGrBrush.SetInterpolationColors(colors, positions,4);  

                // 填充指定區域矩形  

                graphics.FillRectangle(&linGrBrush,100,0,100,100);  

                graphics.ReleaseHDC(pDrawDC->m_hDC);  

                if (pDrawDC != &dc)  

                    // 将繪圖DC貼到真正的裝置DC上  

                    dc.BitBlt(rtDraw.left,rtDraw.top,rtDraw.Width(),rtDraw.Height(),&CompaDC, 0, 0, SRCCOPY);  

                    CompaDC.SelectObject(pOldBitmap);  

}   

    效果圖如下,其中上面的白色區域為繪圖區域:

基于對話框的簡單雙緩沖繪圖架構

    現在你怎麼改變對話框的大小繪圖區域也不會産生非雙緩沖繪圖那種閃爍。

繼續閱讀