A basic framework for a user customisable gui


#1

Okay, I may have got a bit carried away here, but following on from one of my posts in this thread, I’ve come up with a basic framework for a user customisable gui.

What it does is parse an xml file, reading various attributes for the (programmer-defined) gui widgets. Here’s a screenshot:

That’s two instances of the same application :D, the only difference being the xml files passed in.

How it works is through the use of a factory class, which parses the xml file and instantiates each widget, setting each widget’s attributes according to the xml file. When you (the programmer) want to add a widget to the main window (instead of doing the usual addAndMakeVisible() in the window’s constructor), you write a subclass of the FactoryObject class, and then register this class with the factory object, along with the name and attributes it’ll use in the xml file. For example:

[code]class ExampleButton : FactoryObject
{
public:
ExampleButton(ComponentFactory *factory, Component **windowComponent);
~ExampleButton() {};

void create();

static void setText(String text);

private:
static String text;
};

//–static member variables must be declared globally–
String CloseButton::normalImage = T("");

ExampleButton::ExampleButton(ComponentFactory *factory, Component **windowComponent):
FactoryObject(factory, windowComponent)
{
//Register this object with the factory.
factory->registerObject(this, String(“exampleButton”)); //String(“exampleButton”) is the name used for this component in the xml file.

//Register all it's attributes with the factory.
factory->registerStringAttribute(this, String("text"), &CloseButton::setText);

}

//This is called by the factory to create the actual widget and add it to the window.
void ExampleButton::create()
{
ScriptedMainWindow *window;
TextButton *tempComp;

window = static_cast<ScriptedMainWindow *>(factory->getWindow());

window->addAndMakeVisible(tempComp = new TextButton(text, Colours::black, Colours::white, Colours::black, text));
tempComp->addActionListener(window);

*windowComponent = tempComp;

}

void ExampleButton::setText(String val)
{
text = val;
}[/code]
Then you’d add the following to your main window class constructor (I do it in a specific method to keep things tidy):

[code]if(!factory)
return;

//--create any FactoryObjects here--
ExampleButton *nButton = new ExampleButton(factory, reinterpret_cast<Component **>(&button)); //button being the TextButton * you've got in your window class.


//Always leave this last, as it resizes the whole window
MainWindow *window = new MainWindow(factory, 0);

//Actually creates all the widgets for the main window.
factory->createComponents();[/code]

And in your xml file you’d have the following line, which would instantiate a TextButton widget with the text “An Example Button”:

<exampleButton x="10" y="10" //position & size variables are part of the FactoryObject base class width="75" height="25" text="An Example Button"/>
You can see my code for more detail. This approach means you have to write more code than if you were just constructing all your widgets in your window’s constructor, but the main benefit is that you can let the user decide the layout etc. of the gui.

(the wave display component’s pretty much useless, I know, but it’s just an example)

Executable & source code : link.

Anyway, what do people think about this? Is it a valid approach for the sample editor? Is the sample editor even still alive?

  • Niall.

#2

damn. That’s awesome. :slight_smile:

I’ll come back to the editor stuff later. I can’t see why it couldn’t be incorporated though.


#3

Great! :smiley:

I think it could be improved a bit though - it would probably be a better idea to make the factory object classes singletons, so there would only be one of each type in existence at any one time (this is what should happen anyway, but there’s no harm in enforcing it). Also, the Titlebar and MainWindow classes could be improved to allow for bitmaps as well as simple block colours/gradients.

  • Niall.

#4