ListBox correct implementation

I am trying to create a sample HelloWorld app using ListBox but the ListBoxModel member of paintListBoxItem is not drawing any of the rows. Can someone help me understand what I am missing? I thought that the correct way to do this is to create a subclass of ListBoxModel, but I guess I’m not doing it correctly. Any help greatly appreciated.

HelloWorldComponent.cpp:

#include "HelloWorldComponent.h"
class MyListBoxModel : public ListBoxModel
{
public:
        MyListBoxModel();
        ~MyListBoxModel();

        void paintListBoxItem(int rowNumber, Graphics& g, int width, int height, bool rowIsSelected)
        {
                if(rowIsSelected) {
                        g.fillAll(Colours::lightblue);
                }
                g.setColour(Colours::black);
                g.setFont(height * 0.7f);
                g.drawText("Row Number " + String(rowNumber + 1), 5, 0, width, height, Justification::centredLeft, true);

        }
        int getNumRows()
        {
                return 30;
        }
};
MyListBoxModel* blah;

HelloWorldComponent::HelloWorldComponent()
		: lBox(0)
		
{
  	lBox = new ListBox("Test",blah);
	lBox->setModel(blah);
        addAndMakeVisible(lBox);

	setSize (600, 400);
}
void HelloWorldComponent::resized()
{
        lBox->setBounds (proportionOfWidth (0.1893f), proportionOfHeight (0.2076f), proportionOfWidth (0.6502f), proportionOfHeight (0.5741f));
}

HelloWorldComponent.h:

#ifndef HELLOWORLDCOMPONENT_H 
#define HELLOWORLDCOMPONENT_H

#include "includes.h"
class HelloWorldComponent  : public Component, 
                             public ButtonListener
			     //public ListBox,
		 	     //public ListBoxModel
			
{
public:
	HelloWorldComponent ();
	~HelloWorldComponent();

	void paint (Graphics& g);
	void resized();
	void buttonClicked (Button* buttonThatWasClicked);
	//void paintListBoxItem(int rowNumber, Graphics& g, int width, int height, bool rowIsSelected);
	//int getNumRows();

	juce_UseDebuggingNewOperator

private:
	ListBox* lBox;

	HelloWorldComponent (const HelloWorldComponent&);
	const HelloWorldComponent& operator= (const HelloWorldComponent&);
};
#endif

However, when I create a class object that inherits both ListBox and ListBoxModel (as delineated below), everything works fine. I copied this implementation from the Juce Demo application. This is I assume because I am passing “this” pointer to the setModel. This code below works, but I wanted the main content component to be able to control the calls to paintListBoxItem. That is why I am trying for the first implementation example.

HelloWorldComponent2.cpp:

#include "HelloWorldComponent.h"

class MyListBox : public ListBox,
                           public ListBoxModel
{
public:
        MyListBox()
                : ListBox ("Testing", 0)
        {
                setModel(this);
        }
        ~MyListBox()
        {

        }
        int getNumRows()
        {
                return numRows;
        }
        void paintListBoxItem(int rowNumber, Graphics& g, int width, int height, bool rowIsSelected)
        {
		if(rowIsSelected) {
			g.fillAll(Colours::lightblue);
		}
		g.setColour(Colours::black);
		g.setFont(height * 0.7f);
		g.drawText("Row Number " + String(rowNumber + 1), 5, 0, width, height, Justification::centredLeft, true);
		g.drawText(text, 5, 0, width, height, Justification::centredLeft, true);

        }
        void paint(Graphics& g)
        {
                g.fillAll(Colours::white.withAlpha(0.7f));

        }
	void listBoxItemClicked(int row, const MouseEvent& e)
	{
		val = row;

	}
};
MyListBox* lbox;


HelloWorldComponent::HelloWorldComponent()
{

	lbox = new MyListBox();
	addAndMakeVisible(lbox);


}

HelloWorldComponent::~HelloWorldComponent()
{
	deleteAllChildren();

}

