Notifications
Clear all

[Closed] dotNet listview node select

Im trying to work with dotNet, create a menu that has 2 columns

1 column with the name of objects in a scene
1 column with the name of the material that is applied to that object.

So far the listing works great. Ive checked Paul Neale’s website for an example and worked from there. But im trying to add a function that if you select an item in that list it will select the corresponding node.

Ive seen the script from paul for a treeview function in which the selection works superb, but I cant seem to get it to work in a listview function.

here is the code I have so far:

(
 --Destroy dialog if it already exists.
 try(destroyDialog matCheck)catch()
 
 --Create a rollout
 rollout matCheck "Material Checker V1.0" width:300
 (
 
 
 		
 		--Create the dotNet listview control
 	dotNetControl lv "system.windows.forms.listView" height:200 width:275
 	
 	
 	--Create a button for testing. 
 	button refresh "Refresh"pos:[65,210] width:50 height:21
 	button delBut "Delete"pos:[118,210] width:50 height:21
 	button count "Count" pos:[171,210] width:50 height:21
 	label name_lbl "Objects: 0" pos:[224,214] width:75 height:21
 	button closeRoll "Close" tooltip: "This will close your Floating Dialogorama" 
 	
 	-- Sort the items in the list in ascending order.
 	local sortOrder = dotNetClass "System.Windows.Forms.SortOrder"
 	
 	--Innitialize the listview control
 	fn initLv papiLv=
 		(
 			--Setup the forms view
 			papiLv.view=(dotNetClass "system.windows.forms.view").details
 			papiLv.FullRowSelect=true		--Set so full width of listView is selected and not just first column.
 			papiLv.GridLines=true			--Show lines between the items. 
 			papiLv.MultiSelect=true			--Allow for multiple selections. 
 			papilv.Sorting = sortOrder.Ascending; -- this snippet needs the local sortOrder snippet above
 -- 			lv.AllowColumnReorder = pAllowReorder;
 	-- 		papiLv.gridLines = false-- turn off the grid lines
 			papiLv.backColor=lv.backColor.FromArgb 154 154 154 -- Soften the background intensity a bit
 		)
 	
 		
 	--Add columns. 
 	fn addColumns papiLv columnsAr=
 		(
 			w=(papiLv.width/columnsAr.count)-1		--Calculate the width of each column.
 			for x in columnsAr do		--Loop through all the column names to be added. 
 			(
 				papiLv.columns.add x w		--Add each new column to the listview control. 
 			)
 		)
 	
 	--Adds rows of data to the listView
 	fn populateList papiLv=
 		(
 			rows=#()		--Empty array to collect rows of data
 			for x in objects do		--Loop through all the objects in the scene. 
 			(
 				li=dotNetObject "System.Windows.Forms.ListViewItem" x.name		--Create a listViewItem object and name it. 
 				li.subitems.add ((x.material) as string)		--Add material data 
 				
 				
 				append rows li		--Added the listViewItem to the rows array
 			)
 			papiLv.items.addRange rows		--Add the array of rows to the listView control. 
 		)
 	
 
 
 	-- funtion to clear items in lists
 	fn ClearLvItems lv =
 	(
 		lv.items.clear()	
 	)
 	
 	--Select objects function. 
 	fn selectObject theLvNode=
 	(
 		local indexPath=#()	--Array to hold the index of each node in the path.
 		while theLvNode!=undefined do	--While loop to walk backwards from the selected node to root. 
 		(
 			insertItem theLvNode.index indexPath 1	--Insert the index of each node into array at at start.
 			theLvNode=theLvNode.parent	--Set theTvNode to the parent node. 
 		)
 		
 		ol=objectList[indexPath[1]+1]	--Get the root node in objectTree to start with
 		for i = 2 to indexPath.count do	--Loop trough all the index values accept the first.
 		(
 			ol=ol.children[indexPath[i]+1]	--Set ot to each of the structs by index.
 		)
 		if isValidNode ol.obj	then select ol.obj--Select the object that is left. 
 	)
 	
 
 	
 	
 	on delBut pressed do
 		(
 		-- get selected items of list view
 		SelectedIndexs = #()
 		for i = lv.SelectedItems.count to 1 by -1 do
 		(
 			local theItem = lv.SelectedItems.Item[i-1]
 			append SelectedIndexs theItem.index
 			
 			-- delete list view items
 			theItem.Remove()
 			
 		)
 		
 		
 -- 		lv.items.clear()
 -- 		initLv lv
 -- 		populateList lv
 	)
 			
 		
 	
 	
 	on count pressed do
 		(
 			for i = 1 to objects.Count do
 			name_lbl.text = "Objects: " + (i as string)
 		)
 		
 	on refresh pressed do
 		(
 			lv.items.clear()
 			initLv lv
 			populateList lv
 			for i = 1 to objects.Count do
 			name_lbl.text = "Objects: " + (i as string)
 		)
 	
 	
 	
 	on lv mouseDown arg do
 			(
 			selectObject (lv.GetNodeAt arg.location)
 			)
 
 	
 	on closeRoll pressed do
 		(
 		destroydialog matCheck
 		)
 	
 		
 	
 	on matCheck open do
 		(
 			initLv lv
 			addColumns lv #("Objectname","Material")
 			populateList lv
 			for i = 1 to objects.Count do
 			name_lbl.text = "Objects: " + (i as string)
 		)
 
 		
 
 )
 
 --Create a dialog and assign the rollout to it. 
 createDialog matCheck \
 style:#(#style_titlebar, #style_border, #style_sysmenu,#style_minimizebox,#style_resizing)
 
 )

