ListBox and ListBoxModel questions


#1

I made a cute little window in the Jucer, and it was certainly simple to get the buttons to do what I want, but I’m having fits with ListBoxes. The only way I got one to work was making ListBoxModel public to the main component, which obviously isn’t the way I should be doing things. That’s the way it’s done in the JUCE Demo’s FontsAndTextDemo, but it doesn’t work for me because I need four different ListBoxes going.

So, let me just say what I’m doing. I’ll focus on a single ListBox. Here’s how my ListBox “Generic Component” is setup in the Jucer:

member name = "myListBoxBoards"
name = "my List Box Boards"
virtual class = ""
class = "ListBoxBoards"
constructor params = “”

class ListBoxBoards : public Component,
				     	  public ListBoxModel
{
public:
	ListBoxBoards();
	~ListBoxBoards();
	int getNumRows();
	void paintListBoxItem( int rowNumber, Graphics& g, int width, int height, bool rowIsSelected );

private:
	//ListBox*		list;
	JGT_BOARD**	  board;
	int			    numBoards;

	void JgtGetBoards( void );

};

ListBoxBoards::ListBoxBoards()
{
	//list = new ListBox( T("List Box"), this ); 
	JgtGetBoards(); //builds board array and sets numBoards

}

ListBoxBoards::~ListBoxBoards()
{
	for( int i = 0; i < numBoards; i++ )
	{
		free( board[i]->portSuppressed );
		free( board[i] );
		board[i] = NULL;
	}
	free( board );
}


int ListBoxBoards::getNumRows()
{
	return numBoards;
}


void ListBoxBoards::paintListBoxItem( int rowNumber, Graphics& g, int width, int height, bool rowIsSelected )
{
	if (rowIsSelected)
		g.fillAll (Colours::lightblue);

	g.drawText ( (board[rowNumber]->sDevType + " " + board[rowNumber]->sLicKey ).c_str(),
		4, 0, width - 4, height,
		Justification::centredLeft, true );

}

I won’t bother showing all the code that’s getting a list of installed boards in the system. I know that part’s working, because I’ve gotten it working before using the same paintListBoxItem function when I just had one ListBox (and it was public to the main component).

The lines I commented out were just something else I was trying that also wasn’t working. I don’t really know what I’m doing, and I don’t understand the interaction between ListBox and ListBoxModel, and I’m just not figuring things out by cut/pasting other people’s examples (mostly because the only examples I can find are “why is this not working?” posts that don’t show an actual fix).

Thanks for any help!


#2

it often make sense to inherit from both ListBox and ListBoxModel for convenience.


#3

That breaks everything and gives me a buncha “ambiguous access” errors.

For example, in my Jucer generated code:

addAndMakeVisible (myListBoxBoards = new ListBoxBoards());

I get:

error C2385: ambiguous access of ‘delete’ in 'ListBoxBoards’
error C2385: ambiguous access of ‘new’ in ‘ListBoxBoards’


#4

plonk the juce_UseDebuggingNewOperator macro somewhere in your class definition.


#5

Thanks! I had tried that before, but it opened up all kinds of new problems. Then I realized my big problem was that I needed to stop inheriting Component.

I changed things up to:

[code]class ListBoxBoards : public ListBox,
public ListBoxModel
{
public:
ListBoxBoards();
~ListBoxBoards();
int getNumRows();
void paintListBoxItem( int rowNumber, Graphics& g, int width, int height, bool rowIsSelected );

juce_UseDebuggingNewOperator

private:
JGT_BOARD** board;
int numBoards;

void JgtGetBoards( void );

};

ListBoxBoards::ListBoxBoards() : ListBox( T(“List Box”), this )
{
JgtGetBoards();
}
[/code]

Is that the way the constructor should look?

Things are working now, and I can load the code in Jucer and move things around without breaking anything, but I still don’t get exactly what the relationship is between ListBox and ListBoxModel, and I’d like to understand this a little better.


#6

That looks good to me.

The idea behind the listbox and model is that you can provide a fully functional custom listbox without needing to go anywhere near the workings of the listbox itself.

It typically isn’t necessary to derive from listbox, simply creating a direct instance of listbox and throwing it a suitable model sub-class is enough. However, for better or worse[1], it often helps for the model to access to the container list, which is why, I suspect, you’ll see a lot of JUCE code that inherits from both as you have done. The alternative obviously would be to have tight coupling by passing a pointer to the listbox in the model’s constructor.

Also, if ever you need to get nasty with the precise behaviour of the box, for example, suppressing row selections, you may find that it is necessary to derive from listbox.

One nice feature of the model system though, is that if you want your list to have a couple of different behaviours, based on user settings, it might be tidier to have a few different model classes, rather than one monolith with tons of logic. In that case, a single listbox can be initiated, and located on screen. Then subsequent calls to setModel() will allow you to customize the box on the fly.

[1] To be fair, this normally happens if your model is too heavily involved with the management of the actual data, rather than both the box and the model being managed directly by a broker, which would be a better way of doing things. However, in many cases that just creates code bloat, so them’s the breaks…


#7

Thanks very much for all the info!