CDC,CClientDC

本文详细介绍了MFC框架下的绘图实现方法,重点讲解了不同设备上下文(DC)如CClientDC、CPaintDC和CWindowDC的使用场景与区别,并演示了如何通过这些DC进行基本绘图操作,如绘制直线、扇形等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

void CThView::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值

pp = point;

 

CView::OnLButtonDown(nFlags, point);
}

void CThView::OnUpdate32771(CCmdUI *pCmdUI)
{
// TODO: 在此添加命令更新用户界面处理程序代码
//::MessageBoxA(NULL, "ff", "ggg", MB_OK);
}


void CThView::OnLButtonUp(UINT nFlags, CPoint point)
{
//point.x = 144;
     //point.y = 6;

/* 完全API划线
HDC hDc= ::GetDC(::GetParent(this->m_hWnd));
    ::MoveToEx(hDc, pp.x, pp.y, NULL);
::LineTo(hDc, point.x, point.y);
::ReleaseDC(hDc);

   */

/*使用CDC这个类
CDC *dc = GetDC();
dc->MoveTo(pp);
dc->LineTo(point);
ReleaseDC(dc);

*/
//使用CclientDC不需要手动释放DC,
CClientDC    clientD(::GetParent(this->m_hWnd));//这个DC和处于这个窗口的父窗口发生联系;
    clientD.MoveTo(pp);
    clientD.LineTo(point);                          //由此可见,父窗口的客户区包括子窗口的客户区;

 

/*
HWND wnd = ::GetDesktopWindow();//得到顶层窗口 的句柄

//HDC dc = ::GetDC(NULL);//得到整个屏幕的DC,每次运行这个 DC的值都会变化,

HDC dc = ::GetDC(wnd);//得到最顶层窗口的DC,但不是桌面的
BOOL aa = ::MoveToEx(dc, pp.x, pp.y, NULL);
BOOL bb = ::LineTo(dc, point.x, point.y);


::ReleaseDC(wnd, dc);
*/

 

/////////////
/////////经过两次的::getwindow(),返回值是 NULL,所以一下三条语句 =====::getDc(NULL);

HWND wnd = ::GetDesktopWindow();
wnd =::GetWindow(wnd,GW_CHILD);  
wnd =::GetWindow(wnd ,GW_CHILD);//最终得到可以绘图的窗口窗口 的句柄
HDC dc = ::GetDC(wnd);             //得到可以绘图的桌面的DC

BOOL aa = ::MoveToEx(dc, pp.x, pp.y, NULL);
BOOL bb = ::LineTo(dc, point.x, point.y);

 

CView::OnLButtonUp(nFlags, point);
}

 

 

 

类CClientDC派生于CDC,在构造时调用了Windows函数GetDC,在析构时调用了ReleaseDC。这意味着和 CClientDC对象相关的设备上下文是窗口的客户区。要了解有关CClientDC的更详细的信息,请参阅联机文档“Visual C++程序员指南斨械摹吧璞干舷挛臄部分。

#include <afxwin.h>
请参阅   CDC

CClientDC类的成员
构造函数
CClientDC构造一个连接到CWnd上的CClientDC对象

数据成员
m_hWnd CClientDC所在的有效窗口的HWND

成员函数
CClientDC::CClientDC
CClientDC(CWnd* pWnd );
throw( CResourceException );
参数
pWnd设备上下文将要存取的客户区所在的窗口。
说明
本函数构造一个CClientDC对象,它将存取pWnd指向的CWnd的客户区。此构造函数调用了Windows函数GetDC。如果Windows函 数GetDC调用失败,则产生一个CResourceException类型的异常。如果Windows已经分配出了所有可用的设备上下文,则没有新的设 备上下文可用。无论何时,应用总在竞争使用Windows提供的五个公共显示上下文。

数据成员
CClientDC::m_hWnd
说明
m_hWnd是一个保护的变量,是用来构造m_hWnd对象的CWnd指针的HWND。

 

==============================================================


几种DC及区别

CClientDC:(客户区设备上下文)用于客户区的输出,与特定窗口关联,可以让开发者访问目标窗口中客户区,其构造函数中包含了GetDC,析构函 数中包含了ReleaseDC:

CClientDC::CClientDC(CWnd* pWnd)
{
     ...
     if (!Attach(::GetDC(m_hWnd = pWnd->GetSafeHwnd())))
         AfxThrowResourceException();
}

