绘图(VC_Win32)

目录

GUI作图概述
描绘图形
位图
文本输出
设置画刷/画笔/字体
MFC 资源句柄的获得与释放

(本章节中例子都是用 VS2005 编译调试的)


GUI作图概述

作图步骤

  • 获得设备描述表资源句柄
  • 绘图操作
  • 释放设备描述表资源句柄

流程图如下:

获取/释放设备资源描述表

  • 获取设备资源描述表:   BeginPaint / GetDC
  • 释放设备资源描述表:  EndPaint / ReleaseDC

BeginPaint / GetDC 两种方式的区别:

             BeginPaint             GetDC            
使用环境         只用于图形刷新时获取设备环境   使用较为广泛
操作区域         无效区              特定窗口的客户区或者整个窗口
释放设备环境所用函数   EndPaint ()            ReleaseDC ()

代码示例:

在 WM_PAINT 添加 BeginPaint 事件,在 WM_LBUTTONDOWN 添加 GetDC 事件.

BeginPaint 使用:

//获得资源DC
hdc=BeginPaint(hwnd,&ps);
//获得窗口大小
GetClientRect(hwnd,&rect);
//绘制文本
DrawText(hdc,"hellow my first windows program",strlen("hellow my first windows program"),&rect,
    DT_SINGLELINE | DT_CENTER | DT_VCENTER);
//释放资源DC
EndPaint(hwnd,&ps);

 GetDC 使用: 

//获得设备资源描述表
hdc = GetDC(hwnd);
//绘制带圆角矩形
RoundRect(hdc,10,10,110,60,10,10);
//释放设备资源描述表
ReleaseDC(hwnd,hdc);

程序源码

运行结果:

单击鼠标右键和重绘窗口时

在单击鼠标右键后

绘图操作分类

  • 描绘图形
  • 位图
  • 文本输出

与设备描述表相关函数


描绘图形

常用绘图函数:

  • 画贝塞尔曲线:
  • 画点:  SetPixel
  • 画矩形:  Rectangle
  • 画带圆角的矩形:  RoundRect
      函数原型:  BOOL RoundRect( HDC hdc, int nLeftRect, int nTopRect,int nRightRect,int nBottomRect,int nWidth,int nHeight);
      参数说明:
            
  • 画椭圆:  Ellipse
  • 画椭圆的一部分(即画一个弦):  Chord
  • 画一个扇形区并用当前画刷填充:  Pie
  • 画椭圆弧线:   Arc
      函数原型:  BOOL Arc(HDC hdc,int nLeftRect, int nTopRect,int nRightRect,int nBottomRect,int nXStartArc,int nYStartArc,int nXEndArc,int nYEndArc);
      参数说明:

            
  • 画椭圆弧线:   ArcTo
  • 画正圆弧线:  AngleArc
      函数原型:   BOOL AngleArc(HDC hdc,int X,int Y,DWORD dwRadius,FLOAT eStartAngle,FLOAT eSweepAngle);
      参数说明:

          
  • 画一系列相连的直线:
  • 画线条:
    • 设置画笔起始位置:  MoveToEx
    • 设置画笔终止位置:  LineTo

位图

步骤:

  • 建立位图资源
  • 载入/创建位图资源
  • 获取设备内存
  • 选入内存设备
  • 贴图

流程图如下所示:

代码示例:

.rc 内容(位图资源):

IDB_BITMAP1             BITMAP                  "8c8a09f1gw1ds3qh4vtcyj.bmp"

位图(8c8a09f1gw1ds3qh4vtcyj.bmp 尺寸信息:440*622):

在鼠标左键单击事件中添加贴图操作:

加载位图:

hBmp = LoadBitmap(hinstance,MAKEINTRESOURCE(IDB_BITMAP1));

创建兼容 DC 并将位图选入兼容 DC 中:

hcmdc = CreateCompatibleDC(hdc);
SelectObject(hcmdc,hBmp);

 获得窗口大小(被显示的区域),获得位图信息(要显示的区域)

//获取窗口大小
GetClientRect(hwnd,&rect);
//获取位图信息(在 StretchBlt 时候有用到,而 BitBlt 没有)
GetObject(hBmp, sizeof(BITMAP), &bmp);

 显示位图:

//显示方式一,  按原图比例显示
BitBlt(hdc,0,0,rect.right-rect.left,rect.bottom-rect.top,hcmdc,0,0,SRCCOPY);

//显示方式二,  拉伸式显示
StretchBlt(hdc,0,0,rect.right-rect.left,rect.bottom-rect.top,hcmdc,0,0,bmp.bmWidth,bmp.bmHeight,SRCCOPY);

程序源码

运行结果:

  • 在未点击鼠标右键时候:

  • 点击鼠标左键(用 BitBlt 方法):

  • 点击鼠标左键(用 StretchBlt 方法):


文本输出

文本输出操作

  • 文字输出:  TextOut
  • 显示字符串:  DrawText

有关文本操作:

  • 获取文字信息:  GetTextMetrics
  • 格式化文字:  GetTextExtentPoint32
  • 设置字体颜色和背景颜色:
    • 字体:  SetTextColor
    • 背景:  SetBkColor

