Editable TListView?

BlitzMax Forums/BlitzMax Programming/Editable TListView?

Nennig(Posted 2015) [#1]
Hi there,

I am using the TListView.bmx file that I got from Logic GUI but the fields can't be edited directly by the user, the fields are not editable by entering new values on the keyboard.

Is there a possibility to edit the fields values directly?

Many thanks for your help.


skidracer(Posted 2015) [#2]
No, it is not possible. You will need to create a popup window featuring a textfield or similar for such an interaction.


Henri(Posted 2015) [#3]
It is possible, but you have to create it yourself (as it's not native functionality for Windows list control).


Here are the steps to achieve this::

1. When user clicks left mouse button figure out coordinates where button was pressed.

2. Find out which item (aka line) was activated. This is easy because Blitzmax events tell you that.

3. Find out which column resides in those coordinates. One way is to get all column widths and then do the additions going them one by one. Other way is to use win32 messages See listview messages like LVM_SUBITEMHITTEST to determine column.

4. Now that we have column and item we need to use those to get exact coordinates/width/height of the area in that column/item. There is a Windows message called LVM_GETSUBITEMRECT which gives what we want.

5.Create/show an editbox (like MaxGui textfield) in those coordinates with width exactly the width of the column and height exactly the height of the item (line) and set the editbox text with the text in the listview.

6. When editbox looses focus set the edited text in listview and destroy/hide editbox.


Some additional things need to be addressed, but basically thats it.

-Henri


Nennig(Posted 2015) [#4]
Ok, thank you very much guys for this information.
Sounds like a lot of work....

I appreciate the time you took guys to answer my question.


Nennig(Posted 2015) [#5]
Hi there,

In order to figure out the column selected in the selected row of the list view, I added the following code to the TListView.bmx file

In all honesty, I don't really know what I am doing and of course it doesn't work.
Is there a quick fix to this issue?

Many thanks for your help.
Method getListViewColumnSelected:Int(mouse_posx:Int, mouse_posy:Int)
		
	Local LVM_Item:LVHITTESTINFO = New LVHITTESTINFO
		LVM_Item.pt_x = mouse_posx
		LVM_Item.pt_y = mouse_posy
		
	SendMessageW(ListboxHwnd, LVM_SUBITEMHITTEST, 0, Int(Byte Ptr LVM_Item))
	
	Return LVM_Item.iSubItem
	
End Method



Henri(Posted 2015) [#6]
I tried it out and it seems to work for me. In order for Hittest to work it propably needs some mouseaction.

Here's a small example (try changing x-coord):
'EXAMPLE
import maxgui.drivers

Local win:tgadget = CreateWindow("ListView Test", 300, 200, 600, 400)
Local lv:TListView = TListview.Create(0, 0, ClientWidth(win), ClientHeight(win), win)
	lv.addListViewColumn("COL 0",100)
	lv.addListViewColumn("COL 1",100)
	lv.addListViewColumn("COL 2",100)
	lv.deleteListviewColumn(0)
For Local i:Int = 0 To 9
	lv.addListViewItem([String("Item "+i+"|Col 0"), String("Item "+i+"|Col 1"), String("Item "+i+"|Col 2")])
Next

Repeat
	WaitEvent()
	Select EventID()
	Case EVENT_WINDOWCLOSE
		End
	Case EVENT_GADGETACTION
		Select EventSource()
		Case lv
			Print "action"
			Print lv.getListViewColumnSelected(100, 10)
		EndSelect
	EndSelect
Forever


Structure I used:
Type LVHITTESTINFO
	Field pt_x:Int
	Field pt_y:Int
	Field flags:Int
	Field iItem:Int
	Field iSubItem:Int
	Field iGroup:Int
EndType


Not sure if it makes difference, but for my test OS is win7.

-Henri


Nennig(Posted 2015) [#7]
Hi Henri

Many thanks for your help.
I tried to expand on your example but I am still out of luck.
It looks like that getting the position of the mouse over the TListview gadget is a challenge.

Looking at the forum, I came up with the program below. Is there something obvious that I am missing.

I never thought that something that simple to think about would be that difficult to implement ;-)

Many thanks for your kind help.




'EXAMPLE
Import maxgui.drivers
Import "ExternalTypes/TListView.bmx"

Extern "win32"
Function GetCursorPos( point:Byte Ptr )
End Extern

Type TPoint
	Field x,y
End Type
Global point:TPoint = New TPoint


Function MouseX(gadget:tgadget = Null)
If Not gadget gadget=Desktop()
	hwnd=QueryGadget(gadget,GADGET_HWND)
	Local lpPoint[2]
	GetCursorPos lpPoint
	ScreenToClient hwnd,lpPoint
	Return lpPoint[0]
End Function

Function MouseY(gadget:tgadget=Null)
	If Not gadget gadget=Desktop()
	hwnd=QueryGadget(gadget,GADGET_HWND)
	Local lpPoint[2]
	GetCursorPos lpPoint
	ScreenToClient hwnd,lpPoint
	Return lpPoint[1]
End Function


Global win:tgadget = CreateWindow("ListView Test", 300, 200, 600, 400)
Global lv:TListView = TListview.Create(0, 0, ClientWidth(win), ClientHeight(win), win)
	lv.addListViewColumn("COL 0",100)
	lv.addListViewColumn("COL 1",100)
	lv.addListViewColumn("COL 2",100)
	lv.deleteListviewColumn(0)
	For Local i:Int = 0 To 9
		lv.addListViewItem([String("Item "+i+"|Col 0"), String("Item "+i+"|Col 1"), String("Item "+i+"|Col 2")])
	Next

Repeat

	GetCursorPos point

	WaitEvent()
	Select EventID()
	Case EVENT_WINDOWCLOSE
		End
	Case EVENT_MOUSEMOVE
		
	Case EVENT_GADGETACTION
		Select EventSource()
		Case lv
			Print "The column selected is : " + lv.getListViewColumnSelected(MouseX(lv), MouseY(lv))
			
		EndSelect
	EndSelect
Forever




Henri(Posted 2015) [#8]
I believe that the best way to get the mousecoords is straight from the source. There is a NewListProc() function inside TListView type which is a native callback function for listview. Every event that originates from listview goes here first which seems a good place to catch mousecoords.

Add two global variables inside TListView type called xPos:int and yPos:int. Then add this statement inside NewListProc() function
If Msg = WM_LBUTTONDOWN

	'Check mouse location in relative to listview
	xPos = (lParam & $FFFF)  
	yPos = (lParam Shr 16)
EndIf


Now replace lv.getListViewColumnSelected-parameters with lv.xPos and lv.yPos and voila :-)

-Henri


col(Posted 2015) [#9]
Hiya guys...

If i understand what youre trying to achieve here, how about sending a LVM_SUBITEMHITTEST message to the hwnd of the listviewcontrol with a LVHITTESTINFO structure to get the details returned from there?


Nennig(Posted 2015) [#10]
Hi Henri,

You are a genius! Your solution worked liked a charm!
I owe you a beer, for sure!

This was getting frustrating, thank you so much.

I am trying to write an app to help me learn the guitar. The listview has columns for chord names, lyrics etc... I need a way to change the values by double clicking on them in order to create/edit a song.

I suppose that ideally, I would have needed a grid control but I don't think there is one with maxgui.

Also tried to install wxMax to give it a try but I did not manage to compile the module...
Well, sweat for another day.... I mostly do Excel Vba programming at work so this Win32 and gcc stuff is not my forte ;-)

Many thanks for your assistance.

Hi Col,

What you suggest is what we did, but I didn't know how to properly get the position of the mouse over the listview control.


col(Posted 2015) [#11]
Ahh yes, up at post #5.

Ignore me... I'll crawl into my little corner :-)

Good luck with the app, sounds cool.