CClientDC::~CClientDC()
{
     ...
     ::ReleaseDC(m_hWnd, Detach());
}
用法是:
CClientDC dc(this);//this一般指向本窗口或当前活动视图
dc.TextOut(10,10,str,str.GetLength());//利用dc输出文本,如果是在CScrollView中使用,还要注意 调用OnPrepareDC(&dc)调整设备上下文的坐标。
CPaintDC用于响应窗口重绘消息(WM_PAINT)是的绘图输出。CPaintDC在构造函数中调用BeginPaint()取得设备上下文,在 析构函数中调用EndPaint()释放设备上下文。EndPaint()除了释放设备上下文外,还负责从消息队列中清除WM_PAINT消息。因此,在 处理窗口重画时,必须使用CPaintDC,否则WM_PAINT消息无法从消息队列中清除,将引起不断的窗口重画。CPaintDC也只能用在 WM_PAINT消息处理之中。
CPaintDC::CPaintDC(CWnd* pWnd)
{
     ...
     if (!Attach(::BeginPaint(m_hWnd = pWnd->m_hWnd, &m_ps)))
         AfxThrowResourceException();
}

CPaintDC::~CPaintDC()
{
     ...
     ::EndPaint(m_hWnd, &m_ps);
     Detach();
}
CWindowDC:关联一特定窗口,允许开发者在目标窗口的任何一部分进行绘图,包含边界与标题,这种DC同WM_NCPAINT消息一起发送

CWindowDC与CClientDC,CPaintDC的区别:
CWindowDC可在非客户区绘制图形,而CClientDC,CPaintDC只能在客户区绘制图形。
CWindowDC下坐标原点是在屏幕的左上角,CClientDC,CPaintDC下坐标原点是在客户区的左上角。
CClientDC与CPaintDC的区别:

CPaintDC的对象一般用在OnPaint内以响应Windows消息WM_PAINT,自动完成绘制,在整个窗口内进行重画,
维持原有窗口完整性。
CClientDC应用在非响应Windows消息WM_PAINT的情况下,进行实时绘制,绘制的区域内被重画。

 

====================================================================


VC中MFC下的绘图初步解析

 

作者:zieckey(zieckey@yahoo.com.cn )
All Rights Reserved!

首先我们说下通过鼠标的移动来绘制直线。
这里要捕获到鼠标的两个消息:WM_LBUTTONDOWN, WM_LBUTTONUP
响应WM_LBUTTONDOWN消息记录直线的起始点,响应WM_LBUTTONUP消息记录直线的终点并绘制直线。
好了,我们看看怎么响应。
void CDrawView::OnLButtonDown(UINT nFlags, CPoint point)
{
//MessageBox("Left Button Clicks DrawView");
m_ptOrigin = point ;         //这里先定义了一个内部变量保存直线的起始点
CView::OnLButtonDown(nFlags, point);
}


下面看看响应WM_LBUTTONUP消息记录直线的终点并绘制直线。

//方法一
void CDrawView::OnLButtonUp(UINT nFlags, CPoint point)
{
HDC hdc;
hdc = ::GetDC(m_hWnd); //调用全局函数
MoveToEx(hdc,m_ptOrigin.x,m_ptOrigin.y,0);
LineTo(hdc,point.x,point.y);
::ReleaseDC(m_hWnd,hdc);
CView::OnLButtonUp(nFlags, point);
}
//方法二
void CDrawView::OnLButtonUp(UINT nFlags, CPoint point)
{
CDC *pDC = GetDC();
pDC->MoveTo(m_ptOrigin);
pDC->LineTo(point);
ReleaseDC(pDC);
}
//方法三
void CDrawView::OnLButtonUp(UINT nFlags, CPoint point)
{
CClientDC dc(this) ;    //CClientDC对象构造的时候就调用了GetDC,析构的时候调用

ReleaseDC ,只能访问客户区
CClientDC dc(GetParent());
dc.MoveTo(m_ptOrigin);
dc.LineTo(point);
}
//方法四
void CDrawView::OnLButtonUp(UINT nFlags, CPoint point)
{
CWindowDC dc(this) ;   //CWindowDC可以访问客户区和非客户区
dc.MoveTo(m_ptOrigin);
dc.LineTo(point);
}
void CDrawView::OnLButtonUp(UINT nFlags, CPoint point)
{
CWindowDC dc(GetDesktopWindow()) ;   //现在可以访问桌面
dc.MoveTo(m_ptOrigin);
dc.LineTo(point);
}


