WIN98特殊窗口的动态拖动
宋立波
WIN98中常居顶层的无标题条窗口是一种特殊的窗口,典型实例有IME输入法应用程序、UCWIN平台、各种浮动工具箱、OFFICE桌面工具栏等。
一、命令检测与光标动态提示
这种窗口拖动一般分为两种:特定客户命令区域和非特定客户命令区域。特定客户命令区域是指利用"RECT"定义的特定子矩形区域;非特定客户命令区域是指没有明确定义的窗口客户区域部分,即所有特定客户命令区域之外的部分。实现该功能的首要问题是如何检测和处理特定客户命令区域和非特定客户命令区域内的鼠标命令,以及如何利用鼠标光标来动态提示用户何时可以进行窗口的拖动操作。
1、特定客户命令区域检测鼠标命令
要在窗口中设置实现拖动功能的图标命令按钮,就必须在资源文件中定义命令按钮的特定客户区域,该区域一般也就是命令按钮图标的矩形区域,这个区域的定义方法为"RECT DragRT",其中DragRT为定义的检测鼠标命令的矩形区域,它用DragRT.LEFT、DragRT.TOP、DragRT.RIGHT和DragRT.BOTTOM四个参数来描述矩形区域相对于窗口客户区域左上角的相对坐标值。也可用"SETRECT"函数填充。
窗口函数在处理鼠标消息WM_LBUTTONDOWN时,当收到系统传递的鼠标位置参数lParam后,通过MAKEPOINT()函数将其转换为窗口坐标值,然后利用判断某坐标点是否位于特定矩形区域内的函数PtInRect(),判断出鼠标指针是否点击在拖动命令按钮之内。
2、非特定客户命令区域检测鼠标命令
当窗口应用程序中采取了非特定客户命令区域拖动方法时,必须在资源文件中事先确定各个特定客户命令区域的矩形坐标,这时非特定客户命令区域是不规则的区域,它需要根据实际的应用程序窗口及各个命令按钮矩形区域来确定,也就是各个命令按钮矩形区域相对于窗口矩形区域的“非”子集。窗口函数在处理鼠标消息WM_LBUTTONDOWN时,首先利用函数PtInRect()判断当前鼠标指针是否点击在各个命令按钮矩形区域内,如果未点击在任何命令按钮区域内,则可确定鼠标点击在非特定客户命令区域内,从而启动窗口拖动功能。
3、窗口拖动功能的光标动态提示
实现鼠标光标动态提示功能前需要定制鼠标光标形状,窗口拖动功能的动态提示光标形状一般为四箭头图案,这可以利用微软公司的SDK、FPT3.0和VC++4.1等高级开发软件中的资源编辑器"IMAGE EDIT"等来实现。光标资源文件一般为32X32的2色或16色.CUR图形文件。建立起自己的鼠标光标资源文件后,首先需要在应用程序的资源文件中定义鼠标光标,然后在应用程序中利用LoadCursor()调入,并在类中进行设置:wc.hCursor=hCurm。
当鼠标光标需要在窗口的特定客户命令按钮区域内或非特定客户命令区域内进行动态提示时,不能使用上述定义方法,而需要在窗口函数处理WM_MOUSEMOVE消息时进行特殊处理:首先判断鼠标光标指针的当前位置是否在拖动命令按钮或非特定客户命令区域内,如果鼠标指针位置满足拖动窗口功能区域的要求,则利用API函数SETCURSOR()改变鼠标光标图案,提示用户此时可以进行窗口拖动操作,并将鼠标输入控制权交给当前窗口,同时设置改变后的鼠标光标标志;当鼠标指针移出拖动窗口命令启动区域时,恢复原来鼠标光标图案同时释放鼠标输入焦点控制权,并清除鼠标光标动态提示标志单元。
二、动态拖动框的定制
窗口拖动前的关键问题是鼠标拖动窗口过程中的拖动框显示与擦除功能实现。窗口拖动虚框就是在WINDOWS 整个屏幕区域内显示被拖动窗口大小的线框,它的大小需要根据被拖动窗口的矩形区域大小和实际需要来具体确定,一般为被拖动窗口的矩形区域大小。
WINDOWS系统中的绘图方法是通过显示设备描述表实现的,绘图操作需要占用一定的GDI资源。WINDOWS 95中的GDI资源要比WINDOWS3.X中的GDI资源大得多,所以系统可以为窗口、菜单、对话框、字体和各种绘图函数分配足够的GDI资源。WINDOWS中有两种使用显示设备描述符表的方法:更新窗口显示客户区域和直接操作窗口显示客户区域。更新窗口显示客户区域是直接针对应用程序窗口矩形区域而言的,在窗口函数响应WM_PAINT消息时利用图形操作命令进行窗口更新处理:
InvalidateRect(hWnd,&WinRECT,TRUE);//WinRECT为要更新区域
UpdateWindow(hWnd);
窗口初始建立时默认为更新窗口的全部区域,当要更新的矩形区域为NULL时表示更新窗口所有矩形区域。函数UpdateWindow()通知系统向要更新矩形区域的窗口发送WM_PAINT消息,窗口函数接收到WM_PAINT消息后首先利用BeginPaint()函数取得设备描述符表,然后利用图形命令直接对显示设备进行更新操作,最后利用EndPaint()函数通知系统更新操作结束。
更新窗口矩形区域直接使用窗口类中定义的屏幕画刷,即使利用SelectObject()函数选择相应屏幕画刷也无效,而且更新矩形区域范围是通过InvalidateRect()函数累加的,由UpdateWindow()函数通知系统开始进行窗口更新操作。整个过程是由系统来调度的,因此使用这种方法无法实现窗口的拖动虚框绘制和实时操作。
直接操作窗口客户区域的方法是利用GetDC()函数直接取得显示设备句柄,利用各种图形操作命令直接对显示设备进行绘图。它使用屏幕当前设置的画笔和画刷来实现各种图形绘制操作,无须向系统传递任何消息应用程序就可以实时地对屏幕窗口进行更新和绘图操作。其操作过程是首先取得显示设备描述符句柄hDC=GetDC(hWnd),当hWnd 参数为NULL时取得的是整个屏幕的设备描述符表句柄,然后利用SelectObject()函数设置当前屏幕的画笔和画刷,利用各种画图函数完成屏幕的绘图操作,最后利用ReleaseDC()函数释放获取的设备描述表。如果利用画矩形函数Rectangle()实现虚框,那么在设置当前屏幕画笔的同时必须使用SelectObject(hDC,GetStockObject(NULL_BRUSH))屏蔽掉任何屏幕画刷,否则WINDOWS程序会很快吞筮掉所有GDI资源,相当于在屏幕设备资源中增加了无数矩形区域。
对于窗口拖动框的擦除操作,只需在拖动框绘制函数中将屏幕的图形画笔操作方式设置为R2_XORPEN异或方式,即SetROP2(hDC2,R2_XORPEN)。在拖动框绘制结束时注意恢复,在窗口拖动框移动到下一个位置前,在原屏幕位置重新调用绘制函数一次将原来拖动框擦除(见程序1)。
//利用画矩形函数实现拖动实框(由于篇幅画线、画点函数省略)
void DrawMoveRect(int xx1,int yy1,int xx2,int yy2,int xy)
{ HDC hDC;
int oldrop2,m,k;
hDC = GetDC(NULL); //取得全屏幕设备描述句柄
oldrop2= GetROP2(hDC); //取得原来屏幕画图方式
SetROP2(hDC,R2_XORPEN); //设置异或屏幕画图方式
SelectObject(hDC,GetStockObject(NULL_BRUSH));//屏蔽画刷
SelectObject(hDC2,GetStockObject(WHITE_PEN));//选择画笔
for (k=0;k
本文地址:http://com.8s8s.com/it/it3790.htm