Windows DC 画线

好久没搞MFC,复习下知识。

CPaintDC 、CWindowDC、 CClientDC、 CDC

关系图:

一句话概括:

CPaintDC            无效区dc,      相当于BeginPaint,   EndPaint
CClientDC          客户区dc,      相当于GetDC,   ReleaseDC
CWindowDC      整窗口dc,      相当于GetWindowDC,   ReleaseDC
CDC                     任何dc,          相当于CreateDC,   DeleteDC

 一、CPaintDC

 Mfc自动生成的OnPaint函数都会定义一个CPaintDC类型的变量。

如: 

void CXXXXXX::OnPaint()
{
    CPaintDC dc(this); // device context for painting
    // TODO: Add your message handler code here
    // Do not call CView::OnPaint() for painting messages
}
// If you add a minimize button to your dialog, you will need the code below
//  to draw the icon.  For MFC applications using the document/view model,
//  this is automatically done for you by the framework.
void CXXXXDlg::OnPaint()
{
    if (IsIconic())
    {
        CPaintDC dc(this); // device context for painting
 
        SendMessage(WM_ICONERASEBKGND, reinterpret_cast<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
    {
        CDialog::OnPaint();
    }
}

MSDN上的解释:

The CPaintDC class is a device-context class derived from CDC. It performs a CWnd::BeginPaint at construction time and CWnd::EndPaint at destruction time.

(翻译:CPaintDC继承自CDC,它在构造函数中执行CWnd::BeginPaint,在析构函数中调用CWnd::EndPaint

 A CPaintDC object can only be used when responding to aWM_PAINT message, usually in yourOnPaint message-handler member function.

(翻译:CPaintDC对象通常当响应WM_PAINT消息时在OnPaint消息处理函数中被使用。)

题外话,这个英文按照中国人的逻辑来说应该这样表达:

when responding to a WM_PAINT message, a CPaintDC object can only be used usually in yourOnPaint message-handler member function.

 二、CClientDC

MSDN上的解释:

The CClientDC class is derived from CDC and takes care of calling the Windows functionsGetDC at construction time andReleaseDC at destruction time. This means that the device context associated with aCClientDC object is the client area of a window.

(翻译:CClientDC继承自CDC,它在构造函数中调用GetDC,在析构函数中调用ReleaseDC.这意味着与CClientDC对象联系的DC是窗口的客户区。)

 三、CWindowDC

The CWindowDC class is derived from CDC. It calls the Windows functionsGetWindowDC at construction time andReleaseDC at destruction time. This means that aCWindowDC object accesses the entire screen area of aCWnd (both client and nonclient areas).( 翻译:获取整个屏幕区域,包括客户区和非客户区。)

CSDN:

CPaintDC只能在OnPaint()中使用,CClientDC只和客户区有关,可以在任何地方使用。

 CPaintDC代表整个窗口,而CClientDC代表窗口的客户区(不包括标题栏、边框),要选择合适的DC进行绘制。

 CPaintDC一般是用在OnPaint()函数里的。CPaintDC对象一构造,消息队列中的WM_PAINT会被取走,而CClientDC是用在非OnPaint()函数里画图的。

用CClientDC时WM_PAINT消息没有从消息队列中清除,CPaintDC结束时会自动清除该消息。

 CPaintDC是一个特殊的设备环境封闭类,它主要处理windows的wm_paint消息。CClientDC可以自动调用GetDC和ReleaseDC函数。CwindowDC是从CDC类继承,用于得到桌面窗口设备环境指针。

CclinetDC用于窗口客户区,CwindowDC用于整个窗口,包括非客户区。

在OnPaint中用CPaintDC仅仅对需要刷新的地方进行重绘。

> 往一个对话框上画图,在OnPaint()里是不是只能用   CPaintDC?
恰恰相反,CPaintDC是推荐只用在OnPaint中的。诚如   i_noname(晚九朝五)   所言:“它的范围是WM_PAINT消息所要重画的区域大小”,因为这个类的构造函数中调用了BeginPaint,析构函数中调用了EndPaint。这两个API是针对WM_PAINT消息使用的,所以不要把CPaintDC用在非对WM_PAINT消息响应的函数中。

https://blog.csdn.net/arcsinsin/article/details/9861003

鼠标响应关键就是对两个函数进行操作:OnLButtonDown和OnLButtonUp;

1、使用MFC AppWizard(exe)建立一个单文档MFC工程

2、首先要在CxxxView类的定义里加上后续必备的数据成员

class CDrawView : public CView
{
。。。。。。。。。。。。
private:
 CPoint m_ptOrigin;      //用来记录鼠标按下时的点          
 BOOL m_bDraw;           //鼠标按下的标志,用来判断鼠标弹起来了没有
 CPoint m_ptOld;         //用来记录鼠标的移动路劲
};

 

void CDrawView::OnLButtonDown(UINT nFlags, CPoint point) //鼠标按下
{
  MessageBox("Haibara Ai");            //鼠标一按下就会送出消息(以对话框形式)
  m_ptOrigin=m_ptOld=point;            //将当前鼠标按下的位置用m_ptOrigin记录
  m_bDraw=TRUE;                        //将鼠标按下标志置为TURE
  CView::OnLButtonDown(nFlags, point); //函数自调用,循环检测。nFlags 表示控制键状态

                                        //(包括 ctrl,shift,鼠标左、中、右共5个键的状态)
                                        //point表示鼠标坐标。(相对于当前窗口而言的坐标)

}

void CDrawView::OnLButtonUp(UINT nFlags, CPoint point) //鼠标弹起
{

//鼠标画直线方式一
 HDC hdc;                         //先定义一个HDC对象:Handler to a device context(DC),指向一个DC(设备描述表)的句柄
 hdc=::GetDC(m_hWnd);//“::”用全局的函数(即SDK中的函数)

 


 MoveToEx(hdc,m_ptOrigin.x,m_ptOrigin.y,NULL);   //由原点(0,0)移动到起点(即鼠标按下点)
 LineTo(hdc,point.x,point.y);                                         //由当前位置移动到坐标点(x,y)(即鼠标弹起点);
 ::ReleaseDC(m_hWnd,hdc);                                       //释放DC

 

//鼠标画直线方式二  

CWnd::GetDC

CDC* GetDC( );

Return Value

Identifies the device context for the CWnd client area if successful; otherwise, the return value is NULL. The pointer may be temporary and should not be stored for later use.

CDC *pDC=GetDC();                      //获取一个CDC类对象的指针
 pDC->MoveTo(m_ptOrigin);
 pDC->LineTo(point);
 ReleaseDC(pDC);

 

//鼠标画直线方式三
// CClientDC dc(this);                                  //在客户区画直线
 CClientDC dc(GetParent());                      //在框架窗口上画直线
 dc.MoveTo(m_ptOrigin);
 dc.LineTo(point);

 

//鼠标画直线方式四

// CWindowDC dc(this);                                 //在客户区画直线
// CWindowDC dc(GetParent());                   //在框架窗口上画直线
   CWindowDC dc(GetDesktopWindow());  //在整个桌面面板上画直线
   dc.MoveTo(m_ptOrigin);
   dc.LineTo(point);

 

//鼠标画直线方式五(画笔)

 CPen pen(PS_SOLID,20,RGB(255,0,0));        //创建一个笔(CPen类封装了跟画笔相关的操作)

                                                                                   //(线型,线粗,线色)
 CClientDC dc(this);                                                //创建一个DC
 CPen *pOldPen=dc.SelectObject(&pen);           //将笔选到设备描述表中
 dc.MoveTo(m_ptOrigin);
 dc.LineTo(point);
 dc.SelectObject(pOldPen);

 

//鼠标响应画矩形(画刷)
 CBrush brush(RGB(255,0,0));                //创建画刷,红色
 CClientDC dc(this);                          //创建一个dc
 dc.FillRect(CRect(m_ptOrigin,point),&brush); //用一个指定画刷填充一个指定的区域,
                    //第一个参数用于设定这个区域,用画线时保存下来的起点和终点来设定这个区域

 //运行结果是:我们的dc在用我们所创建的红色的画刷去填充了一块矩形的区域

 

//用位图对象填充鼠标画出的矩形框图
CBitmap  bitmap;              //首先定义一个位图
 bitmap.LoadBitmap(IDB_BITMAP1); //用资源的ID加载这个位图
 CBrush  brush(&bitmap);   //有了这个位图之后,就可以创建这个位图的画刷,形参为这个位图对象的指针
 CClientDC dc(this);                              //然后创建一个dc                            
 dc.FillRect(CRect(m_ptOrigin,point),&brush);     //用这个指定的画刷(位图画刷)去填充一块矩形区

 

 



///创建透明画刷,即空画刷    /

 CClientDC dc(this);   
 CBrush *pBrush=CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH));
 //注意这里,GetStockObject函数返回的是一个HGDIOBJ
 //的一个句柄,需要用强制转换将其转换为画刷的句柄
 //(HBRUSH)GetStockObject(NULL_BRUSH)
 //FromHandle是CBrush类的静态成员函数(见MSDN),所以可以直接由类名调用
 CBrush *pOldBrush=dc.SelectObject(pBrush);     //将画刷选到我们的设备描述表中,

                                                                                    //用空画刷去替换我们先前的画刷(缺省画刷、默认画刷)
 dc.Rectangle(CRect(m_ptOrigin,point));         //DC当中用来画矩形矩形的一个函数
 dc.SelectObject(pOldBrush);                   //回到画刷替换前的默认画刷
  m_bDraw=FALSE;                  //鼠标弹起标志,将m_bDraw置为FALSE

  CView::OnLButtonUp(nFlags, point);
}

 

 

//鼠标移动响应函数,应用在画曲线方面

void CDrawView::OnMouseMove(UINT nFlags, CPoint point)  //point为函数获取的当前鼠标所在位置的坐标

                                                        //它会鼠标的移动而不断改变值
{
    CClientDC dc(this);                   //创建一个DC,指向当前窗口(客户区)
    dc.SetROP2(R2_BLACK);                 //设置绘画模式
    CPen pen(PS_SOLID,1,RGB(255,0,0));    //设置画笔(线型、线宽、线颜色)
    CPen  *pOldPen=dc.SelectObject(&pen); //将画笔选到设备描述表中
 if(m_bDraw==TRUE)
 {

  ///
  ///画曲线
  dc.MoveTo(m_ptOrigin); //移动到起始点 
  dc.LineTo(point);       //画线到,注意这里的每一次画线都是很短的。很短的多次画线就得到了曲线
  m_ptOrigin=point;       //将终点设为下一次画线的起点。。。。这样不断循环,直到鼠标弹起,跳出循环结束画线。
  //

  //
  ///画扇形线
  dc.MoveTo(m_ptOrigin); //定下起点不变 
  dc.LineTo(point);    
  //

  //
  //画带边线的扇形线
  dc.MoveTo(m_ptOrigin);    //定下起点不变 
  dc.LineTo(point);          //开始画线
  dc.LineTo(m_ptOld);        //在线的终点处引线到另一条线的终点
  m_ptOld=point;             //将上一条线的终点寄存下,以待下一条线划下时,将终点与之相连。  
  //

 }

   dc.SelectObject(pOldPen);   //回到画刷替换前的默认画笔

  CView::OnMouseMove(nFlags, point);//函数自调用,循环检测。nFlags 表示控制键状态

                                   //(包括 ctrl,shift,鼠标左、中、右共5个键的状态)
                                   //point表示鼠标坐标。(相对于当前窗口而言的坐标)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值