void HelloWorldComponent::paint (Graphics& g)
{
	g.fillAll (Colour (0xffa18a8a));


}

void HelloWorldComponent::resized()
{
	lbox->setBounds (proportionOfWidth (0.1893f), proportionOfHeight (0.2076f), proportionOfWidth (0.6502f), proportionOfHeight (0.5741f));
}
void HelloWorldComponent::buttonClicked (Button* buttonThatWasClicked)
{


}

HelloWorldComponent2.h:

#ifndef HELLOWORLDCOMPONENT_H 
#define HELLOWORLDCOMPONENT_H

#include "includes.h"

class HelloWorldComponent  : public Component,
                             public ButtonListener
			
{
public:
	HelloWorldComponent ();
	~HelloWorldComponent();

	void paint (Graphics& g);
	void resized();
	void buttonClicked (Button* buttonThatWasClicked);

	juce_UseDebuggingNewOperator

private:

	HelloWorldComponent (const HelloWorldComponent&);
	const HelloWorldComponent& operator= (const HelloWorldComponent&);
};
#endif

when you call setModel (blah), it looks like you’re just giving it an uninitialised pointer (unless you’ve not posted the important bit of code that actually creates your model object??)

I didn’t implement the new model object creation. I’ve added it like the following: “blah = new MyListBoxModel();”

However, the rows are still not painting in the ListBox, for some reason.

Here is how it is implemented in the constructor for HelloWorldComponent now:

HelloWorldComponent::HelloWorldComponent()
                : lBox(0),
                  blah(0)

{
        blah = new MyListBoxModel();
        lBox = new ListBox("Test",blah);
        lBox->setModel(blah);
        addAndMakeVisible(lBox);
        setSize (600, 400);

}

HelloWorldComponent.h:

#ifndef HELLOWORLDCOMPONENT_H 
#define HELLOWORLDCOMPONENT_H

#include "includes.h"
#include "MyListBoxModel.h"

class HelloWorldComponent  : public Component, 
                             public ButtonListener
			
{
public:
	HelloWorldComponent ();
	~HelloWorldComponent();

	void paint (Graphics& g);
	void resized();
	void buttonClicked (Button* buttonThatWasClicked);

	juce_UseDebuggingNewOperator

private:
	ListBox* lBox;
	MyListBoxModel* blah;

	HelloWorldComponent (const HelloWorldComponent&);
	const HelloWorldComponent& operator= (const HelloWorldComponent&);
};
#endif

I had to create a new .h file and cpp files, as the following:

MyListBoxModel.cpp:

#include "includes.h"
#include "MyListBoxModel.h"

MyListBoxModel::MyListBoxModel()
{

}
MyListBoxModel::~MyListBoxModel()
{

}
void MyListBoxModel::paintListBoxItem(int rowNumber, Graphics& g, int width, int height, bool rowIsSelected)
{
                if(rowIsSelected) {
                        g.fillAll(Colours::lightblue);
                }
                g.setColour(Colours::black);
                g.setFont(height * 0.7f);
                g.drawText("Row Number " + String(rowNumber + 1), 5, 0, width, height, Justification::centredLeft, true);

}

int MyListBoxModel::getNumRows()
{
	return 30;
}

MyListBoxModel.h:

#include "includes.h"

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

};

I don’t know. Use your debugger and step through everything, watching what happens, and you’ll probably spot what’s going wrong.

Will do. Thanks for confirming that it looks correct.

To resolve this issue, I ended up dropping trying to get the first implementation working, and just kept with the original one that was working, from the Juce Demo project example. I created two separate ListBox objects within the component, and then made them visible or not based on where the Component was, and what I needed it to do. But one thing I did differently - I pass a numeric parameter to the constructor for the ListBox to tell it how to do some custom things within that ListBox.

Like so, basically:

MyListBox* lbox;
MyListBox* lbox2;

and:

lbox = new MyListBox(0);
addAndMakeVisible(lbox);
lbox2 = new MyListBox(1);