Notifications
Clear all

[Closed] dotnet listview look / feel like MultiListBox ?

Hey guys

I finally got exactly the result I was after. I am using a dotnet ListBox with a custom selection color and the ability to customize the color of individual list items. The list item color is based off some condition or predefined data.
Here’s the example code:

(
  	global dnListBoxTestRollout
  	try(destroyDialog dnListBoxTestRollout)catch()
  	
  	local dnColor = (dotNetClass "System.Drawing.Color").Black
  	local brushes = dotNetClass "System.Drawing.Brushes"
  	local brushColors = for p in (getPropNames brushes) collect p as string
  	local ListItems = for c in brushColors collect dotNetObject "System.String" c
  	local colorArr = for i in ListItems collect #(dnColor.red, dnColor.green, dnColor.blue)[random 1 3] --(dotNetClass "System.Drawing.Color").fromARGB (random 0 255) (random 0 255) (random 0 255)
  	
  	rollout dnListBoxTestRollout "dnListBoxTestRollout"
  	(
  		local selColor = (dotNetClass "System.Drawing.Color").fromARGB 238 204 85 -- custom selection color (orangey-yellow)
  		local lbBackColor = (dotNetClass "System.Drawing.Color").fromARGB 225 225 225 -- light grey
  		
  		local selBrush = dotNetObject "System.Drawing.SolidBrush" selColor -- create a brush for the selection color
  		local bgBrush = dotNetObject "System.Drawing.SolidBrush" lbBackColor -- create a brush for the backcolor
  		
  		
  		dotNetControl dnListBox "System.Windows.Forms.Listbox" height:400 -- the ListBox
  		radioButtons rdo_exampleMode "Examples:" labels:#("Custom Selection Color", "Named Brushes Colors","Colored Base Off Array") offset:[0,-30] columns:3
  		
  		
  		on rdo_exampleMode changed state do dnListBox.Refresh() -- toggle the drawing state
  		
  		on dnListBox DrawItem arg do --if arg.index == 0 do
  		(
  			case rdo_exampleMode.state of
  			(
  				1: -- use a custom selection color and alternating text color
  				(
  					-- we need to draw a background rectangle first
  					stringState = arg.state.ToString() -- convert the item state to a string
  					-- test the pattern of the string to see if it contains 'selected' since it can contain multiple states eg 'Selected, Focus'
  					if matchPattern stringState pattern:"*selected*" then arg.Graphics.FillRectangle selBrush arg.bounds -- draw the selection color
  					else arg.DrawBackground() -- else draw the background color
  					
  					-- alternatively draw the background color yourself:
  					-- arg.Graphics.FillRectangle bgBrush arg.bounds
  				   
  					-- define a brush to paint the text color
  					brush = if mod arg.index 2 == 0 then brushes.Red else brushes.Black -- alternate between red and black
  					arg.Graphics.DrawString dnListBox.Items.Item[arg.index] arg.font brush arg.bounds.location.x arg.bounds.location.y -- draw the text string
  				)
  				2: -- this mode is not made for selecting - just a demo of the built in colors
  				(
  					-- we need to draw a background rectangle first
  					fillBrush = getProperty brushes brushColors[arg.index+1] -- choose the current brush color by name from the brushes class
  					arg.Graphics.FillRectangle fillBrush arg.bounds -- draw the background
  				   
  					-- define a brush to paint the text color
  					brush = if fillBrush.color.getBrightness() >= 0.5 then brushes.black else brushes.white -- choose black or white based on brightness
  					arg.Graphics.DrawString dnListBox.Items.Item[arg.index] arg.font brush arg.bounds.location.x arg.bounds.location.y -- draw the text string
  				)
  				3: -- assign colors based off a predefined array. To change a color just change the array color and call invalidate() on that item's rectangle
  				(
  					-- we need to draw a background rectangle first
  					stringState = arg.state.ToString() -- convert the item state to a string
  					-- test the pattern of the string to see if it contains 'selected' since it can contain multiple states eg 'Selected, Focus'
  					if matchPattern stringState pattern:"*selected*" then arg.Graphics.FillRectangle selBrush arg.bounds -- draw the selection color
  					else arg.DrawBackground() -- else draw the background color
  					
  					-- define a brush to paint the text color
  					brush = dotNetObject "System.Drawing.SolidBrush" colorArr[arg.index+1]
  					arg.Graphics.DrawString dnListBox.Items.Item[arg.index] arg.font brush arg.bounds.location.x arg.bounds.location.y -- draw the text string
  				)
  			)
  		   
  			arg.DrawFocusRectangle() -- draw the focus rectangle last
  		)
  		
  		on dnListBoxTestRollout open do
  		(
  -- 			dnListBox.drawMode = dnListBox.drawMode.OwnerDrawVariable
  			dnListBox.drawMode = dnListBox.drawMode.OwnerDrawFixed -- fixed seems to be faster than variable, otherwise I can't tell the difference
  			dnListBox.backcolor = lbBackColor
  			dnListBox.SelectionMode = dnListBox.SelectionMode.MultiExtended
  			dnListBox.Items.AddRange ListItems
  		)
  	)
  	createDialog dnListBoxTestRollout width:410 height:420 --pos:[440,85]
  )

Pete: I’m not using your extended control to do this since it seems to stop working as soon as I use the drawItem event. I’m guessing it overrides your one.

EDIT: fixed code to be max 2008 compatible

1 Reply
(@lonerobot)
Joined: 11 months ago

Posts: 0

no worries, and yes, I am using the ownerdraw mode so you will be overriding the painting that i do in the control. Good job!

 PEN

I get this error when running your code.

-- Error occurred in dnListBoxTestRollout.open(); filename: ; position: 4586
--  Frame:
>> MAXScript Rollout Handler Exception: -- Runtime error: No method found which matched argument list <<
true

What max version are you testing on? I’ve got it going on 2009 here

EDIT: I just tested on 2008 and it seems you have to explicitly convert strings to System.String for it to work… I updated the code to reflect this. Try it again and let me know how it goes

it’s probably a max 2008 issue, it doesnt pass the string value into dotnet array correctly from the deepcopied max array. this has been fixed in 2009, however to max2008 it up you need to do this –

		 on dnListBoxTestRollout open do
		 ( 	
			 dnListBox.drawMode = (dotnetclass "System.Windows.Forms.DrawMode").OwnerDrawFixed -- fixed seems to be faster than variable, otherwise I can't tell the difference
			 dnListBox.backcolor = lbBackColor
			 dnListBox.SelectionMode = (dotnetclass "System.Windows.Forms.SelectionMode").MultiExtended
			 
			DotNetStringArray = dotNetObject "System.string[]" ListItems.count
			for i = 1 to ListItems.count do 
			(
			listring = dotnetobject "System.String" listitems[i]
			DotNetStringArray.setvalue listring (i-1)
			)			
			
			dnListBox.Items.AddRange DotnetStringArray			
		 )

gak!

local ListItems = for c in brushColors collect dotNetObject "System.String" c

that’s much better! i’ll have to update some code with that method! I was trying to be careful and build a dotnet string array, so cheers for that!

Page 3 / 3