Paul M Watt系列文章要点翻译<一>:Guide to WIN32 Paint for Beginners

本文英文原版见http://www.codeproject.com/Articles/1988/Guide-to-WIN-Paint-for-Beginners

1.介绍

2.Device Context设备上下文

浅显的说,DC是用来绘制的画布。同时,DC也是操作系统的资源,用来在显示器上绘制图形的画笔、画刷和字体等等均属于DC范畴。DC是Windows系统图形设备接口的抽象层,对于开发者而言,它屏蔽了显示设备的具体实现细节。通过使用并初始化不同的DC,可以使用相同的代码和方法在屏幕、打印机、甚至内存位图上进行绘制。相比于直接操作视频卡、打印机驱动而言,这种方式对于开发者而言更加简洁高效。
DC分为三大类:
  1. Client DC 客户区DC:一个特定的窗口拥有一个客户区DC,对于开发者而言对于目标窗口具有对客户区DC的访问权限。客户区DC对于开发者而言也是使用最为频繁和重要的DC。当产生WM_PAINT消息时,客户区DC就可以获得;
  2. Window DC 窗口DC:一个特定的窗口拥有一个窗口DC,该DC允许开发者绘制窗口的任何部分,包括窗口边框及标题。当WM_NCPAINT消息产生时,窗口DC就可以获得;
  3. Memory DC 内存DC:该DC只存在于内存中,不和窗口绑定。该DC也是唯一一种能操作用户定义位图的DC。内存DC在缓存图像、后台缓冲、复杂图形绘制上极为有效;
  4. General Device DC 一般设备DC:绘图仪、打印机、监视器采用该DC。

3.Obtaining a Client Device Context获得客户区设备上下文

在使用Win32 Paint API时,经常需要获取一个DC句柄。任何一种类型的DC关于其描述均存储在一个HDC中。
对于MFC框架或WTL框架而言,DC的基类是CDC,CDC持有HDC。CPaintDC和CClientDC则继承自CDC类,它们具有各自特殊的用途。

3.1 BeginPaint获取Client DC

BeginPaint是一种普遍的创建DC的方式,但是该函数只能在WM_PAINT消息句柄中使用!这是因为BeginPaint会使窗口无效或过期的区域有效,当某一窗口存在无效区域时,WM_PAINT消息会产生通知窗口重绘此无效区域。如果在WM_PAINT句柄函数之外调用BeginPaint,任何无效的窗口去将变得有效,此时将不会有WM_PAINT消息产生!对于像subclass控件的人而言,存在一些副作用。
此外,当调用BeginPaint时,如果有必要的话Windows会产生WM_ERASEBKGND和WM_NCPAINT消息。如果在WM_PAINT之外调用BeginPaint,你地窗口边框可能不会正常更新。
调用BeginPaint的示例:
PAINTSTRUCT ps;
HDC            hdc;
hdc = ::BeginPaint(hWnd, &ps);
释放由BeginPaint获得的Client DC的函数是EndPaint。BeginPaint将调用HideCursor将鼠标指针隐藏,EndPaint在结束绘制后将鼠标指针再设成可见。如果在调用BeginPaint后不调用EndPaint将会隐藏鼠标指针。
调用EndPaint的示例:
::EndPaint(hWnd, &ps);
对于MFC和WTL框架而言,Client DC的获取和释放是在CPaintDC类的构造和析构函数中自动完成的。在栈上创建一个CPaintDC对象的实例,该DC也会自动销毁。CPaintDC的构造和析构函数代码如下。
CPaintDC::CPaintDC(CWnd* pWnd)
{
    ...

    if (!Attach(::BeginPaint(m_hWnd = pWnd->m_hWnd, &m_ps)))
        AfxThrowResourceException();
}

CPaintDC::~CPaintDC()
{
    ...

    ::EndPaint(m_hWnd, &m_ps);
    Detach();
}

3.2 GetDC/GetDCEx获取Client DC

另外一种获取客户区DC的方式是通过调用GetDC/GetDCEx。GetDCEx还允许设置一个裁剪区域,这样GetDCEx将不会绘制这些裁剪区域。
GetDC在WM_PAINT句柄函数之外使用很频繁。当需要绘制一些图形时,可以通过GetDC获取DC,这些图形往往不是目标窗口所具有的永久性的图形。比如,在Zoom in和Zoom out操作时用鼠标拉出的像橡皮筋一样的选择区域框,还比如选择一个窗口中的多个对象时的效果,这些图形或效果并不是永久存在的。
通过调用GetDC获得DC和释放DC的一个示例:
HDC hdc;
hdc = GetDC(hWnd);
...
::ReleaseDC(hWnd, hdc);
GetDC和ReleaseDC封装在MFC和WTL框架的CClientDC类中。
CClientDC::CClientDC(CWnd* pWnd)
{
    ...

    if (!Attach(::GetDC(m_hWnd = pWnd->GetSafeHwnd())))
        AfxThrowResourceException();
}

CClientDC::~CClientDC()
{
    ...
    ::ReleaseDC(m_hWnd, Detach());
}

4.使用DC

使用DC非常方便,下面是采用不同的GDI函数使用DC 的示例:
Rectangle(hdc, 100, 100, 200, 300);

Ellipse(hdc, 100, 100, 200, 300);

TCHAR szMessage[] = "Paint Beginner";
UINT  nLen = _tcslen(szMessage);
TextOut(hdc, 100, 325, szMessage, nLen); 
对于CPaintDC而言:
CPaintDC dc;
dc.Rectangle(10, 10, 150, 200);
对于ClientDC而言:
CClientDC dc;
dc.Rectangle(10, 10, 150, 200);

5.例程

该例子程序使用了两种获取DC的方式
1.BeginPaint:用户在WM_PAINT消息句柄中绘制客户区
2.GetDC:用于绘制鼠标按下左键拖动时的橡皮筋效果
在绘制橡皮筋效果时,采用了DC模式的概念,将DC模式设置为R2_NOT后,第二次相同的绘制操作将会完全清除第一次的绘制操作,从而消除第一次的绘制!

void DrawRubberBand(HWND hWnd)
{
    HDC hdc;
            //C: Get a client DC.
    hdc = ::GetDC(hWnd);
            //C: Set the current drawing mode to XOR, this will allow us
            //   to add the rubber band, and later remove it by sending the
            //   exact same drawing command.
    ::SetROP2(hdc, R2_NOT);
            //C: Select a NULL Brush into the DC so that no fill is performed.
    ::SelectObject(hdc, ::GetStockObject(NULL_BRUSH));
            //C: Get the current shape mode.
    HMENU hMenu            = ::GetMenu(hWnd);
    HMENU hShapeMenu    = ::GetSubMenu(hMenu, 1);

    if (::GetMenuState(hShapeMenu, ID_SHAPE_RECTANGLE, MF_BYCOMMAND) & MF_CHECKED)
    {
        ::Rectangle(    
                    hdc, 
                    ptStart.x, 
                    ptStart.y, 
                    ptCurrent.x,
                    ptCurrent.y
                    );
    }
    else
    {
        ::Ellipse(    
                    hdc, 
                    ptStart.x, 
                    ptStart.y, 
                    ptCurrent.x,
                    ptCurrent.y
                    );
    }
            //C: Release the DC.
    ::ReleaseDC(hWnd, hdc);
}
具体可研究一下代码。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 适合毕业设计、课程设计作业。这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。 所有源码均经过严格测试,可以直接运行,可以放心下载使用。有任何使用问题欢迎随时与博主沟通,第一时间进行解答!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值