|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Visual Basic Common Control API
Routines SendMessage: Clicking ListView White Space to De-select Items |
||
Posted: | Monday September 16, 2002 | |
Updated: | Monday December 26, 2011 | |
Applies to: | VB4-32, VB5, VB6 | |
Developed with: | VB6, Windows XP | |
OS restrictions: | None | |
Author: | VBnet - Randy Birch | |
Prerequisites |
This code is equally applicable to the VB4-32, VB5 and VB6 Listview controls operating in either "normal" or FullRowSelect mode. |
|
A
common complaint with the Listview control is that it always returns a
SelectedItem even when no item has been selected, or when you
programmatically attempt to deselect everything using the ListView's
intrinsic commands. This pages shows the code required to deselect a selected item when the user clicks on the white space within the control. White space in a Report-mode listview varies dependant on whether FullRowSelect is active or not. When FullRowSelect is not active (only clicking the main list item selects an item), the white space is defined as :
When FullRowSelect is active, only the last (blue) item is applicable. In addition, white space never includes the non-textual areas within SubItems in Fullrowselect mode. When the red or green white space is clicked, or when a main item is clicked, the SubItem index returned from the SendMessage call is 0. When the blue area is clicked, the SubItem index is -1. Otherwise the SubItem index reflects the SubItem column clicked. This makes it easy to customize the routine to deselect (or select) items based on the index clicked. In fact, you could code for a double click event and if, say, the SubItem index was -1 (tracked from the MouseDown event), you could programmatically do a select all or select none on the control by calling the code shown at SendMessage: ListView Select / Deselect All . This example contains all code required to construct the illustration shown. |
BAS Module Code |
None. |
|
Form Code |
Add a command button (Command1), a check box (Check1) and four labels (Label1 - Label4), with the following code: |
|
Option Explicit '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ' Copyright ©1996-2011 VBnet/Randy Birch, All Rights Reserved. ' Some pages may also contain other copyrights by the author. '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ' Distribution: You can freely use this code in your own ' applications, but you may not reproduce ' or publish this code on any web site, ' online service, or distribute as source ' on any media without express permission. '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' Private Const LVM_FIRST As Long = &H1000 Private Const LVM_SUBITEMHITTEST As Long = (LVM_FIRST + 57) Private Const LVM_HITTEST As Long = (LVM_FIRST + 18) Private Const LVHT_ABOVE = &H8 Private Const LVHT_BELOW = &H10 Private Const LVHT_TORIGHT = &H20 Private Const LVHT_TOLEFT = &H40 Private Const LVHT_NOWHERE As Long = &H1 Private Const LVHT_ONITEMICON As Long = &H2 Private Const LVHT_ONITEMLABEL As Long = &H4 Private Const LVHT_ONITEMSTATEICON As Long = &H8 Private Const LVHT_ONITEM As Long = (LVHT_ONITEMICON Or _ LVHT_ONITEMLABEL Or _ LVHT_ONITEMSTATEICON) Private Type POINTAPI x As Long y As Long End Type Private Type HITTESTINFO pt As POINTAPI flags As Long iItem As Long iSubItem As Long End Type 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 Private Sub Form_Load() Dim itmx As ListItem Dim cnt As Long Dim tmp As Long Randomize Timer With ListView1 .ColumnHeaders.Add , , "Name" .ColumnHeaders.Add , , "Size" .ColumnHeaders.Add , , "Type" .ColumnHeaders.Add , , "Created" .View = lvwReport For cnt = 1 To 100 'create a few random entries 'to simulate real data tmp = Int(Rnd(20) * 20) + 1 Set itmx = .ListItems.Add(, , String(tmp, Chr$(123 - tmp))) itmx.SubItems(1) = tmp & " kb" itmx.SubItems(2) = "winzip file" itmx.SubItems(3) = DateAdd("d", -Int(Rnd(365) * 365), Date) Next End With With Check1 .Caption = "Toggle FullRowSelect" .Value = vbChecked End With End Sub Private Sub Command1_Click() Unload Me End Sub Private Sub Check1_Click() 'VB6 only. VB4-32 and VB5 users will 'require the FullRowSelect API code from 'http://vbnet.mvps.org/code/comctl/lvfullrowselect.htm On Local Error Resume Next ListView1.FullRowSelect = Check1.Value = vbChecked End Sub Private Sub ListView1_MouseDown(Button As Integer, _ Shift As Integer, _ x As Single, _ y As Single) Dim hti As HITTESTINFO Dim itemIndex As Long 'Fill a HITTESTINFO structure with 'information about the point in the 'listview where the mouse was clicked. With hti .pt.x = (x / Screen.TwipsPerPixelX) .pt.y = (y / Screen.TwipsPerPixelY) .flags = LVHT_ABOVE Or LVHT_BELOW Or _ LVHT_TOLEFT Or LVHT_TORIGHT Or _ LVHT_ONITEMICON Or LVHT_ONITEMLABEL Or LVHT_NOWHERE End With itemIndex = SendMessage(ListView1.hwnd, LVM_SUBITEMHITTEST, 0, hti) If itemIndex = -1 And _ (hti.iSubItem = -1 Or _ hti.iSubItem = 0) Then Set ListView1.SelectedItem = Nothing End If 'update labels with index info Label3.Caption = itemIndex Label4.Caption = hti.iSubItem End Sub Private Sub ListView1_MouseUp(Button As Integer, _ Shift As Integer, _ x As Single, _ y As Single) 'update labels with string info, 'first testing to ensure SelectedItem 'can be referenced without error. If Not ListView1.SelectedItem Is Nothing Then Label1.Caption = ListView1.SelectedItem.Index Label2.Caption = ListView1.SelectedItem.Text Else Label1.Caption = "(no selected index)" Label2.Caption = "(nothing)" End If End Sub |
Comments |
Note that the code is split between the MouseDown and MouseUp events. This is due to the fact that in the MouseDown event, it is too early to retrieve the selected item information since it has not been set by the control. Similarly, the MouseDown code can not go into the MouseUp event, because by that time its too late to clear the selected item.. |
|
|
|
|||||
|
|||||
|
|||||
Copyright ©1996-2011 VBnet and Randy Birch. All Rights Reserved. |