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

[教程]第七讲 GDI自绘一个控件

作者:绿色风   发布:2014-12-7 6:34 Sunday   分类:   阅读:6043次   评论:0条  

ACN论坛.讲师:seniors   转载请说明此文出处所在:<<简易工作室>>,谢谢!

GDI 之自绘一个控件
一、控件自绘,实际就是让自己来绘制控件,接管系统的绘制功能
有的控件绘制是用WM_DRAWITEM,有的是用WM_PAINT,有的用WM_NCPAINT
WM_NCPAINT窗口非客户区(框架)的自绘最复杂,因为框架上有三个系统按钮、窗口菜单有的找不到系统是在哪里绘制的
WM_DRAWITEM其实最终也应该是在WM_PAINT中绘制
WM_PAINT窗口客户区绘制,这一讲就用接管WM_PAINT来绘制一个链接地址控件
二、接管WM_PAINT
GUIRegisterMsg能接管到控件的WM_DRAWITEM,但接收不到控件的WM_PAINT
所以我们要用_WinAPI_SetWindowLong($hWnd, $GWL_WNDPROC, $ptrCallback),来设置窗口的自绘
$hWnd, 控件的句柄
$GWL_WNDPROC,说明是设置控件的窗口处理
$ptrCallback,指针指向处理窗口的函数

为此,我们要注册一个回调函数,使用
$hCallback = DllCallbackRegister("YourFunc", "int", "hWnd;uint;wparam;lparam")
再取得回调函数的指针
$ptrCallback = DllCallbackGetPtr($hCallback)

这三句话结合起来,就是说$hWnd这个控件的处理,我让"YourFunc"来处理
我们只需要在YourFunc中处理WM_PAINT消息就行了
在WM_PAINT消息处理中
我们要用_WinAPI_BeginPaint和_WinAPI_EndPaint获得DC和释放DC

这两个函数能可以删除消息队列中的WM_PAINT消息,并使无效区域有效。
_WinAPI_GetDC和_WinAPI_ReleaseDC并不删除WM_PAINT消息也不能使无效区域有效,因此当程序跳出WM_PAINT时,无效区域仍然存在。系统就会不断
发送WM_PAINT消息,于是程序不断处理WM_PAINT消息。

三、其它控制
链接地址控件还需要在鼠标hover时,显示下划线,所以还要处理鼠标移动的消息
同样只要在YourFunc中接管就行了
为了要记住鼠标有没有覆盖,所以我们加了一个全局变量$bHover
这样就带来一个问题,如果我的界面中有两个链接地址控件,那怎么办呢?

大家思考一下,这一讲界面上看就一行文字,其实处理过程中用了很多东西,大家慢慢体会。

下一讲,再讲多个同种控件的自绘

未命名.JPG

本节源码

#include <APIConstants.au3>
#include <WinAPIEx.au3>
Global $bHover = False
;注册回调函数
Global $hCallback = DllCallbackRegister("YourFunc", "int", "hWnd;uint;wparam;lparam");函数名,返回值,参数
Global $ptrCallback = DllCallbackGetPtr($hCallback)

GUICreate("第七讲", 300, 200)
Global $nlableId = GUICtrlCreateLabel("我是一个链接地址:", 10, 10)
Global $hlableWnd = GUICtrlGetHandle($nlableId)

;设置lable控件的处理函数,也就是所谓的控件子类化
Global $hOldProc = _WinAPI_SetWindowLong($hlableWnd, $GWL_WNDPROC, $ptrCallback)
GUISetState()

While 1
        $Msg = GUIGetMsg()
        Switch $Msg
                Case -3
                        ExitLoop
                Case $nlableId
                        ShellExecute("www.autoitx.com")
        EndSwitch
WEnd
GUIDelete()
Exit

Func YourFunc($hWnd, $iMsg, $wParam, $lParam)
        Switch $iMsg
                Case $WM_PAINT
                        Local $tPAINTSTRUCT;接收_WinAPI_BeginPaint返回的$tagPAINTSTRUCT结构,这结构内部参数我还不清晰
                        ;获取控件DC并消除WM_PAINT消息,这函数一定要用_WinAPI_EndPaint($hWnd, $tPAINTSTRUCT)解除
                        Local $hDC = _WinAPI_BeginPaint($hWnd, $tPAINTSTRUCT)
                        ;获取控件长高
                        Local $HWND_CX = _WinAPI_GetWindowWidth($hWnd)
                        Local $HWND_CY = _WinAPI_GetWindowHeight($hWnd)
                        Local $tRect = _WinAPI_CreateRect(0, 0, $HWND_CX, $HWND_CY);控件自绘,坐标总是控件窗口的坐标,和父窗口无关