t.i.a.

updated working code

rollout matCheck "Material Checker V1.0" width:360
(


		
		--Create the dotNet listview control
	dotNetControl lv "system.windows.forms.listView" height:200 width:335
	
	
	--Create a button for testing. 
	button all "All"pos:[12,210] width:50 height:21
	button refresh "Refresh"pos:[65,210] width:50 height:21
	button delBut "Delete"pos:[118,210] width:50 height:21
	button count "Count" pos:[171,210] width:50 height:21
	label name_lbl "Objects: 0" pos:[224,214] width:75 height:21
	
	button closeRoll "Close" tooltip: "This will close your Floating Dialogorama" 


	
	-- Sort the items in the list in ascending order.
	local sortOrder = dotNetClass "System.Windows.Forms.SortOrder"
	
	--Innitialize the listview control
	fn initLv papiLv=
		(
			--Setup the forms view
			papiLv.view=(dotNetClass "system.windows.forms.view").details
			papiLv.FullRowSelect=true		--Set so full width of listView is selected and not just first column.
			papiLv.GridLines=true			--Show lines between the items. 
			papiLv.MultiSelect=true			--Allow for multiple selections. 
			papilv.Sorting = sortOrder.Ascending; -- this snippet needs the local sortOrder snippet above
			papilv.AllowColumnReorder = true -- makes it possible to move columns around
	-- 		papiLv.gridLines = false-- turn off the grid lines
			papiLv.backColor=lv.backColor.FromArgb 154 154 154 -- Soften the background intensity a bit

		)
	
		
	--Add columns. 
	fn addColumns papiLv columnsAr=
		(
			w=(papiLv.width/columnsAr.count)-1		--Calculate the width of each column.
			for x in columnsAr do		--Loop through all the column names to be added. 
			(
				papiLv.columns.add x w		--Add each new column to the listview control. 
			)
		)
	

		
	--Adds rows of data to the listView
	fn populateList papiLv=
		(
			rows=#()		--Empty array to collect rows of data
			for x in objects do		--Loop through all the objects in the scene. 
			(
				li=dotNetObject "System.Windows.Forms.ListViewItem" x.name		--Create a listViewItem object and name it. 
				li.subitems.add ((x.material) as string)		--Add material data 
				li.subitems.add ((x.parent) as string)		--Add material data 
				li.Tag = dotnetMXSValue x
				
				append rows li		--Added the listViewItem to the rows array
			)
			papiLv.items.addRange rows		--Add the array of rows to the listView control. 
		)
	


	-- funtion to clear items in lists
	fn ClearLvItems lv =
	(
		lv.items.clear()	
	)

	on delBut pressed do
		(
			with undo on
			(
				-- get selected items of list view
				SelectedIndexs = #()
				for i = lv.SelectedItems.count to 1 by -1 do
				(
					local theItem = lv.SelectedItems.Item[i-1]
					append SelectedIndexs theItem.index
					
					-- delete list view items
					theItem.Remove()
					-- delete corresponding node
					nodes = for k=0 to lv.selectedItems.count-1 where isvalidnode (node = lv.selectedItems.item[k].tag.value) collect node
					delete nodes
				)
			)
		)
			
		
	on count pressed do
		(
			for i = 1 to objects.Count do
			name_lbl.text = "Objects: " + (i as string)
		)
		
	on refresh pressed do
		(
			lv.items.clear()
			initLv lv
			populateList lv
			for i = 1 to objects.Count do
			name_lbl.text = "Objects: " + (i as string)
		)
	
	
	on lv ItemSelectionChanged s a do
		(
			format "item:% selected:% node:%
" a.item.text a.isSelected a.item.tag.value 
		)
	
	
	
	on lv SelectedIndexChanged s a do
		(
			with undo off 
			(
				nodes = for k=0 to s.selectedItems.count-1 where isvalidnode (node = s.selectedItems.item[k].tag.value) collect node
				if nodes.count == 0 then clearselection() else select nodes
			)
		)



		
		

	

	
	on closeRoll pressed do
		(
		destroydialog matCheck
		)
	
	
	on matCheck open do
		(
			initLv lv
			addColumns lv #("Objectname","Material","Group")
			populateList lv
			for i = 1 to objects.Count do
			name_lbl.text = "Objects: " + (i as string)
		)

		

)

