⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 025.txt

📁 会变语言实现的一些程序
💻 TXT
字号:
第二十五课:位图初步


--------------------------------------------------------------------------------
在这一课,我们将学习怎样在程序中使用位图。 更准确地说,我们要学习的是怎样在一个窗口的客户区中显示位图。 
理论
位图就是存贮于电脑中的图片。位图文件有相当多的格式(译者:如.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 函数的 完型: 
LoadBitmap proto hInstance:HINSTANCE, lpBitmapName:LPSTR 

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

  
第一种方法: 
.386 
.model flat, stdcall 
................ 
.const 
IDB_MYBITMAP    equ 100 
............... 
.data? 
hInstance  dd ? 
.............. 
.code 
............. 
    invoke GetModuleHandle,NULL 
    mov hInstance,eax 
............ 
    invoke LoadBitmap,hInstance,IDB_MYBITMAP 
........... 

第二种方法: 

.386 
.model flat, stdcall 
................ 
.data 
BitmapName  db "MyBitMap",0 
............... 
.data? 
hInstance  dd ? 
.............. 
.code 
............. 
    invoke GetModuleHandle,NULL 
    mov hInstance,eax 
............ 
    invoke LoadBitmap,hInstance,addr BitmapName 
........... 

获得一个设备文本(DC)句柄。你可以在响应WM_PAINT消息时通过API函数BeginPaint获得。 如果在其它消息中则可以用API函数GetDC获得。 
创建这个DC的内存映像。这样做的目的是建立一张“隐藏的画纸”,把位图 “画”在上面,作缓冲之用。完成这项工作后,我们就通过一个函数把“画纸”上的位图复制 到真正的DC中。这就是在屏幕上快速显示图象的双缓冲技术。(译者:可以减少图象抖动) 这张“画纸”用API函数 CreateCompatibleDC 建立,下面是它的完型: 
CreateCompatibleDC  proto  hdc:HDC 

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

现在我们已经有了“画纸”,可以把位图画在上面了。这可以通过API函数 SelectObject 完成, 其中第一个参数是“画纸”的句柄,第二个参数则是位图的句柄,下面是函数的完型: 
SelectObject   proto  hdc:HDC, hGdiObject:DWORD 
现在位图已经画在“画纸”上了。下一步我们要把位图复制到真正的DC中。 有很多API函数都能完成这项工作,例如 BitBlt 和 StretchBlt。 函数 BitBlt 仅仅将一个DC的内容简单地复制到另一个DC中,而函数 StretchBlt 则能够自动调整源DC复制内容的大小已适应目的DC的输出区域大小,因此前者比后者速度更快。 在这里我们只使用函数 BitBlt ,下面是它的完型: 
BitBlt  proto  hdcDest:DWORD, nxDest:DWORD, nyDest:DWORD, nWidth:DWORD, nHeight:DWORD, hdcSrc:DWORD, nxSrc:DWORD, nySrc:DWORD, dwROP:DWORD 
  
hdcDest 目的DC的句柄。 
nxDest, nyDest 目的DC输出区域的左上角坐标。
nWidth, nHeight 目的DC输出区域的长和宽。
hdcSrc 源DC的句柄。
nxSrc, nySrc 源DC中所要复制区域的左上角坐标。 
dwROP 屏面运算码(ROP)。该参数用以确定复制内容的颜色与输出区域原来的颜色按哪种运算 方式处理。通常,只需要简单地用复制内容把输出区域覆盖掉。 
一切办妥后,就用API函数 DeleteObject 释放位图对象,也就是把位图“抹掉”。 
大功告成! 现在再来回顾一下整个过程:首先,你需要把位图定义在资源文件中。 然后,你需要在程序中载入位图资源,并取得位图句柄。随后,你需要获得位图输出区域的DC,以及创建这个DC的内存映像,并把位图放进这个DC内存映像中。最后把位图从DC内存映像复制到真正的DC中。 
例子:
.386 
.model flat,stdcall 
option casemap:none 
include \masm32\include\windows.inc 
include \masm32\include\user32.inc 
include \masm32\include\kernel32.inc 
include \masm32\include\gdi32.inc 
includelib \masm32\lib\user32.lib 
includelib \masm32\lib\kernel32.lib 
includelib \masm32\lib\gdi32.lib 
WinMain proto :DWORD,:DWORD,:DWORD,:DWORD 
IDB_MAIN   equ 1 

.data 
ClassName db "SimpleWin32ASMBitmapClass",0 
AppName  db "Win32ASM Simple Bitmap Example",0 

.data? 
hInstance HINSTANCE ? 
CommandLine LPSTR ? 
hBitmap dd ? 

.code 
start: 
 invoke GetModuleHandle, NULL 
 mov    hInstance,eax 
 invoke GetCommandLine 
 mov    CommandLine,eax 
 invoke WinMain, hInstance,NULL,CommandLine, SW_SHOWDEFAULT 
 invoke ExitProcess,eax 

WinMain proc hInst:HINSTANCE,hPrevInst:HINSTANCE,CmdLine:LPSTR,CmdShow:DWORD 
 LOCAL wc:WNDCLASSEX 
 LOCAL msg:MSG 
 LOCAL hwnd:HWND 
 mov   wc.cbSize,SIZEOF WNDCLASSEX 
 mov   wc.style, CS_HREDRAW or CS_VREDRAW 
 mov   wc.lpfnWndProc, OFFSET WndProc 
 mov   wc.cbClsExtra,NULL 
 mov   wc.cbWndExtra,NULL 
 push  hInstance 
 pop   wc.hInstance 
 mov   wc.hbrBackground,COLOR_WINDOW+1 
 mov   wc.lpszMenuName,NULL 
 mov   wc.lpszClassName,OFFSET ClassName 
 invoke LoadIcon,NULL,IDI_APPLICATION 
 mov   wc.hIcon,eax 
 mov   wc.hIconSm,eax 
 invoke LoadCursor,NULL,IDC_ARROW 
 mov   wc.hCursor,eax 
 invoke RegisterClassEx, addr wc 
 INVOKE CreateWindowEx,NULL,ADDR ClassName,ADDR AppName,\ 
           WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,\ 
           CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,NULL,NULL,\ 
           hInst,NULL 
 mov   hwnd,eax 
 invoke ShowWindow, hwnd,SW_SHOWNORMAL 
 invoke UpdateWindow, hwnd 
 .while TRUE 
  invoke GetMessage, ADDR msg,NULL,0,0 
  .break .if (!eax) 
  invoke TranslateMessage, ADDR msg 
  invoke DispatchMessage, ADDR msg 
 .endw 
 mov     eax,msg.wParam 
 ret 
WinMain endp 

WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM 
   LOCAL ps:PAINTSTRUCT 
   LOCAL hdc:HDC 
   LOCAL hMemDC:HDC 
   LOCAL rect:RECT 
   .if uMsg==WM_CREATE 
      invoke LoadBitmap,hInstance,IDB_MAIN 
      mov hBitmap,eax 
   .elseif uMsg==WM_PAINT 
      invoke BeginPaint,hWnd,addr ps 
      mov    hdc,eax 
      invoke CreateCompatibleDC,hdc 
      mov    hMemDC,eax 
      invoke SelectObject,hMemDC,hBitmap 
      invoke GetClientRect,hWnd,addr rect 
      invoke BitBlt,hdc,0,0,rect.right,rect.bottom,hMemDC,0,0,SRCCOPY 
      invoke DeleteDC,hMemDC 
      invoke EndPaint,hWnd,addr ps 
 .elseif uMsg==WM_DESTROY 
  invoke DeleteObject,hBitmap 
  invoke PostQuitMessage,NULL 
 .ELSE 
  invoke DefWindowProc,hWnd,uMsg,wParam,lParam 
  ret 
 .ENDIF 
 xor eax,eax 
 ret 
WndProc endp 
end start 

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

分析:


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

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

   .elseif uMsg==WM_PAINT 
      invoke BeginPaint,hWnd,addr ps 
      mov    hdc,eax 
      invoke CreateCompatibleDC,hdc 
      mov    hMemDC,eax 
      invoke SelectObject,hMemDC,hBitmap 
      invoke GetClientRect,hWnd,addr rect 
      invoke BitBlt,hdc,0,0,rect.right,rect.bottom,hMemDC,0,0,SRCCOPY 
      invoke DeleteDC,hMemDC 
      invoke EndPaint,hWnd,addr ps 

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

 .elseif uMsg==WM_DESTROY 
  invoke DeleteObject,hBitmap 
  invoke PostQuitMessage,NULL 
当我们不再需要位图时,通过API函数 DeleteObject 把它释放。 
--------------------------------------------------------------------------------

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -