Editor's Note A listview is an advanced listbox. The listview control is typically used to display members of a data collection in table format. Each column has its own column header. The listview is far more complex than the ordinary listbox. While the listbox is easily populated from its associated array, the listview requires each item to be individually assigned. This assignment is accomplished with a rather complicated series of structs and API calls.
A listview demo is included in Alyce Watson's (- Alyce) Liberty 4 Companion ebook. Alyce's demo shows how to construct a listview, add and delete items to the listview, and make a listview selection by highlighting an item and then clicking the select button. Eldron Gill takes Alyce's demo one step further by allowing selection from a double mouse click on the listview item itself.
Capturing mouse clicks in a listview requires a callback function, not easily handled even with Liberty BASIC. Fortunately, Dennis McKinney (- DennisMcK) offers the free msghook.dll designed specifically for this purpose. Here is Eldron's modification of Alyce's listview demo to allow selection by a double left mouse click. As stated in the code, msghook.dll must be accessible within the program folder.
It should be mentioned that Eldron sought and received permission from both Alyce and Dennis before submitting this demo. Our thanks to all three for this collaboration and sharing of resources and knowledge.
'This demo requires msghook.dll by Dennis McKinney
'Get it here: http://www.syberden.net/libertybelle/dlls.htm
'Alyce Watson provided the listview code.
'http://www.alycesrestaurant.com
'listview control with double click 10/09/2006 Eldron Gill
nomainwin
dim info$(0,0)
If fileExists(DefaultDir$, "msghook.dll") < 1 then
notice ""+chr$(13)+"This demo requires msghook.dll by Dennis McKinney"+chr$(13)+_
"Download the dll from here : http://www.syberden.net/libertybelle/dlls.htm"+chr$(13)+_
"Place it in the folder with this code."EndEndIf'constants
LVS.NOSORTHEADER = 32768
LVS.REPORT = 1
LVS.SINGLESEL = 4
LVS.SHOWSELALWAYS = 8
LVS.SORTASCENDING = 16
LVS.SORTDESCENDING = 32
LVS.NOLABELWRAP = 128
LVS.AUTOARRANGE = 256
LVS.NOSCROLL = 8192
LVS.ALIGNTOP = 0
LVS.ALIGNLEFT = 2048
LVS.NOCOLUMNHEADER = 16384
LVIF.TEXT = 1
LVIF.STATE = 8
LVIS.UNSELECTED = 0
LVIS.FOCUSED = 1
LVIS.SELECTED = 2
LVM.FIRST = 4096
LVM.SETITEM = 4102
LVM.INSERTITEM = 4103
LVM.INSERTCOLUMN = 4123
LVM.GETITEMCOUNT = 4100
LVM.GETITEMA = 4101
LVM.GETITEMTEXTA = 4141
LVM.GETITEMSTATE = 4138
LVM.SETITEMSTATE = 4139
LVM.DELETEITEM = 4104
LVM.DELETEALLITEMS = 4105
LVCF.WIDTH = 2
LVCF.TEXT = 4
'create structs
Struct LVCOLUMN, _
mask As ulong, _
fmt Aslong, _
cx Aslong, _
pszText$ As ptr, _
cchTextMax Aslong, _
iSubItem Aslong, _
iImage Aslong, _
iOrder Aslong
Struct LVITEM, _
mask As ulong, _
iItem Aslong, _
iSubItem Aslong, _
state As ulong, _
stateMask As ulong, _
pszText$ As ptr, _
cchTextMax Aslong, _
iImage Aslong, _
lParam Aslong, _
iIndent Aslong
struct msg,_
hndl aslong,_
message aslong,_
wParam aslong,_
lParam aslong,_
LOWORDwparam as word,_
HIWORDwparam as word,_
LOWORDlparam as word,_
HIWORDlparam as word
'initialize common controls:
calldll #comctl32, "InitCommonControls",re as void
' Open a window
WindowWidth = 240: WindowHeight = 200
UpperLeftX = 10: UpperLeftY = 10
button #1.b, "Add",[add],UL,10,10,90,24
button #1.d, "Delete",[delete],UL,120,10,90,24
button #1.GetMsgHookCallback, "", [choice], ul, 0, 0, 0, 0
statictext #1.s, "List count: 2",10,140,100,30
open"Listview Example"for dialog as #1
print #1, "trapclose [quit]"
hwndParent = hwnd(#1)
' Get window instance handle
CallDLL #user32, "GetWindowLongA",_
hwndParent Aslong,_ 'parent window handle
_GWL_HINSTANCE Aslong,_'flag to retrieve instance handle
hInstance Aslong'instance handle
' Create control
style = _WS_CHILD OR _WS_VISIBLE OR LVS.NOSORTHEADER _
OR LVS.REPORT OR LVS.SINGLESEL OR LVS.SHOWSELALWAYS
calldll #user32, "CreateWindowExA",_
_WS_EX_CLIENTEDGE Aslong,_ ' extended style
"SysListView32"as ptr,_ ' class name
""as ptr,_
style aslong,_ ' style
10 aslong,_ ' left x
50 aslong,_ ' top y
200 aslong,_ ' width
80 aslong,_ ' height
hwndParent aslong,_ ' parent hWnd
0 aslong,_
hInstance aslong,_ ' hInstance
""as ptr,_
hwndLV aslong' listview handle
'insert first column:
LVCOLUMN.mask.struct = LVCF.WIDTH OR LVCF.TEXT
LVCOLUMN.cx.struct = 90
LVCOLUMN.pszText$.struct = "Name"
CallDLL #user32, "SendMessageA", _
hwndLV Aslong, _
LVM.INSERTCOLUMN Aslong, _
0 Aslong, _ '0 = first column
LVCOLUMN As struct, _
r Aslong'insert second column:
LVCOLUMN.cx.struct = 65
LVCOLUMN.pszText$.struct = "Rank"
CallDLL #user32, "SendMessageA", _
hwndLV Aslong, _
LVM.INSERTCOLUMN Aslong, _
1 Aslong, _ '1 = second column
LVCOLUMN As struct, _
r Aslong'insert text for first row, first column
'requires message to insert item
LVITEM.mask.struct = LVIF.TEXT
LVITEM.iItem.struct = 0 'first row
LVITEM.iSubItem.struct = 0 'first column
LVITEM.pszText$.struct = "Carl Gundel"
CallDLL #user32, "SendMessageA", _
hwndLV Aslong, _
LVM.INSERTITEM Aslong, _
0 Aslong, _
LVITEM As struct, _
r Aslong'insert text for second column, first row
LVITEM.iItem.struct = 0 'first row
LVITEM.iSubItem.struct = 1 'second column
LVITEM.pszText$.struct = "Expert"
CallDLL #user32, "SendMessageA", _
hwndLV Aslong, _
LVM.SETITEM Aslong, _ '
0 Aslong, _
LVITEM As struct, _
r Aslong'insert second row, first column
LVITEM.iItem.struct = 1 'second row
LVITEM.iSubItem.struct = 0 'first column
LVITEM.pszText$.struct = "Bill Gates"
CallDLL #user32, "SendMessageA", _
hwndLV Aslong, _
LVM.INSERTITEM Aslong, _
0 Aslong, _
LVITEM As struct, _
r Aslong'add second column to second row
LVITEM.iItem.struct = 1 'second row
LVITEM.iSubItem.struct = 1 'second column
LVITEM.pszText$.struct = "Novice"
CallDLL #user32, "SendMessageA", _
hwndLV Aslong, _
LVM.SETITEM Aslong, _ '
0 Aslong, _
LVITEM As struct, _
r Aslong'full row select
LVM.FIRST = hexdec("1000")
LVM.SETEXTENDEDLISTVIEWSTYLE = LVM.FIRST + 54
LVS.EX.FULLROWSELECT = hexdec("20")
CallDLL #user32, "SendMessageA", _
hwndLV Aslong, _
LVM.SETEXTENDEDLISTVIEWSTYLE Aslong, _ '
LVS.EX.FULLROWSELECT Aslong, _
LVS.EX.FULLROWSELECT Aslong, _
r Aslong' if you want a grid, leave next message uncommented...
CallDll #user32, "SendMessageA" , hwndLV as uLong, 4150 asLong,_
1 AsLong, 1 AsLong, re asLong'
open"MsgHook"for dll as #MsgHook
hMsgProc = hwnd(#1.GetMsgHookCallback)
calldll #MsgHook, "TrapMsgFor",hwndLV aslong, ret asboolean
calldll #MsgHook, "WatchMsg", hwndLV aslong, _WM_LBUTTONDBLCLK aslong, ret asboolean
hMsgProc = hwnd(#1.GetMsgHookCallback)
calldll #user32, "GetWindowLongA",hMsgProc aslong,_GWL_ID as short,callbackID aslong
calldll #MsgHook, "CreateGetMsgProcHook", hwndParent aslong, callbackID aslong, _
hMsgProc aslong, hHook aslong
wait
[choice] 'determine user selection
calldll #MsgHook, "GetMsg", msg as struct, ret as void
'get number of items in list:
CallDLL #user32, "SendMessageA", _
hwndLV Aslong, _
LVM.GETITEMCOUNT Aslong, _
0 Aslong, _ 'always 0
0 Aslong, _ 'always 0
total Aslongfor index = 0 to total-1 'check each row
LVITEM.mask.struct = LVIF.TEXT OR LVIF.STATE
LVITEM.iItem.struct = index 'row
LVITEM.iSubItem.struct = 0 'first column
LVITEM.cchTextMax.struct = 32
LVITEM.pszText$.struct = space$(32)
LVITEM.stateMask.struct = LVIS.SELECTED
CallDLL #user32, "SendMessageA", _
hwndLV Aslong, _
LVM.GETITEMA Aslong, _
index Aslong, _ 'index of row
LVITEM As struct, _
r Aslong
state = LVITEM.state.struct 'selected state of item
if state and LVIS.SELECTED then
txt$=winstring(LVITEM.pszText$.struct)
notice "Selected: ";txt$
exitforendifnextif txt$=""then notice "No selection."
txt$=""
wait
[add]
'make sure no item is in selected state:
LVITEM.stateMask.struct = LVIS.SELECTED 'bit to set
LVITEM.state.struct = LVIS.UNSELECTED
CallDLL #user32, "SendMessageA", _
hwndLV Aslong, _
LVM.SETITEMSTATE Aslong, _
-1 Aslong, _ 'change applies to all items
LVITEM As struct, _
r Aslong
CallDLL #user32, "SendMessageA", _
hwndLV Aslong, _
LVM.GETITEMCOUNT Aslong, _
0 Aslong, _ 'always 0
0 Aslong, _ 'always 0
count Aslong
name$="No Name"
prompt "Name?";name$
if name$=""then name$="No Name"'insert next row, first column
LVITEM.mask.struct = LVIF.TEXT
LVITEM.iItem.struct = count 'next row
LVITEM.iSubItem.struct = 0 'first column
LVITEM.pszText$.struct = name$
CallDLL #user32, "SendMessageA", _
hwndLV Aslong, _
LVM.INSERTITEM Aslong, _
0 Aslong, _
LVITEM As struct, _
r Aslong
level$="No Level"
prompt "Level?";level$
if level$=""then level$="No Level"'add second column to row
LVITEM.iItem.struct = count 'next row
LVITEM.iSubItem.struct = 1 'second column
LVITEM.pszText$.struct = level$
CallDLL #user32, "SendMessageA", _
hwndLV Aslong, _
LVM.SETITEM Aslong, _
0 Aslong, _
LVITEM As struct, _
r Aslongprint #1.s, "List count: ";count+1
wait
[delete]'get user selection and delete
'get number of items in list:
CallDLL #user32, "SendMessageA", _
hwndLV Aslong, _
LVM.GETITEMCOUNT Aslong, _
0 Aslong, _ 'always 0
0 Aslong, _ 'always 0
total Aslongfor index = 0 to total-1 'check each row
LVITEM.mask.struct = LVIF.STATE
LVITEM.iItem.struct = index 'row
LVITEM.iSubItem.struct = 0 'first column
LVITEM.stateMask.struct = LVIS.SELECTED
CallDLL #user32, "SendMessageA", _
hwndLV Aslong, _
LVM.GETITEMA Aslong, _
index Aslong, _ 'index of row
LVITEM As struct, _
r Aslong
state = LVITEM.state.struct 'selected state of item
if state and LVIS.SELECTED then
CallDLL #user32, "SendMessageA", _
hwndLV Aslong, _
LVM.DELETEITEM Aslong, _
index Aslong, _
LVITEM As struct, _
r Aslongexitforendifnextprint #1.s, "List count: ";total-1
wait
[quit]
calldll #MsgHook, "UnhookMsgHook", hHook aslong, ret as void
close #MsgHook
calldll #user32, "DestroyWindow", _
hwndLV aslong, re aslong' Close handles.
close #1:end'Function to determine if a file exists
function fileExists(path$, filename$)
files path$, filename$, info$()
fileExists = val(info$(0, 0)) 'non zero is true
endfunction
Trapping a Double Click in a Listview
Demo by Eldron Gill (-
eaglesoar)
Editor's Note
A listview is an advanced listbox. The listview control is typically used to display members of a data collection in table format. Each column has its own column header. The listview is far more complex than the ordinary listbox. While the listbox is easily populated from its associated array, the listview requires each item to be individually assigned. This assignment is accomplished with a rather complicated series of structs and API calls.
A listview demo is included in Alyce Watson's (-
Capturing mouse clicks in a listview requires a callback function, not easily handled even with Liberty BASIC. Fortunately, Dennis McKinney (-
It should be mentioned that Eldron sought and received permission from both Alyce and Dennis before submitting this demo. Our thanks to all three for this collaboration and sharing of resources and knowledge.