第14章 位图和位块传输_14.4 GDI位图对象(3)
14.4.10 非矩形的位图图像
(1)“掩码”位图——单色位图,要显示的像素对应的掩码置1,不显示置0
(2)光栅操作(点这里,见此文分析)
(3)MaskBlt函数
①MaskBlt(hdcDest, nXDest, nYDest, nWidth, nHeight, hdcSrc, nXSrc, nYSrc,hbmMask, xMask, yMask, dwRop);
②前景和背景:在由hbmMask指定的掩码中,数值1表示在那个位置应使用dwRop指定的前景光栅操作码。数值0表示应使用dwRop指定的背景光栅操作码。
③用MAKEROP4(fore,back)组合光栅操作码
【BitMask程序】
效果图
/*------------------------------------------------------------
BITMASK.C -- Bitmap Masking 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("BitMask");
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(LTGRAY_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("Bitmap Masking Demo"), // 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)
{
PAINTSTRUCT ps;
static int cxBitmap, cyBitmap, cxClient, cyClient;
static HINSTANCE hInstance;
static HBITMAP hBitmapImag, hBitmapMask;
HDC hdc, hdcMemImag, hdcMemMask;
BITMAP bitmap;
int x, y;
switch (message)
{
case WM_CREATE:
hInstance = ((LPCREATESTRUCT)lParam)->hInstance;
//加载原始图像并获取图像大小
hBitmapImag = LoadBitmap(hInstance, TEXT("Matthew"));
GetObject(hBitmapImag, sizeof(BITMAP), &bitmap);
cxBitmap = bitmap.bmWidth;
cyBitmap = bitmap.bmHeight;
//将原始图像选入内存DC
hdcMemImag = CreateCompatibleDC(NULL); //这里用NULL没关系,只要是借个DC来修改原始图像
SelectObject(hdcMemImag, hBitmapImag);
//创建单色掩码位图和内存DC
hBitmapMask = CreateBitmap(cxBitmap, cyBitmap, , , NULL); //单色cxBitmap*cybitmap像素位图
hdcMemMask = CreateCompatibleDC(NULL); //这里用NULL没关系,只要是借个DC来修改掩码位图
SelectObject(hdcMemMask, hBitmapMask);
//给掩码位图上色:矩形黑色,椭圆白色。
SelectObject(hdcMemMask, GetStockObject(BLACK_BRUSH));
Rectangle(hdcMemMask, , , cxBitmap, cyBitmap);
SelectObject(hdcMemMask, GetStockObject(WHITE_BRUSH));
Ellipse(hdcMemMask, , , cxBitmap, cyBitmap);
//遮罩原始图像,只显示椭圆内的图像
BitBlt(hdcMemImag, , , cxBitmap, cyBitmap,
hdcMemMask, , , SRCAND); //这里用“与”操作,只显示掩码为1的,但周围是黑色的。 DeleteDC(hdcMemImag); //可以删除,因为图像操作结果己保存在hBitmapImag中了。
DeleteDC(hdcMemMask); //可以删除,因为图像操作结果己保存在hBitmapMask中了。
return ;
case WM_SIZE:
cxClient = LOWORD(lParam);
cyClient = HIWORD(lParam);
return ;
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps); //
hdcMemImag = CreateCompatibleDC(hdc); //这里要显示在客户区了,不用要NULL
SelectObject(hdcMemImag, hBitmapImag);
hdcMemMask = CreateCompatibleDC(hdc);
SelectObject(hdcMemMask, hBitmapMask); x = (cxClient - cxBitmap) / ;
y = (cyClient - cyBitmap) / ;
////掩码位图,至此是一个外部黑色的,里面为白色的椭圆
//0x220326=D&(~S),让椭圆内部为黑,外部白色,再&D,此时屏幕上为一个黑色椭圆。
//BitBlt(hdc, x, y, cxBitmap, cyBitmap, hdcMemMask, 0, 0, 0x220326); //源和目标进行逻辑或运算,或的结果就是黑色,区域将源和目标重叠部分(椭圆区域)显示出来。
//BitBlt(hdc, x, y, cxBitmap, cyBitmap, hdcMemImag, 0, 0, SRCPAINT);
//以上两句也可以用MaskBlt代替:MAKEROP4(fore,back),掩码为1为前景,掩码为0的地方为背景。
//因掩码图椭圆外为黑色,内部白色。因此前景的地方直接拷贝照片相应的地方(SRCCOPY),
//背景的地方用画刷去刷(SRCPAINT)
MaskBlt(hdc, x, y, cxBitmap, cyBitmap, hdcMemImag, , , hBitmapMask, , , MAKEROP4(SRCCOPY, SRCPAINT));
DeleteDC(hdcMemImag);
DeleteDC(hdcMemMask);
EndPaint(hwnd, &ps);
return ; case WM_DESTROY:
PostQuitMessage();
return ;
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
//resource.h
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ 生成的包含文件。
// 供 BitMask.rc 使用
//
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 102
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1001
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif
//BitMask.rc
// Microsoft Visual C++ generated resource script.
//
#include "resource.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "winres.h"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// 中文(简体,中国) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS)
LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
TEXTINCLUDE
BEGIN
"resource.h\0"
END
TEXTINCLUDE
BEGIN
"#include ""winres.h""\r\n"
"\0"
END
TEXTINCLUDE
BEGIN
"\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Bitmap
//
MATTHEW BITMAP "Matthew.bmp"
#endif // 中文(简体,中国) resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED
(1)利用BitBlt在内存设备环境中画出小球
(2)通过计时器实现动画
【Bounce程序】
效果图
/*------------------------------------------------------------
BOUNCE.C -- Bouncing Ball Program
(c) Charles Petzold, 1998
------------------------------------------------------------*/
#include <windows.h>
#define ID_TIMER 1
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName[] = TEXT("Bounce");
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("Bouncing Ball"), // 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)
{
static HBITMAP hBitmap;
HDC hdc, hdcMem;
HBRUSH hBrush;
static int xPixel, yPixel, cxRadius, cyRadius, xCenter, yCenter, cxClient, cyClient,
cxTotal, cyTotal, cxMove, cyMove;
int iScale;
switch (message)
{
case WM_CREATE:
hdc = GetDC(hwnd);
xPixel = GetDeviceCaps(hdc, ASPECTX);
yPixel = GetDeviceCaps(hdc, ASPECTY);
ReleaseDC(hwnd, hdc);
SetTimer(hwnd, ID_TIMER, , NULL);
return ;
case WM_SIZE:
xCenter = (cxClient = LOWORD(lParam)) / ;
yCenter = (cyClient = HIWORD(lParam)) / ;
//小球的半径是客户区高、宽中较小一个的16分之一
iScale = min(cxClient*xPixel, cyClient*yPixel) / ;
cxRadius = iScale / xPixel;
cyRadius = iScale / yPixel;
//cxMove = 半径的1/2
cxMove = max(, cxRadius / );
cyMove = max(, cyRadius / );
//创建一个比球的尺寸多出半径一半的位图,目的是当图运动步长较小时,仍可以用后一张图
//覆盖住前一张,己实现擦图。
cxTotal = * (cxRadius + cxMove);
cyTotal = * (cyRadius + cyMove);
if (hBitmap)
DeleteObject(hBitmap);
hdc = GetDC(hwnd);
hdcMem = CreateCompatibleDC(hdc);
hBitmap = CreateCompatibleBitmap(hdc, cxTotal, cyTotal); //注意是hdc,而不是hdcMem
ReleaseDC(hwnd, hdc);
SelectObject(hdcMem, hBitmap);
//将整个位图填上白色(含边框)
Rectangle(hdcMem, -, -, cxTotal + , cyTotal + );
//创建球,内部用对角线填充
hBrush = CreateHatchBrush(HS_DIAGCROSS, RGB(, , ));
SelectObject(hdcMem, hBrush);
SetBkColor(hdcMem, RGB(, , ));
Ellipse(hdcMem, cxMove, cxMove, cxTotal - cxMove, cyTotal - cyMove);
DeleteDC(hdcMem);
DeleteObject(hBrush);
return ;
case WM_TIMER:
if (!hBitmap) break; hdc = GetDC(hwnd);
hdcMem = CreateCompatibleDC(hdc);
SelectObject(hdcMem, hBitmap);
BitBlt(hdc, xCenter - cxTotal / , yCenter - cyTotal / , cxTotal, cyTotal,
hdcMem, , , SRCCOPY);
DeleteDC(hdcMem);
ReleaseDC(hwnd, hdc);
xCenter += cxMove; //因为步长小,后一幅图大小仍会将前一张图球的那部分覆盖掉
yCenter += cyMove; //从而实现了擦图,如果步长大的话就会留下痕迹。
if ((xCenter + cxRadius >= cxClient) || (xCenter - cxRadius <= ))
cxMove = -cxMove;
if ((yCenter + cyRadius >= cyClient) || (yCenter - cyRadius <= ))
cyMove = -cyMove;
return ; case WM_DESTROY:
if (hBitmap) DeleteObject(hBitmap);
KillTimer(hwnd, ID_TIMER);
PostQuitMessage();
return ;
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
(1)GetDCEx:GetDCEx(HWND hWnd, HRGN hrgnClip, DWORD flags)
flags的值 |
|
DCX_WINDOW |
返回与窗口矩形而不是与客户矩形相对应 |
DXC_CACHE |
从高速缓存而不是从OWNDC或CLASSDC窗口中返回设备环境。从本质上覆盖CS_OWNDC和CS_CLASSDC |
DCX_PARENTCLIP |
使用父窗口的可见区域,父窗口的WS_CIPCHILDREN和CS_PARENTDC风格被忽略,并把设备DC环境的原点,设在由hWnd所标识的窗口的左上角 |
DCX_CLIPSIBLINGS |
排除hWnd参数所标识窗口上的所有兄弟窗口的可见区域 |
DCX_CLIPCHILDREN |
排除hWnd参数所标识窗口上的所有子窗口的可见区域 |
DCX_NORESETATTRS |
当设备DC环境被释放时,并不重置该DC的特性为缺省特性 |
DCX_LOCKWINDOWUPDATE |
即使在指定窗口被LockWindowUpdate的情况下也会绘制,该参数用于在跟踪期间进行绘制 |
DCX_EXCLUDERGN |
从返回设备DC环境的可见区域中排除由hrgnClip指定的剪切区域 |
DCX_INTERSECTRGN |
对hrgnClip指定的剪切区域与返回设备描述的可见区域作交运算 |
DCX_VALIDATE |
当与DCX_INTERSECTUPDATE一起指定时,致使设备DC文环境完全有效,该函数与DCX_INTERSECTUPDATE和DCX_VALIDATE一起使用时与使用BeginPaint函数相同。 |
【Scramble程序】——打乱桌面并自动恢复(利用锁定屏幕更新技术)
效果图
/*----------------------------------------------------------------
SCRAMBLE.C —— Scramble (and UnScramble) Screen
-----------------------------------------------------------------*/
#include <windows.h>
#define NUM 200
//注意,这个程序没有窗口过程,只能WinMain主函数
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PTSTR szCmdLine, int iCmdShow)
{
static int iKeep[NUM][];
HDC hdcSrc, hdcMem;
HBITMAP hBitmap;
HWND hwnd;
int cx, cy;
int x1, y1, x2, y2;
hwnd = GetDesktopWindow();
if (LockWindowUpdate(hwnd))
{
//GetDCEx的参数DCX_LOCKWINDOWUPDATE确保本程序在屏幕锁定期间仍可更新屏幕
hdcSrc = GetDCEx(hwnd, NULL, DCX_CACHE | DCX_LOCKWINDOWUPDATE);
hdcMem = CreateCompatibleDC(hdcSrc);
cx = GetSystemMetrics(SM_CXSCREEN) / ; //位图大小为屏幕的1/10
cy = GetSystemMetrics(SM_CYSCREEN) / ;
hBitmap = CreateCompatibleBitmap(hdcSrc, cx, cy);
SelectObject(hdcMem, hBitmap); srand((int)GetCurrentTime());
for (int i = ; i < ; i++)
for (int j = ; j < NUM; j++)
{
if (i == ) //打乱
{
//rand()产生0-RAND_MAX之间的数,其中RAND_MAX为0x7fff
//随机产生两个矩形并保存起来
iKeep[j][] = x1 = cx*(rand() % );
iKeep[j][] = y1 = cy*(rand() % );
iKeep[j][] = x2 = cx*(rand() % );
iKeep[j][] = y2 = cy*(rand() % );
} else //恢复时,要后面开始
{
x1 = iKeep[NUM - - j][];
y1 = iKeep[NUM - - j][];
x2 = iKeep[NUM - - j][];
y2 = iKeep[NUM - - j][];
} //交换两个矩形内的图像
BitBlt(hdcMem, , , cx, cy, hdcSrc, x1, y1, SRCCOPY); //第1张位图保存
BitBlt(hdcSrc, x1, y1, cx, cy, hdcSrc, x2, y2, SRCCOPY);//第2张位图复制到第1张的位置
BitBlt(hdcSrc, x2, y2, cx, cy, hdcMem, , , SRCCOPY); //从内存DC中复制第1张到第2张的位置
Sleep();
}
DeleteDC(hdcMem);
ReleaseDC(hwnd, hdcSrc);
DeleteObject(hBitmap);
LockWindowUpdate(NULL); //屏幕解锁
} return ;
}
(2)屏幕截图
①剪贴板中使用位图时,可以不是全局句柄,而直接使用位图句柄
②SetStretchBltMode(hdc, COLORONCOLOR);//缩小图片时,删除所有消除的像素行,不保留其信息
【BlowUp程序】——操作方法
①在客户区按下鼠标左键,鼠标变成十字形。
②在按键左键的同时,将指针移到屏幕任意地方,放在要截图位置的左上角。
③保持按住左键的同时,按下右键,并拖出一个矩形框(会反色显示)的右下角,再松开鼠标(松开顺序无关紧要)
④如果从右上角向左下角选取,可以得到左右相反图像。从左下向右上角选择会得到上下相反的图像。从右下向左上,会出现上下、左右都相反的图像。
效果图
/*------------------------------------------------------------
BLOWUP.C -- Video Magnifier Program (放大镜)
(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("BlowUp");
HWND hwnd;
MSG msg;
WNDCLASSEX wndclass;
HACCEL hAccel;
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("Blow-UP Mouse Demo"), // 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);
hAccel = LoadAccelerators(hInstance, szAppName);
while (GetMessage(&msg, NULL, , ))
{
if (!TranslateAccelerator(hwnd, hAccel, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return msg.wParam;
}
//将目标矩形内颜色取反,以表示被选中的区域
void InvertBlock(HWND hwndSrc, HWND hwnd, POINT ptBeg, POINT ptEnd)
{
HDC hdc;
hdc = GetDCEx(hwndSrc, NULL, DCX_CACHE | DCX_LOCKWINDOWUPDATE); //获屏幕DC并允许锁屏期间也可绘图
ClientToScreen(hwnd, &ptBeg); //因为屏幕捕获的原因,这里传进来的是客户区坐标
ClientToScreen(hwnd, &ptEnd);
PatBlt(hdc, ptBeg.x, ptBeg.y, ptEnd.x - ptBeg.x, ptEnd.y - ptBeg.y, DSTINVERT); //DSTINVERT:将目标矩形反向。
ReleaseDC(hwndSrc, hdc);
}
//复制位图
HBITMAP CopyBitmap(HBITMAP hBitmapSrc)
{
HBITMAP hBitmapDst; //目标位图
BITMAP bitmap;
HDC hdcSrc, hdcDst;
GetObject(hBitmapSrc, sizeof(BITMAP), &bitmap);
hBitmapDst = CreateBitmapIndirect(&bitmap);
hdcSrc = CreateCompatibleDC(NULL); //NULL,只是借助桌面DC来复制位图而己
hdcDst = CreateCompatibleDC(NULL); //NULL,只是借助桌面DC来复制位图而己
SelectObject(hdcSrc, hBitmapSrc);
SelectObject(hdcDst, hBitmapDst);
BitBlt(hdcDst, , , bitmap.bmWidth, bitmap.bmHeight, hdcSrc, , , SRCCOPY);
DeleteDC(hdcDst);
DeleteDC(hdcSrc);
return hBitmapDst; //hBitmapDst是局部变量,但这里是值拷贝,会复制一个
//hBitmapDst返回
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static BOOL bCapturing, bBlocking; //正在鼠标捕获和正在画矩形块
static POINT ptBeg, ptEnd;
static HBITMAP hBitmap;
HBITMAP hBitmapClip;
BITMAP bm;
static HWND hwndSrc;
HDC hdc, hdcMem;
PAINTSTRUCT ps;
RECT rect;
int iEnable;
switch (message)
{
case WM_CREATE: return ;
case WM_INITMENUPOPUP: //wParam:handle to menu; lparam:item position and indicator
iEnable = IsClipboardFormatAvailable(CF_BITMAP) ? MF_ENABLED : MF_GRAYED;
EnableMenuItem((HMENU)(wParam), IDM_EDIT_PASTE, iEnable); iEnable = hBitmap ? MF_ENABLED : MF_GRAYED;
EnableMenuItem((HMENU)(wParam), IDM_EDIT_COPY, iEnable);
EnableMenuItem((HMENU)(wParam), IDM_EDIT_CUT, iEnable);
EnableMenuItem((HMENU)(wParam), IDM_EDIT_CLEAR, iEnable);
return ;
case WM_COMMAND:
switch (LOWORD(wParam)) //菜单ID
{
case IDM_EDIT_CUT:
case IDM_EDIT_COPY:
if (hBitmap)
{
hBitmapClip = CopyBitmap(hBitmap);
OpenClipboard(hwnd);
EmptyClipboard();
SetClipboardData(CF_BITMAP, hBitmapClip); //位图时,可以是位图句柄,而不用全局句柄
if (LOWORD(wParam) == IDM_EDIT_COPY)
return ;
//剪切时,继续执行下云
}
case IDM_EDIT_CLEAR:
if (hBitmap)
{
DeleteObject(hBitmap);
hBitmap = NULL;
}
InvalidateRect(hwnd, NULL, TRUE);
return ;
case IDM_EDIT_PASTE:
if (hBitmap)
{
DeleteObject(hBitmap);
hBitmap = NULL;
}
OpenClipboard(hwnd);
hBitmapClip = GetClipboardData(CF_BITMAP); if (hBitmapClip)
{
hBitmap = CopyBitmap(hBitmapClip);
}
CloseClipboard();
InvalidateRect(hwnd, NULL, TRUE);
return ;
}
break;
case WM_LBUTTONDOWN:
if (!bCapturing)
{
hwndSrc = GetDesktopWindow();
if (LockWindowUpdate(hwnd)) //锁定屏幕更新
{
bCapturing = TRUE;
SetCapture(hwnd); //鼠标捕获
SetCursor(LoadCursor(NULL, IDC_CROSS));
} else MessageBeep();
}
return ; case WM_RBUTTONDOWN:
if (bCapturing)
{
bBlocking = TRUE;
ptBeg.x = LOWORD(lParam); //这里可以出现负坐标,从而导致截图不正常
ptBeg.y = HIWORD(lParam);
ptEnd = ptBeg;
InvertBlock(hwndSrc, hwnd, ptBeg, ptEnd);
}
return ;
case WM_MOUSEMOVE:
if (bBlocking)
{
InvertBlock(hwndSrc, hwnd, ptBeg, ptEnd);
ptEnd.x = LOWORD(lParam);
ptEnd.y = HIWORD(lParam);
InvertBlock(hwndSrc, hwnd, ptBeg, ptEnd);
}
return ;
case WM_LBUTTONUP:
case WM_RBUTTONUP:
if (bBlocking)
{
InvertBlock(hwndSrc, hwnd, ptBeg, ptEnd);
ptEnd.x = LOWORD(lParam); //这里可以出现负坐标,从而导致截图不正常
ptEnd.y = HIWORD(lParam);
if (hBitmap)
{
DeleteObject(hBitmap);
hBitmap = NULL;
}
hdc = GetDC(NULL); //这里应获取桌面DC,书本这里有误
ClientToScreen(hwnd, &ptBeg);
ClientToScreen(hwnd, &ptEnd);
hdcMem = CreateCompatibleDC(hdc);
hBitmap = CreateCompatibleBitmap(hdc,
abs(ptEnd.x - ptBeg.x), abs(ptEnd.y - ptBeg.y));
SelectObject(hdcMem, hBitmap);
StretchBlt(hdcMem, , , abs(ptEnd.x - ptBeg.x), abs(ptEnd.y - ptBeg.y),
hdc, ptBeg.x, ptBeg.y,
ptEnd.x - ptBeg.x, ptEnd.y - ptBeg.y, SRCCOPY);
DeleteDC(hdcMem);
DeleteDC(hdc);
InvalidateRect(hwnd, NULL, TRUE);
}
if (bBlocking || bCapturing)
{
bBlocking = bCapturing = FALSE;
SetCursor(LoadCursor(NULL, IDC_ARROW));
ReleaseCapture(); //释放鼠标捕获
LockWindowUpdate(NULL); //屏幕解锁
}
return ;
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);
if (hBitmap)
{
GetClientRect(hwnd, &rect);
hdcMem = CreateCompatibleDC(hdc);
SelectObject(hdcMem, hBitmap);
GetObject(hBitmap, sizeof(BITMAP), &bm);
//该模式删除所有消除的像素行,不保留其信息
SetStretchBltMode(hdc, COLORONCOLOR);
StretchBlt(hdc, , , rect.right, rect.bottom,
hdcMem, , , bm.bmWidth, bm.bmHeight, SRCCOPY); DeleteDC(hdcMem);
} EndPaint(hwnd, &ps);
return ; case WM_DESTROY:
if (hBitmap) DeleteObject(hBitmap);
PostQuitMessage();
return ;
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
//resource.h
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ 生成的包含文件。
// 供 BlowUp.rc 使用
//
#define IDM_EDIT_CUT 40001
#define IDM_EDIT_COPY 40002
#define IDM_EDIT_PASTE 40003
#define IDM_EDIT_CLEAR 40004
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 103
#define _APS_NEXT_COMMAND_VALUE 40010
#define _APS_NEXT_CONTROL_VALUE 1001
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif
//BlowUp.rc
// Microsoft Visual C++ generated resource script.
//
#include "resource.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "winres.h"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// 中文(简体,中国) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS)
LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
TEXTINCLUDE
BEGIN
"resource.h\0"
END
TEXTINCLUDE
BEGIN
"#include ""winres.h""\r\n"
"\0"
END
TEXTINCLUDE
BEGIN
"\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Menu
//
BlowUp MENU
BEGIN
POPUP "&Edit"
BEGIN
MENUITEM "Cu&t\tCtrl+X",
MENUITEM "&Copy\tCtrl+C",
MENUITEM "&Paste\tCtrl+V",
MENUITEM "De&lete\tDelete",
END
END
/////////////////////////////////////////////////////////////////////////////
//
// Accelerator
//
BlowUp ACCELERATORS
BEGIN
"^C", IDM_EDIT_COPY, ASCII, NOINVERT
"^V", IDM_EDIT_PASTE, ASCII, NOINVERT
VK_DELETE, IDM_EDIT_CLEAR, VIRTKEY, NOINVERT
"^X", IDM_EDIT_CUT, ASCII, NOINVERT
END
#endif // 中文(简体,中国) resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED
第14章 位图和位块传输_14.4 GDI位图对象(3)的更多相关文章
- 第14章 位图和位块传输_14.4 GDI位图对象(1)
14.4.1 创建DDB (1)创建 HBITMAP= CreateBitmap(cx,cy,cPlanes,cBitsPixel,lpBits); 参数 说明 cx,cy 指定位图宽度和高度,单位为 ...
- 第14章 位图和位块传输_14.4 GDI位图对象(2)
14.4.7 在位图上绘图 (1)在内存设备环境中绘图(与真实DC不同的是,内存DC的显示表面是个位图) (2)GetTextExtentPoint32函数:用于确定文本字符串的像素大小.(此大小就是 ...
- 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 功能所实现的扩展总是会受到数据库大小的限制,一旦数据库过于庞大,尤其是当写入过于频繁,很难由一台主机支撑的时候,我 ...
随机推荐
- atom编辑markdown之上传图片
01atom编辑markdown之上传图片 :first-child { margin-top: 0px; } .markdown-preview:not([data-use-github-style ...
- js方法实现rgb颜色转换成16进制格式的代码的方法
原文地址:http://www.cnblogs.com/vaal-water/archive/2013/04/08/3008880.html 自己试过很好用 function zero_fill_he ...
- arcgis server 下无法执行复杂的运算符
1.Open the Administrator Directory and log in as a user with administrative permissions to the site. ...
- DevExpress 2015.2发布 看看有哪些更新
下面是besy翻译的部分重要更新,要查看全部更新细节请访问英文官网. | 下载DevExpress 2015.2 Diagram Control 新的DevExpress Diagram Contro ...
- [Android]使用Kotlin+Anko开发Android(一)
以下内容为原创,欢迎转载,转载请注明 来自天天博客:http://www.cnblogs.com/tiantianbyconan/p/4800656.html Kotlin是由JetBrains开发 ...
- 腾讯bugly团队提供的android国内镜像
腾讯bugly团队提供的国内镜像 如果使用Android SDK Manager下载比较慢或者打不开,可以使用国内镜像 使用说明 http://android-mirror.bugly.qq.co ...
- equals()方法
equals()方法是根类Object中的一个方法,子类可以根据需要重写该方法(比如:String类). 一.Object类中的equals()方法实现如下: public boolean equal ...
- unity安卓和IOS读写目录
StreamingAssets文件夹下的只读不可写路径: 安卓读:filePath = Application.streamingAssetsPath + "/文件名.格式名"; ...
- 开发笔记之NSTable 排序
(1)第一步设置一下button IBOutlet NSButton * nameOrderBT; IBOutlet NSButton * sizeOrderBT; (2)切换设置切换相遇函数 -(I ...
- TFS2012 服务器安装
配置: 华硕Z97-A I7 4790K 2*2T 4*8G 操作系统: Win2012 标准 SN: DBGBW-NPF86-BJVTX-K3WKJ-MTB6V http://dinghuqiang ...