zoukankan      html  css  js  c++  java
  • vc 画图控件

    文章来源:http://blog.csdn.net/qiuchengw/article/details/6324791

    这是的确重复造轮子,但是造了一个更适合自己使用的轮子.

    项目的需要,要实现一个画图的功能,在网上搜了N久的代码,可惜那些代码都太"粗糙"了,没有符合自己要求的,所以只好自己写了一个 .

    这是效果图(图像可填充背景色,也可只有边界色,也可两者都有):

     

     

     

    这是代码(由于是自己项目的一部分,就不传工程了):

    QShap 是基类, 继承此类,可实现自己的图形.本代码只实现了自己需要的一些图形,line/curve/ellipse/rectangle

     

    // !!!!注意

    // 此份画图的代码只是为了 "看起来像" ,图形大小不是精确的(会有1到2个像素的大小偏差):

     

    .h

    #pragma once
    #include "afxcolorbutton.h"
    #include "ResLoader.h"
    #include "afxlistctrl.h"
    #include "qstatic.h"
    // !!!!注意
    // 此份画图的代码只是为了 "看起来像" ,图形大小不是精确的(会有1到2个像素的大小偏差)
    const CPoint POINT_NULL = CPoint(-1,-1);
    const CRect RECT_NULL = CRect(-1,-1,-1,-1);
    const CRect RECT_EMPTY = CRect(0,0,0,0);
    enum ENUM_SHAPE_TYPE
    {
    	SHAPE_NONE = 1,
    	SHAPE_RECT,
    	SHAPE_ELLIPSE,
    	SHAPE_CURVE,
    	SHAPE_LINE,
    	SHAPE_ICON,
    	MAX_SHAPE_VALUE,
    };
    // Shape 及其派生类都是用于CPaintPane的专用类.
    class QShape
    {
    public:
    	QShape(ENUM_SHAPE_TYPE eShape);
    	virtual ~QShape(){}
    	virtual void Draw(CDC *pDC) = 0;
    	virtual CRect GetRect()const; 
    	COLORREF GetBorderColor()const { return m_crBoder; };
    	COLORREF GetFillColor()const { return m_crFill; }
    	void SetBorderColor(COLORREF cr=COLOR_BLACK) { m_crBoder = cr; }
    	void SetFillColor(COLORREF cr=COLOR_NONE) { m_crFill = cr; }
    	ENUM_SHAPE_TYPE GetShape()const { return m_ShapeType; }
    	// 在鼠标按下的时候调用SetStartPoint,
    	// 移动的调用UpdateEndPoint
    	// 弹起的时候调用SetEndPoint
    	virtual void SetStartPoint(const CPoint&point) {ASSERT(POINT_NULL != point); m_pt1 = point; };
    	virtual void SetEndPoint(const CPoint&point){ASSERT(POINT_NULL != point); m_pt2 = point; };
    	virtual void UpdateEndPoint(const CPoint&point){ SetEndPoint(point); };
    public:
    	CPoint			m_pt1,m_pt2;
    	COLORREF		m_crBoder;
    	COLORREF		m_crFill;
    private:
    	ENUM_SHAPE_TYPE		m_ShapeType;
    };
    // the shape factory
    QShape* CreateShape( ENUM_SHAPE_TYPE eShape ,LPARAM lParam = 0);
    class QRectangle : public QShape
    {
    public:
    	QRectangle():QShape(SHAPE_RECT){ }
    	virtual void Draw(CDC *pDC);
    };
    class QEllipse : public QShape
    {
    public:
    	QEllipse():QShape(SHAPE_ELLIPSE){}
    	virtual void Draw(CDC *pDC);
    };
    class QCurve : public QShape
    {
    public:
    	QCurve();
    	virtual void Draw(CDC *pDC);
    	// 在curve中,pt1,和pt2标志曲线所占据的矩形,不是开始和结束点
    	virtual void UpdateEndPoint(const CPoint&point);
    	virtual void SetEndPoint(const CPoint&point) { UpdateEndPoint(point); };
    	virtual CRect GetRect()const;
    private:
    	typedef CArray<CPoint,CPoint>	CurvePoint;
    	CurvePoint	m_Points;
    };
    class QLine : public QShape
    {
    public :
    	QLine():QShape(SHAPE_LINE) { }
    	virtual void Draw(CDC *pDC);
    };
    class QIcon : public QShape
    {
    public:
    	QIcon(HICON hIcon);
    	virtual void Draw(CDC *pDC);
    	virtual CRect GetRect()const ;
    	virtual void SetEndPoint(const CPoint&point){};
    	virtual void UpdateEndPoint(const CPoint&point){ };
    private:
    	HICON	m_hIcon;
    };
    // CPainterPane
    class CPainterPane : public CWnd
    {
    	typedef std::vector<QShape *>  SHAPES;
    	typedef SHAPES::iterator  ShapeItr;
    	DECLARE_DYNAMIC(CPainterPane)
    public:
    	CPainterPane();
    	virtual ~CPainterPane();
    	BOOL SetMainBk( LPCTSTR pszDll,UINT nID,LPCTSTR pszType,COLORREF crTrans=COLOR_BLACK );
    	BOOL InitPane(CRect rect,CWnd *pParent,UINT nID);
    	void SetDrawing( ENUM_SHAPE_TYPE eShape,LPARAM lParam =0);
    	void SetShapeColor(COLORREF crBorder,COLORREF crFill=COLOR_NONE);
    	// 清除当前所画的所有内容,不包括背景
    	void ClearDrawed(); 
    	// 撤销nTime次的操作
    	void Undo(int nTimes = 1);
    	int GetShapesCount() { return m_Shapes.size(); }
    protected:
    	void DrawClient(CDC *pDC,const CRect &rect);
    	// 在内存dc中画
    	void DrawMainBack(CDC* pDC , const CRect &rect );
    	void DrawShapes( CDC* pDC ,const CRect &rect );
    	void CopyDC(CDC *pDst,CDC *pSrc,const CRect &rect);
    	// 将pDCSrc 更新显示到界面
    	void CopyDCToSurface(CDC *pDCSrc,const CRect&rect);
    	void Reset();
    	BOOL _IsDrawing()const;
    	BOOL _BeginDrawing( CPoint ptStart );
    	void _UpdateDrawing(CPoint ptEnd);
    	void _EndDrawing(CPoint ptEnd);
    protected:
    	DECLARE_MESSAGE_MAP()
    	afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
    	afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
    	afx_msg void OnMouseMove(UINT nFlags, CPoint point);
    	afx_msg BOOL OnEraseBkgnd(CDC* pDC);
    	afx_msg void OnPaint();
    	class MouseTrack
    	{
    	protected:
    		typedef std::vector<CPoint> LstTrack;
    		typedef LstTrack::iterator LstTrackItr;
    		LstTrack	m_LstTrack; // 第一个点是鼠标按下的位置,最后一个点是最后一次鼠标移动到的位置
    		BOOL		m_bDown;	// 是否已经按下? 需要调用Down设置
    	public:
    		MouseTrack() { m_bDown = FALSE; }
    		void Down(CPoint pt) { Reset(); m_LstTrack.push_back(pt); m_bDown = TRUE; }
    		void Move(CPoint pt) { ASSERT(m_bDown); m_LstTrack.push_back(pt); }
    		void Up(CPoint pt) { m_LstTrack.push_back(pt); m_bDown = FALSE; }
    		void Reset() { m_bDown = FALSE; m_LstTrack.clear(); }
    		BOOL IsDown()const { return m_bDown; }
    		CPoint PointDown()const 
    		{ 
    			if (m_LstTrack.size() > 0)
    				return m_LstTrack[0]; 
    			return POINT_NULL;
    		}
    		// idx 既可以是正数索引,也可以是负数索引,不能为0
    		// -1  为最后一次的矩形 -2 倒数第二次
    		// 1  第一次, 2 第二次
    		CPoint PointX(int idx=-1)const
    		{
    			LstTrack::size_type n = m_LstTrack.size();
    			idx = (idx < 0) ? n + idx : idx;
    			if (n < 2 || idx <= 0 || idx >= n)
    				return POINT_NULL;
    			return m_LstTrack[idx];
    		}
    		// 获取鼠标按下和第idx次移动的矩形, 
    		// idx 既可以是正数索引,也可以是负数索引,不能为0
    		// -1  为最后一次的矩形 -2 倒数第二次
    		// 1  第一次, 2 第二次
    		CRect GetRect(int idx = -1)const 
    		{
    			CPoint pt2 = PointX(idx);
    			if (POINT_NULL == pt2)
    				return RECT_NULL;
    			CRect rect(m_LstTrack[0],pt2);
    			rect.NormalizeRect();
    			return rect;
    		}
    	};
    	MouseTrack	m_MouseTrack;
    	SHAPES	m_Shapes;
    private:
    	HBITMAP		m_hbmpMainBack;
    	CBitmap		m_bmpMemBack;
    	CDC		m_dcMemBack;
    	CBitmap		m_bmpMemDrawed;	
    	CDC		m_dcMemDrawed;
    	CBitmap		m_bmpMemDrawing;
    	CDC		m_dcMemDrawing;
    	HCURSOR		m_hCurCross,m_hCurArrow;
    	ENUM_SHAPE_TYPE	m_eDrawing;	// 
    	LPARAM		m_lShapeParam;
    	QShape*		m_pShapeDrawing;	// 当前正在画的图形
    	COLORREF	m_crShapeBack,m_crShapeBorder;
    };
    // CPainterList
    struct _SHAPE_ITEMS 
    {
    	int	iImg;
    	CString sItem;
    	DWORD	dwData;
    };
    enum 
    {
    	ACTION_CLEAR = MAX_SHAPE_VALUE + 1,
    	ACTION_UNDO,
    	ACTION_SAVE,
    };
    class CPainterList : public CMFCListCtrl
    {
    	DECLARE_DYNAMIC(CPainterList)
    public:
    	CPainterList();
    	virtual ~CPainterList();
    	void SetAssoicatePainter(CPainterPane *pPainter) { m_pPainter = pPainter; };
    	BOOL Init( UINT nImgeList ,COLORREF crMask);
    	void AddButton(LPCTSTR sItem,int iImage,DWORD dwData);
    	void AddButton(const _SHAPE_ITEMS *pItem);
    protected:
    	DECLARE_MESSAGE_MAP()
    	afx_msg void OnNMClick(NMHDR *pNMHDR, LRESULT *pResult);
    	afx_msg void OnLvnItemchanging(NMHDR *pNMHDR, LRESULT *pResult);
    	virtual COLORREF OnGetCellTextColor(int iRow, int iCol);
    	virtual COLORREF OnGetCellBkColor(int iRow, int iCol);
    	virtual void PreSubclassWindow();
    	BOOL IsSelected(int iRow);
    private:
    	CPainterPane*	m_pPainter;
    	CImageList	m_ImageList;	
    };
    // CPainterDlg 对话框
    class CPainterDlg : public CDialogEx
    {
    	DECLARE_DYNAMIC(CPainterDlg)
    public:
    	CPainterDlg(CWnd* pParent = NULL);   // 标准构造函数
    	virtual ~CPainterDlg();
    // 对话框数据
    	enum { IDD = IDD_PAINTER };
    	void SetImageParams( LPCTSTR pszDll,LPCTSTR pszType,UINT nImgID ,COLORREF crTrans);
    protected:
    	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持
    	virtual BOOL OnInitDialog();
    	afx_msg void OnColorChanged();
    	afx_msg void OnPaint();
    	DECLARE_MESSAGE_MAP()
    	enum
    	{
    		IDC_PAINTPANE_COLORBAR = 111,
    	};
    	
    	static const _SHAPE_ITEMS	scm_ShapeItems[];
    private:
    	CMFCColorBar	 m_ColorBar;
    	CPainterPane	m_Painter;
    	CString		m_sDll;
    	CString		m_sType;
    	UINT		m_nImgeID;
    	COLORREF	m_crTrans;
    	CPainterList	m_ListBtns;
    	QGroupBox	m_Box1;
    	CImageList	m_ImageList;
    	QGroupBox m_Box2;
    };
    

     

     

    .cpp

    // PainterDlg.cpp : 实现文件
    //
    #include "stdafx.h"
    #include "QAAS.h"
    #include "PainterDlg.h"
    #include "afxdialogex.h"
    QShape* CreateShape( ENUM_SHAPE_TYPE eShape ,LPARAM lParam)
    {
    	if (SHAPE_NONE == eShape)
    	{
    		ASSERT(FALSE);
    		return NULL;
    	}
    	QShape * pShape = NULL;
    	switch (eShape)
    	{
    	case SHAPE_RECT:
    		{
    			pShape = new QRectangle();
    			break;
    		}
    	case SHAPE_ELLIPSE:
    		{
    			pShape = new QEllipse();
    			break;
    		}
    	case SHAPE_LINE:
    		{
    			pShape = new QLine();
    			break;
    		}
    	case SHAPE_CURVE:
    		{
    			pShape = new QCurve();
    			break;
    		}
    	case SHAPE_ICON:
    		{
    			pShape = new QIcon((HICON)lParam);
    			break;
    		}
    	default:
    		{
    			ASSERT(FALSE);
    			pShape = NULL;
    			break;
    		}
    	}
    	return pShape;
    }
    QShape::QShape( ENUM_SHAPE_TYPE eShape )
    	:m_ShapeType(eShape)
    {
    	m_crBoder = m_crFill = COLOR_NONE; 
    	m_pt1 = m_pt2 = POINT_NULL; 
    }
    CRect QShape::GetRect() const
    {
    	CRect rect(m_pt1,m_pt2);
    	rect.NormalizeRect();
    	return rect;
    }
    void QRectangle::Draw( CDC *pDC )
    {
    	ASSERT(pDC != NULL);
    	CRect rect = GetRect();
    	if (COLOR_NONE != m_crFill)
    	{
    		pDC->FillSolidRect(&rect,m_crFill);
    	}
    	pDC->FrameRect(&rect,&CBrush(m_crBoder));
    }
    void QEllipse::Draw( CDC *pDC )
    {
    	ASSERT(pDC != NULL);
    	using namespace Gdiplus;
    	CRect rect = GetRect();
    	rect.DeflateRect(1,1);	// 防止切边问题,注释此行可以重现重现问题
    	Gdiplus::Graphics gra(pDC->GetSafeHdc());
    	gra.SetSmoothingMode(SmoothingModeAntiAlias);	// 开启反锯齿效果
    	if (COLOR_NONE != m_crFill)
    	{
    		gra.FillEllipse(&SolidBrush(DwordToColor(m_crFill)),(RectF)QRect(rect));
    	}
    	Pen pen(DwordToColor(m_crBoder));
    	gra.DrawEllipse(&pen,(RectF)QRect(rect));
    }
    // 曲线实现比较特殊,要特别处理
    QCurve::QCurve():QShape(SHAPE_CURVE) 
    {
    	// 在curve中,pt1,和pt2标志曲线所占据的矩形,不是开始和结束点
    	m_pt1.x = m_pt1.y = INT_MAX; 
    	m_pt2.x = m_pt2.y = -1;
    }
    CRect QCurve::GetRect()const
    {
    	// 还没有添加点
    	if ((m_pt1.x == INT_MAX) || (m_pt2.x == -1))
    	{
    		return CRect(0,0,0,0);
    	}
    	CRect rect = QShape::GetRect();
    	rect.InflateRect(1,1);	// 为防止切边
    	return rect;
    }
    void QCurve::Draw( CDC *pDC )
    {
    	int nCount = m_Points.GetCount();
    	if (nCount < 2)
    		return;
    	
    	CPen pen(PS_SOLID,1,m_crBoder);
    	CPen *pOldPen = (CPen*)pDC->SelectObject(&pen);
    	pDC->MoveTo(m_Points.GetAt(0));
    	for (int i = 1; i < nCount; i++)
    	{
    		pDC->LineTo(m_Points[i]);
    	}
    	pDC->SelectObject(pOldPen);
    }
    void QCurve::UpdateEndPoint( const CPoint&point )
    {
    	// 在curve中,pt1,和pt2标志曲线所占据的矩形,不是开始和结束点
    	m_pt1.x = min(m_pt1.x,point.x);
    	m_pt1.y = min(m_pt1.y,point.y);
    	m_pt2.x = max(m_pt2.x,point.x);
    	m_pt2.y = max(m_pt2.y,point.y);
    	m_Points.Add(point);
    }
    void QLine::Draw( CDC *pDC )
    {
    	if (POINT_NULL == m_pt1 || POINT_NULL == m_pt2)
    		return;
    	CAADraw aa;
    	aa.DrawLine(pDC->GetSafeHdc(),m_pt1.x,m_pt1.y,m_pt2.x,m_pt2.y,m_crBoder);
    }
    QIcon::QIcon( HICON hIcon )
    	:QShape(SHAPE_ICON)
    {
    	ASSERT(hIcon != NULL);
    	m_hIcon = hIcon;
    }
    void QIcon::Draw( CDC *pDC )
    {
    	if (NULL != m_hIcon)
    	{
    		pDC->DrawIcon(m_pt1,m_hIcon);
    	}
    }
    CRect QIcon::GetRect() const
    {
    	if (NULL != m_hIcon)
    	{
    		CRect rect;
    		ICONINFO ii;
    		if (GetIconInfo(m_hIcon,&ii))
    		{
    			return CRect(m_pt1,CPoint(ii.xHotspot * 2 + m_pt1.x, ii.yHotspot * 2 + m_pt1.y));
    		}
    	}
    	return RECT_EMPTY;
    }
    //////////////////////////////////////////////////////////////////
    // brief	:	2011/03/25 
    // copyright:	qiuchengw @ 2011
    //////////////////////////////////////////////////////////////////
    // CPainterPane
    IMPLEMENT_DYNAMIC(CPainterPane, CWnd)
    CPainterPane::CPainterPane()
    {
    	m_crShapeBack = COLOR_NONE;
    	m_crShapeBorder = COLOR_BLACK;
    	m_eDrawing = SHAPE_NONE;
    	m_pShapeDrawing = NULL;
    	m_hCurCross = NULL;
    	m_hCurArrow = NULL;
    }
    CPainterPane::~CPainterPane()
    {
    	Reset();
    	DeleteObject(m_hCurCross);
    	DeleteObject(m_hCurArrow);
    }
    void CPainterPane::Reset()
    {
    	if (m_dcMemBack.m_hDC)
    		m_dcMemBack.DeleteDC();
    	if (m_dcMemDrawed.m_hDC)
    		m_dcMemDrawed.DeleteDC();
    	if (m_dcMemDrawing.m_hDC)
    		m_dcMemDrawing.DeleteDC();
    	if (m_bmpMemDrawed.m_hObject)
    		m_bmpMemDrawed.DeleteObject();
    	if (m_bmpMemBack.m_hObject)
    		m_bmpMemBack.DeleteObject();
    	if (m_bmpMemDrawing.m_hObject)
    		m_bmpMemDrawing.DeleteObject();
    	for (ShapeItr itr = _BeginItr(m_Shapes); itr != _EndItr(m_Shapes); ++itr)
    	{
    		delete *itr;
    	}
    	m_Shapes.clear();
    	m_eDrawing = SHAPE_NONE;
    	m_pShapeDrawing = NULL;
    	m_crShapeBack = COLOR_NONE;
    	m_crShapeBorder = COLOR_BLACK;
    }
    BEGIN_MESSAGE_MAP(CPainterPane, CWnd)
    	ON_WM_LBUTTONDOWN()
    	ON_WM_LBUTTONUP()
    	ON_WM_MOUSEMOVE()
    	ON_WM_ERASEBKGND()
    	ON_WM_PAINT()
    END_MESSAGE_MAP()
    // CPainterPane 消息处理程序
    void CPainterPane::OnLButtonDown(UINT nFlags, CPoint point)
    {
    	if (SHAPE_NONE != m_eDrawing)
    	{
    		if (!_BeginDrawing(point))
    		{
    			ASSERT(FALSE);
    //			SetDrawing(SHAPE_NONE);
    		}
    	}
    }
    void CPainterPane::OnLButtonUp(UINT nFlags, CPoint point)
    {
    	if (_IsDrawing())
    	{
    		_EndDrawing(point);
    	}
    }
    void CPainterPane::OnMouseMove(UINT nFlags, CPoint point)
    {
    	SetCursor((SHAPE_NONE != m_eDrawing) ? m_hCurCross : m_hCurArrow);
    	if (_IsDrawing())
    	{
    		_UpdateDrawing(point);
    	}
    }
    BOOL CPainterPane::_BeginDrawing( CPoint ptStart )
    {
    	ASSERT(SHAPE_NONE != m_eDrawing);
    	CRect rcClip;
    	GetWindowRect(&rcClip);
    	// 矩形各边界减小1为了避免当鼠标移动到此窗体的边框上
    	// 然后释放鼠标按钮就接收不到WM_LBUTTONUP消息的情况
    	rcClip.DeflateRect(1,1);
    	if ( ClipCursor(&rcClip))
    	{
    		if (NULL != (m_pShapeDrawing = CreateShape(m_eDrawing,m_lShapeParam)))
    		{
    			m_pShapeDrawing->SetStartPoint(ptStart);
    			m_pShapeDrawing->SetBorderColor(m_crShapeBorder);
    			m_pShapeDrawing->SetFillColor(m_crShapeBack);
    			m_MouseTrack.Down(ptStart);
    			return TRUE;
    		}
    	}
    	// 新创建响应的图形
    	ClipCursor(NULL);
    	return TRUE;
    }
    void CPainterPane::_UpdateDrawing( CPoint ptMove )
    {
    	ASSERT(m_pShapeDrawing != NULL);
    	// 鼠标按下到上次移动的矩形位置
    	CRect rcLast = m_MouseTrack.GetRect();
    	// 鼠标按下到此次移动到的矩形位置
    	m_MouseTrack.Move(ptMove);
    	// 设置图形的矩形为当前的移动的位置
    	m_pShapeDrawing->UpdateEndPoint(ptMove);
    	// 当前图像的矩形
    	CRect rcDrawing = m_pShapeDrawing->GetRect();
    	// 取两个矩形的并集进行更新,它们的并集就是当前的脏矩形
    	if (rcDrawing.UnionRect(&rcDrawing,&rcLast))
    	{
    		// 边界增大一点是为了不使图形切边
    		rcDrawing.InflateRect(1,1);
    		// 先拷贝需要更新区域的已画好的图形到正在画的区域中
    		CopyDC(&m_dcMemDrawing,&m_dcMemDrawed,rcDrawing);
    		// 画图形
    		m_pShapeDrawing->Draw(&m_dcMemDrawing);
    		// 更新到显示dc,
    		// 只有当鼠标左键弹起,标志这个图形画好的时候才能更新到m_dcMemDrawed 上
    		CopyDCToSurface(&m_dcMemDrawing,rcDrawing);
    	}
    }
    void CPainterPane::CopyDCToSurface(CDC *pDC,const CRect&rect)
    {
    	CDC *pWndDC = GetDC();
    	if (pDC->GetSafeHdc() != pWndDC->GetSafeHdc())
    	{
    		CopyDC(pWndDC,pDC,rect);
    	}
    	ReleaseDC(pWndDC);
    }
    void CPainterPane::_EndDrawing( CPoint ptEnd )
    {
    	// 画图形已经完成了.
    	ClipCursor(NULL);
    	_UpdateDrawing(ptEnd);
    	// 更新图像最后的坐标
    	m_pShapeDrawing->SetEndPoint(ptEnd);
    	// 此处或许会有一个像素的偏差,因为没有再次调用_UpdateDrawing(ptEnd);
    	m_MouseTrack.Up(ptEnd);
    	CRect rect = m_pShapeDrawing->GetRect();
    	// 保存所画的图像到列表记录
    	m_Shapes.push_back(m_pShapeDrawing);
    	// 所画的图像更新到已画的图的内存dc中
    	CopyDC(&m_dcMemDrawed,&m_dcMemDrawing,rect);
    	// 将更新好的图像显示出来
    	CopyDCToSurface(&m_dcMemDrawed,rect);
    }
    BOOL CPainterPane::InitPane( CRect rect,CWnd *pParent,UINT nID )
    {
    	m_hCurCross = AfxGetApp()->LoadStandardCursor(IDC_CROSS);
    	m_hCurArrow = AfxGetApp()->LoadStandardCursor(IDC_ARROW);
    	LPCTSTR pszClass = AfxRegisterWndClass(CS_VREDRAW|CS_HREDRAW,m_hCurArrow);
    	if (!CWnd::Create(pszClass,L"",WS_VISIBLE|WS_CHILD|WS_BORDER,rect,pParent,nID))
    		return FALSE;
    	return TRUE;
    }
    BOOL CPainterPane::OnEraseBkgnd(CDC* pDC)
    {
    	return TRUE;
    }
    void CPainterPane::OnPaint()
    {
    	CPaintDC dc(this); // device context for painting
    	
    	CRect rect;
    	dc.GetClipBox(&rect);
    	DrawClient(&dc,rect);
    }
    void CPainterPane::DrawClient( CDC *pDC,const CRect &rect )
    {
    	ASSERT(pDC != NULL);
    	// 使用背景清除需要更新的区域
    // 	DrawMainBack(&m_dcMemDrawed,rect);
    // 	DrawShapes(&m_dcMemDrawed,rect);
    	// 从内存中拷贝到显示
    	CopyDC(pDC,&m_dcMemDrawed,rect);
    }
    void CPainterPane::DrawShapes( CDC* pDC ,const CRect &rect )
    {
    	CRect rc; 
    	for (ShapeItr itr = _BeginItr(m_Shapes); itr != _EndItr(m_Shapes); ++itr)
    	{
    		rc = rect;
    		if (rc.IntersectRect(&rc,&rect))
    		{
    			(*itr)->Draw(pDC);
    		}
    	}
    }
    void CPainterPane::DrawMainBack(CDC* pDC , const CRect &rect )
    {
    	// 使用背景清除pDC
    	CopyDC(pDC,&m_dcMemBack,rect);
    }
    BOOL CPainterPane::SetMainBk( LPCTSTR pszDll,UINT nID,LPCTSTR pszType,COLORREF crTrans )
    {
    	Reset();
    	Gdiplus::Image *pImg = NULL;
    	if (CResLoader::LoadFromDll(pszDll,pszType,nID,pImg))
    	{
    		CDC *pDC = GetDC();
    		m_dcMemBack.CreateCompatibleDC(pDC);
    		m_bmpMemBack.CreateCompatibleBitmap(pDC,pImg->GetWidth(),pImg->GetHeight());
    		m_dcMemBack.SelectObject(&m_bmpMemBack);
    		m_dcMemDrawed.CreateCompatibleDC(pDC);
    		m_bmpMemDrawed.CreateCompatibleBitmap(pDC,pImg->GetWidth(),pImg->GetHeight());
    		m_dcMemDrawed.SelectObject(&m_bmpMemDrawed);
    		m_dcMemDrawing.CreateCompatibleDC(pDC);
    		m_bmpMemDrawing.CreateCompatibleBitmap(pDC,pImg->GetWidth(),pImg->GetHeight());
    		m_dcMemDrawing.SelectObject(&m_bmpMemDrawing);
    		ImageAttributes imgati;
    		if (COLOR_NONE != crTrans)
    		{
    			imgati.SetColorKey(DwordToColor(crTrans),DwordToColor(crTrans));
    		}
    		Gdiplus::Graphics(m_dcMemBack.m_hDC).DrawImage(pImg,QRect(0,0,pImg->GetWidth(),pImg->GetHeight()),
    			0,0,pImg->GetWidth(),pImg->GetHeight(),UnitPixel,&imgati);
    		CopyDC(&m_dcMemDrawed,&m_dcMemBack,RECT_EMPTY);
    		CopyDC(&m_dcMemDrawing,&m_dcMemBack,RECT_EMPTY);
    		CopyDC(pDC,&m_dcMemBack,RECT_EMPTY);
    		ReleaseDC(pDC);
    		return TRUE;
    	}
    	return FALSE;
    }
    void CPainterPane::CopyDC( CDC *pDst,CDC *pSrc,const CRect &rect )
    {
    	ASSERT(pDst != NULL && pSrc != NULL);
    	if (pDst->GetSafeHdc() != NULL && pSrc->GetSafeHdc() != NULL)
    	{
    		CRect rc = rect;
    		if (rc.Width() == 0 || rc.Height() == 0)
    		{
    			rc.left = rc.top = 0;
    			rc.bottom = rc.right = 1024;		// 只是假设背景图像不会大于 1024 * 1024
    		}
    		pDst->BitBlt(rc.left,rc.top,rc.Width(),rc.Height(),pSrc,rc.left,rc.top,SRCCOPY);
    	}
    }
    void CPainterPane::SetDrawing( ENUM_SHAPE_TYPE eShape,LPARAM lParam )
    {
    	ASSERT(!_IsDrawing());
    	m_eDrawing = eShape;
    	m_lShapeParam = lParam;
    }
    BOOL CPainterPane::_IsDrawing() const
    {
    	/*
    #ifdef _DEBUG
    	if (m_pShapeDrawing != NULL)
    	{
    		ASSERT(m_pShapeDrawing->GetShape() == m_eDrawing);
    		return TRUE;
    	}
    	return FALSE;
    #else
    	return (m_pShapeDrawing != NULL);
    #endif
    	*/
    	return (m_eDrawing != SHAPE_NONE) && (m_MouseTrack.IsDown());
    }
    void CPainterPane::SetShapeColor( COLORREF crBorder,COLORREF crFill/*=COLOR_NONE*/ )
    {
    	m_crShapeBorder = crBorder;
    	m_crShapeBack = crFill;
    }
    void CPainterPane::ClearDrawed()
    {
    	if (GetShapesCount() > 0)
    	{
    		for (ShapeItr itr = _BeginItr(m_Shapes); itr != _EndItr(m_Shapes); ++itr)
    		{ // 将所有的已画的图形都删掉
    			delete *itr;
    		}
    		m_Shapes.clear();
    		// 使用主背景清除已画的图形
    		CopyDC(&m_dcMemDrawed,&m_dcMemBack,RECT_EMPTY);
    		CopyDC(&m_dcMemDrawing,&m_dcMemBack,RECT_EMPTY);
    		// 更新到显示
    		Invalidate(TRUE);
    	}
    	ASSERT(GetShapesCount() == 0);
    }
    void CPainterPane::Undo( int nTimes /*= 1*/ )
    {
    	ASSERT(nTimes > 0);
    	
    	if (GetShapesCount() > 0 )
    	{
    		CRect rcUpdate = RECT_EMPTY; // 所要清除的图像的区域并集,最后要更新
    		for (SHAPES::size_type i = GetShapesCount() - 1 ; i >= 0 && nTimes > 0;  --i,--nTimes)
    		{
    			rcUpdate.UnionRect(&rcUpdate,&(m_Shapes[i]->GetRect()));
    			delete m_Shapes[i];
    			m_Shapes.pop_back();
    		}
    		// 更新已清除的图形的并集区域
    		rcUpdate.InflateRect(1,1);
    		DrawMainBack(&m_dcMemDrawed,rcUpdate);
    		DrawShapes(&m_dcMemDrawed,rcUpdate);
    		InvalidateRect(&rcUpdate,FALSE);
    	}
    }
    //////////////////////////////////////////////////////////////////
    // brief	:	2011/03/24 
    // copyright:	qiuchengw @ 2011
    //////////////////////////////////////////////////////////////////
    // CPainterDlg 对话框
    const _SHAPE_ITEMS CPainterDlg::scm_ShapeItems[] = 
    {
    	{ 0, L"直线", SHAPE_LINE },
    	{ 1, L"矩形", SHAPE_RECT },
    	{ 2, L"椭圆", SHAPE_ELLIPSE },
    	{ 3, L"曲线", SHAPE_CURVE },
    	{ 4, L"撤销上一步",ACTION_UNDO  },
    	{ 5, L"清除所有", ACTION_CLEAR },
    	{ 6, L"保存",  ACTION_SAVE },
    };
    IMPLEMENT_DYNAMIC(CPainterDlg, CDialogEx)
    CPainterDlg::CPainterDlg(CWnd* pParent /*=NULL*/)
    	: CDialogEx(CPainterDlg::IDD, pParent)
    {
    }
    CPainterDlg::~CPainterDlg()
    {
    }
    void CPainterDlg::DoDataExchange(CDataExchange* pDX)
    {
    	CDialogEx::DoDataExchange(pDX);
    	DDX_Control(pDX, IDC_LIST_BTNS, m_ListBtns);
    	DDX_Control(pDX, IDC_BOX1, m_Box1);
    	DDX_Control(pDX, IDC_BOX2, m_Box2);
    }
    BEGIN_MESSAGE_MAP(CPainterDlg, CDialogEx)
    	ON_BN_CLICKED(IDC_PAINTPANE_COLORBAR, &CPainterDlg::OnColorChanged)
    	ON_WM_PAINT()
    END_MESSAGE_MAP()
    BOOL CPainterDlg::OnInitDialog()
    {
    	CDialogEx::OnInitDialog();
    	SetBackgroundColor(RGB(240,240,240));
    	CRect rect = GetDlgItemRect(IDC_RECT_COLORBAR,this);
    	m_ColorBar.CreateControl(this,rect,IDC_PAINTPANE_COLORBAR,5);
    	m_ColorBar.ShowWindow(SW_SHOW);
    	m_ColorBar.SetColor(RGB(0,0,0));
    	m_Box1.SetHeaderHeight(1);
    	m_Box1.SetBorderColor(RGB(130,135,144));
    	m_Box2.SetHeaderHeight(1);
    	m_Box2.SetBorderColor(RGB(130,135,144));
    	rect = GetDlgItemRect(IDC_RECT_PAINTPANE,this);
    	if (!m_Painter.InitPane(rect,this,112))
    		return FALSE;
    	m_Painter.ShowWindow(SW_SHOW);
    	m_Painter.SetMainBk(m_sDll,m_nImgeID,m_sType,m_crTrans);
    	m_ListBtns.Init(IDB_PAINTER,RGB(239,239,239));
    	for (int i = 0; i < _countof(scm_ShapeItems); ++i)
    	{
    		m_ListBtns.AddButton(&scm_ShapeItems[i]);
    	}
    	m_ListBtns.SetAssoicatePainter(&m_Painter);
    	return TRUE;
    }
    void CPainterDlg::SetImageParams( LPCTSTR pszDll,LPCTSTR pszType,UINT nImgID ,COLORREF crTrans)
    {
    	m_sDll = pszDll;
    	m_sType = pszType;
    	m_nImgeID = nImgID;
    	m_crTrans = crTrans;
    }
    void CPainterDlg::OnColorChanged()
    {
    	COLORREF cr = m_ColorBar.GetColor();
    	m_Painter.SetShapeColor(cr,COLOR_NONE);
    }
    void CPainterDlg::OnPaint()
    {
    	CPaintDC dc(this);
    	m_Box1.Draw(&dc);
    	m_Box2.Draw(&dc);
    }
    // CPainterList
    IMPLEMENT_DYNAMIC(CPainterList, CMFCListCtrl)
    CPainterList::CPainterList()
    {
    	m_pPainter = NULL;
    }
    CPainterList::~CPainterList()
    {
    }
    BEGIN_MESSAGE_MAP(CPainterList, CMFCListCtrl)
    	ON_NOTIFY_REFLECT(NM_CLICK, &CPainterList::OnNMClick)
    	ON_NOTIFY_REFLECT(LVN_ITEMCHANGING, &CPainterList::OnLvnItemchanging)
    END_MESSAGE_MAP()
    void	g_listAutoSizeColumns(CListCtrl&   rList,int   col   /*=-1*/) 
    { 
    	//   Call   this   after   your   list   control   is   filled 
    	if(!rList.GetHeaderCtrl())return; 
    	rList.ShowWindow(SW_HIDE); 
    	rList.SetRedraw(FALSE); 
    	int   mincol   =   col   <   0   ?   0   :   col; 
    	int   maxcol   =   col   <   0   ?   (rList.GetHeaderCtrl()->GetItemCount())-1   :   col; 
    	for   (col   =   mincol;   col   <=   maxcol;   col++)   { 
    		rList.SetColumnWidth(col,LVSCW_AUTOSIZE); 
    		int   wc1   =   rList.GetColumnWidth(col); 
    		rList.SetColumnWidth(col,LVSCW_AUTOSIZE_USEHEADER); 
    		int   wc2   =   rList.GetColumnWidth(col); 
    		int   iFrom=rList.GetTopIndex(); 
    		int   nCountPerpage=rList.GetCountPerPage(); 
    		if(nCountPerpage <=0) 
    			nCountPerpage=rList.GetItemCount(); 
    		int   iTo=iFrom+nCountPerpage; 
    		int   nImgWidth=0; 
    		int   iIndent=0; 
    		LVITEM	li; 
    		li.mask=LVIF_IMAGE|LVIF_INDENT; 
    		IMAGEINFO	ImageInfo; 
    		for(int   iItem=iFrom;iItem <iTo;iItem++){ 
    			li.iItem=iItem; 
    			li.iSubItem=col; 
    			rList.GetItem(&li); 
    			iIndent=max(li.iIndent,iIndent); 
    			if(li.iImage!=-1){ 
    				CImageList*	pImageList=rList.GetImageList(LVSIL_SMALL); 
    				if(pImageList-> GetSafeHandle()){ 
    					pImageList-> GetImageInfo(li.iImage,&ImageInfo); 
    					nImgWidth=max(nImgWidth,ImageInfo.rcImage.right-ImageInfo.rcImage.left); 
    				} 
    			} 
    		} 
    		int   wc   =   max(20,max(wc1,wc2)); 
    		if(col==0) 
    			wc+=nImgWidth*(iIndent+1); 
    		else 
    			wc+=nImgWidth; 
    		rList.SetColumnWidth(col,wc); 
    	} 
    	rList.SetRedraw(TRUE); 
    	rList.ShowWindow(SW_SHOW); 
    } 
    // CPainterList 消息处理程序
    void CPainterList::PreSubclassWindow()
    {
    	CMFCListCtrl::PreSubclassWindow();
    	ModifyStyle(0,LVS_SHOWSELALWAYS|LVS_SINGLESEL|LVS_LIST);
    }
    COLORREF CPainterList::OnGetCellTextColor( int iRow, int iCol )
    {
    	if (IsSelected(iRow))
    		return RGB(255,0,0);
    	else
    		return RGB(0,0,0);
    }
    COLORREF CPainterList::OnGetCellBkColor( int iRow, int iCol )
    {
    	if (IsSelected(iRow))
    		return RGB(255,255,225);
    	else
    		return RGB(255,255,255);
    }
    BOOL CPainterList::IsSelected( int iRow )
    {
    	POSITION pos = GetFirstSelectedItemPosition();
    	while (pos != NULL)
    	{
    		if (GetNextSelectedItem(pos) == iRow)
    			return TRUE;
    	}
    	return FALSE;
    }
    void CPainterList::OnNMClick(NMHDR *pNMHDR, LRESULT *pResult)
    {
    	LPNMITEMACTIVATE pNMItemActivate = reinterpret_cast<LPNMITEMACTIVATE>(pNMHDR);
    	// TODO: 在此添加控件通知处理程序代码
    	if (NULL == m_pPainter)
    		return;
    	int iSel = pNMItemActivate->iItem;
    	if (-1 == iSel)
    	{
    		// 没有选中项
    		m_pPainter->SetDrawing(SHAPE_NONE);
    	}
    	else
    	{
    		DWORD dwData = GetItemData(iSel);
    		switch (dwData)
    		{
    		case SHAPE_LINE:
    		case SHAPE_RECT:
    		case SHAPE_ELLIPSE:
    		case SHAPE_CURVE:
    			{
    				m_pPainter->SetDrawing((ENUM_SHAPE_TYPE)dwData);
    				break;
    			}
    		case SHAPE_ICON:
    			{
    				m_pPainter->SetDrawing(ENUM_SHAPE_TYPE(dwData),(LPARAM)m_ImageList.ExtractIcon(7));
    				break;
    			}
    		case ACTION_CLEAR:
    			{
    				if (YesNoMessageBox(L"清除后不能恢复,确定清除吗?"))
    					m_pPainter->ClearDrawed();
    				break;
    			}
    		case ACTION_UNDO:
    			{
    				m_pPainter->Undo(1);
    				break;
    			}
    		}
    	}
    	*pResult = 0;
    }
    void CPainterList::OnLvnItemchanging(NMHDR *pNMHDR, LRESULT *pResult)
    {
    	LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);
    	// TODO: 在此添加控件通知处理程序代码
    	int iSel = pNMLV->iItem;
    	if (-1 != iSel)
    	{
    		if (GetItemData(iSel) > MAX_SHAPE_VALUE)
    		{
    			*pResult = 1;
    			return ;
    		}
    	}
    	*pResult = 0;
    }
    BOOL CPainterList::Init( UINT nImgeList ,COLORREF crMask)
    {
    	if (m_ImageList.GetSafeHandle() != NULL)
    		return TRUE;
    	if (!m_ImageList.Create(24,24,ILC_COLORDDB|ILC_MASK,8,0))
    		return FALSE;
    	
    	CBitmap bmp;
    	if (!bmp.LoadBitmap(nImgeList))
    		return FALSE;
    	m_ImageList.Add(&bmp,crMask);
    	SetImageList(&m_ImageList,LVSIL_SMALL);
    	
    	return TRUE;
    }
    void CPainterList::AddButton( LPCTSTR sItem,int iImage,DWORD dwData )
    {
    	int idx = GetItemCount();
    	idx = InsertItem(idx,sItem,iImage);
    	SetItemData(idx,dwData);
    	g_listAutoSizeColumns(*this,0);
    }
    void CPainterList::AddButton( const _SHAPE_ITEMS *pItem )
    {
    	AddButton(pItem->sItem,pItem->iImg,pItem->dwData);
    }
    

     

     

    ----------------------------------------

    2011/5/18 更新:

    _UpdateDrawing 对于QIcon需要特殊对待,可以提高绘图效率.

    void CPainterPane::_UpdateDrawing( CPoint ptMove )
    {
    	ASSERT(m_pShapeDrawing != NULL);
    	// 鼠标按下到上次移动的矩形位置
    	CRect rcLast = m_MouseTrack.GetRect();
    	// 鼠标按下到此次移动到的矩形位置
    	m_MouseTrack.Move(ptMove);
    	// 设置图形的矩形为当前的移动的位置
    	m_pShapeDrawing->UpdateEndPoint(ptMove);
    	// 当前图像的矩形
    	CRect rcDrawing = m_pShapeDrawing->GetRect();
    	// 取两个矩形的并集进行更新,它们的并集就是当前的脏矩形
    	BOOL bOK = TRUE;
    	if (SHAPE_ICON != m_eDrawing)
    	{
    		if(bOK = rcDrawing.UnionRect(&rcDrawing,&rcLast))
    		{
    			// 边界增大一点是为了不使图形切边
    			rcDrawing.InflateRect(1,1);
    		}
    	}
    	if (bOK)
    	{
    		// 先拷贝需要更新区域的已画好的图形到正在画的区域中
    		CopyDC(&m_dcMemDrawing,&m_dcMemDrawed,rcDrawing);
    		// 画图形
    		m_pShapeDrawing->Draw(&m_dcMemDrawing);
    		// 更新到显示dc,
    		// 只有当鼠标左键弹起,标志这个图形画好的时候才能更新到m_dcMemDrawed 上
    		CopyDCToSurface(&m_dcMemDrawing,rcDrawing);
    	}
    }



     

    同时: QIcon::Draw是错误的.因为DrawIcon绘制出的图标大小是GetSystemMetrics(SM_CXICON)GetSystemMetrics(SM_CYICON)得到的大小,可以使用DrawIconEx代替之.

    void QIcon::Draw( CDC *pDC )
    {
    	if (NULL != m_hIcon)
    	{
    		CRect rc = GetRect();
    		DrawIconEx(pDC->GetSafeHdc(),m_pt1.x,m_pt1.y,m_hIcon,rc.Width(),
    			rc.Height(),0,NULL,DI_NORMAL);
    	}
    }


     

    同时: QIcon::Draw是错误的.因为DrawIcon绘制出的图标大小是GetSystemMetrics(SM_CXICON)GetSystemMetrics(SM_CYICON)得到的大小,可以使用DrawIconEx代替之.

  • 相关阅读:
    SAP OPEN UI5 Step 8: Translatable Texts
    SAP OPEN UI5 Step7 JSON Model
    SAP OPEN UI5 Step6 Modules
    SAP OPEN UI5 Step5 Controllers
    SAP OPEN UI5 Step4 Xml View
    SAP OPEN UI5 Step3 Controls
    SAP OPEN UI5 Step2 Bootstrap
    SAP OPEN UI5 Step1 环境安装和hello world
    2021php最新composer的使用攻略
    Php使用gzdeflate和ZLIB_ENCODING_DEFLATE结果gzinflate报data error
  • 原文地址:https://www.cnblogs.com/SunkingYang/p/11049260.html
Copyright © 2011-2022 走看看