When I started out with REALbasic / Xojo I used the ListBox both to store and display data. It worked but the code was cumbersome and hard to maintain and expand as everything tended to be hardwired like this:
ListBoxEmplyees(0, 0).cell = TextFieldName.text ListBoxEmplyees(0, 1).cell = TextFieldFirstName.text ListBoxEmplyees(0, 2).cell = TextFieldStreet.text ListBoxEmplyees(0, 0).cell = TextFieldCity.text
Nowadays I don’t pass strings around anymore, I use objects like this:
// create new Employee object dim Employee as new cEmployee // set properties of Employee object Employee.name = TextFieldName.text Employee.FirstName = TextFieldFirstName.text Employee.Street = TextFieldStreet.text Employee.City = TextFieldCity.text
and then I simply pass around those objects:
// store Employee object in array Window1.ListOfEmplyees.append Employee // store Employee object in ListBox RowTag // first create a new row in the ListBox ListBoxEmplyees.addRow "" ListBoxEmplyees.RowTag(ListBoxEmplyees.LastIndex) = Employee
Note that there is only ONE object, and that it is only a pointer to that object that is stored in the ListOfEmplyees and a RowTag of the ListBox
Now I want my objects to be able to draw themselves, so they need to have a Draw method. I could simply add a Draw method to the object itself, but a better way is to define an interface CanDrawItself with two methods DrawAsList and DrawAsBusinessCard, and pass a graphics object to them for them to draw themselves on:
Public Sub DrawAsList(g as Graphics) // actual drawing code End Sub Public Sub DrawAsBusinessCard(g as Graphics) // actual drawing code End Sub
Of course you can have many more drawing methods.
The advantages of using an interface are manyfold. For one thing - and very unlike a subclass - you can add it to many different objects! So all you have to do now in the Listbox CellBackgroundPaint event is to pass the ListBox cell’s graphic parameter g to the draw method of the object in the RowTag like this (in pseudo-code … note the Casting):
if PopupDrawSelection.text = "List" then ObjectType( me.RowTag( row ) ).DrawAsList( g ) end if if PopupDrawSelection.text = "Business Card" then ObjectType( me.RowTag( row ) ).DrawAsBusinessCard( g ) end if
and it will draw on the graphics of the cell.
Um. One moment? ObjectType? How do I know what kind of object is in the RowTag???
That’s the beauty of it: it doesn’t matter what type the object is because any object that implements the interface can be called as being of that type like this:
If row < Me.ListCount Then CanDrawItself( me.RowTag( row ) ).Draw( g ) end if
With this is becomes easy to make a ListBox like this (note that this ListBox uses just one column):
Note that there are THREE different types of rows: one is based on a class cHEADER, one on a class cDEPARTMENT, and one on a class cEMPLOYEE. Each of them implements the CanDrawItself interface and draws itself in a one column listbox according to the code in its draw method.
A longer version of this will be an article in the forthcoming issue of xDev magazine, and the code will be on GitHub afterwards …