绿色风's Blog
专注AutoIT(Au3)
  • 首页
  • 流●年
  • 笔●记
    • 学习随记
    • 源码示例
  • 脚●本
    • UDF(收集)
    • 工作室UDF
    • 工具●教程
    • 教程之GDI
  • 作●品
  • 下●载
  • 情怀ExcelTip
12月92014

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

作者:绿色风   发布:2014-12-9 12:35 Tuesday   分类:   阅读:9000次   评论:0条  

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是非排除消息,直接发送到窗口过程中

未命名.PNG

2.PNG


本讲源码
把以保存为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://www.jianyiit.com/post-44.html

blogger
该日志由 绿色风 于2014-12-9 12:35 Tuesday发表在 分类下。
版权所有:《绿色风's Blog》 → 《[教程] 第八讲 GDI完全自绘控件,超链接控件》;
除特别标注,本博客很多文章均为原创. 互联分享,尊重版权,转载请以链接形式标明本文地址;
本文标签:

扫描二维码,在手机上阅读
上一篇::AU3中按时间排序杯举文件列表[秒开]
下一篇:[教程]第七讲 GDI自绘一个控件

热门文章

相关文章

  • [教程]第十四讲 GDI+图像之图元文件
  • AU3音频波谱图
  • [教程] 第十六讲 GDI+图像之图像属性项读取EXIF信息及缩略图读取
  • [教程]第三讲 GDI画笔、线型
  • [教程] 第六讲 GDI设置图像到控件
取消回复

发表评论

亲,头像对么?

39 + 93 =

提交中,请稍候……


木有头像就木JJ啦!还木有头像吗?点这里申请属于你的个性Gravatar头像吧!


    站点统计
    • 运行时间: 20254 天
    • 日志总数: 365 篇
    • 评论数量: 7237 条
    • 微语数量: 6 条
    • 附件总量: 388 件
  • 逝出的青春

  • 打赏"绿色风"



      扫码关注本站公众号 可搜本站内容

  • Autoit V3 脚本交流群

      常驻群1:905774875
      常驻群2:40672266


  • 链接

    • AU3中文论坛
    • Excel资料库
    • 完美者博客
    • 顺网小哥'S Blog
    • 猛牛哥的博客
    • 网吧系统下载
  • 分类

    • 流●年(66)
    • 笔●记(0)
    • 脚●本(0)
    • 作品(21)
    • 学习随记(51)
    • 源码示例(68)
    • UDF(收集)(26)
    • 工作室UDF(30)
    • 工具●教程(62)
    • 教程之GDI(24)
Copyright © 2013 绿色风's Blog. Powered by emlog. Theme by 射雕天龙. 鄂ICP备2021011689号-1 鄂公网安备42102302000078号 sitemap