1. 鼠标的基础知识:

1) 一般Windows程序会为程序窗口中的每个按钮都分配一个键盘快捷键,但是鼠标的便利还是无法逾越的;

2) 双键鼠标的右键:一般用于打开一些特殊的菜单(即上下文菜单)或执行一些特殊的拖动,而上下文菜单就是指在普通菜单栏之外的窗口中的菜单;

3) 查看鼠标是否接上或者鼠标上一共有几个键:

GetSystemMetrics( SM_MOUSEPRESENT ); // 接上为TRUE否则为FALSE

GetSystemMetrics( SM_CMOUSEBUTTONS ); // 返回鼠标上键的个数,如果鼠标没接上则返回0

4) 鼠标指针及热点:

i) 鼠标指针指图像显示器上显示的一个鼠标的位图小图标;

ii) 热点是指该小图标上的一个但像素精度的点,真正指示了鼠标的位置;

iii) IDI_ARROW的热点是箭头顶点,IDI_CROSS的热点是十字中点;

5) 对鼠标的三种操作:

i) 单击:按下按钮然后松开;

ii) 双击:连续两次快速单击(中间时间间隔要小,该时间可以设定);

iii) 拖动:按下按钮不放,并移动鼠标;

2. 客户区鼠标消息:

1) Windows定义了21种鼠标消息,但是只有10种和客户区有关,其余11种应用程序经常忽略都交由DefWindowProc自动处理;

2) 鼠标消息和键盘消息的一个不同之处在于,键盘消息只有输入焦点才能接受,但是当鼠标经过窗口或者在窗口内击中即使该窗口不是焦点也会收到鼠标消息;

3) 罗列10种客户区鼠标消息,第一种是WM_MOUSEMOVE,当鼠标在窗口中移动时就会受到该消息(不管其是不是焦点窗口):

!!!注意:只有当wndclass.style里加了CS_DBLCLKS选项时才可以接受双键消息!

4) lParam:LOWORD中存放x坐标,HIWORD中存放y坐标;

5) wParam:存放此时鼠标的附加状态,以MK_为前缀的位掩码表示(检测的时候用位与&),表示Mouse Key,即鼠标键,有:

MK_LBUTTON: 按下了左键

MK_RBUTTON:按下了右键

MK_MBUTTON:按下了中键

MK_SHIFT:按下了Shift键

MK_CONTROL:按下了Ctrl键

6) 利用鼠标击键改变当前活动窗口:通过鼠标左击可以将非活动窗口变为活动窗口,即当窗口收到WM_LBUTTONDOWN消息时就可以安全的保证该窗口是活动窗口了;

介绍一种特殊情况,先在一个窗口左击,按下后拖到另一个窗口再释放,则第一个窗口会收到WM_LBUTTONDOWN消息但收不到WM_LBUTTONUP消息,但第二个窗口刚好相反,但是第一个窗口仍然是活动窗口(因为第一个窗口收到了WM_LBUTTONDOWN消息但是第二个没有);

7) 两个特殊的例外:

i) 捕获鼠标:即鼠标位于窗口之外也能捕获其鼠标消息(捕获技术后面会将);

ii) 模态对话框:当一个模块对话框被启动后其它任何程序都不能接受鼠标消息,必须现处理模态对话框并关闭后才能恢复正常;

8) 延时:系统不会为每个鼠标经过的像素都产生WM_MOUSEMOVE消息,具体产生多少个这样的消息取决于过程处理的速度,接下来的程序Connect将展示这一特性,程序为鼠标一次拖动所经过的所有位置两两之间连上线,你会发现如果拖动的慢几乎整个凸包(由鼠标经过的位置形成)多会被填充上黑色,但是如果拖动的快就会看出明显的连线痕迹,因为拖动慢则就能及时处理鼠标消息导致鼠标经过的每个像素都来得及处理,而拖动快则过程来不及处理每个经过的像素;

事实上Windows这样处理WM_MOUSEMOVE消息,消息队列中只能有一个WM_MOUSEMOVE消息,只要该消息没被处理就不会再向队列中假如WM_MOUSEMOVE消息了,所以能处理多少个WM_MOUSEMOVE消息取决于处理速度:

