ExcelHome技术论坛

 找回密码
 免费注册

QQ登录

只需一步,快速开始

快捷登录

搜索
EH技术汇-专业的职场技能充电站 妙哉!函数段子手趣味讲函数 Excel服务器-会Excel,做管理系统 效率神器,一键搞定繁琐工作
HR薪酬管理数字化实战 Excel 2021函数公式学习大典 Excel数据透视表实战秘技 打造核心竞争力的职场宝典
让更多数据处理,一键完成 数据工作者的案头书 免费直播课集锦 ExcelHome出品 - VBA代码宝免费下载
用ChatGPT与VBA一键搞定Excel WPS表格从入门到精通 Excel VBA经典代码实践指南
查看: 7310|回复: 26

[原创] 纯代码实现窗体Listview控件网格线颜色、行高和选中行颜色的设置

  [复制链接]

TA的精华主题

TA的得分主题

发表于 2023-3-25 00:01 | 显示全部楼层 |阅读模式
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
本帖最后由 ivccav 于 2023-3-25 13:49 编辑

之前写过3篇关于Listview控件的帖子(如下),阅读人数还挺多,其中一帖阅读量10W+,该控件受欢迎程度可见一斑。
随着64位Office开始支持Listview控件,我想需要了解该控件使用的需求只会更大。

VBA窗体Listview控件完全教程
https://club.excelhome.net/thread-1424969-1-1.html

用NM_CUSTOMDRAW自定义绘制技术实现Listview控件隔行换色
https://club.excelhome.net/thread-1428537-1-1.html

窗体Listview控件实现可编辑功能的完美解决方法
https://club.excelhome.net/thread-1423746-1-1.html


虽然曾经写过“完全教程”,但有一个问题始终没有解决,即Listview控件的网格线颜色无法设定。
我在微软官网查阅了很多NM_CUSTOMDRAW内容,找不到设置网格线颜色的内容。NM_CUSTOMDRAW用于设置每行交替色是很方便的,代码简单。

众所周知,控件绘制可有三种方式:

1.处理 WM_PAINT消息
这是最极端的方式,执行一个 WM_PAINT 处理程序,并且自己完成所有的绘制工作。这意味着代码将需要进行一些与呈现控件相关的琐事 — 创建适当的设备上下文(一个或多个),决定控件的大小和位置,绘制控件等。在绘制过程中,很少需要这种级别的控件。

2.所有者绘制(OwnerDraw)
控制控件绘制的第2种方法是所有者绘制,它是用于开发自定义控件最普通的技术。该技术普遍使用的主要原因在于,系统可为提供很多帮助。在呈现控件的之前,Windows已经创建并填写了设备上下文,决定了控件的大小和位置,并且向您传递信息以使您了解此刻绘制的需求。对于列表控件(例如Listbox和Listview等),Windows将为列表中的每一项调用绘制代码,这意味着您只需绘制这些项,而无需考虑控件的其他方面。这里的”Owner”可以理解为控件类的派生类。

如何启用控件的OwnerDraw属性呢?对于ListView控件,可以设置LVS_OWNERDRAWFIXED风格。
使用OwnerDraw方式,我们需要处理WM_MEASUREITEM和WM_DRAWITEM消息。
如果要设置每行行高,只能使用OwnerDraw方式绘制,且只有在收到WM_MEASUREITEM消息时能进行设置。
设置行高在MEASUREITEMSTRUCT结构体的ItemHeight成员中设置。

Private Type MEASUREITEMSTRUCT
    CtlType                         As Long
    CtlID                           As Long
    itemID                          As Long
    itemWidth                       As Long
    ItemHeight                      As Long
    itemData                        As Long
End Type
所有者绘制(OwnerDraw)方式主要处理WM_DRAWITEM消息对Item和Subitem进行边框绘制。

3.自定义绘制(CustomDraw)
CustomDraw不需要设置风格。只需在接收到NM_CUSTOMDRAW通知时(借由WM_NOTIFY消息)给父窗口。控件的父窗口可以选择处理或不处理此通知。在CustomDraw场景下,控件的大部分绘制工作还是由系统默认完成,我们只是在系统绘制之前或者之后对控件的呈现进行某种方式的”微调”。比如,我们可以使用CustomDraw机制来修改ListView控件中的项目背景色,文字的前景或背景色等。在控件绘制的整个阶段中,系统划分了一系列不同的阶段,开发者设置了感兴趣的阶段后,系统就会在每个开发者感兴趣的阶段发送NM_CUSTOMDRAW通知。当我们收到NM_CUSTOMDRAW通知的时候,我们可以根据通知中的DrawStage知道当前绘制的阶段。具体可看微软官方文档。

本帖使用的是第二种方式。代码来源于网络,是VB6环境下写的一个类模块。如果直接放在VBA中运行,会导致应用软件直接崩溃。我修改了少量参数,让其可以在VBA中正常运行,并针对在VBA中无法触发WM_MEASUREITEM消息导致无法设置行高的问题,写了触发该消息的子过程。还写了应用示例。

该类的接口如下:

image.png

应用实际效果图:

aaaa.png

1024.gif


附件下载见10楼:

64位API声明参考:
https://club.excelhome.net/thread-1656964-1-1.html


评分

5

查看全部评分

TA的精华主题

TA的得分主题

 楼主| 发表于 2023-3-25 00:27 | 显示全部楼层
本帖最后由 ivccav 于 2023-3-27 09:08 编辑



完整源代码和应用案例:







纯代码实现窗体Listview控件网格线颜色、行高和选中行颜色的设置.zip (117.06 KB, 下载次数: 530)

评分

5

查看全部评分

TA的精华主题

TA的得分主题

 楼主| 发表于 2023-3-25 00:06 | 显示全部楼层

新建一个类模块,取名为:CCustomListView