--Create a dialog and assign the rollout to it. 
createDialog matCheck \
style:#(#style_titlebar, #style_border, #style_sysmenu,#style_minimizebox,#style_resizing)
13 Replies

anyone???


      on dv MouseClick sender args do
      (
         local leftClick  = false ; local rightClick = false
         if args.button.value__ == args.Button.left.value__ then leftClick = true else if args.button.value__ == args.Button.right.value__ do rightClick = true

          if rightClick do print dv.SelectedItems.item[0].tag
       )

1 Reply
(@denist)
Joined: 1 year ago

Posts: 0

on lv MouseClick sender args do if args.Button == args.Button.Left do ( ... )

Unfortunately it doesn’t work. NO selection and no selection being printed with rightmouse.

Could you also please elaborate how this snippet works. To which value is the mousearg being compared? Bit confused

Btw dv and dv.selectedItems… they are the lv handlers right? So with my script they should be lv instead of dv right?

yes they should be lv for you
its compared to the args.Button.left.value__, dont worry it works

also it doesnt print anything because your .tag properties are empty
in mine i use em to store filePath strings so it prints them
and with singleSelection its alllways item 0 you want as its in the array of selected nodes

Hmmm Im sorry i cant seem to get it to work even with LV for tags.

I added a small line to check the mouseclick

if leftClick do print "ok!"

but that works fine. But it doesnt select any object int the scene.

to catch list view item selection change use ItemSelectionChanged event. MouseClick might not cause the selection change. Also the selection can be changed other way then mouse use (keybord for example).

headache!!!

This is a difficult script. Im getting all kinds of errors including an isselected error dialog after a couple of dozen trials.

Ive googled for some expamples of how to use this itemselectionchange in a script but only get 2 results and the rest is for C# programming which I have no clue on how to translate that into maxscript.

The mouseclick function works fine, but the items in the list are not being connected to the items in the scene. Which makes me think, would it be easier to add checkboxes to the list and connect them to a node in the scene through a boolean script. checked is selected, unchecked is not selected. Its a bit way around and I prefer without checkboxes tho.

1 Reply
(@denist)
Joined: 1 year ago

Posts: 0

