找回密码
 加入
搜索
查看: 17981|回复: 11

[交流] 第八讲 GDI完全自绘控件,超链接控件

 火.. [复制链接]
发表于 2013-5-21 20:54:45 | 显示全部楼层 |阅读模式
本帖最后由 seniors 于 2013-6-16 07:59 编辑

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+最终一讲,我想试着看能不能举个自绘主窗口例子,努力争取了。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?加入

×

评分

参与人数 3威望 +2 金钱 +150 贡献 +19 收起 理由
xms77 + 50 + 5 学习中。。。楼主辛苦了~
lpxx + 50 + 11
afan + 2 + 50 + 3 +

查看全部评分

发表于 2013-5-21 21:13:40 | 显示全部楼层
等了好几天终于等到8啦,慢慢吸收消化。谢谢楼主,因为分享,所以快乐!
发表于 2013-5-21 23:40:47 | 显示全部楼层
回复 1# seniors

第八讲 终于漏出了小头梢
发表于 2013-5-22 10:09:59 | 显示全部楼层
占个位置,晚上回去学习~
发表于 2013-5-22 12:31:46 | 显示全部楼层
等着自绘360主窗口例子哈。。。
发表于 2013-5-22 18:45:39 | 显示全部楼层
回复 5# menfan1
S大的360自绘窗口不是早出来了么?
发表于 2013-5-22 21:03:30 | 显示全部楼层
受教受教了
发表于 2013-5-22 22:26:56 | 显示全部楼层

win7 是这样显示的

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?加入

×
 楼主| 发表于 2013-5-23 07:02:58 | 显示全部楼层
回复 8# xlcwxl
第7讲的能显示不?
win7就是一垃圾产品,从来不用,估计win7,win8就会像以前的win me一样
发表于 2013-10-4 11:58:24 | 显示全部楼层
回复 9# seniors

非常感谢楼主分享,正在学习中
发表于 2020-3-3 02:31:38 | 显示全部楼层
看了GDI好像又打开了一扇门,这个时间点了居然有点激动
发表于 2020-8-13 00:31:44 | 显示全部楼层
本帖最后由 kk_lee69 于 2020-8-13 00:36 编辑

有個問題 想提問  不曉得 放在這邊是否洽當
這個是 因為
https://www.autoitx.com/thread-72140-1-1.html

這個問題產生的......在解決這個問題前 找了很多資料 終於 找到官網的解決方案.....
https://www.autoitscript.com/forum/topic/182405-solved-set-headercolumn-color-in-listview/?tab=comments#comment-1310008

但是 這個解決方案卻留下了一個遺憾..........(這個是 LISTVIEW 的頭 上顏色 但是最後 如果拉動頭的部分,會出現頭的背景色是白色)


這個位置無法設定 背景設.......

繼續追查下去的 結果發現 好像使用 _WinAPI_CreateWindowEx 這個創建出來的控件 都無法設定背景色........

所以想請教專家  是否真的是這樣??...難道真的無法解決嗎??  
會想發在這邊是因為  這篇文章中  提到了 _WinAPI_CreateWindowEx  這個函數......
本想從 改變 _GUICtrlHeader_Create 函數,看看能不能加入 固定的背景色.....所已找到這邊來....

希望  老大如果有空  可以幫抽空看看 問題 是否可以解決..............

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?加入

×
您需要登录后才可以回帖 登录 | 加入

本版积分规则

QQ|手机版|小黑屋|AUTOIT CN ( 鲁ICP备19019924号-1 )谷歌 百度

GMT+8, 2024-4-18 09:36 , Processed in 0.077346 second(s), 21 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表