Juce UI performance - number of components

Hi, I am designing a standalone midi plugin to to manupilate some incoming data. The UI design is made such:
Smallest components:

  1. Glow button based on juce Button - uses glow effect when clicked ON
  2. Tuning Info based on Juce Component that has a rotary slider and a combo box

A “Key” has 5 glow buttons and 1 “Tuning Info”. Then finally an “Octave” displays 12 “Keys”

I have just got to the point where I am handling the events from the the various buttons and am noticing a sluggish response to button clicks. Things work well on the “Key” level, but get slow at the “Octave” level (around one second delay from click to response)

Should I be re-looking at flattening out my component hierarchy or is there something I am missing? I am guessing that by the time the event from the “Glow button” gets propagated to “Key” and then to the “Octave”, it’s causing the delay. But there is absolutely no heavy logic in those events - just receiving the event and raising another for the parent.

I am using the Button Listener class method to issue the callbacks. I have overridden the paint method in the Glow Button to display an image and text using drawFittedText. The “Key” also has some panel labels being drawn using DrawText.

I am using an Owned Array to create all the “Keys”. All components are using the resize method to lay out the controls.

Any advise on how to go about approaching the UI?

In my experience the GlowEffect is a real CPU hog. Have you tried disabling it and seeing if the GUI still lags?

Thanks Liam for your reply.

I disabled the glow. No effect on the UI response. Surprisingly my CPU is only between 5-10%. So I am not sure if the UI is straining the system. While at it, I also tried setOpaque(true) on the GlowButton and fillRect(getLocalBounds()) just to be sure the slowness is not due to any delay in painting transparent component. I have also played around with setPaintingIsUnclipped(true).

I am pasting part of the code for my paint below for the OSC label. A similar paint method is called for Pres, Abs, and Diff labels.

void paint(Graphics& g) override
{
g.setColour(AppUIDefinitions::getSubPanelBorderColour());
//g.drawRoundedRectangle(getLocalBounds().toFloat(), 3, 0.4);

    //Paint out the labels
    g.setFont(AppUIDefinitions::getPanelTextFont());
    g.setColour(AppUIDefinitions::getPanelTextColour());
    g.drawFittedText("OSC.", rectPresenceLabel, Justification::centred, 1, 0.1);

    //Draw the lines around Presence text
    g.setColour(AppUIDefinitions::getPanelTextColour());
    float height = rectPresenceLabel.getHeight() / 2;
    
    Point<float> leftButtonStart(btnPitchLower->getX() + (btnPitchLower->getWidth() / 2), btnPitchLower->getY());
    Point<float> rightButtonStart(btnPitchHigher->getX() + (btnPitchHigher->getWidth() / 2), btnPitchHigher->getY());

    Line<float> leftVert(leftButtonStart, Point<float>{leftButtonStart.getX(), leftButtonStart.getY() - height});
    Line<float> rightVert(rightButtonStart, Point<float>{rightButtonStart.getX(), rightButtonStart.getY() - height});

    Line<float> leftHorizontal(Point<float>(leftButtonStart.getX(), leftButtonStart.getY() - height),
        Point<float>(leftButtonStart.getX() + 5, leftButtonStart.getY() - height));
    Line<float> rightHorizontal(Point<float>(rightButtonStart.getX(), rightButtonStart.getY() - height),
        Point<float>(rightButtonStart.getX() - 5, rightButtonStart.getY() - height));
        
    
    g.drawLine(leftVert, 1);
    g.drawLine(rightVert, 1);
    g.drawLine(leftHorizontal, 1);
    g.drawLine(rightHorizontal, 1);
}

I read in some places that vector drawing is slow. Is it possible that the calculations in the paint is slowing the response?

Just quickly checked - commenting out the code that paints the labels improves the response BIG TIME. So drawing the labels and the little square lines around it seems to be the culprit.

Are there any approaches that can be used to create such kind of UIs? I was going for a Hardware synth based look where labels are printed on the panel (rather than the buttons). I an leaning towards converting the entire panel into an image, but again read that images are being replaced by vector graphics.

Any suggestions welcome.

have a juce component for your whole background with all the labels and use a setBufferedToImage so its repaint will be just like drawing an image.

The painting seems to me not that expensive. But, you should use draw Rectangle instead of lines. Have you tested, if the painting is done only ones per need? You can test it out with the JUCE_ENABLE_REPAINT_DEBUGGING flag.

OK. I started off re-organising the code based on otritan’s suggestion. Once done, will re-visit by old version keeping JUCE_ENABLE_REPAINT_DEBUGGING flag and report back.

So - I have an update and it is good. Here is what I did:

  1. Separated out all the label rendering logic to a separate PanelLabels component.
  2. In the constructor of this component, I added the line setBufferedToImage(true)
  3. Added this component to my MainComponent.
  4. In the constructor of the MainComponent, added panelLabels->toBack();

All works great now with the glow-effect on buttons.

PS: @baramgb - I tried converting the drawLines into rectangles, but this did not fit my purpose. The rectangle border could be seen below the text and I wanted the line to stop just before the text and start just after it. I did however create a Path and removed the drawLines.

Thanks all for the help. Proceeding to the next phase of development.

1 Like