Page 1
Page 2
Page 3
And the code for the Find_Subitem is...
Private Sub Find_Subitem(X As Long, Y
As Long)
Dim xlv As Long
Dim Rect As Long
Dim subitem As Long
xlv = AllocPointer(20)
Call SetLongAt(xlv, 0, X)
Call SetLongAt(xlv, 4, Y)
Dim Lret As Long
lv.SetFocus
Lret = SendMessage(GetFocus(), _
LVM_SUBITEMHITTEST, 0, xlv)
subitem = GetLongAt(xlv, 16)
FreePointer (xlv)
Rect = AllocPointer(16)
Call SetLongAt(Rect, 0, LVIR_LABEL)
Call SetLongAt(Rect, 4, subitem)
Lret = SendMessage(GetFocus(), _
LVM_GETSUBITEMRECT, _
lv.SelectedItem.Index, Rect)
Lret = MapWindowPoints(GetFocus(), _
frmGrdPerf.hWnd, Rect, 2)
siLeft = GetLongAt(Rect, 0)
siTop = GetLongAt(Rect, 4)
siRight = GetLongAt(Rect, 8)
siBottom = GetLongAt(Rect, 12)
txtFocus.Move _
(siLeft + 4) * Screen.TwipsPerPixelX, _
(siTop * Screen.TwipsPerPixelY) - 200, _
(siRight - siLeft) * Screen.TwipsPerPixelX, _
(siBottom - siTop) * Screen.TwipsPerPixelY
FreePointer (Rect)
If subitem <> 0 Then
txtFocus.Text = _
lv.SelectedItem.SubItems(subitem)
Else
txtFocus.Text = _
lv.ListItems(lv.SelectedItem)
End If
txtFocus.Visible = True
txtFocus.ZOrder
txtFocus.SelStart = 0
txtFocus.SelLength = Len(txtFocus.Text)
txtFocus.SetFocus
End Sub
The structure used for LVM_SUBITEMHITTEST
is...
Public Type LVHITTESTINFO
pt As POINTAPI
flags As Long
iItem As Long
iSubItem As Long
End Type
And pointapi
is...
Public Type POINTAPI
X As Long
Y As Long
End Type
First of all we allocate 20 bytes
for the structure we need for the LVM_SUBITEMHITTEST.
Next we supply the x and y values using SetLongAt,
and do a sendmessage of LVM_SUBITEMHITTEST.
This will return us the number of the subitem selected,
and we extract it using GetLongAt. If the subitem
returned is 0, it means the user has clicked on the item
as opposed to the subitem. The next task is to 'highlight'
the item or subitem. VB6 uses the 'rect' structure...
Public Type RECT
Left As Long
Top As Long
Right As Long
Bottom As Long
End Type
Using a sendmessage of LVM_GETSUBITEMRECT,
we get the coordinates of the sub item. This is now where
I get a bit lost. According to MSDN, "The MapWindowPoints
function converts (maps) a set of points from a coordinate
space relative to one window to a coordinate space relative
to another window." It may well do, but as it was in
Brads code, it needs to be in ours. We get back the coordinates,
and move the text box to those coordinates. We then take
the value from the grid, and enter it in the text box, and
finally, make the text box visible.

A menu is provided in the demo code,
so that you can see the effect of switching on gridlines
etc.
In conclusion
Phew - that is it. Not the easiest of
solutions, but in the worst case above, we have created
a solution that is 70 TIMES QUICKER, and even in
the best case, we are 9 TIMES QUICKER!
If anybody can suggest improvements
on the code, or any ideas to make the grid perform as quickly
as the listview control, I am sure we would all be pleased
to take it on board. Maybe one idea is to use method 3,
but clip the grid every 100 records or so, as constantly
adding to the string will affect performance.
Meanwhile, I am steering clear of the
grid control.
Thanks to articles written by Yaroslav
Goncharov, Chris Tacke and Brad Martinez.
As a final aside, I did some testing
on my 'real world' app. This read and formatted 2623 records
each containing 19 fields, and displayed them. The test
was run 10 times.
The average time using a grid, and the
.clip method was 102.1 seconds per run.
The average time using the listview
control was 71.9 seconds per run.
Previous Page