// connect.c#include <windows.h>// 追踪轨迹的最大点个数
// 拖动时间太长,轨迹太长的太耗内存
#define CMAXPOINTS      1000LRESULT CALLBACK WndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam );int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow )
{static TCHAR   szAppName[] = TEXT("connect");WNDCLASS   wndclass;HWND       hWnd;MSG            msg;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;RegisterClass( &wndclass );hWnd = CreateWindow(szAppName, TEXT("Connect-the-Points Mouse demo"),WS_OVERLAPPEDWINDOW,CW_USEDEFAULT, CW_USEDEFAULT,CW_USEDEFAULT, CW_USEDEFAULT,NULL, NULL, hInstance, NULL);ShowWindow( hWnd, nCmdShow );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 POINT   pt[CMAXPOINTS];static int       iCount; // 轨迹上的点数HDC                hdc;PAINTSTRUCT     ps;int      i, j;switch ( message ){case WM_LBUTTONDOWN: // 按下左键就代表一次重新开始iCount = 0;InvalidateRect( hWnd, NULL, TRUE ); // 队列重刷而不是立即重刷return 0;case WM_MOUSEMOVE: // 这里规定必须是鼠标左键拖动才行if ( wParam & MK_LBUTTON && iCount < CMAXPOINTS ){pt[iCount].x = LOWORD( lParam );pt[iCount].y = HIWORD( lParam );hdc = GetDC( hWnd );// 将轨迹上的点通过对像素点着色记录下来// 最后一个参数是COLORREF,0就是RGB( 0, 0, 0 )黑色SetPixel( hdc, pt[iCount].x, pt[iCount].y, 0 );ReleaseDC( hWnd, hdc );iCount++;}return 0;case WM_LBUTTONUP: // 释放后对轨迹上的点两两连线InvalidateRect( hWnd, NULL, FALSE ); // 背景不刷白,留下轨迹点return 0;case WM_PAINT: // 连线在重刷中进行// 当鼠标左键按下时iCount = 0,并且Invalidate为TRUE,因此一片空白,相当于重新开始hdc = BeginPaint( hWnd, &ps );SetCursor( LoadCursor( NULL, IDC_WAIT ) ); // 连线较慢设成等待图标ShowCursor( TRUE ); // 显示计数加1,显示计数开始默认为0,只有非负时才能显示鼠标// 因此现在显示计数为1了for ( i = 0; i < iCount; i++ )for ( j = i + 1; j < iCount; j++ ){MoveToEx( hdc, pt[i].x, pt[i].y, NULL );LineTo( hdc, pt[j].x, pt[j].y );}SetCursor( LoadCursor( NULL, IDC_CROSS ) ); // 连线完毕后将图标设回来ShowCursor( FALSE ); // 把显示计数减到0EndPaint( hWnd, &ps );return 0;case WM_DESTROY:PostQuitMessage( 0 );return 0;}return DefWindowProc( hWnd, message, wParam, lParam );
}

3. 处理Shift键和Control键:

有时需要监控按下鼠标键时Shift和Ctrl是否也被同时按下:

if ( wParam & MK_SHIFT )
{if ( wParam & MK_CONTROL ){[Shift + Ctrl]}else{[Shift]}
}
else
{if ( wParam & MK_CONTROL ){[Ctrl]}else{[No Key Down]}
}

4. 处理鼠标双击:

1) 双击的两个标准:

i) 位置标准:两次单击的位置间隔不超过一个平均系统字体宽度;

ii) 时间标准:两次单击间隔必须规定在一个特定时长范围内(该时长可以在控制面板中定义);

2) 开启双击功能,必须在wndclass.style中加上CS_DBLCLKS选项才行,这样才能接受WM_DBLCLK消息;

3) 接受双击和连续两次单击的区别:

i) 连续两次单击:

WM_LBUTTONDOWN

WM_LBUTTONUP

WM_LBUTTONDOWN

WM_LBUTTONUP

ii) 双击消息:

WM_LBUTTONDOWN

WM_LBUTTONUP

WM_LBUTTONDBLCLK

WM_LBUTTONUP

可以看到仅仅是将第二个WM_LBUTTONDOWN替换成了WM_LBUTTONDBLCLK,这样更符合逻辑,一般第一次单击执行和普通单击同样的功能,而第二个双击消息执行一些特殊功能,比如双击打开一个文件夹时第一次单击的作用就是选中(此时Windows会反向高亮显示该文件夹),第二次双击消息则打开该文件,这种逻辑非常简洁有效!

5. 非客户区鼠标消息:

