VB:如何隐藏ListView的某一列?

这是个很有意思的问题,通常的思路是先保存数据、再动态添加数据,这里给出的是另外一种方法,即先将该列的列宽设为0,在想办法让用户无法改变该列的列宽,原理我不多说了,看看MSDN,那上面都有^_^。还是给出代码吧:

一个模块,一个窗体:

模块代码:

Option Explicit

Public Type POINTAPI

X As Long

Y As Long

End Type

Public Const GWL_WNDPROC As Long = -4

Public Const GWL_STYLE As Long = -16

Public Const WM_NOTIFY As Long = &H4E&

Public Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)

Public Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA" (ByVal hWnd As Long, ByVal nIndex As Long) As Long

Public Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hWnd As Long, ByVal nIndex As Long, ByVal wNewWord As Long) As Long

Public Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" (ByVal lpPrevWndFunc As Long, ByVal hWnd As Long, ByVal msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long

Public Declare Function GetCursorPos Lib "user32" (lpPoint As POINTAPI) As Long

Public Declare Function ScreenToClient Lib "user32" (ByVal hWnd As Long, lpPoint As POINTAPI) As Long

Public Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hWnd As Long, ByVal wMsg As Long, ByVal wParam As Any, lParam As Any) As Long

Public Declare Function GetProp Lib "user32" Alias "GetPropA" (ByVal hWnd As Long, ByVal lpString As String) As Long

Public Declare Function SetProp Lib "user32" Alias "SetPropA" (ByVal hWnd As Long, ByVal lpString As String, ByVal hData As Long) As Long

Private Const LVM_FIRST = &H1000

Private Const LVM_GETHEADER = (LVM_FIRST + 31)

Private Type NMHDR

hWndFrom As Long

idfrom As Long

code As Long

End Type

Private Type HD_HITTESTINFO

pt As POINTAPI

flags As Long

iItem As Long

End Type

Private Const HHT_ONHEADER = &H2

Private Const HHT_ONDIVIDER = &H4

Private Const HDM_HITTEST As Long = &H1206

Private Const HDN_FIRST As Long = -300&

Private Const HDN_ITEMCLICK As Long = (HDN_FIRST - 2)

Private Const HDN_DIVIDERDBLCLICK As Long = (HDN_FIRST - 5)

Private Const HDN_BEGINTRACK As Long = (HDN_FIRST - 6)

Private Const HDN_ENDTRACK As Long = (HDN_FIRST - 7)

Private Const HDN_TRACK As Long = (HDN_FIRST - 8)

Private Const HDN_GETDISPINFO As Long = (HDN_FIRST - 9)

Private Const HDN_BEGINDRAG As Long = (HDN_FIRST - 10)

Private Const HDN_ENDDRAG As Long = (HDN_FIRST - 11)

Private Const HDN_ITEMCHANGING As Long = (HDN_FIRST - 0)

Private Const HDN_ITEMCHANGED As Long = (HDN_FIRST - 1)

Private Const HDN_ITEMDBLCLICK As Long = (HDN_FIRST - 3)

Private Const HDN_NM_RCLICK As Long = -5

' 列标头事件

Public Enum lvHeaderActions

lvHeaderActionClick = 1

lvHeaderActionRightClick = 2

lvHeaderActionDividerDoubleClick = 3

lvHeaderActionResizeBegin = 4

lvHeaderActionResizeEnd = 5

lvHeaderActionChanging = 6

lvHeaderActionChanged = 7

lvHeaderActionDragBegin = 8

lvHeaderActionDragEnd = 9

End Enum

Private RegisteredListViewControls As New Collection

Public Sub RegisterListView(ByVal ListViewControl As ListView)

Call SetProp(ListViewControl.hWnd, "OrigWindowProc", GetWindowLong(ListViewControl.hWnd, GWL_WNDPROC))

Call SetWindowLong(ListViewControl.hWnd, GWL_WNDPROC, AddressOf HandleListViewHeaderMsgs)

Call RegisteredListViewControls.Add(ListViewControl, CStr(ListViewControl.hWnd))

End Sub

Public Sub UnregisterListView(ByVal ListViewControl As ListView)

Dim OrigWindowProc As Long

OrigWindowProc = GetProp(ListViewControl.hWnd, "OrigWindowProc")

If (OrigWindowProc <> 0) Then

Call SetWindowLong(ListViewControl.hWnd, GWL_WNDPROC, OrigWindowProc)

End If

Call RegisteredListViewControls.Remove(CStr(ListViewControl.hWnd))

End Sub

Public Function HandleListViewHeaderMsgs(ByVal ListViewhWnd As Long, ByVal msg As Long, ByVal wp As Long, ByVal lp As Long) As Long

Const EVENT_SUFFIX As String = "_HeaderEvent"

Dim ListViewControl As ListView

Dim NmHdrMsg As NMHDR

Dim PointStruct As POINTAPI

Dim HitTestInfo As HD_HITTESTINFO

Dim HeaderhWnd As Long