Not at all. Here is a snippet that has help you to understand how lv selection events work.


try(destroyDialog listview_rollout) catch()
rollout listview_rollout "List View"
(
	local align = dotNetClass "HorizontalAlignment"
	
	dotNetControl lv "ListView" width:340 height:200 pos:[0,0]
	
	local headers = #(#("Node", 140, align.Left), #("Comments",140, align.Left))
	fn initLV =
	(
		lv.view = lv.view.Details
		lv.HideSelection = off
		lv.FullRowSelect = on
		lv.MultiSelect = on
		for c in headers do lv.Columns.add c[1] c[2] c[3] 
	)
	fn fillLV =
	(
		lv.items.clear()
		for node in objects as array do 
		(
			item = lv.items.add node.name
			item.tag = dotnetmxsvalue node
		)
	)
	
	on lv ItemSelectionChanged s a do
	(
		format "item:% selected:% node:%
" a.item.text a.isSelected a.item.tag.value 
	)
	on lv SelectedIndexChanged s a do
	(
		with undo off 
		(
			nodes = for k=0 to s.selectedItems.count-1 where isvalidnode (node = s.selectedItems.item[k].tag.value) collect node
			if nodes.count == 0 then clearselection() else select nodes
		)
	)
	
	on listview_rollout open do
	(	
		initLV()
		fillLV()
		ok
	)
)
createDialog listview_rollout 340 200

/* execute to populate the scene:
with undo off
(
	delete objects
	for k=1 to 20 do box width:10 pos:[k*12,0,0]
)
*/

PS. It’s just a sample and it doesn’t show the best way of the storing and the selecting scene nodes.

Denis has already given you the solution – the ItemSelectionChanged event.

You can also take advantage of the dotnetMXSValue class and store a reference to your scene node in the Tag property of each of ListViewItem.

So in your code in your populateList function you can add to your for loop:

li.Tag = dotnetMXSValue x

Then your ItemSelectionChanged event becomes:

on lv ItemSelectionChanged arg do
 (
 tag = arg.item.tag
 if classof tag == dotnetMXSValue AND isValidNode tag.value do select tag.value
 )
 

w00t! Joel and Denis thnx. Finally your codes combined made it work properly. Trust me Denis for you its much easier to understand this coding, I have no idea what im looking at, just guess here and there how it should work (did some html in the past, although its not comparable heh).

I still have 3 small remaining questions tho that I hope you can answer.

1. I have a delete button, but it deletes everything that is selected in the list EXCEPT for the last one. So select 3 items, deletes 2, 5 deletes 4, theres always 1 remaining. Code:

on delBut pressed do
		(
			with undo on
			(
				-- get selected items of list view
				SelectedIndexs = #()
				for i = lv.SelectedItems.count to 1 by -1 do
				(
					local theItem = lv.SelectedItems.Item[i-1]
					append SelectedIndexs theItem.index
					
					-- delete list view items
					theItem.Remove()
					-- delete corresponding node
					nodes = for k=0 to lv.selectedItems.count-1 where isvalidnode (node = lv.selectedItems.item[k].tag.value) collect node
					delete nodes
				)
			)
		)

I figure I have to play with the selecteditems.count but adjusting that one just gives errors or deletes less items.

2.I would like to play more with the look and feel of listforms in dotnet and yesterday I found a snippet that shows the properties for a list
showproperties (dotNetClass “system.windows.forms.view”) or something like that ( forgot the string), is there a snippet that shows the properties for column? I currently have:
FullRowSelect=true –Set so full width of listView is selected and not just first column.
GridLines=true –Show lines between the items.
MultiSelect=true –Allow for multiple selections.
Sorting = sortOrder.Ascending; – this snippet needs the local sortOrder snippet above
AllowColumnReorder

Where could I find more of these properties?

3.And last but not least, if I search for dotnet stuff on the internet I always get results for programming language C#. Do you guys use that code and convert it for maxscript with a software or in your head? How does it work if you want to use something out of C#

thnx for the help, much appreciated

btw updated code is the first post.

Page 1 / 2