结构体、枚举和常量声明:
  1. Private Type TRACKMOUSEEVENTTYPE
  2.     cbSize                          As Long
  3.     dwFlags                         As Long
  4.     hwndTrack                       As Long
  5.     dwHoverTime                     As Long
  6. End Type

  7. Private Type tSubData
  8.     hwnd                            As Long
  9.     nAddrSub                        As Long
  10.     nAddrOrig                       As Long
  11.     nMsgCntA                        As Long
  12.     nMsgCntB                        As Long
  13.     aMsgTblA()                      As Long
  14.     aMsgTblB()                      As Long
  15. End Type

  16. Private Enum eMsgWhen
  17.     [MSG_AFTER] = &H1
  18.     [MSG_BEFORE] = &H2
  19.     [MSG_BEFORE_AND_AFTER] = MSG_AFTER Or MSG_BEFORE
  20. End Enum

  21. Private Const ALL_MESSAGES          As Long = &HFFFF
  22. Private Const CODE_LEN              As Long = &HC5
  23. Private Const GWL_WNDPROC           As Long = &HFFFC
  24. Private Const PATCH_04              As Long = &H58
  25. Private Const PATCH_05              As Long = &H5D
  26. Private Const PATCH_08              As Long = &H84
  27. Private Const PATCH_09              As Long = &H89

  28. Private Type RECT
  29.     Left                            As Long
  30.     Top                             As Long
  31.     Right                           As Long
  32.     Bottom                          As Long
  33. End Type

  34. Private Type MEASUREITEMSTRUCT
  35.     CtlType                         As Long
  36.     CtlID                           As Long
  37.     itemID                          As Long
  38.     itemWidth                       As Long
  39.     ItemHeight                      As Long
  40.     itemData                        As Long
  41. End Type

  42. Private Type DRAWITEMSTRUCT
  43.     CtlType                         As Long
  44.     CtlID                           As Long
  45.     itemID                          As Long
  46.     itemAction                      As Long
  47.     itemState                       As Long
  48.     hwndItem                        As Long
  49.     hdc                             As Long
  50.     rcItem                          As RECT
  51.     itemData                        As Long
  52. End Type

  53. Private Type NMHDR
  54.     hWndFrom                        As Long
  55.     idFrom                          As Long
  56.     Code                            As Long
  57. End Type

  58. Private Type NMCUSTOMDRAW
  59.     hdr                             As NMHDR
  60.     dwDrawStage                     As Long
  61.     hdc                             As Long
  62.     rc                              As RECT
  63.     dwItemSpec                      As Long
  64.     uItemState                      As Long
  65.     lItemlParam                     As Long
  66. End Type

  67. Private Type NMLVCUSTOMDRAW
  68.     nmcd                                As NMCUSTOMDRAW
  69.     clrText                             As Long
  70.     clrTextBk                           As Long
  71.     iSubItem                            As Long
  72. End Type

  73. Private Type LVITEM
  74.     mask                                As Long
  75.     iItem                               As Long
  76.     iSubItem                            As Long
  77.     state                               As Long
  78.     stateMask                           As Long
  79.     pszText                             As Long
  80.     cchTextMax                          As Long
  81.     iImage                              As Long
  82.     lParam                              As Long
  83.     iIndent                             As Long
  84. End Type


  85. Private Type HDITEM
  86.     mask                                As Long
  87.     cxy                                 As Long
  88.     pszText                             As Long
  89.     hbm                                 As Long
  90.     cchTextMax                          As Long
  91.     fmt                                 As Long
  92.     lParam                              As Long
  93.     iImage                              As Long
  94.     iOrder                              As Long
  95.     type                                As Long
  96.     pvFilter                            As Long
  97.     state                               As Long
  98. End Type

  99. Private Const WM_NCDESTROY              As Long = &H82
  100. Private Const WM_MEASUREITEM            As Long = &H2C
  101. Private Const WM_DRAWITEM               As Long = &H2B

  102. Private Const LVM_FIRST                 As Long = &H1000
  103. Private Const LVM_GETHEADER             As Long = (LVM_FIRST + 31)
  104. Private Const LVM_GETITEMTEXTA          As Long = (LVM_FIRST + 45)

  105. Private Const LVS_OWNERDRAWFIXED        As Long = &H400

  106. Private Const LVIF_TEXT                 As Long = &H1

  107. Private Const DT_LEFT                   As Long = &H0
  108. Private Const DT_TOP                    As Long = &H0
  109. Private Const DT_CENTER                 As Long = &H1
  110. Private Const DT_RIGHT                  As Long = &H2
  111. Private Const DT_VCENTER                As Long = &H4
  112. Private Const DT_BOTTOM                 As Long = &H8
  113. Private Const DT_SINGLELINE             As Long = &H20
  114. Private Const DT_END_ELLIPSIS           As Long = &H8000&

  115. Private Const DCB_ACCUMULATE        As Long = &H2
  116. Private Const DCB_DISABLE           As Long = &H8
  117. Private Const DCB_ENABLE            As Long = &H4
  118. Private Const DCB_RESET             As Long = &H1
  119. Private Const DCB_SET               As Long = (DCB_RESET Or DCB_ACCUMULATE)

  120. Private Const HDM_FIRST                 As Long = &H1200
  121. Private Const HDM_GETITEMCOUNT          As Long = (HDM_FIRST + 0)
  122. Private Const HDM_GETITEMA              As Long = (HDM_FIRST + 3)
  123. Private Const HDM_GETITEMRECT           As Long = (HDM_FIRST + 7)

  124. Private Const HDI_FORMAT                As Long = &H4

  125. Private Const HDF_LEFT                  As Long = 0
  126. Private Const HDF_RIGHT                 As Long = 1
  127. Private Const HDF_CENTER                As Long = 2

  128. Private Const GWL_STYLE                 As Long = (-16)

  129. Private Const PS_SOLID                  As Long = 0

  130. Private Const ODT_LISTVIEW              As Long = 102
  131. Private Const ODS_SELECTED              As Long = &H1
复制代码


TA的精华主题

TA的得分主题

 楼主| 发表于 2023-3-25 00:08 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册