Dim HeaderAction As lvHeaderActions

Dim CancelMsg As Boolean

If msg = WM_NOTIFY Then

HandleListViewHeaderMsgs = CallWindowProc(GetProp(ListViewhWnd, "OrigWindowProc"), ListViewhWnd, msg, wp, lp)

Call CopyMemory(NmHdrMsg, ByVal lp, Len(NmHdrMsg))

HeaderhWnd = SendMessage(ListViewhWnd, LVM_GETHEADER, 0&, ByVal 0&)

If (HeaderhWnd <> 0) Then

Call GetCursorPos(PointStruct)

Call ScreenToClient(HeaderhWnd, PointStruct)

HitTestInfo.flags = HHT_ONHEADER Or HHT_ONDIVIDER

HitTestInfo.pt = PointStruct

Call SendMessage(HeaderhWnd, HDM_HITTEST, 0&, HitTestInfo)

Select Case NmHdrMsg.code

Case HDN_ITEMCLICK: HeaderAction = lvHeaderActionClick

Case HDN_NM_RCLICK: HeaderAction = lvHeaderActionRightClick

Case HDN_DIVIDERDBLCLICK: HeaderAction = lvHeaderActionDividerDoubleClick

Case HDN_BEGINTRACK: HeaderAction = lvHeaderActionResizeBegin

Case HDN_ENDTRACK: HeaderAction = lvHeaderActionResizeEnd

Case HDN_ITEMCHANGING: HeaderAction = lvHeaderActionChanging

Case HDN_ITEMCHANGED: HeaderAction = lvHeaderActionChanged

Case HDN_BEGINDRAG: HeaderAction = lvHeaderActionDragBegin

Case HDN_ENDDRAG: HeaderAction = lvHeaderActionDragEnd

End Select

If HeaderAction <> 0 Then

On Error Resume Next

Set ListViewControl = RegisteredListViewControls(CStr(ListViewhWnd))

CancelMsg = CallByName(ListViewControl.Parent, ListViewControl.Name & EVENT_SUFFIX, VbCallType.VbMethod, HeaderAction, HitTestInfo.iItem + 1)

On Error GoTo 0

If CancelMsg Then

HandleListViewHeaderMsgs = 1

Exit Function

End If

End If

End If

End If

HandleListViewHeaderMsgs = CallWindowProc(GetProp(ListViewhWnd, "OrigWindowProc"), ListViewhWnd, msg, wp, lp)

End Function

Public Sub ListViewHeaderEventDebugPrint(ByVal ListViewControl As ListView, ByVal Action As lvHeaderActions, ByVal Column As Long)

Dim msg As String

Select Case Action

Case lvHeaderActionClick: msg = "clicked"

Case lvHeaderActionRightClick: msg = "right-clicked"

Case lvHeaderActionDividerDoubleClick: msg = "divider dbl-clicked"

Case lvHeaderActionResizeBegin: msg = "resize begin"

Case lvHeaderActionResizeEnd: msg = "resize end"

Case lvHeaderActionChanging: msg = "changing"

Case lvHeaderActionChanged: msg = "changed"

Case lvHeaderActionDragBegin: msg = "drag begin"

Case lvHeaderActionDragEnd: msg = "drag end"

End Select

Debug.Print ListViewControl.Parent.Name & "." & ListViewControl.Name & ": " & msg & " (col=" & CStr(Column) & ")"

End Sub

窗体上一个listview,两个按钮:

Option Explicit

Dim HideFlag As Boolean, OldWidth As Single

Private Sub Command1_Click()

HideFlag = True

OldWidth = ListView1.ColumnHeaders(2).Width

ListView1.ColumnHeaders(2).Width = 0

End Sub

Private Sub Command2_Click()

HideFlag = False

ListView1.ColumnHeaders(2).Width = OldWidth

End Sub

Private Sub Form_Load()

Command1.Caption = "隐藏第2列"

Command2.Caption = "显示第2列"

ListView1.View = lvwReport

ListView1.ColumnHeaders.Add , , "第1列"

ListView1.ColumnHeaders.Add , , "第2列"

ListView1.ColumnHeaders.Add , , "第3列"

With ListView1.ListItems.Add(, , "d")

.ListSubItems.Add , , "d1"

.ListSubItems.Add , , "d2"

End With

With ListView1.ListItems.Add(, , "e")

.ListSubItems.Add , , "e1"

.ListSubItems.Add , , "e2"

End With

With ListView1.ListItems.Add(, , "f")

.ListSubItems.Add , , "f1"

.ListSubItems.Add , , "f2"

End With

Call RegisterListView(ListView1)

End Sub

Private Sub Form_Unload(Cancel As Integer)

Call UnregisterListView(ListView1)

End Sub

Public Function ListView1_HeaderEvent(ByVal Action As lvHeaderActions, ByVal Column As Long) As Boolean

If Column = 2 And HideFlag = True Then

ListView1_HeaderEvent = True

End If

End Function