设置画刷/画笔/字体

相关结构体:

字体结构体

TEXTMETRIC

作用:  记录基本的字体信息

结构体定义(MSDN 链接):

View Code
typedef struct tagTEXTMETRIC {
  LONG  tmHeight; // Specifies the height (ascent descent) of characters.
  LONG  tmAscent; // Specifies the ascent (units above the base line) of characters.
  LONG  tmDescent; // Specifies the descent (units below the base line) of characters.
  LONG  tmInternalLeading; // Specifies the amount of leading (space) inside the bounds set by the tmHeight member. 
  LONG  tmExternalLeading; // Specifies the amount of extra leading (space) that the application adds between rows. 
  LONG  tmAveCharWidth; // Specifies the average width of characters in the font.
  LONG  tmMaxCharWidth; // Specifies the width of the widest character in the font.
  LONG  tmWeight; // Specifies the weight of the font.
  LONG  tmOverhang; // Specifies the extra width per string that may be added to some synthesized fonts
  LONG  tmDigitizedAspectX; // Specifies the horizontal aspect of the device for which the font was designed.
  LONG  tmDigitizedAspectY; // Specifies the vertical aspect of the device for which the font was designed. 
  TCHAR tmFirstChar; // Specifies the value of the first character defined in the font.
  TCHAR tmLastChar; // Specifies the value of the last character defined in the font.
  TCHAR tmDefaultChar; // Specifies the value of the character to be substituted for characters not in the font.
  TCHAR tmBreakChar; // Specifies the value of the character that will be used to define word breaks for text justification.
  BYTE  tmItalic; // Specifies an italic font if it is nonzero.
  BYTE  tmUnderlined; // Specifies an underlined font if it is nonzero.
  BYTE  tmStruckOut; // Specifies a strikeout font if it is nonzero.
  BYTE  tmPitchAndFamily; // Specifies information about the pitch, the technology, and the family of a physical font.
  BYTE  tmCharSet; // Specifies the character set of the font. 
} TEXTMETRIC, *PTEXTMETRIC;

 图示:

步骤:

  • 创建资源句柄
  • 创建自定义资源/调用系统资源
  • 将资源选入系统

如下图所示:

代码示例:

在窗口重画的时候添加创建新画笔操作:

创建新画笔,并将画笔选入设备描述表中

pen = CreatePen(PS_DOT,3,RGB(255,100,100));
SelectObject(hdc,pen);

为了区别创建画笔前和创建画笔后的作图的区别

在创建画笔前绘制一条直线:

//rect 为记录窗口大小的 RECT 结构体
MoveToEx(hdc,(rect.left+rect.right)/2-130,(rect.top+rect.bottom)/2-50,NULL);
LineTo(hdc,(rect.left+rect.right)/2+130,(rect.top+rect.bottom)/2-50);

在创建画笔后绘制一条直线:

MoveToEx(hdc,(rect.left+rect.right)/2-130,(rect.top+rect.bottom)/2+50,NULL);
LineTo(hdc,(rect.left+rect.right)/2+130,(rect.top+rect.bottom)/2+50);

程序源码

运行结果:


程序源码

View Code
#include<windows.h>
#include"resource.h"

HINSTANCE hinstance;

LRESULT CALLBACK textprom(
  HWND hwnd,      // handle to window
  UINT uMsg,      // message identifier
  WPARAM wParam,  // first message parameter
  LPARAM lParam   // second message parameter
);

