windows sdk编程系列文章 ---- 位图

为微软windows操作系统编写的应用程序可以使用两种图像工具来存储图像:元文件和位图,在这一课,我们将学习怎样在程序中使用位图,更准确地说,我们要学习的是怎样在一个窗口的客户区显示位图。

 

理论:

位图就是存贮于电脑中的图片。位图文件有相当多的格式(如.BMP.JPG.GIF.PIC 等)但Windows仅支持Windows Bitmap Graphics 格式,即BMP文件。 本课所指的位图也是BMP文件。 使用位图最简单的方法就是把它定义在资源文件(.rc)中。 定义的方法有两种。第一种方法是把它定义为整数宏,具体如下:

#define IDB_MYBITMAP   100

IDB_MYBITMAP BITMAP "c:/project/example.bmp"

第一行我们定义了一个值为100的整数宏。 第二行我们把这个整数宏指向所要定义的位图, 这样,编译器就能知道位图所在的路径。

另一种方法是给它起一个名字,也就是把它定义为字符串,具体如下:

MyBitMap BITMAP "c:/project/example.bmp"

两种方法效果是一样的。 选择哪一种方法,视乎在程序中你喜欢用整数宏还是用字符串来指向位图。

现在我们已经把位图定义在资源文件中,下一步就是把它显示在窗口的客户区上。

在程序中,我们使用API函数 LoadBitmap 取得位图句柄。 下面是 LoadBitmap 函数的原型:

 

HBITMAP LoadBitmap( HINSTANCE hInstance , LPCTSTR lpBitmapName );

该函数返回一个位图句柄。函数有两个参数,其中 hInstance 是程序句柄。 lpBitmapName 是位图名字的指针(适用于第二种定义方法)。如果你使用了第一种 定义方法,你可以填入指向位图的值或整数宏 (对应上例这个值就是100,整数宏是IDB_MYBITMAP)。

获得一个设备文本(DC)句柄。你可以在响应WM_PAINT消息时通过API函数BeginPaint获得。 如果在其它

消息中则可以用API函数GetDC获得。

创建这个DC的内存映像。这样做的目的是建立一张“隐藏的画纸”,把位图 “画”在上面,作缓冲之用。完成这项工作后,我们就通过一个函数把“画纸”上的位图复制 到真正的DC中。这就是在屏幕上快速显示图象的双缓冲技术。(译者:可以减少图象抖动) 这张“画纸”用API函数 CreateCompatibleDC 建立,下面是它的完型:

HDC CreateCompatibleDC( HDC hdc );

 

如果函数执行成功,将返回DC内存映像也即“画纸”的句柄。

现在我们已经有了“画纸”,可以把位图画在上面了。这可以通过API函数 SelectObject 完成, 其中第一个参数是“画纸”的句柄,第二个参数则是位图的句柄,下面是函数的完型:

HGDIOBJ SelectObject( HDC hdc , HGDIOBJ hgdiobj );

现在位图已经画在“画纸”上了。下一步我们要把位图复制到真正的DC中。 有很多API函数都能完成这项工作,例如 BitBlt 和 StretchBlt。 函数 BitBlt 仅仅将一个DC的内容简单地复制到另一个DC中,而函数 StretchBlt 则能够自动调整源DC复制内容的大小已适应目的DC的输出区域大小,因此前者比后者速度更快。 在这里我们只使用函数 BitBlt ,下面是它的完型:

