Good practice to handle look & feel of custom UI components


while working on the user interface of my current application, I wonder what’s the best practice to handle the look and feel of custom UI components.
For an example, I use some more or less realistic designed buttons, looking just like some LED-lightened on/off buttons on traditional analog hardware.

My first approach was to write a class named DrawableToggleButton, inheriting from Button, that implements some kind of toggle button with two drawable pointers passed to the constructor, one for the “on”-state image and one for the “off”-state image. Now, I create multiple subclasses, inheriting from DrawableToggleButton, e.g. YellowLEDToggleButton and GreenLEDToggleButton, which have a unique set of drawables for the on & off state as private members and simply pass those pointers to the base class at construction time.
This works but doesn’t seem to fit into the juce concept of look & feel.

Now my next idea was to create a custom look & feel subclass for every type of button, that owns the two drawables for the on & off state as private members and overrides the drawToggleButton member function. So I’d just implement e.g. YellowLEDToggleButtonLookAndFeel, YellowLEDToggleButtonLookAndFeel…, implement the usual toggle buttons and assign those special look and feels to those buttons.

But this seems to have a downside when it comes to more complex types of elements, such as rotary sliders with a textbox for their value. If I had multiple knob-types with different knob designs on my UI, but their textbox should all use the same font as the rest of the text elements on the UI uses, a custom “global” look and feel would seem to be the more suitable approach. But how should I handle the drawing of the individual knob designs here?
What do you think of an approach somehow according to this idea:

class CustomSlider : public Slider {


enum {
} KnobStyle;

CustomSlider (KnobStyle ks, TextEntryBoxPosition tbp) : Slider (SliderStyle::Rotary, tbp), sliderKnobStyle (ks) {};
~CustomSlider() {};

void paint (Graphics &g) override {
    lookAndFeel->drawCustomRotary(sliderKnobStyle, ... all the other arguments)


const KnobStyle sliderKnobStyle;

class CustomLookAndFeel : public LookAndFeel_V4 {


// override some existing member functions here

void drawCustomRotary (CustomSlider::KnobStyle sliderKnobStye, ... all the other arguments) {
    Drawable *knobToDraw;
    switch (sliderKnobStyle) {
        case flatKnob:
            knobToDraw = flatKnobDrawable.get();
        case realisticKnob:
            knobToDraw = realisticKnobDrawable.get();
        case evenMoreRealisticKnob:
            knobToDraw = evenMoreRealisticKnobDrawable.get();
    // rotate the drawable and draw it...


ScopedPointer<Drawable> flatKnobDrawable = Drawable::createFromImageData(BinaryData::flatKnob_svg, BinaryData::flatKnob_svgSize);
ScopedPointer<Drawable> realisticKnobDrawable = Drawable::createFromImageData(BinaryData::realisticKnob_svg, BinaryData::realisticKnob_svgSize);
ScopedPointer<Drawable> evenMoreRealisticKnobDrawable = Drawable::createFromImageData(BinaryData::evenMoreRealisticKnob_svg, BinaryData::evenMoreRealisticKnob_svgSize);

Please note that I wrote the code above just to explain my idea, it’s not meant to be error-free :wink:

So, how do you handle similar cases? What is the “JUCE-way” to do this clean & efficiently and to generate code that could be easially re-used for future projects?

Looking forward to your ideas!

1 Like

Instead of inheriting direct from Slider, use a mixin based programming

template <class BaseSlider> class MyCustomSlider : public BaseSlider
  template <typename ...Args>
  MyCustomSlider (Args &&...args)
    : BaseSlider(std::forward<Args>(args)...)
virtual void paint(Graphics &g)
// custom draw here

so you can subclass different Slider class

my 2 cents


I never subclassed from Slider at all. It’s a class that’s already far too complex.

I’m working with JUCE since almost 10 years now and the approach I settled with is to always do the drawing only in the LookAndFeel classes.

So, if you need your Sliders to have different looks, assign different LookAndFeels to them.
If those LookAndFeels have some parts in common, promote those parts to a base LookAndFeel class that’s used for inheriting all the other specific LookAndFeels that you need.

In your specific case, you could implement a base SliderLookAndFeel class which in reality only overrides the methods for drawing the text boxes.

Then, derive from that SliderLookAndFeel the specific FlatKnobLookAndFeel, RealisticKnobLookAndFeel, etc. where you will override the methods that actually draw the rotary slider as you desire.

Last point is to assign to each Slider in your UI the appropriate FlatKnobLookAndFeel, RealisticKnobLookAndFeel, etc.


Thank you for your helpful approaches. I think yfede’s approach seems to be the most straightforward way of doing things - I somehow never thought of subclassing my basic LookAndFeel for the special sliders, although this really seems to be the easiest way to handle those everything :wink:

+1 to @yfede’s comment.

I have another component, a LevelMeter class on github, where I dived into an architecture with a separated LookAndFeel, and how to attach it to the existing juce::LookAndFeel classes.
It might serve as inspiration, and if anybody wants to comment, I am looking forward for criticisms. I am always happy to improve my code and myself.

My main grip with Juce LnF system is that it is not ref counted.
So if you assign a custom LnF to a single widget, the widget (or someone else) have to take care of the LnF deletion
So either custom widget or store the LnF in the class that includes this custom widget, which make the whole LnF for a single widget system painful.


It’s a good point.

at the moment, I gather all LookAndFeels in a singleton that owns them, something like a “look and feel library”, where they can be obtained by a name associated with them upon registration in that singleton.

That way, I also avoid having to create the LookAndFeel multiple times for multiple instances of the plug-ins


I’m in LookAndFeel honeymoon since last weekend! I love it. Therefore, I would like to follow the same pattern for a new control (it would be MIDI sequencer / note editor – something like simpler version of Cubase’s MIDI event editor). Can you guys share some thoughts on right road to take? The control would inherit from from basic component (juce::Component), how to integrate new LookAndFeel methods for it? (I’m learning from Juce code - but if you have any experience/thoughts/advice on such or similar thing, please share.

1 Like

Option 1: do the painting of your derived component by overriding its paint() method.
As tempting as it may be, perhaps using the LookAndFeel approach is only making things more complicated than they should be in this context.
The component is entirely yours and you certainly know how to paint it. There’s no need to delegate that painting to a different object, unless… (and here comes the option 2)

Option 2: If you need to have different “styles” for your component, then yes, following the LookAndFeel pattern may be useful, but I’d do it like this, thus avoiding to inherit from LookAndFeel at all:

class YourComponent

    class PaintDelegate 
        virtual ~PaintDelegate() {}
        virtual void paint(Graphics& g, YourComponent& c) = 0

    void setPaintDelegate (PaintDelegate* const delegate) { paintDelegate = delegate; }

    void paint (Graphics& g) override 
         if (paintDelegate != nullptr)
              return paintDelegate->paint (g, *this);

         /* some default painting here */

     PaintDelegate* paintDelegate;
1 Like