int WINAPI WinMain(  HINSTANCE hInstance,  // handle to current instance
  HINSTANCE hPrevInstance,  // handle to previous instance
  LPSTR lpCmdLine,      // pointer to command line
  int nCmdShow          // show state of window
)
{
    WNDCLASS wndclass;
    HWND hwnd;
    MSG msg;

    //设计窗口类
    wndclass.cbClsExtra=0;
    wndclass.cbWndExtra=0;
    wndclass.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH);
    wndclass.hCursor=LoadCursor(NULL,IDC_ARROW);
    wndclass.hIcon=LoadIcon(NULL,IDI_ERROR);
    wndclass.hInstance=hInstance;
    wndclass.lpfnWndProc=textprom;
    wndclass.lpszClassName="text";
    wndclass.lpszMenuName=NULL;
    wndclass.style=CS_HREDRAW | CS_VREDRAW;
    
    //注册窗口类
    if(!RegisterClass(&wndclass))
    {
        MessageBox(NULL,"create windows error!","error",MB_OK | MB_ICONSTOP);
    }

    //创建无菜单资源的窗口窗口
    hwnd=CreateWindow("text","hellow world",WS_DLGFRAME | WS_MINIMIZEBOX | WS_SYSMENU,0,0,500,300,NULL,NULL,hInstance,NULL);


    //显示更新窗口
    ShowWindow(hwnd,nCmdShow);
    UpdateWindow(hwnd);

    hinstance = hInstance;

    //消息循环
    while(GetMessage(&msg,NULL,0,0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return msg.wParam;
}

LRESULT CALLBACK textprom(
  HWND hwnd,      // handle to window
  UINT uMsg,      // message identifier
  WPARAM wParam,  // first message parameter
  LPARAM lParam   // second message parameter
)
{
    HDC hdc,hcmdc;
    PAINTSTRUCT ps;
    RECT rect;
    HBITMAP hBmp;
    SIZE   size;
    BITMAP bmp;
    HPEN pen;

    switch(uMsg)
    {
    //重绘事件
    case WM_PAINT:
        hdc=BeginPaint(hwnd,&ps);
        //显示文本
        GetClientRect(hwnd,&rect);
        DrawText(hdc,"hellow my first windows program",strlen("hellow my first windows program"),&rect,
            DT_SINGLELINE | DT_CENTER | DT_VCENTER);
        //画笔
        MoveToEx(hdc,(rect.left+rect.right)/2-130,(rect.top+rect.bottom)/2-50,NULL);
        LineTo(hdc,(rect.left+rect.right)/2+130,(rect.top+rect.bottom)/2-50);
        pen = CreatePen(PS_DOT,3,RGB(255,100,100));
        SelectObject(hdc,pen);
        MoveToEx(hdc,(rect.left+rect.right)/2-130,(rect.top+rect.bottom)/2+50,NULL);
        LineTo(hdc,(rect.left+rect.right)/2+130,(rect.top+rect.bottom)/2+50);
        EndPaint(hwnd,&ps);
        break;
    //绘制圆角矩形
    case WM_LBUTTONDOWN:
        hdc = GetDC(hwnd);
        RoundRect(hdc,10,10,110,60,10,10);
        ReleaseDC(hwnd,hdc);
        break;
    //贴图
    case WM_RBUTTONDOWN:
        hdc = GetDC(hwnd);
        hBmp = LoadBitmap(hinstance,MAKEINTRESOURCE(IDB_BITMAP1));
        hcmdc = CreateCompatibleDC(hdc);
        SelectObject(hcmdc,hBmp);    
        GetClientRect(hwnd,&rect);
        GetObject(hBmp, sizeof(BITMAP), &bmp);
        StretchBlt(hdc,0,0,rect.right-rect.left,rect.bottom-rect.top,hcmdc,0,0,bmp.bmWidth,bmp.bmHeight,SRCCOPY);
        //BitBlt(hdc,0,0,rect.right-rect.left,rect.bottom-rect.top,hcmdc,0,0,SRCCOPY);
        ReleaseDC(hwnd,hdc);
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    }
    return DefWindowProc(hwnd,uMsg,wParam,lParam);
}

MFC 资源句柄的获得与释放

绘图是选用GDI资源的说明

在程序中,当构造函数构造一个GDI对象后,该对象并不会立刻生效,必须选入设备描述表,它才会在以后的操作中生效,利用SelectObject函数可以实现把GDI对象选入设备描述表中,并且返回指向先前GDI设备对象的指针,一般情况下,在完成绘图操作后,都要利用SelectObject函数吧先前的GDI对象选入设备表,以便使恢复到先前状态

GDI绘图对象(CPen,CFont.CBitmap,CBrush)都派生于CGdiObject类对象,都有一个m_hObject记录与对应资源联系的关系,当其对象与对应的资源调用CreateXXXX建立联系后若想把对象关联上新的资源时候,必须先对旧的资源释放才能和新的资源建立上联系,可以用CGdiObject对象的DeleteObject函数去切断与旧资源的联系,并释放旧的资源

相关函数

获得资源设备表

函数原型

CDC* GetDC();

返回值:  如果调用成功,则返回CWnd客户区的设备环境;否则,返回NULL。这个指针可能是临时的,不能被保存以供将来使用

说明:   这个函数获得一个指针,指向一个客户区的公用的、属于类的或者私有的设备环境,依赖于为CWnd指定的类风格。对于公用的设备环境,GetDC每次获得设备环境时都给它赋予缺省值。对于属于类的或者私有的设备环境,GetDC保持原来的属性不变。在随后的图形设备接口(GDI)函数中可以使用设备环境以在客户区中绘图

释放资源设备表

函数原型

int ReleaseDC( CDC* pDC );

参数说明:   pDC 标识了要释放的设备环境
返回值:    如果成功,则返回非零值;否则返回0
说明:     释放设备环境,以供其它应用程序使用。ReleaseDC成员函数的效果依赖于设备环境的

CPainDC与CCleintDC的区别

  • CPaintDC
    • CPaintDC继承于CDC
    • 在构造函数中调用BeginPaint
    • 在析构函数调用EndPaint函数
    • 用于相应WM_PAINT消息的函数中
  • CClientDC
    • CClientDC继承于CDC
    • 在析构函数中调用GetDC
    • 在析构函数中调用ReleaseDC
    • 用于非WM_PAINT消息的GDI绘图函数中

获得设备资源描述表实现步骤

posted @ 2012-11-01 11:40  kzangv  阅读(6958)  评论(0编辑  收藏  举报
top