第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 功能所实现的扩展总是会受到数据库大小的限制,一旦数据库过于庞大,尤其是当写入过于频繁,很难由一台主机支撑的时候,我 ...
随机推荐
- go语言 安装版 Windows7安装截图
这个比较简单的 一路next. 查看:解压版安装go. //http://www.cnblogs.com/osfipin/
- go语言最新版本 下载地址
国内官方网站无法打开.放在了百度云中,定期会更新: 链接:http://pan.baidu.com/s/1dD59duh 密码:46ek 备用地址:http://pan.baidu.com/s/1hq ...
- iOS UISlider的使用
UISlider是一个方便的控件,让用户能够以可视化的方式设置指定范围内的值. 和按钮一样,滑块也能响应事件,还可像文本框一样被读取.如果希望用户对滑块的调整立刻影响应用程序,则需要让他触发操作. 下 ...
- js基本算法:冒泡排序,二分查找
知识扩充: 时间复杂度:算法的时间复杂度是一个函数,描述了算法的运行时间.时间复杂度越低,效率越高. 自我理解:一个算法,运行了几次时间复杂度就为多少,如运行了n次,则时间复杂度为O(n). 1.冒泡 ...
- linux命令学习使用记录
1.文件批量重命名:把所有.xml文件重命名.txt,第一个参数为文件名中字符串,第二个参数为替换后文件名,第三个为当前目录文件列表 rename .xml .txt *.xml 2.解压不显示过程: ...
- 【Openlayers3】在地图上添加highcharts图表
今天试用了一下ol3,效果很是不错! ol3中有个ol.Overlay,使用这个类我们可以在地图中添加各种html要素. 下面我们在地图中添加一个饼图 html中添加一个div容器: <div ...
- 2016春招Android开发实习生(网易传媒)笔试
一.单选题 1.下列不属于网络层协议的为 TCP IP IPX ICMP 2.关于activity的状态恢复,错误的是 onSaveInstanceState中,activity会自动收集恢复view ...
- iOS runtime的理解和应用
项目中经常会有一些的功能模块用到runtime,最近也在学习它.对于要不要阅读runtime的源码,我觉得仅仅是处理正常的开发,那真的没有必要,只要把常用的一些函数看下和原理理解下就可以了. 但是如果 ...
- Mark一下,Android ListView的上下间隙
困扰很久的问题,怎么给ListView上下加padding,可以跟随滚动的那种 android:paddingTop="10dp" android:paddingBottom=&q ...
- Xcode 8.1 : Unable to read from device
今天升级了Xcode 8.1,准备在iOS10.0.2的iPhone 6 Plus上调试,提示:Unable to read from device. 查看文件路径:"~/Library/D ...