12月92014
[教程] 第八讲 GDI完全自绘控件,超链接控件
ACN论坛.讲师:seniors 转载请说明此文出处所在:<<简易工作室>>,谢谢!
GDI之完全自绘控件
一、注册窗口类
一个应用程序在创建某个类型的窗口(CreateWindow)前(注:控件都是窗口),必须首先注册“窗口类”(Windows Class,WNDCLASS)。注册了窗口类之后就可以生成这个类型的窗口。如果更改了窗口类,那么该类创建的所有窗口的属性都会发生变化。
完全自绘控件就是不使用系统已经定义的窗口类,而是使用自己定义的窗口类
$tWCEX = DllStructCreate($tagWNDCLASSEX);建立WNDCLASSEX结构 DllStructSetData($tWCEX, 'Size', DllStructGetSize($tWCEX));结构的大小 DllStructSetData($tWCEX, 'Style', 3);窗口类的风格,3是指CS_HREDRAW CS_VREDRAW窗口位置、宽、高变化时重绘 DllStructSetData($tWCEX, 'hWndProc', DllCallbackGetPtr($hProc));负责窗口的程序 ;hWndProc这个程序要全权负责好窗口的处理过程,它整个自给窗口的关键 DllStructSetData($tWCEX, 'ClsExtra', 0);窗口类的额外数据,0是没有 DllStructSetData($tWCEX, 'WndExtra', 0);窗口实例的额外数据,0是指没有 ;WndExtra就是_WinAPI_GetWindowLong($hWnd, $GWL_USERDATA)读取的窗口用户数据,如果有额外数据则设置为4,是指4个字节,所以是32位的数据 DllStructSetData($tWCEX, 'hInstance', $hInstance);当前实例句柄 DllStructSetData($tWCEX, 'hIcon', 0);窗口类的图标,因为是控件所以不要图标 DllStructSetData($tWCEX, 'hCursor', $hCursor);窗口类的鼠标 DllStructSetData($tWCEX, 'hBackground', 0);_WinAPI_GetSysColorBrush($COLOR_3DFACE));窗口类的背景画刷 DllStructSetData($tWCEX, 'MenuName', 0);窗口类的菜单 DllStructSetData($tWCEX, 'ClassName', _WinAPI_CreateString($ClassName, $tClass));窗口类名称 DllStructSetData($tWCEX, 'hIconSm', 0);窗口类的小图标 ```
这样再用_WinAPI_RegisterClassEx($tWCEX)注册窗口类,然后就可以使用自己定义的窗口类了
二、编写窗口处理进程
Func WndProc($hWnd, $iMsg, $wParam, $lParam) Switch $iMsg Case $WM_PAINT; ;这里写绘制的界面 Case $WM_MOUSEMOVE;鼠标覆盖 ;这里是鼠标侦测 Case $WM_MOUSELEAVE;鼠标离开 ;这里是鼠标离开的处理 ;这两个鼠标事件因为是记录下鼠标是覆盖还是离开所以需要一个参数来记录 ;这样就需要在创建控件时,给他一个参数,可以在WndExtra窗口实例额外数据中申请,我是本例中是用 ;_SetProp来建立额外参数,名字定为“UrlLableStata” Case $WM_LBUTTONDOWN;左键点击 ;左击处理 Case $WM_LBUTTONUP;左键释放 ;左键释放处理 ;你可以只处理点击,不是释放时处理,我喜欢释放时有动作 ;由于我举例是链接lable控件,本来系统中没有点击处理,所以需要自己定义一个窗口消息 ;上次我的自绘按钮控件,我是借用的按钮消息 Case $WM_DESTROY ;使用_SetProp建立的窗口实例额外数据在控件窗口删除时,一定要移除 ;_RemoveProp($hWnd, "UrlLableStata") EndSwitch EndFunc ;==>WndProc ```
三、自定义一个窗口消息
Global Const $WM_MYMESSAGE = _WinAPI_RegisterWindowMessage('MyMessage') ```
我们发送消息时可以把wParam设定为子窗口ID。
如果在该子窗口单击,那么lParam可以被设为1;
如果未在该子窗口上单击,那么lParam将被设为0。
我们在左键释放时要给父窗口发送消息,发送消息有两种方式
SendMessage和PostMessage的区别
PostMessage是排队消息,消息进入先进先出队列,一般鼠标键盘消息多是post方式
SendMessage是非排除消息,直接发送到窗口过程中
本讲源码
把以保存为DirUIUrlLable.au3
#include-once #include <Constants.au3> #include <APIConstants.au3> #include <GUIConstantsEx.au3> #include <WindowsConstants.au3> #include <UDFGlobalID.au3> #include <WinAPI.au3> #include <WinAPIEx.au3> ; 变量=================================================================================================================== Global $_ghDirUIUrlLableLastWnd;UDFGlobalID.au3要用到的变量 Global $DirUrlLableClick = 0x01;控件点击消息值 ; 常量=================================================================================================================== Global Const $__DirUIUrlLableCONSTANT_ClassName = "DirUIUrlLable" Global $__DirUIUrlLable_tClass;_WinAPI_CreateString要用到的变量 Global Const $WM_MYMESSAGE = _WinAPI_RegisterWindowMessage('MyMessage');自定义消息 Global Const $DirUIUrlLable_HOVER = 0x0001;鼠标覆盖事件标志,如果还要其它的标志,可以增加 ; 获取当前进程的模块句柄 $__DirUIUrlLable_hInstance = _WinAPI_GetModuleHandle(0) ; 创建类光标 $__DirUIUrlLable_hCursor = _WinAPI_LoadCursor(0, 32649);手形鼠标指针 ; 创建 DLL 回调函数 (窗口过程) $__DirUIUrlLable_hProc = DllCallbackRegister('__DirUIUrlLable_WndProc', 'lresult', 'hwnd;uint;wparam;lparam') ; 创建并填充 $tagWNDCLASSEX 结构 $__DirUIUrlLable_tWCEX = DllStructCreate($tagWNDCLASSEX) DllStructSetData($__DirUIUrlLable_tWCEX, 'Size', DllStructGetSize($__DirUIUrlLable_tWCEX)) DllStructSetData($__DirUIUrlLable_tWCEX, 'Style', 3) DllStructSetData($__DirUIUrlLable_tWCEX, 'hWndProc', DllCallbackGetPtr($__DirUIUrlLable_hProc)) DllStructSetData($__DirUIUrlLable_tWCEX, 'ClsExtra', 0) DllStructSetData($__DirUIUrlLable_tWCEX, 'WndExtra', 0) DllStructSetData($__DirUIUrlLable_tWCEX, 'hInstance', $__DirUIUrlLable_hInstance) DllStructSetData($__DirUIUrlLable_tWCEX, 'hIcon', 0) DllStructSetData($__DirUIUrlLable_tWCEX, 'hCursor', $__DirUIUrlLable_hCursor) DllStructSetData($__DirUIUrlLable_tWCEX, 'hBackground', _WinAPI_GetSysColorBrush($COLOR_3DFACE)) DllStructSetData($__DirUIUrlLable_tWCEX, 'MenuName', 0) DllStructSetData($__DirUIUrlLable_tWCEX, 'ClassName', _WinAPI_CreateString($__DirUIUrlLableCONSTANT_ClassName, $__DirUIUrlLable_tClass)) ;_WinAPI_CreateString作用是把字符串复制到内存,返回内存地址指针 DllStructSetData($__DirUIUrlLable_tWCEX, 'hIconSm', 0) ; 注册窗口类 _WinAPI_RegisterClassEx($__DirUIUrlLable_tWCEX) ;创建链接地址控件,函数返回值是窗口ID Func _DirUIUrlLable_Create($hWnd, $sText, $iX, $iY, $iWidth, $iHeight, $iStyle = -1, $iExStyle = -1) If Not IsHWnd($hWnd) Then Return SetError(1, 0, 0) EndIf If Not IsString($sText) Then Return SetError(2, 0, 0) EndIf ;上面是从其它控件的UDF中抄来的,如果你能保证调用准确,不要也行 Local $iForcedStyle = BitOR($WS_VISIBLE, $WS_CHILD);控件默认样式 If $iStyle = -1 Then $iStyle = $iForcedStyle Else $iStyle = BitOR($iStyle, $iForcedStyle) EndIf If $iExStyle = -1 Then $iExStyle = 0 Local $nCtrlID = __UDF_GetNextGlobalID($hWnd);寻找可用的ID分配给控件,这个UDF是从10000开始分配 If @error Then Return SetError(@error, @extended, 0) Local $hUrlLable = _WinAPI_CreateWindowEx($iExStyle, $__DirUIUrlLableCONSTANT_ClassName, $sText, $iStyle, $iX, $iY, $iWidth, $iHeight, $hWnd, $nCtrlID) ;$hUrlLable是控件句柄,你可以选择返回句柄或者ID ;下面三句是设置默认颜色,字体 Local $hFont = _WinAPI_GetStockObject($DEFAULT_GUI_FONT) __DirUIUrlLable__SetProp($hUrlLable, "deColor", 0xFFB206) __DirUIUrlLable__SetProp($hUrlLable, "deFont", $hFont) Return $nCtrlID;这里我选择返回控件ID EndFunc ;==>_DirUIUrlLable_Create ;设置链接地址控件颜色 Func _DirUIUrlLable_SetColor($hWnd, $nColor) If Not _WinAPI_IsClassName($hWnd, $__DirUIUrlLableCONSTANT_ClassName) Then Return SetError(2, 2, False) If IsHWnd($hWnd) Then __DirUIUrlLable__SetProp($hWnd, "deColor", $nColor) _WinAPI_InvalidateRect($hWnd, 0, False) EndIf Return EndFunc ;==>_DirUIUrlLable_SetColor ;设置链接地址控件字体,$hFont = _WINAPI_CREATEFONT返回值,使用完后应该自己清除字体 Func _DirUIUrlLable_SetFont($hWnd, $hFont) If Not _WinAPI_IsClassName($hWnd, $__DirUIUrlLableCONSTANT_ClassName) Then Return SetError(2, 2, False) If IsHWnd($hWnd) Then __DirUIUrlLable__SetProp($hWnd, "deFont", $hFont) _WinAPI_InvalidateRect($hWnd, 0, False) EndIf Return EndFunc ;==>_DirUIUrlLable_SetFont ;删除链接地址控件 Func _DirUIUrlLable_Destroy(ByRef $hWnd) If Not _WinAPI_IsClassName($hWnd, $__DirUIUrlLableCONSTANT_ClassName) Then Return SetError(2, 2, False) Local $Destroyed = 0 If IsHWnd($hWnd) Then If _WinAPI_InProcess($hWnd, $_ghDirUIUrlLableLastWnd) Then Local $nCtrlID = _WinAPI_GetDlgCtrlID($hWnd) Local $hParent = _WinAPI_GetParent($hWnd) $Destroyed = _WinAPI_DestroyWindow($hWnd) Local $iRet = __UDF_FreeGlobalID($hParent, $nCtrlID) If Not $iRet Then ; can check for errors here if needed, for debug EndIf Else ; Not Allowed to Destroy Other Applications Control(s) Return SetError(1, 1, False) EndIf Else $Destroyed = GUICtrlDelete($hWnd) EndIf If $Destroyed Then $hWnd = 0 Return $Destroyed <> 0 EndFunc ;==>_DirUIUrlLable_Destroy ;以下是UDF要用到的函数,一般用户不需调用 Func __DirUIUrlLable_WndProc($hWnd, $iMsg, $wParam, $lParam) Local $UrlLableStat = __DirUIUrlLable__GetProp($hWnd, "UrlLableStata") Local $bHover = BitAND($UrlLableStat, $DirUIUrlLable_HOVER) Switch $iMsg Case $WM_PAINT;处理绘制信息 Local $nColor = __DirUIUrlLable__GetProp($hWnd, "deColor") Local $hFont = __DirUIUrlLable__GetProp($hWnd, "deFont") Local $tPaint Local $hDC = _WinAPI_BeginPaint($hWnd, $tPaint) Local $HWND_CX = _WinAPI_GetWindowWidth($hWnd) Local $HWND_CY = _WinAPI_GetWindowHeight($hWnd) ;绘制控件底色,你也可以在$WM_ERASEBKGND中处理,在第七讲中就是在$WM_ERASEBKGND中处理的 Local $tRect = _WinAPI_CreateRect(0, 0, $HWND_CX, $HWND_CY) _WinAPI_FillRect($hDC, DllStructGetPtr($tRect), _WinAPI_GetSysColorBrush($COLOR_3DFACE)) ;写链接地址控件文字 _WinAPI_SetTextColor($hDC, $nColor) _WinAPI_SetBkMode($hDC, $TRANSPARENT) Local $sText = _WinAPI_GetWindowText($hWnd) If $bHover Then;如果是鼠标覆盖,就设置字体带下划线 Local $tLOGFONT = DllStructCreate($tagLOGFONT) Local $iSizeLOGFONT = DllStructGetSize($tLOGFONT) Local $pLOGFONT = DllStructGetPtr($tLOGFONT) _WinAPI_GetObject($hFont, $iSizeLOGFONT, $pLOGFONT) DllStructSetData($tLOGFONT, "Underline", True) $hUnderLineFont = _WinAPI_CreateFontIndirect($tLOGFONT) _WinAPI_SelectObject($hDC, $hUnderLineFont) _WinAPI_DrawText($hDC, $sText, $tRect, BitOR($DT_LEFT, $DT_SINGLELINE)) _WinAPI_DeleteObject($hUnderLineFont) Else;不是鼠标覆盖时,直接写 _WinAPI_SelectObject($hDC, $hFont) _WinAPI_DrawText($hDC, $sText, $tRect, BitOR($DT_LEFT, $DT_SINGLELINE)) EndIf Return _WinAPI_EndPaint($hWnd, $tPaint) Case $WM_MOUSEMOVE;鼠标覆盖,设置覆盖标志并重绘,侦测鼠标离开事件 If Not $bHover Then __DirUIUrlLable__SetProp($hWnd, "UrlLableStata", BitOR($UrlLableStat, $DirUIUrlLable_HOVER)) _WinAPI_InvalidateRect($hWnd, 0, False) EndIf _WinAPI_TrackMouseEvent($hWnd, 0x00000002) Case $WM_MOUSELEAVE;鼠标离开,去除覆盖标志并重绘 __DirUIUrlLable__SetProp($hWnd, "UrlLableStata", BitXOR($UrlLableStat, $DirUIUrlLable_HOVER)) _WinAPI_InvalidateRect($hWnd, 0, False) Case $WM_LBUTTONDOWN;左键点击 ; Case $WM_LBUTTONUP;左键释放 _WinAPI_PostMessage(_WinAPI_GetParent($hWnd), $WM_MYMESSAGE, _WinAPI_GetDlgCtrlID($hWnd), $DirUrlLableClick) ;给父窗口发送自定义消息$WM_MYMESSAGE,WP是控件ID,LP是鼠标点击 Case $WM_DESTROY ;控件窗口删除时,一定要移除 __DirUIUrlLable__RemoveProp($hWnd, "deColor") __DirUIUrlLable__RemoveProp($hWnd, "deFont") __DirUIUrlLable__RemoveProp($hWnd, "UrlLableStata") EndSwitch ;其它事件交给默认窗口程序处理 Return __DirUIUrlLable__DefWindowProc($hWnd, $iMsg, $wParam, $lParam) EndFunc ;==>__DirUIUrlLable_WndProc Func __DirUIUrlLable__DefWindowProc($hWnd, $iMsg, $wParam, $lParam) Local $iResult = DllCall("User32.dll", "lresult", "DefWindowProcW", "hwnd", $hWnd, "long", $iMsg, "wparam", $wParam, "lparam", $lParam) Return $iResult[0] EndFunc ;==>__DirUIUrlLable__DefWindowProc Func __DirUIUrlLable__GetProp($hWnd, $sProperty) Local $iResult = DllCall("User32.dll", "long", "GetPropW", "hwnd", $hWnd, "wstr", $sProperty) Return $iResult[0] EndFunc ;==>__DirUIUrlLable__GetProp Func __DirUIUrlLable__SetProp($hWnd, $sProperty, $vData) Local $iResult = DllCall("User32.dll", "bool", "SetPropW", "hwnd", $hWnd, "wstr", $sProperty, "long", $vData) Return $iResult[0] EndFunc ;==>__DirUIUrlLable__SetProp Func __DirUIUrlLable__RemoveProp($hWnd, $sProperty) Local $iResult = DllCall("User32.dll", "bool", "RemovePropW", "hwnd", $hWnd, "wstr", $sProperty) Return $iResult[0] EndFunc ;==>__DirUIUrlLable__RemoveProp ```
以下是使用的程序
#include "DirUIUrlLable.au3" GUIRegisterMsg($WM_MYMESSAGE, "WM_MYMESSAGE") $FatherWnd = GUICreate("第八讲", 300, 200) $Link1 = _DirUIUrlLable_Create($FatherWnd, "我是默认的链接样式", 10, 10, 200, 20) $Link2 = _DirUIUrlLable_Create($FatherWnd, "颜色不同的链接样式", 10, 40, 200, 20) _DirUIUrlLable_SetColor(_WinAPI_GetDlgItem($FatherWnd, $Link2), 0x0066CC) ;由于创建函数返回值是ID,所以必须要用_WinAPI_GetDlgItem来获得句柄,所以自绘控件返回句柄比较方便 $Link3 = _DirUIUrlLable_Create($FatherWnd, "我是大字的链接样式", 10, 70, 200, 20) $hFont = _WinAPI_CreateFont(16, 0) _DirUIUrlLable_SetFont(_WinAPI_GetDlgItem($FatherWnd, $Link3), $hFont) GUISetState() While 1 $Msg = GUIGetMsg() Switch $Msg Case -3 ExitLoop EndSwitch WEnd _WinAPI_DeleteObject($hFont) GUIDelete() Exit Func WM_MYMESSAGE($hWnd, $iMsg, $wParam, $lParam) Switch $wParam Case $Link1 ShellExecute("www.autoitx.com") Case $Link2 ShellExecute("http://www.autoitx.com/thread-38578-1-1.html") Case $Link3 ShellExecute("www.autoitx.com") EndSwitch EndFunc ;==>WM_MYMESSAGE ```下讲开始先把GDI放一下,虽然还有很多没讲,下一讲开始讲GDI+,使用GDI+最终一讲,我想试着看能不能举个自绘主窗口例子,努力争取了。
本文固定链接: http://jianyiit.com/post-44.html
扫描二维码,在手机上阅读
发表评论
木有头像就木JJ啦!还木有头像吗?点这里申请属于你的个性Gravatar头像吧!