第十四章 位图和Bitblt(GDI 位图对象2)
来源:互联网 发布:田径女神走红网络 编辑:程序博客网 时间:2024/06/05 11:09
HELLOBIT.C
/*-----------------------------------------------------------------------
HELLOBIT.C -- Bitmap Demonstration
(c) Charles Petzold, 1998
-------------------------------------------------------------------------*/
#include <windows.h>
#include "resource.h"
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName [] = TEXT ("HelloBit") ;
HWND hwnd ;
MSG msg ;
WNDCLASS wndclass ;
wndclass.style = CS_HREDRAW | CS_VREDRAW ;
wndclass.lpfnWndProc = WndProc ;
wndclass.cbClsExtra = 0 ;
wndclass.cbWndExtra = 0 ;
wndclass.hInstance = hInstance ;
wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION) ;
wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ;
wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
wndclass.lpszMenuName = szAppName ;
wndclass.lpszClassName = szAppName ;
if (!RegisterClass (&wndclass))
{
MessageBox ( NULL, TEXT ("This program requires Windows NT!"),
szAppName, MB_ICONERROR) ;
return 0 ;
}
hwnd = CreateWindow (szAppName, TEXT ("HelloBit"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
NULL, NULL, hInstance, NULL) ;
ShowWindow (hwnd, iCmdShow) ;
UpdateWindow (hwnd) ;
while (GetMessage (&msg, NULL, 0, 0))
{
TranslateMessage (&msg) ;
DispatchMessage (&msg) ;
}
return msg.wParam ;
}
LRESULT CALLBACK WndProc ( HWND hwnd, UINT message, WPARAM wParam,LPARAM lParam)
{
static HBITMAP hBitmap ;
static HDC hdcMem ;
static int cxBitmap, cyBitmap, cxClient, cyClient, iSize = IDM_BIG ;
static TCHAR * szText = TEXT (" Hello, world! ") ;
HDC hdc ;
HMENU hMenu ;
int x, y ;
PAINTSTRUCT ps ;
SIZE size ;
switch (message)
{
case WM_CREATE:
hdc = GetDC (hwnd) ;
hdcMem = CreateCompatibleDC (hdc) ;
GetTextExtentPoint32 (hdc, szText, lstrlen (szText), &size) ;
cxBitmap = size.cx ;
cyBitmap = size.cy ;
hBitmap = CreateCompatibleBitmap (hdc, cxBitmap, cyBitmap) ;
ReleaseDC (hwnd, hdc) ;
SelectObject (hdcMem, hBitmap) ;
TextOut (hdcMem, 0, 0, szText, lstrlen (szText)) ;
return 0 ;
case WM_SIZE:
cxClient = LOWORD (lParam) ;
cyClient = HIWORD (lParam) ;
return 0 ;
case WM_COMMAND:
hMenu = GetMenu (hwnd) ;
switch (LOWORD (wParam))
{
case IDM_BIG:
case IDM_SMALL:
CheckMenuItem (hMenu, iSize, MF_UNCHECKED) ;
iSize = LOWORD (wParam) ;
CheckMenuItem (hMenu, iSize, MF_CHECKED) ;
InvalidateRect (hwnd, NULL, TRUE) ;
break ;
}
return 0 ;
case WM_PAINT:
hdc = BeginPaint (hwnd, &ps) ;
switch (iSize)
{
case IDM_BIG:
StretchBlt (hdc, 0, 0, cxClient, cyClient,
hdcMem, 0, 0, cxBitmap, cyBitmap, SRCCOPY) ;
break ;
case IDM_SMALL:
for (y = 0 ; y < cyClient ; y += cyBitmap)
for (x = 0 ; x < cxClient ; x += cxBitmap)
{
BitBlt (hdc, x, y, cxBitmap, cyBitmap,
hdcMem, 0, 0, SRCCOPY) ;
}
break ;
}
EndPaint (hwnd, &ps) ;
return 0 ;
case WM_DESTROY:
DeleteDC (hdcMem) ;
DeleteObject (hBitmap) ;
PostQuitMessage (0) ;
return 0 ;
}
return DefWindowProc (hwnd, message, wParam, lParam) ;
}
HELLOBIT.RC (摘录)
//Microsoft Developer Studio generated resource script.
#include "resource.h"
#include "afxres.h"
/////////////////////////////////////////////////////////////////////////////
// Menu
HELLOBIT MENU DISCARDABLE
BEGIN
POPUP "&Size"
BEGIN
MENUITEM "&Big", IDM_BIG, CHECKED
MENUITEM "&Small", IDM_SMALL
END
END
RESOURCE.H (摘录)
// Microsoft Developer Studio generated include file.
// Used by HelloBit.rc
#define IDM_BIG 40001
#define IDM_SMALL 40002
程序从呼叫GetTextExtentPoint32确定字符串的图素尺寸开始。这些尺寸将成为与视讯显示兼容的位图尺寸。当此位图被选进内存设备 内容(也与视讯显示兼容)后,再呼叫TextOut将文字显示在位图上。内存设备内容在程序执行期间保留。在处理WM_DESTROY信息期间, HELLOBIT删除了位图和内存设备内容。
HELLOBIT中的一条菜单选项允许您显示位图尺寸,此尺寸或者是显示区域中水平和垂直方向平铺的实际尺寸,或者是缩放成显示区域大小的尺寸,如图14-4所示。正与您所见到的一样,这不是显示大尺寸字符的好方法!它只是小字体的放大版,并带有放大时产生的锯齿线。
图14-4 HELLOBIT的屏幕显示
您可能想知道一个程序,例如HELLOBIT,是否需要处理WM_DISPLAYCHANGE消息。只要使用者(或者其它应用程序)修改了视讯显示 大小或者颜色深度,应用程序就接收到此讯息。其中颜色深度的改变会导致内存设备内容和视讯设备内容不兼容。但这并不会发生,因为当显示模式修改后, Windows自动修改了内存设备内容的颜色分辨率。选进内存设备内容的位图仍然保持原样,但不会造成任何问题。
阴影位图
在内存设备内容绘图(也就是位图)的技术是执行「阴影位图(shadow bitmap)」的关键。此位图包含窗口显示区域中显示的所有内容。这样,对WM_PAINT消息的处理就简化到简单的BitBlt。
阴影位图在绘画程序中最有用。程序14-7所示的SKETCH程序并不是一个最完美的绘画程序,但它是一个开始。
程序14-7 SKETCH
SKETCH.C
/*-------------------------------------------------------------------------
SKETCH.C -- Shadow Bitmap Demonstration
(c) Charles Petzold, 1998
---------------------------------------------------------------------------*/
#include <windows.h>
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName [] = TEXT ("Sketch") ;
HWND hwnd ;
MSG msg ;
WNDCLASS wndclass ;
wndclass.style = CS_HREDRAW | CS_VREDRAW ;
wndclass.lpfnWndProc = WndProc ;
wndclass.cbClsExtra = 0 ;
wndclass.cbWndExtra = 0 ;
wndclass.hInstance = hInstance ;
wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION) ;
wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ;
wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
wndclass.lpszMenuName = NULL ;
wndclass.lpszClassName = szAppName ;
if (!RegisterClass (&wndclass))
{
MessageBox ( NULL, TEXT ("This program requires Windows NT!"),
szAppName, MB_ICONERROR) ;
return 0 ;
}
hwnd = CreateWindow (szAppName, TEXT ("Sketch"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
NULL, NULL, hInstance, NULL) ;
if (hwnd == NULL)
{
MessageBox ( NULL, TEXT ("Not enough memory to create bitmap!"),
szAppName, MB_ICONERROR) ;
return 0 ;
}
ShowWindow (hwnd, iCmdShow) ;
UpdateWindow (hwnd) ;
while (GetMessage (&msg, NULL, 0, 0))
{
TranslateMessage (&msg) ;
DispatchMessage (&msg) ;
}
return msg.wParam ;
}
void GetLargestDisplayMode (int * pcxBitmap, int * pcyBitmap)
{
DEVMODE devmode ;
int iModeNum = 0 ;
* pcxBitmap = * pcyBitmap = 0 ;
ZeroMemory (&devmode, sizeof (DEVMODE)) ;
devmode.dmSize = sizeof (DEVMODE) ;
while (EnumDisplaySettings (NULL, iModeNum++, &devmode))
{
* pcxBitmap = max (* pcxBitmap, (int) devmode.dmPelsWidth) ;
* pcyBitmap = max (* pcyBitmap, (int) devmode.dmPelsHeight) ;
}
}
LRESULT CALLBACK WndProc ( HWND hwnd, UINT message, WPARAM wParam,LPARAM lParam)
{
static BOOL fLeftButtonDown, fRightButtonDown ;
static HBITMAP hBitmap ;
static HDC hdcMem ;
static int cxBitmap, cyBitmap, cxClient, cyClient, xMouse, yMouse ;
HDC hdc ;
PAINTSTRUCT ps ;
switch (message)
{
case WM_CREATE:
GetLargestDisplayMode (&cxBitmap, &cyBitmap) ;
hdc = GetDC (hwnd) ;
hBitmap = CreateCompatibleBitmap (hdc, cxBitmap, cyBitmap) ;
hdcMem = CreateCompatibleDC (hdc) ;
ReleaseDC (hwnd, hdc) ;
if (!hBitmap) // no memory for bitmap
{
DeleteDC (hdcMem) ;
return -1 ;
}
SelectObject (hdcMem, hBitmap) ;
PatBlt (hdcMem, 0, 0, cxBitmap, cyBitmap, WHITENESS) ;
return 0 ;
case WM_SIZE:
cxClient = LOWORD (lParam) ;
cyClient = HIWORD (lParam) ;
return 0 ;
case WM_LBUTTONDOWN:
if (!fRightButtonDown)
SetCapture (hwnd) ;
xMouse = LOWORD (lParam) ;
yMouse = HIWORD (lParam) ;
fLeftButtonDown = TRUE ;
return 0 ;
case WM_LBUTTONUP:
if (fLeftButtonDown)
SetCapture (NULL) ;
fLeftButtonDown = FALSE ;
return 0 ;
case WM_RBUTTONDOWN:
if (!fLeftButtonDown)
SetCapture (hwnd) ;
xMouse = LOWORD (lParam) ;
yMouse = HIWORD (lParam) ;
fRightButtonDown = TRUE ;
return 0 ;
case WM_RBUTTONUP:
if (fRightButtonDown)
SetCapture (NULL) ;
fRightButtonDown = FALSE ;
return 0 ;
case WM_MOUSEMOVE:
if (!fLeftButtonDown && !fRightButtonDown)
return 0 ;
hdc = GetDC (hwnd) ;
SelectObject (hdc,
GetStockObject (fLeftButtonDown ? BLACK_PEN : WHITE_PEN)) ;
SelectObject (hdcMem,
GetStockObject (fLeftButtonDown ? BLACK_PEN : WHITE_PEN)) ;
MoveToEx (hdc, xMouse, yMouse, NULL) ;
MoveToEx (hdcMem, xMouse, yMouse, NULL) ;
xMouse = (short) LOWORD (lParam) ;
yMouse = (short) HIWORD (lParam) ;
LineTo (hdc, xMouse, yMouse) ;
LineTo (hdcMem, xMouse, yMouse) ;
ReleaseDC (hwnd, hdc) ;
return 0 ;
case WM_PAINT:
hdc = BeginPaint (hwnd, &ps) ;
BitBlt (hdc, 0, 0, cxClient, cyClient, hdcMem, 0, 0, SRCCOPY) ;
EndPaint (hwnd, &ps) ;
return 0 ;
case WM_DESTROY:
DeleteDC (hdcMem) ;
DeleteObject (hBitmap) ;
PostQuitMessage (0) ;
return 0 ;
}
return DefWindowProc (hwnd, message, wParam, lParam) ;
}
要想在SKETCH中画线,请按下鼠标左键并拖动鼠标。要擦掉画过的东西(更确切地说,是画白线),请按下鼠标右键并拖动鼠标。要清空整个窗口, 请…结束程序,然后重新加载,一切从头再来。图14-5中显示的SKETCH程序图样表达了对频果公司的麦金塔计算机早期广告的敬意。
图14-5 SKETCH的屏幕显示
此阴影位图应多大?在本程序中,它应该大到能包含最大化窗口的整个显示区域。这一问题很容易根据GetSystemMetrics信息计算得出,但 如果使用者修改了显示设定后再显示,进而扩大了最大化时窗口的尺寸,这时将发生什么呢?SKETCH程序在EnumDisplaySettings函数的 帮助下解决了此问题。此函数使用DEVMODE结构来传回全部有效视讯显示模式的信息。第一次呼叫此函数时,应将EnumDisplaySettings 的第二参数设为0,以后每次呼叫此值都增加。EnumDisplaySettings传回FALSE时完成。
与此同时,SKETCH将建立一个阴影位图,它比目前视讯显示模式的表面还多四倍,而且需要几兆字节的内存。由于如此,SKETCH将检查位图是否建立成功了,如果没有建立,就从WM_CREATE传回-1,以表示错误。
在WM_MOUSEMOVE消息处理期间,按下鼠标左键或者右键,并在内存设备内容和显示区域设备内容中画线时,SKETCH拦截鼠标。如果画线方式更复杂的话,您可能想在一个函数中实作,程序将呼叫此函数两次-一次画在视讯设备内容上,一次画在内存设备内容上。
下面是一个有趣的实验:使SKETCH窗口小于全画面尺寸。随着鼠标左键的按下,将鼠标拖出窗口的右下角。因为SKETCH拦截鼠标,所以它继续接收并处理WM_MOUSEMOVE消息。现在扩大窗口,您将看到阴影位图包含您在SKETCH窗口外所画的内容。
在菜单中使用位图
您也可以用位图在菜单上显示选项。如果您联想起菜单中文件夹、剪贴簿和资源回收筒的图片,那么不要再想那些图片了。您应该考虑一下,菜单上显示位图对画图程序用途有多大,想象一下在菜单中使用不同字体和字体大小、线宽、阴影图案以及颜色。
GRAFMENU是展示图形菜单选项的范例程序。此程序顶层菜单如图14-6所示。放大的字母来自于40×16图素的单色位图文件,该文件在Visual C++ Developer Studio建立。从菜单上选择「FONT」将弹出三个选择项-「Courier New」、「 Arial」和「Times New Roman」。它们是标准的Windows TrueType字体,并且每一个都按其相关的字体显示,如图14-7所示。这些位图在程序中用内存设备内容建立。
图14-6 GRAFMENU程序的顶层菜单
图14-7 GRAFMENU程序弹出的「FONT」菜单
最后,在拉下系统菜单时,您将获得一些「辅助」信息,用「HELP」表示了新使用者的在线求助项目(参见图14-8)。此64×64图素的单色位图是在Developer Studio中建立的。
图14-8 GRAFMENU程序系统菜单
GRAFMENU程序,包括四个Developer Studio中建立的位图,如程序14-8所示。
GRAFMENU.C
/*----------------------------------------------------------------------------
GRAFMENU.C -- Demonstrates Bitmap Menu Items
(c) Charles Petzold, 1998
-----------------------------------------------------------------------------*/
#include <windows.h>
#include "resource.h"
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
void AddHelpToSys (HINSTANCE, HWND) ;
HMENU CreateMyMenu (HINSTANCE) ;
HBITMAP StretchBitmap (HBITMAP) ;
HBITMAP GetBitmapFont (int) ;
void DeleteAllBitmaps (HWND) ;
TCHAR szAppName[] = TEXT ("GrafMenu") ;
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
HWND hwnd ;
MSG msg ;
WNDCLASS wndclass ;
wndclass.style = CS_HREDRAW | CS_VREDRAW ;
wndclass.lpfnWndProc = WndProc ;
wndclass.cbClsExtra = 0 ;
wndclass.cbWndExtra = 0 ;
wndclass.hInstance = hInstance ;
wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION) ;
wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ;
wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
wndclass.lpszMenuName = NULL ;
wndclass.lpszClassName = szAppName ;
if (!RegisterClass (&wndclass))
{
MessageBox ( NULL, TEXT ("This program requires Windows NT!"),
szAppName, MB_ICONERROR) ;
return 0 ;
}
hwnd = CreateWindow (szAppName,TEXT ("Bitmap Menu Demonstration"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
NULL, NULL, hInstance, NULL) ;
ShowWindow (hwnd, iCmdShow) ;
UpdateWindow (hwnd) ;
while (GetMessage (&msg, NULL, 0, 0))
{
TranslateMessage (&msg) ;
DispatchMessage (&msg) ;
}
return msg.wParam ;
}
- 第十四章 位图和Bitblt(GDI 位图对象2)
- 第十四章 位图和Bitblt(GDI 位图对象1)
- 第十四章 位图和Bitblt(位图入门,位图尺寸)
- 第十四章 位图和Bitblt(位块传输)
- 位图和BitBlt
- 位图和Bitblt
- 位图和Bitblt
- GDI位图和DIB位图
- 位图,设备上下文和BitBlt
- windows程序设计:位图和bitblt
- 位图与bitblt【位图知识】
- 14.4 GDI 位图对象 (I)
- 14.4 GDI 位图对象 (II)
- 如何加载和显示位图bitblt
- GDI位图和DIB位图是两种不同的Windows位图
- MFC GDI绘图(2)位图
- 用BitBlt制作透明位图(1)
- BitBlt 画透明位图
- 第十五章 与设备无关的位图(DIB 和 DDB 的结合2)
- 第十五章 与设备无关的位图(DIB 和 DDB 的结合2)
- 第十五章 与设备无关的位图(DIB 和 DDB 的结合2)
- 第十五章 与设备无关的位图(显示和打印3)
- 第十四章 位图和Bitblt(GDI 位图对象1)
- 第十四章 位图和Bitblt(GDI 位图对象2)
- 第十四章 位图和Bitblt(位块传输)
- 第十四章 位图和Bitblt(位图入门,位图尺寸)
- 二叉树的三种遍历
- 第十三章 使用打印机(打印图形和文字1)
- 切换数据挖掘系统后台有感---我也谈一次“架构”
- 复习15:类的层次结构
- 第五章 图像基础(GDI 映像方式)(1)
- 第五章 图像基础(GDI 映像方式)(2)