最近公司事情太多,一直没有时间再看看书,周末抽空看看。
Note:
1.子窗口向父窗口发送消息时,子窗口向父窗口发送WM_COMMAND消息。
其中LOWORD(wParam)为子窗口ID,HIWORD(wParam)为通知码,lParam为子窗口句柄
2.id = GetWindowLong(hwndChild,GWL_ID);//获取ID
id = GetDlgCtrlID(hwndChild);//同上
hwnd = GetDlgItem(hwndParent,ID);//获取句柄
3.SendMessage(hwndButton,BM_SETSTATE,1,0);//模拟鼠标按下按钮消息
SendMessage(hwndButton,BM_SETSTATE,0,0);//使鼠标恢复正常状态
4.WM_KILLFOCUS 消息的wParam是接受输入焦点的窗口句柄
WM_SETFOCUS消息的wParam是即将失去输入焦点的窗口句柄
通过处理WM_KILLFOCUS消息可以组织子窗口获得输入焦点
case WM_KILLFOCUS:
if(hwnd == GetParent((HWND)wParam))
SetFocus(hwnd);
return 0;
5.
Note:
1.SetTimer、KillTimer、WM_TIMER —— 三个关键字。
2.WM_TIMER并非异步消息,因此不能保证计时一定准确。
3.///////////////////////////////////////////////////////////////////////////////////////////////////
//将计时器消息发送给窗口
SetTimer(hwnd,uintTimerID,uims,NULL);
KillTimer(hwnd,uintTimerID);
WM_TIMER消息的wParam等于计时器的标志ID:uingTimerID
///////////////////////////////////////////////////////////////////////////////////////////////////
//通过回调函数处理计时器消息1
SetTimer(hwnd,uintTimerID,uims,TimerProc);
Void CALLBACK TimerProc(HWND hwnd,UINT message,UINT iTimerID,DWORD dwTime)
{
//Process your timerproc
}
///////////////////////////////////////////////////////////////////////////////////////////////////
//通过回调函数处理计时器消息2
iTimerID = SetTimer(NULL,0,uims,TimerProc);
Void CALLBACK TimerProc(HWND hwnd,UINT message,UINT iTimerID,DWORD dwTime)
{
//Process your timerproc
}
Note:
1.iMouse = GetSystemMetrics(SM_MOUSEPRESENT);//检查鼠标是否安装
cButtons = GetSystemMetrics(SM_CMOUSEBUTTONS);///检查鼠标键个数
wdnclass.hCursor = LoadCursor(NULL, IDC_ARROW);//指定窗口的默认光标
2.鼠标事件中lParam值包含了鼠标位置。
x = LOWORD(lParam);
y = HIWORD(lParam);
wParam值指示鼠标键及Shift及Ctrl键状态。
wParam&MK_SHIFT !=0 //说明按鼠标键时Shift键也按下了。
3.希望窗口接受到双击事件,需要设定窗口风格。
wndclass.style = CS_DBLCLKS;
4.非客户区鼠标消息。
NC not client,有此标记的大多为非客户区消息,如NCPAINT等。
wParam、lParam与客户区鼠标消息有区别。
wParam指明移动或者单击鼠标键的非客户区位置,WINUSER.h中以HT开头的标志符。
lParam高、低位分别表示y、x坐标,注意是屏幕的而不像客户区内消息的是客户区坐标,使用时需要装换。
ScreenToClient(hwnd,&pt);
ClientToScreen(hwnd,&pt);
5.WM_NCHITTEST
非客户区命中测试,此消息优先于所有其他的客户区和非客户区鼠标消息。其中lParam含有鼠标x、y值,wParam没有实际意义。对此消息的操作可以屏蔽所有鼠标消息,很强大。
6.Windows使用WM_NCHITTEST消息产生所有其他鼠标消息。
7.鼠标光标的操作
鼠标光标有个显示计数,通过ShowCursor(TRUE)增加,通过ShowCursor(FALSE)减少。GetCursorPos(&pt)获取光标位置。SetCursorPos(x,y)设置位置。
8.GetWindowLong(hwnd,GWL_HINSTANCE);//获取窗口的hinstance
9.GetCapture ReleaseCapture。获取、释放鼠标,即使鼠标不在当前窗口内。
ps:鼠标操作是当前Windows最为常用的操作之一,使用较为频繁,但是不难,较易理解。
Note:
1.键盘消息的处理分为2步:首先在系统消息队列中保存消息,然后将它们放入应用程序的消息队列,目的是为了同步。考虑键盘输入导致窗口焦点切换,若直接放到应用程序消息队列中可能切换后的窗口不再能够接受到键盘输入。
2.对产生可显示字符的击键组合,Window产生击键消息以及字符消息;对于不产生字符的键则只产生击键消息。
3.WM_KEYDOWN可能会重复发送,WM_KEYUP每次击键只会发生一次。
4.对于所有击键消息,wParam是击键代码,表示按下或释放的键;而lParam则包含属于击键的其他数据。
5.功能键的判断。
iState = GetKeyState(VK_SHIFT);
iState = GetKeyState(VK_CAPITAL);//根据iSate的不同位来查看
6.合理的键盘操作应该根据WM_CHAR、WM_DEADCHAR、WM_SYSCHAR、WM_STSDEADCHAR来进行,WM_KEYDOWN类消息有可能因为键盘布局的差异性出现错误。TranslateMessage消息从WM_KEYDOWN消息产生了字符消息。WM_CHAR消息夹在击键消息之间。DEADKEY基本上可以无视了。
如,巧了A键,产生的消息顺序为:WM_KEYDOWN | WM_CHAR | WM_KEYUP
7.规则:如果需要读取输入到窗口的键盘字符,处理WM_CHAR消息;如果需要读取光标键、功能键等,处理WM_KEYDOWN消息。
8.插入符函数。
CreateCaret、SetCaretPos、ShowCaret、HideCaret、DestroyCaret、GetCaretPos、GetCaretBlinkTime、SetCaretBlinkTime
一个消息队列只能支持一个插入符,所以不应该在窗口Create时创建Caret避免多个窗口的情况。只有获取焦点的窗口才应该有Caret很容易理解~~
HideCaret具有累积性,也就是说Hide了多少次就要Show多少次才能把Caret搞出来...
Note:
1.图形输出设备分为光棚设备和矢量设备。大部分pc输出设备都是光棚设备,即以点模式表示图像。矢量设备使用线来绘制图像,如绘图仪。使用矢量的程序是在硬件之上的一层抽象。
2.GDI函数的分类。
获取(创建)、释放(清除)设备描述表的函数,如GetDc,ReleaseDC;获取设备描述表信息的函数,如GetTextMetrics;绘图函数,如TextOut;设着和获取设备描述表参数的函数,如SetTextColor控制TextOut输出字颜色;使用GDI对象的函数,如CreatePen等。
3.图元。直线和曲线,由Pen画;填充区域;位图;文本;
4.设备描述表的获取方式:
1)hdc = BeginPaint(hwnd,&ps);
EndPaint(hwnd,&ps);
2)hdc = GetDC(hwnd); // Note:GetDC(NULL)获取整个屏幕的DC
ReleaseDC(hwnd,hdc);
3)hwd = GetWindowDC(hwnd);
ReleaseDC(hwnd,hdc);
4)hdc = CreateDC(lpszDriverName, lpszDeviceName, lpszOutput, lpInitData); // Note:CreateDC(_T("DISPLAY"),NULL,NULL,NULL)获取整个屏幕DC
DeleteDC(hdc);
5)hdcMem = CreateCompatibleDC(hdc); //使用位图时,可用内存设备描述表
DeleteDC(hdcMem);
6)hdcMeta = CreateMetaFile(pszFileName); //获取元文件设备描述表
hmf = CloseMetaFile(hdcMeta);
5.一个设备描述表通常就是一个物理显示设备。
iValue = GetDeviceCaps(hdc, iIndex); //根据iIndex获取dc的相关属性。
6.保存设备描述表。
wndclass.style = CS_OWNDC; //可以为窗口建立自己的DC,在修改DC之后DC一直有效直到EndPaint或者ReleaseDC。
idSaved = SaveDC(hdc);
//修改DC属性
RestoreDC(hdc,idSaved); //恢复保存的DC
上述语句等价于 SaveDC(hdc);
RestoreDC(hdc,-1);
7.画线。
影响画线的dc属性:当前画笔位置;画笔;背景方式;背景色;绘图模式。
画直线:
MoveToEx(hdc,xBeg,yBeg,NULL);
LineTo(hdc,xEnd,yEnd);
GetCurrentPositionEx(hdc,&pt);//获取当前位置
8.画笔。
HPEN hPen,hPenOld;
hPen = GetStockObject(WHITE_PEN); //获取现有画笔的句柄
hPenOld = SelectObject(hdc,hPen);//将画笔选进设备描述表,hPenOld记录老的画笔
//CreateOwnPen
HPEN hPen = CreatePen(iPenStyle,iPenWidth,crColor); // 一种方法
LOGPEN logpen;
HPEN hPen = CreatePenIndirect(&logpen);//另一种方法
DelectObject(SelectObject(hdc,hPen));//及时删除画笔,节省资源
//获取画笔信息
GetObject(hPen,sizeof(LOGPEN),(LPVOID)&logpen);//获取hPen属性
hPen = GetCurrenObject(hdc,OBJ_PEN);//获取当前dc中HPEN
//点画线和虚线的空隙填充,受dc的背景模式和背景色影响
SetBkColor(hdc,crColor);//设置背景颜色
SetBkMode(hdc,TRASPARENT);//TRANSPARENT组织填充背景,OPAQUE模式将用背景色填充空隙
//绘图方式
//画笔像素与目标位置处原来像素之间按位运算,叫做“光栅运算”ROP,画线只有二维,称为ROP2,有意思的东西。
SetROP2(hdc,iDrawMode);
iDrawMode=GetROP2(hdc);//默认为R2_COPYPEN,画笔色彩替代背景
9.填充区域。
Rectangle、Ellipse、RoundRect、Chord、Pie、Polygon、PolyPolygon
边界框画法跟画线一样、封闭区域使用HBRUSH填充。
HBRUSH hBrush = GetStockObject(WHITE_BURSH);
SelectObject(hdc,hBrush);
SelectObject(hdc,GetStockObject(NULL_PEN));//画无边界框
SelectObject(hdc,GetStockObject(NULL_BRUSH));//不填充区域
//多边形的填充方式有ALTERNATE和WINDING两种,区别很神奇。
10.画刷。
HBRUSH hBrush = CreateSolidBrush(crColor);//创建画刷
hBrush = CreateHatchBrush(iHatchStyle,crColor);//创建斜影画刷
hBrush = CreatePatternBrush/*CreateDIBPatternBrushPt*/; //创建基于位图的画刷
LOGBRUSH logBrush;
hBrush = CreateBrushIndirect(&logBrush);
//其余操作类似HPEN
11.GDI映射方式。
SetMapMode(hdc,iMapMode);
iMapMode = GetMapMode(hdc);
//至于其他相关映射方式,个人认为使用的可能性很小。
12.矩形、区域、剪裁。
FillRect(hdc,&rect,hBrush);//无需将hBrush选进hdc
FrameRect(hdc,&rect,hBrush); //用brush画矩形框,但不填充
InvertRect(hdc,&rect); //将矩形框中所有像素翻转
SetRect(&rect,xLeft,yTop,xRight,yBottom);
OffsetRect(&rect,x,y);//将矩形移动几个单元
InflateRect(&rect,x,y);//增减矩形的尺寸
SetRectEmpty(&rect);//矩形为0
CopyRect(&rcDest,&rcSrc);//拷贝
IntersectRect(&rcDest,&rcSrc1,&rcSrc2);//取两矩形交集
UnionRect(&rcDest,&rcSrc1,&rcSrc2);//取两矩形并集
bEmpty = IsRectEmpty(&rect);//确定是否为空
bInRect = PtInRect(&rect,Point);//点是否在矩形内
13.PeekMessage(&msg,NULL,0,0,PM_REMOVE);//大家伙,值得注意
The PeekMessage function normally does not remove WM_PAINT messages from the queue. WM_PAINT messages remain in the queue until they are processed. However, if a WM_PAINT message has a NULL update region, PeekMessage does remove it from the queue. —— 摘自MSDN 貌似跟书上说的有出入,需要注意
14.区域
HRGN hRgn = CreateRectRgn(xLeft,yTop,xRight,yBottom);
hRgn = CreateRectRgnIndirect(&rect);
hRgn = CreateEllipticRgn(xLeft,yTop,xRight,yBottom);
hRgn = CreateEllipticRgnIndirect(&rect);
iRgnType = CombineRgn(hDestRgn,hSrcRgn1,hSrcRgn2,iCombine);
//区域填充参数类似Rect
小结:
最近公司项目用到了大量画图操作,主要设计界面自画,重复的将bitmap贴到特定rect,设置透明色。作为windows程序设计,不可避免的都会涉及到自画控件的开发,而自画控件很大一部分工作就是改变控件的UI,画图基础可以让自己更好的理解代码,
Note:
1.WinMain进入循环之前,通常会有UpdateWindow来向窗口过程投放WM_PAINT消息。
2.触发WM_PAINT消息的事件:之前隐藏的窗口部分重新可见;改变窗口的大小;ScrollWindow或ScrollDC滚动客户区;InvalidRect或者InvalidRgn显示产生WM_PAINT消息;而Validate则会将WM_PAINT取消掉。
3.程序应该组织成可以保留绘制客户区需要的所有信息。
4.客户区无效区域、有效区域的理解,处理WM_PAINT时,窗口过程可以通过GetUpdateRect获取无效区域的坐标。
5.设备描述表总是与显示器上的特定窗口相关。
6.WM_ERASEBKGND处理无效区域的擦除,并利用WNDCLASS.hbrbackground中的刷子属性填充无效区域。
7.PAINTSTRUCT结构。
8.InvalidateRect(hwnd,NULL,TRUE)使整个客户区无效,并擦除背景,如果最后一个参数位FALSE则不擦除背景。
9.获取设备描述表的方法:
1) hdc = BeginPaint(hwnd,&ps);
EndPaint(hwnd,&ps); 此方法仅在无效区域上画图
2) hdc = GetDC(hwnd);
ReleaseDC(hwnd,hdc); 此方法可在客户端任何区域上画图,且不会使无效变有效。
GetWindowDC,返回整个窗口的设备描述表,可修改窗口标题等。
今天下午跟新,服务器出了问题,没提交上去,郁闷!后面的部分很重要,涉及到TextOut、ScrollBar等有用信息,以后提交时切记先保存再提交。