OptionExplicit ' ' Copyright ?1997-1999 Brad Martinez, http://www.mvps.org ' ' Demonstrates how to in place do SubItem editing in the VB ListView. Private m_hwndLV AsLong' ListView1.hWnd Private m_hwndTB AsLong' TextBox1.hWnd Private m_iItem AsLong' ListItem.Index whose SubItem is being edited Private m_iSubItem AsLong' zero based index of ListView1.ListItems(m_iItem).SubItem being edited ' PrivateSub Form_Load()Sub Form_Load() Dim i AsLong Dim item As ListItem ' Text1.Appearance = ccFlat ' ComctlLib enum value Text1.Visible =False m_hwndTB = Text1.hWnd ' Initialize the ImageLists With ImageList1 .ImageHeight =32 .ImageWidth =32 .ListImages.Add Picture:=Icon EndWith With ImageList2 .ImageHeight =16 .ImageWidth =16 .ListImages.Add Picture:=Icon EndWith ' Initialize the ListView With ListView1 ' .LabelEdit = lvwManual .HideSelection =False .Icons = ImageList1 .SmallIcons = ImageList2 m_hwndLV = .hWnd For i =1To4 .ColumnHeaders.Add Text:="column"& i Next For i =0To&H3F Set item = .ListItems.Add(, , "item"& i, 1, 1) item.SubItems(1) = i *10 item.SubItems(2) = i *100 item.SubItems(3) = i *1000 Next EndWith End Sub PrivateSub Form_Resize()Sub Form_Resize() ' ListView1.Move 0, 0, ScaleWidth, ScaleHeight End Sub PrivateSub ListView1_DblClick()Sub ListView1_DblClick() Dim lvhti As LVHITTESTINFO Dim rc As RECT Dim li As ListItem ' If a left button double-click... (change to suit) If (GetKeyState(vbKeyLButton) And&H8000) Then ' If a ListView SubItem is double clicked... Call GetCursorPos(lvhti.pt) Call ScreenToClient(m_hwndLV, lvhti.pt) If (ListView_SubItemHitTest(m_hwndLV, lvhti) <> LVI_NOITEM) Then If lvhti.iSubItem Then ' Get the SubItem's label (and icon) rect. If ListView_GetSubItemRect(m_hwndLV, lvhti.iItem, lvhti.iSubItem, LVIR_LABEL, rc) Then ' Either set the ListView as the TextBox parent window in order to ' have the TextBox Move method use ListView client coords, or just ' map the ListView client coords to the TextBox's paent Form ' Call SetParent(m_hwndTB, m_hwndLV) Call MapWindowPoints(m_hwndLV, hWnd, rc, 2) Text1.Move (rc.Left +4) * Screen.TwipsPerPixelX, _ rc.Top * Screen.TwipsPerPixelY, _ (rc.Right - rc.Left) * Screen.TwipsPerPixelX, _ (rc.Bottom - rc.Top) * Screen.TwipsPerPixelY ' Save the one-based index of the ListItem and the zero-based index ' of the SubItem(if the ListView is sorted via the API, then ListItem.Index ' will be different than lvhti.iItem +1...) m_iItem = lvhti.iItem +1 m_iSubItem = lvhti.iSubItem ' Put the SubItem's text in the TextBox, save the SubItem's text, ' and clear the SubItem's text. Text1 = ListView1.ListItems(m_iItem).SubItems(m_iSubItem) Text1.Tag = Text1 ListView1.ListItems(m_iItem).SubItems(m_iSubItem) ="" ' Make the TextBox the topmost Form control, make the it visible, select ' its text, give it the focus, and subclass it. Text1.ZOrder 0 Text1.Visible =True Text1.SelStart =0 Text1.SelLength =Len(Text1) Text1.SetFocus Call SubClass(m_hwndTB, AddressOf WndProc) EndIf' ListView_GetSubItemRect EndIf' lvhti.iSubItem EndIf' ListView_SubItemHitTest EndIf' GetKeyState(vbKeyLButton) End Sub ' Selects the ListItem whose SubItem is being edited... PrivateSub Text1_GotFocus()Sub Text1_GotFocus() ListView1.ListItems(m_iItem).Selected =True End Sub ' If the TextBox is shown, size its width so that it's always a little ' longer than the length of its Text. PrivateSub Text1_Change()Sub Text1_Change() If m_iItem Then Text1.Width = TextWidth(Text1) +180 End Sub ' Update the SubItem text on the Enter key, cancel on the Escape Key. PrivateSub Text1_KeyPress()Sub Text1_KeyPress(KeyAscii AsInteger) If (KeyAscii = vbKeyReturn) Then Call HideTextBox(True) KeyAscii =0 ElseIf (KeyAscii = vbKeyEscape) Then Call HideTextBox(False) KeyAscii =0 EndIf End Sub FriendSub HideTextBox()Sub HideTextBox(fApplyChanges AsBoolean) If fApplyChanges Then ListView1.ListItems(m_iItem).SubItems(m_iSubItem) = Text1 Else ListView1.ListItems(m_iItem).SubItems(m_iSubItem) = Text1.Tag EndIf Call UnSubClass(m_hwndTB) Text1.Visible =False Text1 ="" ' Call SetParent(m_hwndTB, hWnd) ' ListView1.SetFocus m_iItem =0 End Sub 文件二:Module1.bas OptionExplicit ' ' Copyright ?1997-1999 Brad Martinez, http://www.mvps.org ' Public Type POINTAPI ' pt X AsLong Y AsLong End Type Public Type RECT ' rct LeftAsLong Top AsLong RightAsLong Bottom AsLong End Type DeclareFunction GetCursorPos()Function GetCursorPos Lib"user32" (lpPoint As POINTAPI) AsLong DeclareFunction ScreenToClient()Function ScreenToClient Lib"user32" (ByVal hWnd AsLong, lpPoint As POINTAPI) AsLong DeclareFunction GetKeyState()Function GetKeyState Lib"user32" (ByVal nVirtKey As KeyCodeConstants) AsInteger DeclareFunction SetParent()Function SetParent Lib"user32" (ByVal hWndChild AsLong, ByVal hWndNewParent AsLong) AsLong DeclareFunction MapWindowPoints()Function MapWindowPoints Lib"user32" (ByVal hwndFrom AsLong, ByVal hwndTo AsLong, lppt As Any, ByVal cPoints AsLong) AsLong DeclareFunction SendMessage()Function SendMessage Lib"user32"Alias"SendMessageA" _ (ByVal hWnd AsLong, _ ByVal wMsg AsLong, _ ByVal wParam AsLong, _ lParam As Any) AsLong' <--- ' ======================================================================== ' listview defs #Const WIN32_IE =&H300 ' user-defined PublicConst LVI_NOITEM =-1 ' messages PublicConst LVM_FIRST =&H1000 #If (WIN32_IE >=&H300) Then PublicConst LVM_GETSUBITEMRECT = (LVM_FIRST +56) PublicConst LVM_SUBITEMHITTEST = (LVM_FIRST +57) #EndIf ' LVM_GETSUBITEMRECT rct.Left PublicConst LVIR_ICON =1 PublicConst LVIR_LABEL =2 Public Type LVHITTESTINFO ' was LV_HITTESTINFO pt As POINTAPI flags AsLong iItem AsLong #If (WIN32_IE >=&H300) Then iSubItem AsLong' this is was NOT in win95. valid only for LVM_SUBITEMHITTEST #EndIf End Type ' LVHITTESTINFO flags PublicConst LVHT_ONITEMLABEL =&H4 ' #If (WIN32_IE >=&H300) Then PublicFunction ListView_GetSubItemRect()Function ListView_GetSubItemRect(hWnd AsLong, iItem AsLong, iSubItem AsLong, _ code AsLong, prc As RECT) AsBoolean prc.Top = iSubItem prc.Left = code ListView_GetSubItemRect = SendMessage(hWnd, LVM_GETSUBITEMRECT, ByVal iItem, prc) End Function PublicFunction ListView_SubItemHitTest()Function ListView_SubItemHitTest(hWnd AsLong, plvhti As LVHITTESTINFO) AsLong ListView_SubItemHitTest = SendMessage(hWnd, LVM_SUBITEMHITTEST, 0, plvhti) End Function #EndIf' ' WIN32_IE >= &H300 文件三:mSubClass.bas OptionExplicit ' ' Copyright ?1997-1999 Brad Martinez, http://www.mvps.org ' PrivateConst WM_DESTROY =&H2 PrivateConst WM_KILLFOCUS =&H8 PrivateDeclareFunction GetProp()Function GetProp Lib"user32"Alias"GetPropA" (ByVal hWnd AsLong, ByVal lpString AsString) AsLong PrivateDeclareFunction SetProp()Function SetProp Lib"user32"Alias"SetPropA" (ByVal hWnd AsLong, ByVal lpString AsString, ByVal hData AsLong) AsLong PrivateDeclareFunction RemoveProp()Function RemoveProp Lib"user32"Alias"RemovePropA" (ByVal hWnd AsLong, ByVal lpString AsString) AsLong DeclareFunction SetWindowLong()Function SetWindowLong Lib"user32"Alias"SetWindowLongA" (ByVal hWnd AsLong, ByVal nIndex AsLong, ByVal dwNewLong AsLong) AsLong PrivateConst GWL_WNDPROC = (-4) PrivateDeclareFunction CallWindowProc()Function CallWindowProc Lib"user32"Alias"CallWindowProcA" (ByVal lpPrevWndFunc AsLong, ByVal hWnd AsLong, ByVal uMsg AsLong, ByVal wParam AsLong, ByVal lParam AsLong) AsLong PrivateConst OLDWNDPROC ="OldWndProc" ' PublicFunction SubClass()Function SubClass(hWnd AsLong, lpfnNew AsLong) AsBoolean Dim lpfnOld AsLong Dim fSuccess AsBoolean If (GetProp(hWnd, OLDWNDPROC) =0) Then lpfnOld = SetWindowLong(hWnd, GWL_WNDPROC, lpfnNew) If lpfnOld Then fSuccess = SetProp(hWnd, OLDWNDPROC, lpfnOld) EndIf EndIf If fSuccess Then SubClass =True Else If lpfnOld ThenCall UnSubClass(hWnd) MsgBox"Unable to successfully subclass &H"&Hex(hWnd), vbCritical EndIf End Function PublicFunction UnSubClass()Function UnSubClass(hWnd AsLong) AsBoolean Dim lpfnOld AsLong lpfnOld = GetProp(hWnd, OLDWNDPROC) If lpfnOld Then If RemoveProp(hWnd, OLDWNDPROC) Then UnSubClass = SetWindowLong(hWnd, GWL_WNDPROC, lpfnOld) EndIf EndIf End Function PublicFunction WndProc()Function WndProc(ByVal hWnd AsLong, ByVal uMsg AsLong, ByVal wParam AsLong, ByVal lParam AsLong) AsLong SelectCase uMsg ' ====================================================== ' Hide the TextBox when it loses focus (its LostFocus event it not fired ' when losing focus to a window outside the app). Case WM_KILLFOCUS ' OLDWNDPROC will be gone after UnSubClass is called, HideTextBox ' calls UnSubClass. Call CallWindowProc(GetProp(hWnd, OLDWNDPROC), hWnd, uMsg, wParam, lParam) Call Form1.HideTextBox(True) Exit Function ' ====================================================== ' Unsubclass the window when it's destroyed in case someone forgot... Case WM_DESTROY ' OLDWNDPROC will be gone after UnSubClass is called! Call CallWindowProc(GetProp(hWnd, OLDWNDPROC), hWnd, uMsg, wParam, lParam) Call UnSubClass(hWnd) Exit Function EndSelect WndProc = CallWindowProc(GetProp(hWnd, OLDWNDPROC), hWnd, uMsg, wParam, lParam) End Function