连续线绘图:
思路:鼠标移动的信号被捕捉到,然后随时响应该信号,绘制图线
这里要设置一个BOOL变量 m_bDraw 来判断是否鼠标左键按下了。

//画连续的线条
void CDrawView::OnMouseMove(UINT nFlags, CPoint point)
{
if ( m_bDraw )
{
   CClientDC dc(this) ;
   dc.MoveTo(m_ptOrigin);   //移动到原来的点
   dc.LineTo(point); //绘制直线
   m_ptOrigin = point ; //将现在的点赋值给原来的坐标,以便下次调用
}
CView::OnMouseMove(nFlags, point);
}

//改变画笔的颜色
void CDrawView::OnMouseMove(UINT nFlags, CPoint point)
{
if ( m_bDraw )
{
   CClientDC dc(this) ;
   CPen pen( PS_SOLID , 1 , RGB(255,128,128) );
   CPen *pOldPen = dc.SelectObject(&pen);
   dc.MoveTo(m_ptOrigin);
   dc.LineTo(point);
   m_ptOrigin = point ;
   dc.SelectObject(pOldPen);
}
CView::OnMouseMove(nFlags, point);
}

//画扇型
void CDrawView::OnMouseMove(UINT nFlags, CPoint point)
{
if ( m_bDraw )
{
   CClientDC dc(this) ;
   CPen pen( PS_SOLID , 1 , RGB(255,128,128) );
   CPen *pOldPen = dc.SelectObject(&pen);
   dc.MoveTo(m_ptOrigin);
   dc.LineTo(m_ptOld);
   dc.MoveTo(m_ptOrigin);
   dc.LineTo(point);
   m_ptOld = point ;
   dc.SelectObject(pOldPen);
}
CView::OnMouseMove(nFlags, point);
}
//画带边线的扇型
void CDrawView::OnMouseMove(UINT nFlags, CPoint point)
{

if ( m_bDraw )
{
   CClientDC dc(this) ;
   CPen pen( PS_SOLID , 1 , RGB(255,128,128) );
   CPen *pOldPen = dc.SelectObject(&pen);
   dc.MoveTo(m_ptOrigin);
   dc.LineTo(m_ptOld);
   dc.MoveTo(m_ptOrigin);
   dc.LineTo(point);
   dc.MoveTo(m_ptOld);
   dc.LineTo(point);
   m_ptOld = point ;
   dc.SelectObject(pOldPen);
}
CView::OnMouseMove(nFlags, point);
}

//看看绘图的模式设置方法
void CDrawView::OnMouseMove(UINT nFlags, CPoint point)
{
if ( m_bDraw )
{
   CClientDC dc(this) ;
   dc.SetROP2(R2_BLACK);   //绘图的模式设置,始终绘制黑色图形
   CPen pen( PS_SOLID , 1 , RGB(255,128,128) );
   CPen *pOldPen = dc.SelectObject(&pen);
   dc.MoveTo(m_ptOrigin);
   dc.LineTo(m_ptOld);
   dc.MoveTo(m_ptOrigin);
   dc.LineTo(point);
   dc.MoveTo(m_ptOld);
   dc.LineTo(point);
   m_ptOld = point ;
   dc.SelectObject(pOldPen);
}

CView::OnMouseMove(nFlags, point);
}

到此,我们知道了一般地绘图方法了。

 

==============================================


图像文件相关操作

1,显示一张位图:

int CThreadPoolDlg::ShowFace(int xPos, int yPos, CString FilePath)
{
// TODO: Add your control notification handler code here
CClientDC *pDC = new CClientDC(this);
CBitmap Bitmap;
HBITMAP hBitmap = (HBITMAP)LoadImage(NULL,FilePath,IMAGE_BITMAP,0,0,LR_LOADFROMFILE);
Bitmap.Attach(hBitmap);
CDC DCCompatible;
DCCompatible.CreateCompatibleDC(pDC);
DCCompatible.SelectObject(&Bitmap);
BITMAP bmInfo;
Bitmap.GetObject(sizeof(bmInfo),&bmInfo);
pDC->BitBlt(xPos,yPos,bmInfo.bmWidth,bmInfo.bmHeight,&DCCompatible,0,0,SRCCOPY);
return 1;

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值