API和模块变量声明

  1. Private Declare Function FreeLibrary Lib "kernel32" (ByVal hLibModule As Long) As Long
  2. Private Declare Function GetModuleHandleA Lib "kernel32" (ByVal lpModuleName As String) As Long
  3. Private Declare Function GetProcAddress Lib "kernel32" (ByVal hModule As Long, ByVal lpProcName As String) As Long
  4. Private Declare Function GlobalAlloc Lib "kernel32" (ByVal wFlags As Long, ByVal dwBytes As Long) As Long
  5. Private Declare Function GlobalFree Lib "kernel32" (ByVal hMem As Long) As Long
  6. Private Declare Function LoadLibraryA Lib "kernel32" (ByVal lpLibFileName As String) As Long
  7. Private Declare Sub RtlMoveMemory Lib "kernel32" (Destination As Any, Source As Any, ByVal Length As Long)
  8. Private Declare Function SetWindowLongA Lib "user32" (ByVal hwnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
  9. Private Declare Function LoadLibrary Lib "kernel32.dll" Alias "LoadLibraryA" (ByVal lpLibFileName As String) As Long
  10. Private Declare Function VirtualProtect Lib "kernel32" (lpAddress As Any, ByVal dwSize As Long, ByVal flNewProtect As Long, lpflOldProtect As Long) As Long

  11. Private Declare Function TrackMouseEvent2 Lib "comctl32.dll" Alias "_TrackMouseEvent" (ByRef lpEventTrack As TRACKMOUSEEVENTTYPE) As Long ' Win95 w/ IE 3.0
  12. Private Declare Function TrackMouseEvent Lib "user32.dll" (ByRef lpEventTrack As TRACKMOUSEEVENTTYPE) As Long ' Win98 or later

  13. Private Declare Function LocalAlloc Lib "kernel32" (ByVal wFlags As Long, ByVal wBytes As Long) As Long
  14. Private Declare Function LocalFree Lib "kernel32" (ByVal hMem As Long) As Long

  15. Private Declare Function SetBoundsRect Lib "gdi32" (ByVal hdc As Long, lprcBounds As RECT, ByVal flags As Long) As Long
  16. Private Declare Function GetBoundsRect Lib "gdi32" (ByVal hdc As Long, lprcBounds As RECT, ByVal flags As Long) As Long
  17. Private Declare Function IntersectRect Lib "user32" (lpDestRect As RECT, lpSrc1Rect As RECT, lpSrc2Rect As RECT) As Long
  18. Private Declare Function IsRectEmpty Lib "user32" (lpRect As RECT) As Long
  19. Private Declare Function SetRect Lib "user32" (lpRect As RECT, ByVal X1 As Long, ByVal Y1 As Long, ByVal X2 As Long, ByVal Y2 As Long) As Long
  20. Private Declare Function InflateRect Lib "user32" (lpRect As RECT, ByVal x As Long, ByVal y As Long) As Long
  21. Private Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long) As Long
  22. Private Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
  23. Private Declare Function GetClientRect Lib "user32" (ByVal hwnd As Long, lpRect As RECT) As Long

  24. Private Declare Function GetParent Lib "user32" (ByVal hwnd As Long) As Long
  25. Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
  26. Private Declare Function FillRect Lib "user32" (ByVal hdc As Long, lpRect As RECT, ByVal hBrush As Long) As Long
  27. Private Declare Function InvalidateRect Lib "user32" (ByVal hwnd As Long, lpRect As Any, ByVal bErase As Long) As Long
  28. Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long
  29. Private Declare Function GetObject Lib "gdi32" Alias "GetObjectA" (ByVal hObject As Long, ByVal nCount As Long, lpObject As Any) As Long
  30. Private Declare Function DeleteObject Lib "gdi32" (ByVal hObject As Long) As Long
  31. Private Declare Function CreateSolidBrush Lib "gdi32" (ByVal crColor As Long) As Long
  32. Private Declare Function DrawText Lib "user32" Alias "DrawTextA" (ByVal hdc As Long, ByVal lpStr As String, ByVal nCount As Long, lpRect As RECT, ByVal wFormat As Long) As Long
  33. Private Declare Function SelectObject Lib "gdi32" (ByVal hdc As Long, ByVal hObject As Long) As Long
  34. Private Declare Function Rectangle Lib "gdi32" (ByVal hdc As Long, ByVal X1 As Long, ByVal Y1 As Long, ByVal X2 As Long, ByVal Y2 As Long) As Long
  35. Private Declare Function CreatePen Lib "gdi32" (ByVal nPenStyle As Long, ByVal nWidth As Long, ByVal crColor As Long) As Long
  36. Private Declare Function GetDlgItem Lib "user32" (ByVal hDlg As Long, ByVal nIDDlgItem As Long) As Long

  37. Private sc_aSubData()           As tSubData
  38. Private sc_aBuf(1 To CODE_LEN)  As Byte
  39. Private sc_pCWP                 As Long
  40. Private sc_pEbMode              As Long
  41. Private sc_pSWL                 As Long

  42. '''''''''''''''''''''''''''''''''''''''''''''''''''''
  43. Private m_bIsTrackHandler32     As Boolean
  44. Private m_bIsTracked            As Boolean

  45. Private m_hWnd                  As Long
  46. Private m_hHeaderWnd            As Long
  47. Private m_hParentWnd            As Long
  48. Private m_dwOriginStyle         As Long

  49. Private m_clrItemBkColor1       As Long
  50. Private m_clrItemBkColor2       As Long
  51. Private m_clrGridColor          As Long
  52. Private m_clrSelectedItemBkColor       As Long

  53. Private m_hItemBkBrush1         As Long
  54. Private m_hItemBkBrush2         As Long
  55. Private m_hGridPen              As Long
  56. Private m_hSelectedItemBkBrush  As Long

  57. Private m_bItemBkColorHorizontal    As Boolean
  58. Private m_bShowGrid             As Boolean
  59. Private m_nItemHeight           As Long
复制代码


TA的精华主题

TA的得分主题

 楼主| 发表于 2023-3-25 00:12 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册



入口函数和消息处理:

  1. Public Sub zSubclass_Proc(ByVal bBefore As Boolean, ByRef bHandled As Boolean, ByRef lReturn As Long, ByRef lhWnd As Long, ByRef uMsg As Long, ByRef wParam As Long, ByRef lParam As Long)
  2.     Select Case uMsg
  3.         Case WM_NCDESTROY
  4.             Detach
  5.             Exit Sub
  6.             
  7.         Case WM_MEASUREITEM
  8.             lReturn = OnMeasureItem(lhWnd, uMsg, wParam, lParam, bHandled)
  9.             Exit Sub
  10.             
  11.         Case WM_DRAWITEM
  12.             lReturn = OnDrawItem(lhWnd, uMsg, wParam, lParam, bHandled)
  13.             Exit Sub
  14.             
  15.     End Select
  16. End Sub

  17. Private Sub Subclass_AddMsg(ByVal lng_hWnd As Long, ByVal uMsg As Long, Optional ByVal When As eMsgWhen = MSG_AFTER)
  18.     With sc_aSubData(zIdx(lng_hWnd))
  19.         If (When And eMsgWhen.MSG_BEFORE) Then
  20.             Call zAddMsg(uMsg, .aMsgTblB, .nMsgCntB, eMsgWhen.MSG_BEFORE, .nAddrSub)
  21.         End If
  22.         If (When And eMsgWhen.MSG_AFTER) Then
  23.             Call zAddMsg(uMsg, .aMsgTblA, .nMsgCntA, eMsgWhen.MSG_AFTER, .nAddrSub)
  24.         End If
  25.     End With
  26. End Sub

  27. Private Sub Subclass_DelMsg(ByVal lng_hWnd As Long, ByVal uMsg As Long, Optional ByVal When As eMsgWhen = MSG_AFTER)
  28.   
  29.     With sc_aSubData(zIdx(lng_hWnd))
  30.         If (When And eMsgWhen.MSG_BEFORE) Then
  31.             Call zDelMsg(uMsg, .aMsgTblB, .nMsgCntB, eMsgWhen.MSG_BEFORE, .nAddrSub)
  32.         End If
  33.         If (When And eMsgWhen.MSG_AFTER) Then
  34.             Call zDelMsg(uMsg, .aMsgTblA, .nMsgCntA, eMsgWhen.MSG_AFTER, .nAddrSub)
  35.         End If
  36.     End With
  37. End Sub
复制代码


TA的精华主题

TA的得分主题

 楼主| 发表于 2023-3-25 00:15 | 显示全部楼层



汇编处理。功能是把入口函数完全封装在类中。避免使用标准模块的小尾巴。

  1. Private Function Subclass_InIDE() As Boolean
  2.     Subclass_InIDE = False
  3. End Function

  4. Private Function Subclass_Start(ByVal lng_hWnd As Long) As Long

  5.   Dim i                        As Long
  6.   Dim j                        As Long
  7.   Dim nSubIdx                  As Long
  8.   Dim sSubCode                 As String
  9.   
  10.   Const GMEM_FIXED             As Long = 0
  11.   Const PAGE_EXECUTE_READWRITE As Long = &H40&
  12.   Const PATCH_01               As Long = 18
  13.   Const PATCH_02               As Long = 68
  14.   Const PATCH_03               As Long = 78
  15.   Const PATCH_06               As Long = 116
  16.   Const PATCH_07               As Long = 121
  17.   Const PATCH_0A               As Long = 186
  18.   Const FUNC_CWP               As String = "CallWindowProcA"
  19.   Const FUNC_EBM               As String = "EbMode"
  20.   Const FUNC_SWL               As String = "SetWindowLongA"
  21.   Const MOD_USER               As String = "user32"
  22.   Const MOD_VBA5               As String = "vba5"
  23.   Const MOD_VBA6               As String = "vba6"

  24.     If (sc_aBuf(1) = 0) Then

  25.         sSubCode = "5589E583C4F85731C08945FC8945F8EB0EE80000000083F802742185C07424E830000000837DF800750AE838000000E84D0000005F8B45FCC9C21000E826000000EBF168000000006AFCFF7508E800000000EBE031D24ABF00000000B900000000E82D000000C3FF7514FF7510FF750CFF75086800000000E8000000008945FCC331D2BF00000000B900000000E801000000C3E32F09C978078B450CF2AF75248D4514508D4510508D450C508D4508508D45FC508D45F85052B800000000508B00FF501CC3"
  26.         i = 1
  27.         Do While j < CODE_LEN
  28.             j = j + 1
  29.             sc_aBuf(j) = CByte("&H" & Mid$(sSubCode, i, 2))
  30.             i = i + 2
  31.         Loop
  32.    
  33.         If (Subclass_InIDE) Then
  34.             sc_aBuf(16) = &H90
  35.             sc_aBuf(17) = &H90
  36.             sc_pEbMode = zAddrFunc(MOD_VBA6, FUNC_EBM)
  37.             If (sc_pEbMode = 0) Then
  38.                 sc_pEbMode = zAddrFunc(MOD_VBA5, FUNC_EBM)
  39.             End If
  40.         End If
  41.    
  42.         Call zPatchVal(VarPtr(sc_aBuf(1)), PATCH_0A, ObjPtr(Me))
  43.    
  44.         sc_pCWP = zAddrFunc(MOD_USER, FUNC_CWP)
  45.         sc_pSWL = zAddrFunc(MOD_USER, FUNC_SWL)
  46.         ReDim sc_aSubData(0 To 0) As tSubData
  47.    
  48.       Else
  49.         nSubIdx = zIdx(lng_hWnd, True)
  50.         If (nSubIdx = -1) Then
  51.             nSubIdx = UBound(sc_aSubData()) + 1
  52.             ReDim Preserve sc_aSubData(0 To nSubIdx) As tSubData
  53.         End If
  54.    
  55.         Subclass_Start = nSubIdx
  56.     End If

  57.     With sc_aSubData(nSubIdx)
  58.         
  59.         .nAddrSub = GlobalAlloc(GMEM_FIXED, CODE_LEN)
  60.         Call VirtualProtect(ByVal .nAddrSub, CODE_LEN, PAGE_EXECUTE_READWRITE, i)
  61.         Call RtlMoveMemory(ByVal .nAddrSub, sc_aBuf(1), CODE_LEN)
  62.    
  63.         .hwnd = lng_hWnd
  64.         .nAddrOrig = SetWindowLongA(.hwnd, GWL_WNDPROC, .nAddrSub)
  65.    
  66.         Call zPatchRel(.nAddrSub, PATCH_01, sc_pEbMode)
  67.         Call zPatchVal(.nAddrSub, PATCH_02, .nAddrOrig)
  68.         Call zPatchRel(.nAddrSub, PATCH_03, sc_pSWL)
  69.         Call zPatchVal(.nAddrSub, PATCH_06, .nAddrOrig)
  70.         Call zPatchRel(.nAddrSub, PATCH_07, sc_pCWP)
  71.     End With
  72. End Function

  73. Private Sub Subclass_StopAll()
  74.   
  75.   Dim i As Long
  76.   
  77.     i = UBound(sc_aSubData())
  78.     Do While i >= 0
  79.         With sc_aSubData(i)
  80.             If (.hwnd <> 0) Then
  81.                 Call Subclass_Stop(.hwnd)
  82.             End If
  83.         End With
  84.    
  85.         i = i - 1
  86.     Loop
  87. End Sub

  88. Private Sub Subclass_Stop(ByVal lng_hWnd As Long)
  89.   
  90.     With sc_aSubData(zIdx(lng_hWnd))
  91.         Call SetWindowLongA(.hwnd, GWL_WNDPROC, .nAddrOrig)
  92.         Call zPatchVal(.nAddrSub, PATCH_05, 0)
  93.         Call zPatchVal(.nAddrSub, PATCH_09, 0)
  94.         Call GlobalFree(.nAddrSub)
  95.         .hwnd = 0
  96.         .nMsgCntB = 0
  97.         .nMsgCntA = 0
  98.         Erase .aMsgTblB
  99.         Erase .aMsgTblA
  100.     End With
  101. End Sub


  102. Private Sub zAddMsg(ByVal uMsg As Long, ByRef aMsgTbl() As Long, ByRef nMsgCnt As Long, ByVal When As eMsgWhen, ByVal nAddr As Long)
  103.   
  104.   Dim nEntry  As Long
  105.   Dim nOff1   As Long
  106.   Dim nOff2   As Long
  107.   
  108.     If (uMsg = ALL_MESSAGES) Then
  109.         nMsgCnt = ALL_MESSAGES
  110.       Else
  111.         Do While nEntry < nMsgCnt
  112.             nEntry = nEntry + 1
  113.         
  114.             If (aMsgTbl(nEntry) = 0) Then
  115.                 aMsgTbl(nEntry) = uMsg
  116.                 Exit Sub
  117.             ElseIf (aMsgTbl(nEntry) = uMsg) Then
  118.                 Exit Sub
  119.             End If
  120.         Loop

  121.         nMsgCnt = nMsgCnt + 1
  122.         ReDim Preserve aMsgTbl(1 To nMsgCnt) As Long
  123.         aMsgTbl(nMsgCnt) = uMsg
  124.     End If

  125.     If (When = eMsgWhen.MSG_BEFORE) Then
  126.         nOff1 = PATCH_04
  127.         nOff2 = PATCH_05
  128.       Else
  129.         nOff1 = PATCH_08
  130.         nOff2 = PATCH_09
  131.     End If

  132.     If (uMsg <> ALL_MESSAGES) Then
  133.         Call zPatchVal(nAddr, nOff1, VarPtr(aMsgTbl(1)))
  134.     End If
  135.     Call zPatchVal(nAddr, nOff2, nMsgCnt)
  136. End Sub

  137. Private Function zAddrFunc(ByVal sDLL As String, ByVal sProc As String) As Long
  138.     zAddrFunc = GetProcAddress(GetModuleHandleA(sDLL), sProc)
  139.     Debug.Assert zAddrFunc
  140. End Function

  141. Private Sub zDelMsg(ByVal uMsg As Long, ByRef aMsgTbl() As Long, ByRef nMsgCnt As Long, ByVal When As eMsgWhen, ByVal nAddr As Long)
  142.   
  143.   Dim nEntry As Long
  144.   
  145.     If (uMsg = ALL_MESSAGES) Then
  146.         nMsgCnt = 0
  147.         If When = eMsgWhen.MSG_BEFORE Then
  148.             nEntry = PATCH_05
  149.           Else
  150.             nEntry = PATCH_09
  151.         End If
  152.         Call zPatchVal(nAddr, nEntry, 0)
  153.       Else
  154.         Do While nEntry < nMsgCnt
  155.             nEntry = nEntry + 1
  156.             If (aMsgTbl(nEntry) = uMsg) Then
  157.                 aMsgTbl(nEntry) = 0
  158.                 Exit Do
  159.             End If
  160.         Loop
  161.     End If
  162. End Sub

  163. Private Function zIdx(ByVal lng_hWnd As Long, Optional ByVal bAdd As Boolean = False) As Long
  164.   
  165.     zIdx = UBound(sc_aSubData)
  166.     Do While zIdx >= 0
  167.         With sc_aSubData(zIdx)
  168.             If (.hwnd = lng_hWnd) Then
  169.                 If (Not bAdd) Then
  170.                     Exit Function
  171.                 End If
  172.             ElseIf (.hwnd = 0) Then
  173.                 If (bAdd) Then
  174.                     Exit Function
  175.                 End If
  176.             End If
  177.         End With
  178.         zIdx = zIdx - 1
  179.     Loop
  180.   
  181.     If (Not bAdd) Then
  182.         Debug.Assert False
  183.     End If

  184. End Function

  185. Private Sub zPatchRel(ByVal nAddr As Long, ByVal nOffset As Long, ByVal nTargetAddr As Long)
  186.     Call RtlMoveMemory(ByVal nAddr + nOffset, nTargetAddr - nAddr - nOffset - 4, 4)
  187. End Sub

  188. Private Sub zPatchVal(ByVal nAddr As Long, ByVal nOffset As Long, ByVal nValue As Long)
  189.     Call RtlMoveMemory(ByVal nAddr + nOffset, nValue, 4)
  190. End Sub

  191. Private Function zSetTrue(ByRef bValue As Boolean) As Boolean
  192.     zSetTrue = True
  193.     bValue = True
  194. End Function
复制代码


评分

1

查看全部评分

TA的精华主题

TA的得分主题

 楼主| 发表于 2023-3-25 00:16 | 显示全部楼层



类的初始化和销毁:

  1. Private Sub Class_Initialize()
  2.     m_bIsTrackHandler32 = IsFunctionSupported("TrackMouseEvent", "User32")
  3.    
  4.     m_hWnd = 0
  5.     m_dwOriginStyle = 0
  6.    
  7.     m_hItemBkBrush1 = m_hItemBkBrush2 = 0
  8.     m_hGridPen = 0
  9.     m_bItemBkColorHorizontal = False
  10.     ItemHeight = 20
  11.     ShowGird = True
  12.    
  13.     ItemBkColor1 = &HFFFFFF
  14.     ItemBkColor2 = &HFDF8F0
  15.     GridColor = &HE5D7D0
  16.     SelectedItemBkColor = &HABECFC
  17. End Sub

  18. Private Sub Class_Terminate()
  19.     Call Detach
  20.    
  21.     If (m_hItemBkBrush1 <> 0) Then
  22.         Call DeleteObject(m_hItemBkBrush1)
  23.         m_hItemBkBrush1 = 0
  24.     End If
  25.    
  26.     If (m_hItemBkBrush2 <> 0) Then
  27.         Call DeleteObject(m_hItemBkBrush2)
  28.         m_hItemBkBrush2 = 0
  29.     End If
  30.    
  31.     If (m_hSelectedItemBkBrush <> 0) Then
  32.         Call DeleteObject(m_hSelectedItemBkBrush)
  33.         m_hSelectedItemBkBrush = 0
  34.     End If
  35.    
  36.     If (m_hGridPen <> 0) Then
  37.         Call DeleteObject(m_hGridPen)
  38.         m_hGridPen = 0
  39.     End If
  40. End Sub

  41. Private Function IsFunctionSupported(sFunction As String, sModule As String) As Boolean
  42.     Dim hModule As Long
  43.         hModule = GetModuleHandleA(sModule)
  44.     If (hModule = 0) Then
  45.         hModule = LoadLibrary(sModule)
  46.     End If
  47.     If (hModule) Then
  48.         If (GetProcAddress(hModule, sFunction)) Then
  49.             IsFunctionSupported = True
  50.         End If
  51.         FreeLibrary hModule
  52.     End If
  53. End Function

  54. Private Sub TrackMouseTracking(hwnd As Long)
  55.     Dim lpEventTrack As TRACKMOUSEEVENTTYPE
  56.     With lpEventTrack
  57.         .cbSize = Len(lpEventTrack)
  58.         '.dwFlags = &H1 Or &H2  ' TM_HOVER OR TM_LEAVE
  59.         .dwFlags = &H2
  60.         .dwHoverTime = 100
  61.         .hwndTrack = hwnd
  62.     End With
  63.     If (m_bIsTrackHandler32) Then
  64.         TrackMouseEvent lpEventTrack
  65.     Else
  66.         TrackMouseEvent2 lpEventTrack
  67.     End If
  68. End Sub

  69. Private Sub UpdateAll()
  70.     If (m_hWnd <> 0) Then
  71.         Call InvalidateRect(m_hWnd, ByVal 0, 1)
  72.     End If
  73. End Sub
复制代码


TA的精华主题

TA的得分主题

 楼主| 发表于 2023-3-25 00:18 | 显示全部楼层



核心代码。处理WM_MEASUREITEM和WM_DRAWITEM消息,绘制ITEM和SUBITEM的边框和文字。

  1. Private Function OnMeasureItem(ByVal hwnd As Long, ByVal uMsg As Long, ByVal wParam As Long, ByVal lParam As Long, ByRef bHandled As Boolean) As Long
  2.     Dim mis As MEASUREITEMSTRUCT
  3.     OnMeasureItem = 0
  4.     bHandled = False
  5.    
  6.     Call CopyMemory(mis, ByVal lParam, Len(mis))
  7.    
  8.     If (mis.CtlType = ODT_LISTVIEW And GetDlgItem(m_hParentWnd, mis.CtlID) = m_hWnd) Then
  9.         mis.ItemHeight = m_nItemHeight
  10.         
  11.         Call CopyMemory(ByVal lParam, mis, Len(mis))
  12.         
  13.         bHandled = True
  14.         OnMeasureItem = 1
  15.     End If
  16. End Function

  17. Private Function OnDrawItem(ByVal hwnd As Long, ByVal uMsg As Long, ByVal wParam As Long, ByVal lParam As Long, ByRef bHandled As Boolean) As Long
  18.     Dim dis As DRAWITEMSTRUCT
  19.     Dim rcSubItem As RECT, rcHeaderItem As RECT
  20.    
  21.     Dim nHeaderItemCount As Long
  22.     Dim i As Integer
  23.    
  24.     OnDrawItem = 0
  25.     bHandled = False
  26.    
  27.     Call CopyMemory(dis, ByVal lParam, Len(dis))
  28.    
  29.     If (dis.CtlType = ODT_LISTVIEW And GetDlgItem(m_hParentWnd, dis.CtlID) = m_hWnd) Then
  30.    
  31.         ' 获取列表头个数
  32.         nHeaderItemCount = SendMessage(m_hHeaderWnd, HDM_GETITEMCOUNT, 0, 0)
  33.         Call SetRect(rcSubItem, dis.rcItem.Left, dis.rcItem.Top, dis.rcItem.Left, dis.rcItem.Bottom)
  34.             
  35.         For i = 0 To nHeaderItemCount - 1
  36.             
  37.             Call SendMessage(m_hHeaderWnd, HDM_GETITEMRECT, i, rcHeaderItem)
  38.             
  39.             rcSubItem.Left = rcSubItem.Right
  40.             rcSubItem.Right = rcSubItem.Left + rcHeaderItem.Right - rcHeaderItem.Left
  41.             
  42.             Call OnDrawSubItem(dis, i, rcSubItem)
  43.         Next
  44.     End If
  45.    
  46. End Function

  47. Private Sub OnDrawSubItem(dis As DRAWITEMSTRUCT, ByVal nSubItem As Long, rcSubItem As RECT)
  48.     Dim hdi As HDITEM
  49.     Dim li As LVITEM
  50.     Dim szBuff() As Byte
  51.     Dim szText As String
  52.     Dim wTextFormat As Long
  53.     Dim rcPaint As RECT, rcIntersect As RECT
  54.     Dim hOldBrush As Long
  55.     Dim hOldPen As Long
  56.    
  57.     Call GetBoundsRect(dis.hdc, rcPaint, 0)
  58.     If IsRectEmpty(rcPaint) Then
  59.         Call GetClientRect(m_hWnd, rcPaint)
  60.     End If
  61.     Call IntersectRect(rcIntersect, rcPaint, rcSubItem)
  62.    
  63.     If Not IsRectEmpty(rcPaint) Then
  64.    
  65.         ' 设置绘图边界
  66.         Call SetBoundsRect(dis.hdc, rcIntersect, DCB_SET)

  67.         ' 获取列表项文本
  68.         li.mask = LVIF_TEXT
  69.         li.iItem = dis.itemID
  70.         li.iSubItem = nSubItem
  71.         li.stateMask = -1
  72.         li.pszText = LocalAlloc(&H40, 255)
  73.         li.cchTextMax = 255
  74.         Call SendMessage(m_hWnd, LVM_GETITEMTEXTA, li.iItem, li)
  75.         
  76.         szBuff = StrConv(String$(255, 0), vbFromUnicode)
  77.         Call CopyMemory(szBuff(0), ByVal li.pszText, 255)
  78.         Call LocalFree(li.pszText)
  79.         
  80.         szText = StrConv(szBuff, vbUnicode)
  81.         szText = Left$(szText, InStr(1, szText, vbNullChar) - 1)
  82.         
  83.         ' 获取列表头对齐格式
  84.         hdi.mask = HDI_FORMAT
  85.         Call SendMessage(m_hHeaderWnd, HDM_GETITEMA, li.iSubItem, hdi)
  86.         wTextFormat = DT_LEFT Or DT_VCENTER Or DT_SINGLELINE
  87.         If (hdi.fmt And HDF_CENTER) Then
  88.             wTextFormat = wTextFormat Or DT_CENTER
  89.         ElseIf (hdi.fmt And HDF_RIGHT) Then
  90.             wTextFormat = wTextFormat Or DT_RIGHT
  91.         End If
  92.                
  93.         ' 填充背景
  94.         If ShowGird = True Then
  95.             If (dis.itemState And ODS_SELECTED) Then
  96.                 hOldBrush = SelectObject(dis.hdc, m_hSelectedItemBkBrush)
  97.             ElseIf m_bItemBkColorHorizontal = True Then
  98.                 hOldBrush = SelectObject(dis.hdc, IIf(nSubItem Mod 2, m_hItemBkBrush1, m_hItemBkBrush2))
  99.             Else
  100.                 hOldBrush = SelectObject(dis.hdc, IIf(dis.itemID Mod 2, m_hItemBkBrush1, m_hItemBkBrush2))
  101.             End If
  102.             hOldPen = SelectObject(dis.hdc, m_hGridPen)
  103.             Call Rectangle(dis.hdc, rcSubItem.Left, rcSubItem.Top - 1, rcSubItem.Right + 1, rcSubItem.Bottom)
  104.         Else
  105.             If (dis.itemState And ODS_SELECTED) Then
  106.                 Call FillRect(dis.hdc, rcSubItem, m_hSelectedItemBkBrush)
  107.             ElseIf m_bItemBkColorHorizontal = True Then
  108.                 Call FillRect(dis.hdc, rcSubItem, IIf(nSubItem Mod 2, m_hItemBkBrush1, m_hItemBkBrush2))
  109.             Else
  110.                 Call FillRect(dis.hdc, rcSubItem, IIf(dis.itemID Mod 2, m_hItemBkBrush1, m_hItemBkBrush2))
  111.             End If
  112.         End If
  113.         
  114.         Call InflateRect(rcSubItem, -1, -1)
  115.         Call DrawText(dis.hdc, szText, -1, rcSubItem, wTextFormat)
  116.         Call InflateRect(rcSubItem, 1, 1)
  117.         
  118.         ' 还原设备上下文
  119.         If (hOldBrush <> 0) Then Call SelectObject(dis.hdc, hOldBrush)
  120.         If (hOldPen <> 0) Then Call SelectObject(dis.hdc, hOldPen)
  121.         Call SetBoundsRect(dis.hdc, rcPaint, DCB_SET)
  122.     End If
  123. End Sub
复制代码


TA的精华主题

TA的得分主题

 楼主| 发表于 2023-3-25 00:19 | 显示全部楼层



连接方法,还有一些属性:

  1. Public Function Attach(ByVal hwnd As Long) As Boolean
  2.     Dim dwNewStyle As Long
  3.    
  4.     Attach = False
  5.     If Not (m_hWnd = 0) Then Exit Function
  6.    
  7.     m_hWnd = hwnd
  8.     m_dwOriginStyle = GetWindowLong(m_hWnd, GWL_STYLE)
  9.    
  10.     dwNewStyle = m_dwOriginStyle Or LVS_OWNERDRAWFIXED
  11.     Call SetWindowLong(m_hWnd, GWL_STYLE, dwNewStyle)
  12.    
  13.     m_hHeaderWnd = SendMessage(m_hWnd, LVM_GETHEADER, 0, 0)
  14.     m_hParentWnd = GetParent(m_hWnd)
  15.    
  16.     Call Subclass_Start(m_hWnd)
  17.     Call Subclass_Start(m_hParentWnd)
  18.     Call Subclass_AddMsg(m_hWnd, WM_NCDESTROY, MSG_BEFORE)
  19.     Call Subclass_AddMsg(m_hParentWnd, WM_MEASUREITEM, MSG_BEFORE)
  20.     Call Subclass_AddMsg(m_hParentWnd, WM_DRAWITEM, MSG_BEFORE)

  21.     Call UpdateAll
  22.    
  23.     Attach = True
  24. End Function

  25. Public Function Detach() As Boolean
  26.     Detach = False
  27.     If (m_hWnd = 0) Then Exit Function
  28.    
  29.     Call SetWindowLong(m_hWnd, GWL_STYLE, m_dwOriginStyle)
  30.    
  31.     Call Subclass_StopAll
  32.    
  33.    
  34.     Call UpdateAll
  35.    
  36.     m_hWnd = 0
  37.     m_dwOriginStyle = 0
  38.    
  39.     Detach = True
  40. End Function

  41. Public Property Get ItemBkColor1() As Long
  42.     Let ItemBkColor1 = m_clrItemBkColor1
  43. End Property

  44. Public Property Let ItemBkColor1(ByVal clr As Long)
  45.     m_clrItemBkColor1 = clr
  46.    
  47.     If (m_hItemBkBrush1 <> 0) Then
  48.         Call DeleteObject(m_hItemBkBrush1)
  49.         m_hItemBkBrush1 = 0
  50.     End If
  51.     m_hItemBkBrush1 = CreateSolidBrush(m_clrItemBkColor1)
  52.    
  53.     Call UpdateAll
  54. End Property

  55. Public Property Get ItemBkColor2() As Long
  56.     Let ItemBkColor2 = m_clrItemBkColor2
  57. End Property

  58. Public Property Let ItemBkColor2(ByVal clr As Long)
  59.     m_clrItemBkColor2 = clr
  60.    
  61.     If (m_hItemBkBrush2 <> 0) Then
  62.         Call DeleteObject(m_hItemBkBrush2)
  63.         m_hItemBkBrush2 = 0
  64.     End If
  65.     m_hItemBkBrush2 = CreateSolidBrush(m_clrItemBkColor2)
  66.    
  67.     Call UpdateAll
  68. End Property

  69. Public Property Get GridColor() As Long
  70.     Let GridColor = m_clrGridColor
  71. End Property

  72. Public Property Let GridColor(ByVal clr As Long)
  73.     m_clrGridColor = clr
  74.    
  75.     If (m_hGridPen <> 0) Then
  76.         Call DeleteObject(m_hGridPen)
  77.         m_hGridPen = 0
  78.     End If
  79.     m_hGridPen = CreatePen(PS_SOLID, 1, m_clrGridColor)
  80.    
  81.     Call UpdateAll
  82. End Property

  83. Public Property Get SelectedItemBkColor() As Long
  84.     Let SelectedItemBkColor = m_clrSelectedItemBkColor
  85. End Property

  86. Public Property Let SelectedItemBkColor(ByVal clr As Long)
  87.     m_clrSelectedItemBkColor = clr
  88.    
  89.     If (m_hSelectedItemBkBrush <> 0) Then
  90.         Call DeleteObject(m_hSelectedItemBkBrush)
  91.         m_hSelectedItemBkBrush = 0
  92.     End If
  93.     m_hSelectedItemBkBrush = CreateSolidBrush(m_clrSelectedItemBkColor)
  94.    
  95.     Call UpdateAll
  96. End Property

  97. Public Property Get ItemBkColorHorizontal() As Boolean
  98.     ItemBkColorHorizontal = m_bItemBkColorHorizontal
  99. End Property

  100. Public Property Let ItemBkColorHorizontal(ByVal b As Boolean)
  101.     m_bItemBkColorHorizontal = b
  102.     Call UpdateAll
  103. End Property

  104. Public Property Get ItemHeight() As Long
  105.     ItemHeight = m_nItemHeight
  106. End Property

  107. Public Property Let ItemHeight(ByVal n As Long)
  108.     m_nItemHeight = n
  109.     Call UpdateAll
  110. End Property

  111. Public Property Get ShowGird() As Boolean
  112.     ShowGird = m_bShowGrid
  113. End Property

  114. Public Property Let ShowGird(ByVal b As Boolean)
  115.     m_bShowGrid = b
  116.     Call UpdateAll
  117. End Property
复制代码


TA的精华主题

TA的得分主题

 楼主| 发表于 2023-3-25 00:21 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助



应用案例。窗体中有一个textbox,一个Listview,是一个模糊查询的通用界面


  1. Option Explicit

  2. Private Type RECT
  3.         Left                        As Long
  4.         Top                         As Long
  5.         Right                       As Long
  6.         Bottom                      As Long
  7. End Type

  8. Private Type WINDOWPOS
  9.   hwnd                              As Long
  10.   hWndInsertAfter                   As Long
  11.   x                                 As Long
  12.   y                                 As Long
  13.   cx                                As Long
  14.   cy                                As Long
  15.   flags                             As Long
  16. End Type

  17. Private Const WM_WINDOWPOSCHANGED   As Long = &H47
  18. Private Const SWP_NOACTIVATE        As Long = &H10
  19. Private Const SWP_NOMOVE            As Long = &H2
  20. Private Const SWP_NOOWNERZORDER     As Long = &H200
  21. Private Const SWP_NOZORDER          As Long = &H4

  22. Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" ( _
  23.     ByVal hwnd As Long, _
  24.     ByVal wMsg As Long, _
  25.     ByVal wParam As Long, _
  26.     lParam As Any) As Long
  27. Private Declare Function GetWindowRect Lib "user32" ( _
  28.     ByVal hwnd As Long, _
  29.     lpRect As RECT) As Long
  30. Private Declare Function GetParent Lib "user32" ( _
  31.     ByVal hwnd As Long) As Long

  32. Private arrdata
  33. Private Custom_Listview As CCustomListView
  34. '
  35. Private Sub UserForm_Initialize()
  36.     Dim i&, j&
  37.     TextBox1.ControlTipText = "关键词按销售合约或产品编号模糊查询"
  38.     arrdata = Sheet1.Range("a1").CurrentRegion
  39.     With ListView1
  40.         .View = lvwReport '必选
  41.         .FullRowSelect = True '必选
  42.         .Font.Size = 12
  43.         .LabelEdit = lvwManual
  44.         .MultiSelect = True
  45.         .CheckBoxes = True '未实现复选框功能,但可按住ctrl多选
  46.         .ColumnHeaders.Add , , arrdata(1, 1), 60, lvwColumnLeft
  47.         
  48.         For i = 2 To UBound(arrdata, 2)
  49.             .ColumnHeaders.Add , , arrdata(1, i), 80, lvwColumnCenter
  50.         Next
  51.         For i = 2 To UBound(arrdata)
  52.             With .ListItems.Add
  53.                 .Text = arrdata(i, 1)
  54.                 For j = 2 To UBound(arrdata, 2)
  55.                     .SubItems(j - 1) = arrdata(i, j)
  56.                 Next
  57.             End With
  58.         Next
  59.     End With
  60.    
  61.     Set Custom_Listview = New CCustomListView
  62.     With Custom_Listview
  63.         .ItemBkColor1 = &HFFC0C0 '交替换色1,实际用于第2行/列颜色
  64.         .ItemBkColor2 = &HFDF8F0 '交替换色2,实际用于第1行/列颜色
  65.         .SelectedItemBkColor = &HABECFC '被选中行的高亮颜色
  66.         .ItemHeight = 32 '行高设置
  67.         .ItemBkColorHorizontal = False '为False时隔行换色,True时隔列
  68.         .ShowGird = True '为True时显示网格线
  69.         .GridColor = vbRed '设置网格线颜色
  70.         .Attach ListView1.hwnd
  71.     End With
  72.     TextBox1.SetFocus
  73. End Sub

  74. Private Sub UserForm_Activate()
  75.     ListViewRefresh
  76. End Sub

  77. Private Sub TextBox1_Change()
  78.     Dim i As Long, j As Long
  79.     Dim lstitem As ListItem
  80.     Dim strKey As String
  81.     If IsEmpty(arrdata) Then Exit Sub
  82.     With ListView1
  83.         For i = 1 To .ColumnHeaders.Count
  84.             .ColumnHeaders(i).Icon = 0
  85.         Next
  86.         .ListItems.Clear '清空原有所有数据
  87.         For i = 2 To UBound(arrdata)
  88.             strKey = arrdata(i, 3) & arrdata(i, 5)  '按第3、5列内容为关键词模糊查询
  89.             If InStr(strKey, UCase(TextBox1)) Then '可以使用Instr,也可以使用Like语句
  90.                 Set lstitem = .ListItems.Add 'Add方法在Listview最后面添加一行空行
  91.                 lstitem.Text = arrdata(i, 1) '给新增的空行第一列赋值
  92.                 For j = 2 To UBound(arrdata, 2)
  93.                     lstitem.SubItems(j - 1) = arrdata(i, j) '给新增行除第一列之外的其他列赋值,用SubItems属性
  94.                 Next
  95.             End If
  96.         Next
  97.     End With
  98.     ListViewRefresh
  99. End Sub

  100. '新增的过程。无此过程,控件无法触发WM_MEASUREITEM消息
  101. '修改行高只能在收到发WM_MEASUREITEM时进行修改

  102. Private Sub ListViewRefresh()
  103.     Dim rc As RECT, wp As WINDOWPOS
  104.     ListView1.Refresh
  105.     GetWindowRect ListView1.hwnd, rc
  106.     wp.hwnd = ListView1.hwnd
  107.     wp.cx = rc.Right - rc.Left
  108.     wp.cy = rc.Bottom - rc.Top
  109.     wp.flags = SWP_NOACTIVATE Or SWP_NOMOVE Or SWP_NOOWNERZORDER Or SWP_NOZORDER
  110.     SendMessage ListView1.hwnd, WM_WINDOWPOSCHANGED, 0, wp
  111. End Sub



复制代码


您需要登录后才可以回帖 登录 | 免费注册

本版积分规则

手机版|关于我们|联系我们|ExcelHome

GMT+8, 2024-12-22 20:18 , Processed in 0.050294 second(s), 13 queries , Gzip On, MemCache On.

Powered by Discuz! X3.4

© 1999-2023 Wooffice Inc.

沪公网安备 31011702000001号 沪ICP备11019229号-2

本论坛言论纯属发表者个人意见,任何违反国家相关法律的言论,本站将协助国家相关部门追究发言者责任!     本站特聘法律顾问:李志群律师

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