::Python Objects In A TextScrollList::

May 14th, 2011 by hamish download the zooToolBox

One of the more useful classes in baseMelUI is the MelObjectScrollList.  Its simplified UI code enough times for me that I figured it’d be worthwhile pointing it out to others.

The MelObjectScrollList class is subclass of MelTextScrollList – which is a wrapper to the cmds.textScrollList widget command.  The class provides a neat object oriented way to interact with the scroll list.  It hides some of the weirdness of the command (such as indices starting at 1 – WTF?!) and makes it possible to write object oriented code with all the good stuff you expect.

Back to the MelObjectScrollList – so the idea with this class is to use the textScrollList widget to display lists of data of any kind.  Want a list of dictionaries?  No problem.  Want a list of MObjects?  Vectors?  You get the idea.  You can pass any python object you want into the UI and it will display them in the widget, let users select them, and then return you the list of objects that the user selected.  Its very useful.

So how does it work?

Well, the base class contains most of the functionality you need.  There are two general cases.  If you want to display lists of objects that already have a reasonably sensible, user friendly string representation, then you can use the MelObjectScrollList directly:

import maya.cmds as cmds
from baseMelUI import MelObjectScrollList

w = cmds.window( 'test', t='test', h=300, w=300 )
c = cmds.columnLayout()
objScrollList = MelObjectScrollList( c, h=250 )
objScrollList.setItems( [ [], {}, ['some', 'list', 'of', 'strings'], dict, MelObjectScrollList ] )
cmds.showWindow( w )

def onSel( *a ):
	print objScrollList.getSelectedItems()

objScrollList.setChangeCB( onSel )

Incidentally I don’t normally write UI code like this – I just figured doing it this way might make it more available to folks who don’t use baseMelUI for their UI creation. Its also a good demonstration of how the library can be used in a mix and match way (even with pymel!).

So as you can see if you run this code (and have the zooToolbox – or at the very least, the baseMelUI module in your python path) you’ll see a window pop up with the above objects in it. They look just as if you’d called print on each one.

Now if you want to customize the way these objects are displayed in the UI, then you simply need to subclass the MelObjectScrollList and override the itemToStr method. Here is an example:

from filesystem import Path
from baseMelUI import MelVLayout, MelObjectScrollList, BaseMelWindow

class FilenameScrollList(MelObjectScrollList):
	def itemAsStr( self, item ):
		return Path( item )[-1]

class Test(BaseMelWindow):
	WINDOW_NAME = 'test'

	def __init__( self ):
		f = MelVLayout( self )
		self.fileListUI = FilenameScrollList( f )
		self.fileListUI.setItems( Path( "c:/windows" ).files() )
		self.fileListUI.setChangeCB( self.on_itemSelect )
		f.expand = True
		f.layout()
		self.show()
	def on_itemSelect( self, *a ):
		print self.fileListUI.getSelectedItems()

Test()

In this example you should see a window open up with a list of the file names in c:\windows. When you select an entry in the list, you’ll see the full path to that file printed in the script editor. The FilenameScrollList keeps track of the objects you put into it. It acts as a broker between the data and the UI. So using it simplifies code a heap.

Another neat feature thats built into the base class is view filtering. So building on the above code you can do things like this:

ui = Test()
ui.fileListUI.setFilter( '.exe' )

As you can see, once you run the setFilter() method the list now only displays files containing “.exe”. The UI still retains a list of all the files, but it only displays the items that pass the filter.

Lastly the other useful feature the class provides is re-ordering. The methods are “moveSelectedItemsUp()” and “moveSelectedItemsDown()”. You can easily hook up these methods to buttons, popup menus or whatever else you want.

from filesystem import Path
from baseMelUI import BaseMelWindow, MelHSingleStretchLayout, MelVLayout, MelObjectScrollList, MelButton

class FilenameScrollList(MelObjectScrollList):
	ALLOW_MULTI_SELECTION = True

	def itemAsStr( self, item ):
		return Path( item )[-1]

class Test(BaseMelWindow):
	WINDOW_NAME = 'test'

	def __init__( self ):
		f = MelHSingleStretchLayout( self )
		self.fileListUI = FilenameScrollList( f )
		self.fileListUI.setItems( Path( "c:/windows" ).files() )
		self.fileListUI.setChangeCB( self.on_itemSelect )
		f.setStretchWidget( self.fileListUI )

		v = MelVLayout( self )
		MelButton( v, l='up', c=self.on_up )
		MelButton( v, l='down', c=self.on_down )
		v.expand = True
		v.layout()

		f.expand = True
		f.layout()
		self.show()
	def on_itemSelect( self, *a ):
		print self.fileListUI.getSelectedItems()
	def on_up( self, *a ):
		self.fileListUI.moveSelectedItemsUp()
	def on_down( self, *a ):
		self.fileListUI.moveSelectedItemsDown()

Test()

NOTE: make sure to grab the latest baseMelUI.py from here. While writing this post I fixed a bug with the moveSelectedItems methods when a filter is set.

Share

This post is public domain

This entry was posted on Saturday, May 14th, 2011 at 21:09 and is filed under main. You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site.