;~                      _WinAPI_FillRect($hDC, DllStructGetPtr($tRect), _WinAPI_GetSysColorBrush($COLOR_3DFACE));用系统背景画刷清空背景

                        Local $sText = _WinAPI_GetWindowText($hWnd);获取窗口标题,就是lable上的文字
                        _WinAPI_SetTextColor($hDC, 0xFF0000);设置文字颜色
                        _WinAPI_SetBkMode($hDC, $TRANSPARENT);设置背景透明
                        ;获得系统默认字体
                        Local $hFont = _WinAPI_GetStockObject($DEFAULT_GUI_FONT)
                        If $bHover Then;如果鼠标覆盖的话,设置下划线字体
                                Local $tLOGFONT = DllStructCreate($tagLOGFONT)
                                Local $iSizeLOGFONT = DllStructGetSize($tLOGFONT)
                                Local $pLOGFONT = DllStructGetPtr($tLOGFONT)
                                _WinAPI_GetObject($hFont, $iSizeLOGFONT, $pLOGFONT);获取字体结构
                                DllStructSetData($tLOGFONT, "Underline", True);设置字体加下划线,False是没有下划线
                                $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, $tPAINTSTRUCT);返回,一定要用_WinAPI_EndPaint($hWnd, $tPAINTSTRUCT) 结束WM_PAINT
                Case $WM_MOUSEMOVE;鼠标覆盖
                        If Not $bHover Then;如果本来没有覆盖就设置覆盖标志,并重绘控件窗口
                                $bHover = True
                                _WinAPI_InvalidateRect($hWnd, 0, False);False是不擦除背景,因为加了一个下划线,本来的图案不影响我们
                        EndIf
                        _WinAPI_TrackMouseEvent($hWnd, 0x00000002);0x00000002是侦测鼠标离开客户区事件,如果离开则发送$WM_MOUSELEAVE消息,不加这一句是永远没有$WM_MOUSELEAVE消息的
                        ;TME_CANCEL 0x80000000
                        ;TME_HOVER 0x00000001
                        ;TME_LEAVE 0x00000002
                        ;TME_NONCLIENT 0x00000010
                        ;TME_QUERY 0x40000000
                Case $WM_MOUSELEAVE;鼠标离开
                        $bHover = False;离开则置覆盖标志为否
                        _WinAPI_InvalidateRect($hWnd, 0, True);重绘控件窗口,True为擦除背景,因为本来已经绘制了下划线,如果不擦除的话,则只写文字是遮挡不信下划线的,也就是一直能看到下划线
                        ;WM_PAINT收到重绘消息后,看到擦除背景为true,会先发出$WM_ERASEBKGND消息,再重绘
                        ;你也可以用false,那就要在WM_PAINT里清空背景,也就是WM_PAINT里注释掉的那句,这样下面的$WM_ERASEBKGND就不要了,我这里是演示用$WM_ERASEBKGND来擦除背景
                        ;你甚至可以在$WM_ERASEBKGND里画各种好看的背景
                Case $WM_ERASEBKGND
                        Local $hDC = $wParam
                        Local $HWND_CX = _WinAPI_GetWindowWidth($hWnd)
                        Local $HWND_CY = _WinAPI_GetWindowHeight($hWnd)
                        Local $tRect = _WinAPI_CreateRect(0, 0, $HWND_CX, $HWND_CY);控件自绘,坐标总是控件窗口的坐标,和父窗口无关
                        _WinAPI_FillRect($hDC, DllStructGetPtr($tRect), _WinAPI_GetSysColorBrush($COLOR_3DFACE));用系统背景画刷清空背景
                        Return 1
        EndSwitch
        Return _WinAPI_CallWindowProc($hOldProc, $hWnd, $iMsg, $wParam, $lParam);没有处理的消息让原先的处理程序处理
EndFunc   ;==>YourFunc```
 
    


 





本文固定链接: http://www.jianyiit.com/post-43.html

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

扫描二维码,在手机上阅读
上一篇::[教程] 第八讲 GDI完全自绘控件,超链接控件
下一篇:[教程] 第六讲 GDI设置图像到控件

热门文章

相关文章

  • [教程]第十讲之分解2-多色渐变画刷
  • [教程]第三讲 GDI画笔、线型
  • [教程]第十七讲 GDI+混合模式透明度
  • [教程]第十三讲 GDI+区域及剪切区域
  • [教程]第十四讲 GDI+图像之图元文件
取消回复

发表评论

亲,头像对么?

44 + 23 =

提交中,请稍候……


木有头像就木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