第14章 位图和位块传输_14.4 GDI位图对象(2)
(1)在内存设备环境中绘图(与真实DC不同的是,内存DC的显示表面是个位图)
(2)GetTextExtentPoint32函数:用于确定文本字符串的像素大小。(此大小就是与视频显示兼容的位图的尺寸)。
|
参数 |
说明 |
|
hdc |
设备环境句柄 |
|
lpString |
文本字符串,如szText |
|
cbString |
文本字符串中字符的个数。如lstrlen(szText) |
|
lpSize |
指向一个结构体,用来存放结果 |
(3)当显示器的颜色深度和大小改变时,windows会自动改变内存设备环境的彩色分辩率。也就是内存设备环境与视频设备环境仍然会保持兼容。所以在WM_DISPLAYCHANGE消息中不用去关心这个问题。
【HelloBit程序】
效果图

/*------------------------------------------------------------
HELLOBIT.C -- Bitmap Demostration
(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;
WNDCLASSEX wndclass;
wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.cbSize = sizeof(WNDCLASSEX);
wndclass.lpfnWndProc = WndProc;
wndclass.cbClsExtra = ;
wndclass.cbWndExtra = ;
wndclass.hInstance = hInstance;
wndclass.hIcon = LoadIcon(hInstance, szAppName);
wndclass.hIconSm = LoadIcon(hInstance, szAppName);
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wndclass.lpszMenuName = szAppName;
wndclass.lpszClassName = szAppName;
if (!RegisterClassEx(&wndclass))
{
MessageBox(NULL, TEXT("This program requires Windows NT!"),
szAppName, MB_ICONERROR);
return ;
} hwnd = CreateWindow(szAppName, // window class name
TEXT("HelloBit"), // window caption
WS_OVERLAPPEDWINDOW, // window style
CW_USEDEFAULT, // initial x position
CW_USEDEFAULT, // initial y position
CW_USEDEFAULT, // initial x size
CW_USEDEFAULT, // initial y size
NULL, // parent window handle
NULL, // window menu handle
hInstance, // program instance handle
NULL); // creation parameters ShowWindow(hwnd, iCmdShow);
UpdateWindow(hwnd); while (GetMessage(&msg, NULL, , ))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
HDC hdc;
static HDC hdcMem;
PAINTSTRUCT ps;
static int cxBitmap, cyBitmap, cxClient, cyClient, iSize = IDM_BIG;
static HBITMAP hBitmap;
static TCHAR* szText = TEXT("Hello,World!");
SIZE size;
HMENU hMenu;
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, , , szText, lstrlen(szText));
return ;
case WM_COMMAND:
hMenu = GetMenu(hwnd);
switch (LOWORD(wParam)) //菜单ID
{
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 ;
case WM_SIZE:
cxClient = LOWORD(lParam);
cyClient = HIWORD(lParam);
return ;
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps); switch (iSize)
{
case IDM_BIG:
StretchBlt(hdc, , , cxClient, cyClient,
hdcMem, , , cxBitmap, cyBitmap, SRCCOPY);
break;
case IDM_SMALL:
for (int y = ; y < cyClient; y += cyBitmap)
for (int x = ; x < cxClient; x += cxBitmap)
{
BitBlt(hdc, x, y, cxBitmap, cyBitmap, hdcMem, , , SRCCOPY);
}
break;
} EndPaint(hwnd, &ps);
return ; case WM_DESTROY:
DeleteDC(hdcMem);
DeleteObject(hBitmap);
PostQuitMessage();
return ;
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
//resource.h
//{{NO_DEPENDENCIES}}
// Microsoft Developer Studio generated include file.
// Used by HelloBit.rc
//
#define IDM_BIG 40001
#define IDM_SMALL 40002
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 102
#define _APS_NEXT_COMMAND_VALUE 40003
#define _APS_NEXT_CONTROL_VALUE 1000
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif
//HelloBit.rc
//Microsoft Developer Studio generated resource script.
//
#include "resource.h" #define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "afxres.h" /////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS /////////////////////////////////////////////////////////////////////////////
// English (U.S.) resources #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
#ifdef _WIN32
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
#pragma code_page(1252)
#endif //_WIN32 #ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
// TEXTINCLUDE DISCARDABLE
BEGIN
"resource.h\0"
END TEXTINCLUDE DISCARDABLE
BEGIN
"#include ""afxres.h""\r\n"
"\0"
END TEXTINCLUDE DISCARDABLE
BEGIN
"\r\n"
"\0"
END #endif // APSTUDIO_INVOKED /////////////////////////////////////////////////////////////////////////////
//
// Menu
// HELLOBIT MENU DISCARDABLE
BEGIN
POPUP "&Size"
BEGIN
MENUITEM "&Big", IDM_BIG, CHECKED
MENUITEM "&Small", IDM_SMALL
END
END #endif // English (U.S.) resources
///////////////////////////////////////////////////////////////////////////// #ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
// /////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED
(1)EnumDisplaySettings:该函数用来获取显示设备的参数信息,要想获取所有显示设备的所有信息,就要循环使用该函数。
|
参数 |
说明 |
|
lpszDeviceName |
设备的名称,以NULL结尾的设备名称字符串。 当NULL表示当前使用的显示设备 |
|
iModeNum |
①获取设备类型信息。该值可以是索引号或也可以使下值之一: ENUM_CURRENT_SETTINGS:获取当前显示设备的配置 ENUM_REGISTRY_SETTINGS:注册表中所有当前存储的显示设备的配置。 ②如果从0开始,要获得所有显示设备的物理模式,就要循环调用EnumDisplaySettings函数,直到返回返回值为FALSE。 ③当以iModeNum为0而调用函数时,操作系统将初始化和填充相关显示设备信息。 ④当以iModeNum为非0而调用函数时,操作系统将返回最后一次填充的信息。 |
|
lpDevMode |
该参数是一个结构体用来接收物理模式的信息参数,在使用此结构体前要先初始化该结构体。函数会获取到以下五个字段的值:dmBitsPerpel、dmPelsWidth、dmPelsHeight(设备宽度和高度,以像素为单位,不会随分辨率而改变,可以用来测量显示器的大小!)、dmDisplayFlags、dmDisplayFrequency。 |
(2)【Sketch程序】——先将图绘到内存设备,再绘到显示设备的DC环境。
效果图

/*------------------------------------------------------------
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;
WNDCLASSEX wndclass;
wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.cbSize = sizeof(WNDCLASSEX);
wndclass.lpfnWndProc = WndProc;
wndclass.cbClsExtra = ;
wndclass.cbWndExtra = ;
wndclass.hInstance = hInstance;
wndclass.hIcon = LoadIcon(hInstance, szAppName);
wndclass.hIconSm = LoadIcon(hInstance, szAppName);
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = szAppName;
if (!RegisterClassEx(&wndclass))
{
MessageBox(NULL, TEXT("This program requires Windows NT!"),
szAppName, MB_ICONERROR);
return ;
} hwnd = CreateWindow(szAppName, // window class name
TEXT("Sketch"), // window caption
WS_OVERLAPPEDWINDOW, // window style
CW_USEDEFAULT, // initial x position
CW_USEDEFAULT, // initial y position
CW_USEDEFAULT, // initial x size
CW_USEDEFAULT, // initial y size
NULL, // parent window handle
NULL, // window menu handle
hInstance, // program instance handle
NULL); // creation parameters //因为在CreateWindow会发送WM_CREATE,在WM_CREATE消息中会创建一个位图
//如果位图太大,会导致创建失败,WM_CREATE会返回-1,如下处理这种情况.
if (hwnd == NULL)
{
MessageBox(NULL, TEXT("Not enough memory to create bitmap!"),
szAppName, MB_ICONERROR);
return ;
}
ShowWindow(hwnd, iCmdShow);
UpdateWindow(hwnd); while (GetMessage(&msg, NULL, , ))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
//获得最大可显示的位图
void GetLargestDisplayMode(int* pcxBitmap, int* pcyBitmap)
{
DEVMODE devmode;
int iModeNum = ;
*pcxBitmap = *pcyBitmap = ;
ZeroMemory(&devmode, sizeof(DEVMODE));
devmode.dmSize = sizeof(DEVMODE); //这个要记得设置!
//EnumDisplaySettins第1个参数为NULL,表示当前正在使用的显示设备,可以不止一个。
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:
hdc = GetDC(hwnd);
GetLargestDisplayMode(&cxBitmap, &cyBitmap);
hBitmap = CreateCompatibleBitmap(hdc, cxBitmap, cyBitmap);
hdcMem = CreateCompatibleDC(hdc);
ReleaseDC(hwnd, hdc);
SelectObject(hdcMem, hBitmap);
PatBlt(hdcMem, , , cxBitmap, cyBitmap, WHITENESS); //给显示表面涂上白色
return ;
case WM_SIZE:
cxClient = LOWORD(lParam);
cyClient = HIWORD(lParam);
return ;
//左键用来画图(用黑色画)
case WM_LBUTTONDOWN:
if (!fRightButtonDown) //因为当右键按下时,说明正在用白色擦图,此时鼠标是被捕捉的
SetCapture(hwnd);
xMouse = LOWORD(lParam);
yMouse = HIWORD(lParam);
fLeftButtonDown = TRUE;
return ;
case WM_LBUTTONUP:
if (fLeftButtonDown)
//SetCapture(NULL);
ReleaseCapture();//课本用SetCapture(NULL); fLeftButtonDown = FALSE;
return ; //右键用来擦图(用白色绘图,等于在擦图)
case WM_RBUTTONDOWN:
if (!fLeftButtonDown) //因为当左键按下时,说明正在用白色擦图,此时鼠标是被捕捉的
SetCapture(hwnd);
xMouse = LOWORD(lParam);
yMouse = HIWORD(lParam);
fRightButtonDown = TRUE;
return ;
case WM_RBUTTONUP:
if (fRightButtonDown)
//SetCapture(NULL);
ReleaseCapture();
fRightButtonDown = FALSE;
return ;
case WM_MOUSEMOVE:
//己知问题:当鼠标在客户区内按下一个键时并拖动绘图,到客户区外依次释放两个键,
//重回客户区时,这里鼠标己经松开,但仍会画图——原因是当客户区外释放时,就ReleaseCapture
//了,导致其中一个鼠标按键的ButtonUp消息收不到,即仍处于fButtonDown状态,从而下列的判断会通过,
//所以仍会执行后面的代码
if (!fLeftButtonDown && !fRightButtonDown) //左右键都没按下时,退出
return ;
hdc = GetDC(hwnd);
//左键按下时,选黑色画笔,右键时白色画笔。同时按下时仍然是黑色的画笔
SelectObject(hdc, GetStockObject(fLeftButtonDown ? BLACK_PEN : WHITE_PEN));
SelectObject(hdcMem, GetStockObject(fLeftButtonDown ? BLACK_PEN : WHITE_PEN));
//同时在屏幕dc与内存dc中绘图
MoveToEx(hdc, xMouse, yMouse, NULL);
MoveToEx(hdcMem, xMouse, yMouse, NULL);
xMouse = LOWORD(lParam);
yMouse = HIWORD(lParam);
LineTo(hdc, xMouse, yMouse);
LineTo(hdcMem, xMouse, yMouse);
ReleaseDC(hwnd, hdc);
return ;
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps); //这里的图形来自内存设备环境
BitBlt(hdc, , , cxClient, cyClient,
hdcMem, , , SRCCOPY); EndPaint(hwnd, &ps);
return ; case WM_DESTROY:
PostQuitMessage();
return ;
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
14.4.9 在菜单中使用位图
(1)GetMenuItemInfo(hMenu,uMenuItem,fByPosition,lpmii);
①uMenuItem:菜单ID或位置索引(看fByPositon是否是TRUE)
②lpmii,指一个MENUITEMINFO结构体
|
MENUITEMINFO结构体 |
|
|
字段 |
说明 |
|
cbSize |
结构的大小(字节) |
|
fMask |
MIIM_CHECKMARKS:获取或设置hbmpChecked和hbmpUnchecked成员 MIIM_DATA:获取或设置dwItemData成员 MIIM_ID :获取或设置wID成员 MIIM_STATE: 获取或设置fState成员 MIIM_SUBMENU: 获取或设置hSubMenu成员 MIIM_TYPE :获取或设置fType和dwTypeData成员 |
|
fType |
菜单项类型 MFT_BITMAP:使用一个位图显示菜单项.dwTypeData低位字是该位图的句柄.并且cch被忽视 MFT_MENUBARBREAK:放置菜单项在新行上(适用于菜单栏)或在新列内 MFT_SEPARATOR:指定那个菜单项是一个分隔条 MFT_STRING:用一个文本字符串显示菜单项.dwTypeData成员指示一个以NULL结尾的字符串 MFT_RADIOCHECK:如果hbmpChecked成员是NULL,显示选中的菜单项使用一个单选按钮来代替一个复选标记 |
|
fState |
菜单项的状态 MFS_CHECKED:复选的菜单项.至于更多关于菜单项选中的信息,看hbmpChecked成员 MFS_DISABLED:菜单项无效并变灰使得它不能被选择.等效于MFS_GRAYED MFS_ENABLED: 激活菜单项使它可以被选择 MFS_GRAYED:菜单项无效并变灰使得它不能被选择.等效于MFS_DISABLED MFS_HILITE:菜单项高亮显示 MFS_UNCHECKED:取消复选菜单项 MFS_UNHILITE:移除菜单项的高亮显示,这是默认状态 |
|
wID |
菜单项ID, 只有在设置了fMask的MIIM_ID时才能使用 |
|
hSubMenu |
菜单项相关联的下拉菜单或子菜单的的句柄。如果菜单项不是一个打开的下拉菜单或子菜单,那这个成员是NULL, 该项只有在设置了fMask的MIIM_SUBMENU时才能使用 |
|
hbmpChecked |
菜单项被选中时显示在一侧的位图的句柄。 |
|
hbmpUnchecked |
菜单项没有被选中时显示在一侧的位图的句柄 |
|
dwItemData |
应用程序定义的菜单项相关联的值,该项只有在设置了fMask的MIIM_DATA时才能使用 |
|
dwTypeData |
菜单项的内容,它的具体意义依赖于fTYPE值,并且它只能在fMask设置了MIIM_TYPE标记时才能被使用; 要获取一个MFT_STRING类型的菜单项,首先要得到该字符串的大小,通过设置MENUITEMINFO结构的dwTypeData值为空并调用函数GetMenuItemInfo得到的cch值就是字符串的大小,然后分配一个字符串大小的缓冲区,把指向缓冲区的指针存赋给dwTypeData并再次调用GetMenuItemInfo函数用字符串来填充缓冲区。 如果获取其它类型的菜单项,GetMenuItemInfo函数会赋给dwTypeData一个类型由fType成员指定的值。当使用SetMenuItemInfo函数时,dwTypeData必须包含一个类型由fType成员指定的值,该项只有在设置了fMask成员的MIIM_STRING标记时才能使用。 |
|
cch |
当检索一个MFT_STRING类型菜单项的信息时,为菜单项文本(TCHAR)的长度 |
|
hbmpItem |
菜单项上显示位图的句柄,它可能是以下标记中的一个,该项只有在设置了fMask成员的MIIM_BITMAP标记时才能使用。 HBMMENU_CALLBACK:一个由拥有该菜单的窗口绘制的位图 HBMMENU_MBAR_CLOSE:菜单栏的关闭按钮 HBMMENU_MBAR_MINIMIZE:菜单栏的最小化按钮 HBMMENU_MBAR_RESTORE:菜单栏的还原按钮 …… |
(2)使用位图做菜单项时的注意事项
①Windows会调整菜单栏高度来适应最高的位图,其他位图(包括文字)和菜单上沿顶端对齐。
②如果把一个位图放入顶级菜单,那么SM_CYMENU调用和GetSystemMetrics得到的菜单高度值不同。
③当菜单包含文本时,Windows会自动添加键盘接口。但一旦加入位图,就没有键盘接口了。可以使用WM_MENUCHAR消息,在按下Alt键以及没有映射到任何菜单项的某个字母键时,Windows会向应用程序发送一个WM_MENUCHAR消息。wParam为被按下键的ASCII码。如果和某个菜单项对应,就要向Windows返回一个双字(即return的返回值),并将高位字设为2(即MNC_EXECUTE),将低位字设成对应菜单项的索引。Windows会向窗口发送WM_COMMAND消息。
【GrafMenu程序】
效果图


/*------------------------------------------------------------
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;
WNDCLASSEX wndclass;
wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.cbSize = sizeof(WNDCLASSEX);
wndclass.lpfnWndProc = WndProc;
wndclass.cbClsExtra = ;
wndclass.cbWndExtra = ;
wndclass.hInstance = hInstance;
wndclass.hIcon = LoadIcon(hInstance, szAppName);
wndclass.hIconSm = LoadIcon(hInstance, szAppName);
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = szAppName;
if (!RegisterClassEx(&wndclass))
{
MessageBox(NULL, TEXT("This program requires Windows NT!"),
szAppName, MB_ICONERROR);
return ;
} hwnd = CreateWindow(szAppName, // window class name
TEXT("Sketch"), // window caption
WS_OVERLAPPEDWINDOW, // window style
CW_USEDEFAULT, // initial x position
CW_USEDEFAULT, // initial y position
CW_USEDEFAULT, // initial x size
CW_USEDEFAULT, // initial y size
NULL, // parent window handle
NULL, // window menu handle
hInstance, // program instance handle
NULL); // creation parameters //因为在CreateWindow会发送WM_CREATE,在WM_CREATE消息中会创建一个位图
//如果位图太大,会导致创建失败,WM_CREATE会返回-1,如下处理这种情况.
if (hwnd == NULL)
{
MessageBox(NULL, TEXT("Not enough memory to create bitmap!"),
szAppName, MB_ICONERROR);
return ;
}
ShowWindow(hwnd, iCmdShow);
UpdateWindow(hwnd); while (GetMessage(&msg, NULL, , ))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
//获得最大可显示的位图
void GetLargestDisplayMode(int* pcxBitmap, int* pcyBitmap)
{
DEVMODE devmode;
int iModeNum = ;
*pcxBitmap = *pcyBitmap = ;
ZeroMemory(&devmode, sizeof(DEVMODE));
devmode.dmSize = sizeof(DEVMODE); //这个要记得设置!
//EnumDisplaySettins第1个参数为NULL,表示当前正在使用的显示设备,可以不止一个。
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:
hdc = GetDC(hwnd);
GetLargestDisplayMode(&cxBitmap, &cyBitmap);
hBitmap = CreateCompatibleBitmap(hdc, cxBitmap, cyBitmap);
hdcMem = CreateCompatibleDC(hdc);
ReleaseDC(hwnd, hdc);
SelectObject(hdcMem, hBitmap);
PatBlt(hdcMem, , , cxBitmap, cyBitmap, WHITENESS); //给显示表面涂上白色
return ;
case WM_SIZE:
cxClient = LOWORD(lParam);
cyClient = HIWORD(lParam);
return ;
//左键用来画图(用黑色画)
case WM_LBUTTONDOWN:
if (!fRightButtonDown) //因为当右键按下时,说明正在用白色擦图,此时鼠标是被捕捉的
SetCapture(hwnd);
xMouse = LOWORD(lParam);
yMouse = HIWORD(lParam);
fLeftButtonDown = TRUE;
return ;
case WM_LBUTTONUP:
if (fLeftButtonDown)
//SetCapture(NULL);
ReleaseCapture();//课本用SetCapture(NULL); fLeftButtonDown = FALSE;
return ; //右键用来擦图(用白色绘图,等于在擦图)
case WM_RBUTTONDOWN:
if (!fLeftButtonDown) //因为当左键按下时,说明正在用白色擦图,此时鼠标是被捕捉的
SetCapture(hwnd);
xMouse = LOWORD(lParam);
yMouse = HIWORD(lParam);
fRightButtonDown = TRUE;
return ;
case WM_RBUTTONUP:
if (fRightButtonDown)
//SetCapture(NULL);
ReleaseCapture();
fRightButtonDown = FALSE;
return ;
case WM_MOUSEMOVE:
//己知问题:当鼠标在客户区内按下一个键时并拖动绘图,到客户区外依次释放两个键,
//重回客户区时,这里鼠标己经松开,但仍会画图——原因是当客户区外释放时,就ReleaseCapture
//了,导致其中一个鼠标按键的ButtonUp消息收不到,即仍处于fButtonDown状态,从而下列的判断会通过,
//所以仍会执行后面的代码
if (!fLeftButtonDown && !fRightButtonDown) //左右键都没按下时,退出
return ;
hdc = GetDC(hwnd);
//左键按下时,选黑色画笔,右键时白色画笔。同时按下时仍然是黑色的画笔
SelectObject(hdc, GetStockObject(fLeftButtonDown ? BLACK_PEN : WHITE_PEN));
SelectObject(hdcMem, GetStockObject(fLeftButtonDown ? BLACK_PEN : WHITE_PEN));
//同时在屏幕dc与内存dc中绘图
MoveToEx(hdc, xMouse, yMouse, NULL);
MoveToEx(hdcMem, xMouse, yMouse, NULL);
xMouse = LOWORD(lParam);
yMouse = HIWORD(lParam);
LineTo(hdc, xMouse, yMouse);
LineTo(hdcMem, xMouse, yMouse);
ReleaseDC(hwnd, hdc);
return ;
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps); //这里的图形来自内存设备环境
BitBlt(hdc, , , cxClient, cyClient,
hdcMem, , , SRCCOPY); EndPaint(hwnd, &ps);
return ; case WM_DESTROY:
PostQuitMessage();
return ;
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
//resource.h
//{{NO_DEPENDENCIES}}
// Microsoft Developer Studio generated include file.
// Used by GrafMenu.rc
//
#define IDM_FONT_COUR 101
#define IDM_FONT_ARIAL 102
#define IDM_FONT_TIMES 103
#define IDM_HELP 104
#define IDM_EDIT_UNDO 40005
#define IDM_EDIT_CUT 40006
#define IDM_EDIT_COPY 40007
#define IDM_EDIT_PASTE 40008
#define IDM_EDIT_CLEAR 40009
#define IDM_FILE_NEW 40010
#define IDM_FILE_OPEN 40011
#define IDM_FILE_SAVE 40012
#define IDM_FILE_SAVE_AS 40013
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 108
#define _APS_NEXT_COMMAND_VALUE 40014
#define _APS_NEXT_CONTROL_VALUE 1000
#define _APS_NEXT_SYMED_VALUE 105
#endif
#endif
//GrafMenu.rc
//Microsoft Developer Studio generated resource script.
//
#include "resource.h" #define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "afxres.h" /////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS /////////////////////////////////////////////////////////////////////////////
// English (U.S.) resources #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
#ifdef _WIN32
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
#pragma code_page(1252)
#endif //_WIN32 #ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
// TEXTINCLUDE DISCARDABLE
BEGIN
"resource.h\0"
END TEXTINCLUDE DISCARDABLE
BEGIN
"#include ""afxres.h""\r\n"
"\0"
END TEXTINCLUDE DISCARDABLE
BEGIN
"\r\n"
"\0"
END #endif // APSTUDIO_INVOKED /////////////////////////////////////////////////////////////////////////////
//
// Menu
// MENUFILE MENU DISCARDABLE
BEGIN
MENUITEM "&New", IDM_FILE_NEW
MENUITEM "&Open...", IDM_FILE_OPEN
MENUITEM "&Save", IDM_FILE_SAVE
MENUITEM "Save &As...", IDM_FILE_SAVE_AS
END MENUEDIT MENU DISCARDABLE
BEGIN
MENUITEM "&Undo", IDM_EDIT_UNDO
MENUITEM SEPARATOR
MENUITEM "Cu&t", IDM_EDIT_CUT
MENUITEM "&Copy", IDM_EDIT_COPY
MENUITEM "&Paste", IDM_EDIT_PASTE
MENUITEM "De&lete", IDM_EDIT_CLEAR
END /////////////////////////////////////////////////////////////////////////////
//
// Bitmap
// BITMAPFONT BITMAP DISCARDABLE "Fontlabl.bmp"
BITMAPHELP BITMAP DISCARDABLE "Bighelp.bmp"
BITMAPEDIT BITMAP DISCARDABLE "Editlabl.bmp"
BITMAPFILE BITMAP DISCARDABLE "Filelabl.bmp"
#endif // English (U.S.) resources
///////////////////////////////////////////////////////////////////////////// #ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
// /////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED
第14章 位图和位块传输_14.4 GDI位图对象(2)的更多相关文章
- 第14章 位图和位块传输_14.4 GDI位图对象(3)
14.4.10 非矩形的位图图像 (1)“掩码”位图——单色位图,要显示的像素对应的掩码置1,不显示置0(2)光栅操作(点这里,见此文分析) (3)MaskBlt函数 ①MaskBlt(hdcDest ...
- 第14章 位图和位块传输_14.4 GDI位图对象(1)
14.4.1 创建DDB (1)创建 HBITMAP= CreateBitmap(cx,cy,cPlanes,cBitsPixel,lpBits); 参数 说明 cx,cy 指定位图宽度和高度,单位为 ...
- ASM:《X86汇编语言-从实模式到保护模式》第14章:保护模式下的特权保护和任务概述
★PART1:32位保护模式下任务的隔离和特权级保护 这一章是全书的重点之一,这一张必须要理解特权级(包括CPL,RPL和DPL的含义)是什么,调用门的使用,还有LDT和TSS的工作原理(15章着重 ...
- 【STM32H7教程】第56章 STM32H7的DMA2D应用之刷色块,位图和Alpha混合
完整教程下载地址:http://www.armbbs.cn/forum.php?mod=viewthread&tid=86980 第56章 STM32H7的DMA2D应用之刷色块, ...
- Linux就这个范儿 第14章 身在江湖
Linux就这个范儿 第14章 身在江湖 “有人的地方就有江湖”,如今的计算机世界就像一个“江湖”.且不说冠希哥有多么无奈,把微博当QQ的局长有多么失败,就说如此平凡的你我什么时候就成了任人摆布的羔羊 ...
- 【RL-TCPnet网络教程】第14章 RL-TCPnet之TCP客户端
第14章 RL-TCPnet之TCP客户端 本章节为大家讲解RL-TCPnet的TCP客户端实现,学习本章节前,务必要优先学习第12章TCP传输控制协议基础知识.有了这些基础知识之后,再搞本 ...
- 【二代示波器教程】第14章 uCOS-III操作系统版本二代示波器实现
第14章 uCOS-III操作系统版本二代示波器实现 本章教程为大家讲解uCOS-III操作系统版本的二代示波器实现.主要讲解RTOS设计框架,即各个任务实现的功能,任务间的通信方案选择,任 ...
- Java核心技术卷一基础知识-第14章-多线程-读书笔记
第 14 章 多线程 本章内容: * 什么是线程 * 中断线程 * 线程状态 * 线程属性 * 同步 * 阻塞队列 * 线程安全的集合 * Collable与Future * 执行器 * 同步器 * ...
- MySQL性能调优与架构设计——第 14 章 可扩展性设计之数据切分
第 14 章 可扩展性设计之数据切分 前言 通过 MySQL Replication 功能所实现的扩展总是会受到数据库大小的限制,一旦数据库过于庞大,尤其是当写入过于频繁,很难由一台主机支撑的时候,我 ...
随机推荐
- JavaScript数组与对象的关系
JavaScript的数组,相比其他语言,是比较特殊的.数组是Object类型,只不过,有几个比较特殊的地方: 有索引下标 有默认的length属性 是有序的(注意,对象是无序的) 可以使用一些特殊的 ...
- Chrome 控制台console的用法
下面我们来看看console里面具体提供了哪些方法可以供我们平时调试时使用. 目前控制台方法和属性有: ["$$", "$x", "dir" ...
- Sharepoint学习笔记—习题系列--70-576习题解析 -(Q72-Q74)
Question 72 You are designing a SharePoint 2010 application and a Web application. You need to desi ...
- Java虚拟机JVM学习06 自定义类加载器 父委托机制和命名空间的再讨论
Java虚拟机JVM学习06 自定义类加载器 父委托机制和命名空间的再讨论 创建用户自定义的类加载器 要创建用户自定义的类加载器,只需要扩展java.lang.ClassLoader类,然后覆盖它的f ...
- Android-Universal-Image-Loader 框架使用
1.Android-Universal-Image-Loader github下载地址 https://github.com/nostra13/Android-Universal-Image ...
- iOS 页面跳转传值,属性传值,代理传值,代码块传值,单例传值,通知传值
有时候我们在页面跳转的时候回传递相应的参数,如,你想把在第一个页面的文本框里的内容显示在第二个文本框中,或者你又想把第二个文本框中的内容改变之后到第一个页面的文本框中,所有,这个时候我们就要用到页面跳 ...
- C++语言-08-命名空间
概述 命名空间通常作为附加信息来区分不同库中相同名称的函数.类.变量.命名空间的本质是定义一个范围,该范围即为一个上下文,一个上下文中通常不允许出现相同名称的函数.类.变量. 定义 定义格式 普通的命 ...
- MyEclipse、Eclipse优化设置
第一步: 取消自动validation validation有一堆,什么xml.jsp.jsf.js等等,我们没有必要全部都去自动校验一下,只是需要的时候才会手工校验一下! 取消方法: windows ...
- [译] MYSQL索引最佳实践
近日整理文档时发现多年前的这个文档还是蛮实用的,然后在网络搜索了一下并没有相关的译文,所以决定把它翻译过来,如有不当的地方请多包涵和指正.原文地址:https://www.percona.com/fi ...
- Web API在OWIN下实现OAuth
OAuth(Open Authorization) 为用户资源的授权提供了一个安全的.开放而又简易的标准.与以往的授权方式不同之处是OAuth的授权不会使第三方触及到用户的帐号信息(如用户名与密码), ...