BOOL BitBlt( HDC hdcDest , // handle to destination DC

              int nXDest , // x-coord of destination upper-left corner

              int nYDest , // y-coord of destination upper-left corner

              int nWidth , // width of destination rectangle

              int nHeight , // height of destination rectangle

              HDC hdcSrc , // handle to source DC

              int nXSrc , // x-coordinate of source upper-left corner

              int nYSrc , // y-coordinate of source upper-left corner

              DWORD dwRop // raster operation code );

 

hdcDest 目的DC的句柄。

nxDest, nyDest 目的DC输出区域的左上角坐标。

nWidth, nHeight 目的DC输出区域的长和宽。

hdcSrc 源DC的句柄。

nxSrc, nySrc 源DC中所要复制区域的左上角坐标。

dwROP 屏面运算码(ROP)。该参数用以确定复制内容的颜色与输出区域原来的颜色按哪种运算 方式处理。通常,只需要简单地用复制内容把输出区域覆盖掉。

一切办妥后,就用API函数 DeleteObject 释放位图对象,也就是把位图“抹掉”。

大功告成! 现在再来回顾一下整个过程:首先,你需要把位图定义在资源文件中。 然后,你需要在程序中载入位图资源,并取得位图句柄。随后,你需要获得位图输出区域的DC, 以及创建这个DC的内存映像,并把位图放进这个DC内存映像中。最后把位图从DC内存映像复制到 真正的DC中。

例子:见光盘FirstWindow23

#include "windows.h"
#include "tchar.h"
#define IDB_MAIN 1
TCHAR szClassName[] = _T("Simple Bitmap class");
TCHAR szAppName[] = _T("Win32 Simple Bitmap Example");
HINSTANCE g_hInstance;
HBITMAP   g_hBitmap;

LRESULT CALLBACK WndProc(HWND hWnd,UINT uMsg,WPARAM wParam, LPARAM lParam)
{
    PAINTSTRUCT ps;
    HDC hDC;
    HDC hMemDC;
    RECT rc;

    switch(uMsg)
    {
    case WM_CREATE:
       
        g_hBitmap = LoadBitmap(g_hInstance,MAKEINTRESOURCE(IDB_MAIN));
        break;
    case WM_PAINT:
        hDC = BeginPaint(hWnd,&ps);
        hMemDC = CreateCompatibleDC(hDC);
       
        SelectObject(hMemDC,g_hBitmap);
        GetClientRect(hWnd,&rc);
        BitBlt(hDC,0,0,rc.right,rc.bottom,hMemDC,0,0,SRCCOPY);
        DeleteDC(hMemDC);
        EndPaint(hWnd,&ps);
        break;

    case WM_CLOSE:
        DestroyWindow(hWnd);
        DeleteObject(g_hBitmap);
        PostQuitMessage(NULL);
        break;
    default:
        return DefWindowProc(hWnd,uMsg,wParam,lParam);
    }
    return 0;
}

int __stdcall WinMain(IN HINSTANCE hInstance, IN HINSTANCE hPrevInstance, IN LPSTR lpCmdLine, IN int nShowCmd )
{
    WNDCLASSEX wc;
    MSG msg;
    HWND hWnd;

    g_hInstance = hInstance;
    RtlZeroMemory(&wc,sizeof(WNDCLASSEX));
    wc.cbSize = sizeof(WNDCLASSEX);
    wc.style = CS_VREDRAW | CS_HREDRAW;
    wc.lpfnWndProc = WndProc;
    wc.hInstance = hInstance;
    wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
    wc.lpszClassName = szClassName;
    wc.hIcon = LoadIcon(NULL,IDI_APPLICATION);
    wc.hIconSm = wc.hIcon;
    wc.hCursor = LoadCursor(NULL,IDC_ARROW);
    RegisterClassEx(&wc);

    hWnd = CreateWindowEx(NULL,szClassName,szAppName,
        WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,
        NULL,NULL,hInstance,NULL);
    if(!hWnd)
        return 0;

    ShowWindow(hWnd,SW_NORMAL);
    UpdateWindow(hWnd);

    while(GetMessage(&msg,NULL,0,0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return msg.wParam;

}

;---------------------------------------------------------------------
;                            资源定义
;---------------------------------------------------------------------
#define IDB_MAIN 1
IDB_MAIN BITMAP "tweety78.bmp"

分析:

#define IDB_MAIN 1
IDB_MAIN BITMAP "tweety78.bmp"
定义整数宏IDB_MAIN的值为1,然后把它指向一个与资源文件处于相同目录文件名为“tweety.bmp"的位图。

case WM_CREATE:
      
       g_hBitmap = LoadBitmap(g_hInstance,MAKEINTRESOURCE(IDB_MAIN));
       break;

在处理 WM_CREATE 消息时, 我们通过API函数 LoadBitmap 载入位图资源,并通过函数 返回值取得位图句柄。 然后,我们就可以把位图画在窗口客户区上。

       case WM_PAINT:
       hDC = BeginPaint(hWnd,&ps);
       hMemDC = CreateCompatibleDC(hDC);
      
       SelectObject(hMemDC,g_hBitmap);
       GetClientRect(hWnd,&rc);
       BitBlt(hDC,0,0,rc.right,rc.bottom,hMemDC,0,0,SRCCOPY);
       DeleteDC(hMemDC);
       EndPaint(hWnd,&ps);
       break;

在本例中,我们选用在响应WM_PAINT消息时画出位图。首先我们通过API函数l BeginPaint 获得窗口客户区的DC句柄。 接着我们通过API函数 CreateCompatibleDC 创建该DC 的内存映像,并通过API函数 SelectObject 把位图放进内存映像中。下一步,我们通过API函数 GetClientRect 取得窗口客户区的大小。最后,我们通过API函数 BitBlt 把位图从DC内存映像复制到真正的客户区DC中。 完成显示工作后,我们通过API函数 DeleteDC 释放DC内存映像,并用API函数 EndPaint 释放客户区DC, 结束画图工作。

    case WM_CLOSE:
       DestroyWindow(hWnd);
       DeleteObject(g_hBitmap);
       PostQuitMessage(NULL);
       break;
当我们不再需要位图时,通过API函数 DeleteObject 把它释放。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值