1) 是指窗口内部,并且是客户区以外的区域中的鼠标消息,包括标题栏、菜单栏、滚条等等;

2) 一般非客户去的鼠标消息和系统键盘消息一样都交由DefWindowProc来处理;

3) 和客户区鼠标消息一样,非客户区鼠标消息也对应着10种消息,移动消息是WM_NCMOUSEMOVE,其中NC指的是NoneClient:

4) lParam和非客户区的相同,而wParm不再是鼠标键标记,而是位置信息,表示鼠标落在了那片区域中,比如标题栏、滚条、菜单按钮上等等,前缀为HT,即Hit Test,击中测试的意思,击中测试就是指测试击中的位置在哪个区域中,比如HTSYSMENU,就表示击中了系统菜单按钮的意思,由于击中的在非客户区,因此lParam中的坐标不在是客户区中的坐标,而是整个屏幕的坐标了!可以利用一下两个函数进行客户区和屏幕坐标之间的转换:

ScreenToClient( hwnd, &pt )和ClientToScreen( hwnd, &pt ),两个函数都会将原来pt中的坐标抹去换成新坐标,并且不备份原坐标!

当击中位置在客户区左上方时转换而成的客户区坐标为负的!

6. 击中测试以及消息产生消息机制:

1) 击中测试的概念:鼠标按下 -> 确定坐标 -> 根据坐标判断鼠标落在哪个区域

结束上述过程后就可以真正产生响应的精确的鼠标消息了,比如判断好了鼠标落在客户区,在可以产生WM_LBUTTONDOWN消息了,如果判断好了鼠标落在系统菜单上则可以产生WM_NCLBUTTONDOWN消息并且wParam为HTSYSMENU;

2) 事实上Windows是严格遵照上述过程的,这就要引出最后一种鼠标消息——WM_NCHTTEST消息,Windows由该消息产生其它所有的鼠标消息,这就是鼠标击中测试消息,用来完成1)中讲述的击中测试的过程,在产生任何一个精确的鼠标消息之前都是先产生WM_NCHTTEST消息的,该消息用于测试击中区域,因此wParam没用,只有lParam中的坐标有用,该坐标交由Windows来判断落在哪个区域(一般应用程序不响应都交由DefWindowProc来处理),比如判断好了落在客户区,则DefWindowProc返回HTCLIENT(表示击中了客户区),之后便自动产生一条WM_LBUTTONDOWN的消息插入消息队列中,如果判断好了落在系统菜单按钮上,则DefWindowProc返回HTSYSMENU,并产生一个WM_NCLBUTTONDOWN消息,并将该返回值作为消息的wParam,再将该消息插入到消息队列中去,因此击中消息是优先级最高的鼠标消息,用来产生所有客户区和非客户区的鼠标消息,这就是Windows其中一个消息产生消息的案例;

3) DefWindowProc处理WM_NCHTTEST消息的返回值可以是所有非客户区鼠标消息的wParam值也可以是HTCLIENT(击中客户区)、HTNOWHERE(不在任何窗口)、HTTRANSPARENT(击中了被另一个窗口遮住的窗口)、HTERROR(使DefWindowProc产生一个警示声),当击中客户区后Windows会将WM_NCHTTEST的屏幕坐标转化成客户区坐标产生客户区鼠标消息;

WM_NCHTTEST的坐标必定是屏幕坐标(以为逻辑上它属于非客户区鼠标消息)!

4) 屏蔽所有鼠标消息:

很简单,只要在应用程序中响应WM_WMNCHTTEST消息,并直接返回即可:

case WM_NCHTTEST: return ( LRESULT )HTNOWHERE;

这样不管是客户区还是非客户区都接收不到鼠标消息了,什么菜单、滚条、关闭按钮都将无效!

7. 一个简单的击中测试程序Checker:

将客户区划分成一个5×5的矩形区域,如果鼠标击中某个小区域,就在该区域中画叉,再次击中则叉消失:

// checker1.c#include <windows.h>// 分成5×5的区域
#define CDIVISIONS      5BOOL   fState[CDIVISIONS][CDIVISIONS]; // 记录各个区域的状态,有叉为1,空位0
int     cxBlock, cyBlock; // 记录区域的坐标LRESULT CALLBACK WndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lPram );
void DrawCross( HDC hdc, int x, int y ); // 画叉int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd )
{static TCHAR   szAppName[] = TEXT("checker1");WNDCLASS  wndclass;HWND       hWnd;MSG            msg;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;RegisterClass( &wndclass );hWnd = CreateWindow(szAppName, TEXT("Checker1"),WS_OVERLAPPEDWINDOW,CW_USEDEFAULT, CW_USEDEFAULT,CW_USEDEFAULT, CW_USEDEFAULT,NULL, NULL, hInstance, NULL);ShowWindow( hWnd, nShowCmd );UpdateWindow( hWnd );while ( GetMessage( &msg, NULL, 0, 0 ) ){TranslateMessage( &msg );DispatchMessage( &msg );}return msg.wParam;
}void DrawCross( HDC hdc, int x, int y )
{if ( !fState[x][y] ) // 白笔覆盖黑笔抹掉叉,不要费时非资源地重画{SelectObject( hdc, GetStockObject( WHITE_PEN ) );}MoveToEx( hdc, x * cxBlock, y * cyBlock, NULL );LineTo( hdc, ( x + 1 ) * cxBlock, ( y + 1 ) * cyBlock );MoveToEx( hdc, x * cxBlock, ( y + 1 ) * cyBlock, NULL );LineTo( hdc, ( x + 1 ) * cxBlock, y * cyBlock );if ( !fState[x][y] ) // 抹掉后要恢复黑笔,否则会影响其他区域的绘制{SelectObject( hdc, GetStockObject( BLACK_PEN ) );}
}LRESULT CALLBACK WndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
{HDC                hdc;PAINTSTRUCT     ps;int      x, y;switch ( message ){case WM_SIZE:cxBlock = LOWORD( lParam ) / CDIVISIONS;cyBlock = HIWORD( lParam ) / CDIVISIONS;return 0;case WM_LBUTTONDOWN:x = LOWORD( lParam ) / cxBlock;y = HIWORD( lParam ) / cyBlock;if ( x < CDIVISIONS && y < CDIVISIONS ) // 击中测试,确定落在哪个区域中{fState[x][y] ^= 1; // 状态改变hdc = GetDC( hWnd );DrawCross( hdc, x, y );ReleaseDC( hWnd, hdc );}elseMessageBeep( 0 ); // 击中了客户区以内但又没落在小格子中则蜂鸣警报// 即击中了边界区域return 0;case WM_PAINT:hdc = BeginPaint( hWnd, &ps );for ( x = 0; x < CDIVISIONS; x++ ) // 重绘了话需要绘制网格,并还原所有网格的状态for ( y = 0; y < CDIVISIONS; y++ ){Rectangle( hdc, x * cxBlock, y * cyBlock, ( x + 1 ) * cxBlock, ( y + 1 ) * cyBlock );DrawCross( hdc, x, y );}EndPaint( hWnd, &ps );return 0;case WM_DESTROY:PostQuitMessage( 0 );return 0;}return DefWindowProc( hWnd, message, wParam, lParam );
}

8. 加入键盘接口的Checker:

在checker1的基础上加入键盘接口,可以直接使用方向键控制鼠标,当使用方向键时鼠标只能落在小格子的中心,空格键和回车键可以模拟鼠标左击的功能;

当然,在使用方向键的时候需要获取鼠标的实际位置,并以该位置为参考坐标进行移动,此时需要用到GetCursorPos函数,参数为POINT指针,但是其没有hwnd参数,因此获得的坐标肯定跟窗口无关(即屏幕坐标),需要使用ScreenToClient函数转化成客户区坐标,同样当用键盘移动鼠标之后也需要显示鼠标的新位置,此时需要SetCursorPos函数,其有两个参数,分别为鼠标的x和y坐标,同样也没有hwnd参数,因此改坐标为屏幕坐标,所以需要使用ClientToScreen函数将客户区坐标转化成屏幕坐标再设置;

!!GetCursorPos函数是具有时效性的,即得到的是调用该函数时鼠标的坐标,而鼠标消息中的lParam存储的是产生该消息那一刻的坐标,这两个概念是不一样的,使用的时候一定要注意!

// checker2.c#include <windows.h>#define CDIVISIONS        5LRESULT CALLBACK WndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam );int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd )
{static TCHAR   szAppName[] = TEXT("checker2");WNDCLASS  wndclass;HWND       hwnd;MSG            msg;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;RegisterClass( &wndclass );hwnd = CreateWindow(szAppName, TEXT("Checker2 Mouse Hit-Test Demo"),WS_OVERLAPPEDWINDOW,CW_USEDEFAULT, CW_USEDEFAULT,CW_USEDEFAULT, CW_USEDEFAULT,NULL, NULL, hInstance, NULL);ShowWindow( hwnd, nShowCmd );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 BOOL        fState[CDIVISIONS][CDIVISIONS];static int       cxBlock, cyBlock;HDC                hdc;PAINTSTRUCT     ps;POINT        point;RECT      rect;int        x, y;switch ( message ){case WM_SIZE:cxBlock = LOWORD( lParam ) / CDIVISIONS;cyBlock = HIWORD( lParam ) / CDIVISIONS;return 0;case WM_SETFOCUS: // 考虑到没有鼠标接入电脑的情形// 如果没有鼠标接入电脑则显示计数值初始为-1// 所以在这种情况下也要支持鼠标的话就需要将显示计数值增加到非负才行ShowCursor( TRUE );return 0;case WM_KILLFOCUS:ShowCursor( FALSE );return 0;case WM_LBUTTONDOWN:x = LOWORD( lParam ) / cxBlock;y = HIWORD( lParam ) / cyBlock;if ( x < CDIVISIONS && y < CDIVISIONS ){fState[x][y] ^= 1;rect.left = x * cxBlock;rect.top = y * cyBlock;rect.right   = ( x + 1 ) * cxBlock;rect.bottom = ( y + 1 ) * cyBlock;InvalidateRect( hwnd, &rect, FALSE ); // 只刷新该方形区域,并且背景不重新抹}else{MessageBeep( 0 );}return 0;case WM_KEYDOWN: // 用键盘模拟鼠标的操作GetCursorPos( &point );ScreenToClient( hwnd, &point ); // 获取此时鼠标的位置并转化成客户区坐标// 这样就有了一个操作的起始位置,这样接下来的操作都是相对该起始位置的x = max( 0, min( CDIVISIONS - 1, point.x / cxBlock ) ); // 计算此时鼠标所在的方块区域y = max( 0, min( CDIVISIONS - 1, point.y / cyBlock ) );switch ( wParam ){case VK_UP: // 上下左右移动鼠标一格y--;break;case VK_DOWN:y++;break;case VK_LEFT:x--;break;case VK_RIGHT:x++;break;case VK_HOME:x = y = 0;break;case VK_END:x = y = CDIVISIONS - 1;break;case VK_RETURN: // 回车和空格模拟鼠标左击case VK_SPACE:SendMessage( hwnd, WM_LBUTTONDOWN, MK_LBUTTON, MAKELONG( x * cxBlock, y * cyBlock ) );// MAKELONG可以做一个32位值,低16位是第一个参数,高16位是第二个参数break;}// 越界的要跑到另一头x = ( x + CDIVISIONS ) % CDIVISIONS;y = ( y + CDIVISIONS ) % CDIVISIONS;// 通过键盘移动鼠标则把坐标都规整到格子的中心位置point.x = x * cxBlock + cxBlock / 2;point.y = y * cyBlock + cyBlock / 2;ClientToScreen( hwnd, &point ); // 转化成屏幕坐标再调整鼠标位置SetCursorPos( point.x, point.y );return 0;case WM_PAINT:hdc = BeginPaint( hwnd, &ps );for ( x = 0; x < CDIVISIONS; x++ )for ( y = 0; y < CDIVISIONS; y++ ){Rectangle( hdc, x * cxBlock, y * cyBlock, ( x + 1 ) * cxBlock, ( y + 1 ) * cyBlock );if ( fState[x][y] ){MoveToEx( hdc, x * cxBlock, y * cyBlock, NULL );LineTo( hdc, ( x + 1 ) * cxBlock, ( y + 1 ) * cyBlock );MoveToEx( hdc, x * cxBlock, ( y + 1 ) * cyBlock, NULL );LineTo( hdc, ( x + 1 ) * cxBlock, y * cyBlock );}}EndPaint( hwnd, &ps );return 0;case WM_DESTROY:PostQuitMessage( 0 );return 0;}return DefWindowProc( hwnd, message, wParam, lParam );
}

[Win32]鼠标的基本概念以及击中测试相关推荐

  1. Win32 鼠标消息 - 客户区鼠标消息、非客户区鼠标消息、击中测试、鼠标滚轮

    注:以下内容为学习笔记,多数是从书本.资料中得来,只为加深印象,及日后参考.然而本人表达能力较差,写的不好.因非翻译.非转载,只好选原创,但多数乃摘抄,实为惭愧.但若能帮助一二访客,幸甚! 注:以下内 ...

  2. 【办公类-13-04】20220709python模拟鼠标微信发消息(字典测试 给不同的人发不同的密码)01-简略版

    背景需求: 三年前,我接任信息员,前任信息员叮嘱--有网上的信息培训时,出于信息保密的需要,就需要将每位教师的登录账号和密码发给个人."把他们的账号密码截图发给他们哦",这就出现了 ...

  3. 单应矩阵(Homography)基本概念和代码测试

    简 介: 应用棋盘格图片或者相机图片中与标准棋盘格之间的单应矩阵.其中应用到opencv中的findChessboardCorners, findHomographys等函数. 这位利用单应矩阵进行下 ...

  4. 契约测试概念以及契约测试框架SCC VS PACT对比

    契约测试 基于契约,对消费者与生产者间的协作的验证, 本质上就是验证生产者所提供的内容是否满足消费者的期望. 契约测试在行业内,主要分为两种类型,消费者驱动的契约测试和生产者驱动的契约测试,最常见的就 ...

  5. MySQL基线测试概念_MySQL基线测试

    前言 其实MySQL基线测试已经不是什么新鲜的话题了,这应该是作为DBA的基本的技能了.大家都知道使用一些工具去做(sysbench.tpcc-mysql.tpc-c等等).本篇文章不是告诉你相关的工 ...

  6. NHibernate 状态的概念 以及 小测试

    在 NHibernate中有三种状态. 临时态(Transient):用new创建的对象,它没有持久化,没有纳入Session中,随时可以被垃圾回收,处于此状态的对象叫临时对象.特点:数据库中没有与之 ...

  7. Win32 鼠标绘图代码研究

    http://download.csdn.net/detail/u012313945/9534690 下面摘录绘图部分代码以供研究:winmain和相关窗口过程函数参阅相关资料: #include&l ...

  8. Win32消息集合----方便查阅

    // #include "AFXPRIV.H"//消息值的定义来源 #include "Dde.h"//DDE消息值的定义来源 #include "C ...

  9. 窗口发送消息参数详解

    窗口发送消息参数详解 //    窗口.发送消息    函数功能: 将指定的消息发送到一个窗口,同win32 api 里面的SendMessage等同的效果 中文函数原型: 发送消息(hwnd,msg ...

最新文章

  1. SQL2005 BCP
  2. android studio使用nodejs本地服务器json数据_使用Node.js的Alexa技巧
  3. 30kJava程序员升为全栈架构师的晋升之路
  4. 机器学习在金融风控实践经验
  5. latex如何使节标题居左_为使节构建控制平面的指南第3部分-特定于域的配置API...
  6. kmeans算法中的sse_聚类算法入门:k-means
  7. awk是命令还是编程语言
  8. Win32API 数据基本类型
  9. 07MySQL综合应用
  10. Data Structures[翻译]
  11. 计算机中哪些服务是可以禁止的,win10哪些服务可以禁用?优化win10系统服务的方法...
  12. 江阴:智慧融入城市血液,打造创新发展新名片
  13. 蜀山前传之二---------------第八回
  14. 微信新动作!加好友解除5000上限,扫码进群开放至200人
  15. 【庄碰辉】万般滋味,皆是生活常态
  16. 依赖注入和反转控制的区别
  17. Android使用MediaCodec和OpenGL对多段视频画面进行裁剪和拼接
  18. HTML如何设置复选框、单选框以及默认选项?
  19. 奥巴马筹款网站的制作过程
  20. 一文读懂——光纤通信技术

热门文章

  1. 2019联想创新科技大会:“端边云网智”一切就绪
  2. 向Linux增加一个系统调用或内核模块
  3. 计算机主板上的ide,计算机主板上的IDE接口通常是连接什么设备的数据接口?
  4. SQL学习之使用order by 按照指定顺序排序或自定义顺序排序
  5. php实现星座查询,php-十二星座查询系统(原创)
  6. 基于EFR32的Zigbee开发-介绍
  7. P1424 小鱼的航程(改进版)
  8. 泛型学习笔记:泛型使用的注意点、泛型在继承方面的体现、自定义泛型结构、泛型应用举例、通配符
  9. 大数据与编程语言关系
  10. 跟上学期给我们带过课的那个夹克男一样