Best Practices for Graphics

Hello!

I have two questions: a specific one, and general one:

1. All the drawings happens in the Component::paint method. I have added two AwesomeFonts as a Secondary font to display icons, and as a main Font of my application. Is ia added as a BinaryData and I can switch between them in my app like this:

/// Set main font of the application
void MainComponentBase::setAppFont(Graphics &g) {
    juce::Font font = Font(Typeface::createSystemTypefaceFor(BinaryData::JuraLight_ttf, BinaryData::JuraLight_ttfSize));
    g.setFont(font);
}

/// Set AwesomeFont to display awesome font icons
void MainComponentBase::setAwsomeFontRegular(Graphics &g) {
    juce::Font font = Font(Typeface::createSystemTypefaceFor(BinaryData::fasolid900_ttf, BinaryData::fasolid900_ttfSize));
    g.setFont(font);
}

A problem starts when I have a many controls where I combine these two fonts in a one control, switching between them in a ::paint method: During a scroll or resizing I can see some freezes, blinking, and sometimes some artefacts in UI. But if I remove ant Font switch, all the problems are gone and everything is nice.
Question: Can you share the best practices how to use different fonts in one component and avoid such UI glitches?

2. When an application has a rich UI, then graphics in big resolutions is not smooth. Example: imagine a stock graph with Japanese candles, and you scroll it horizontally. When application resolution is small, then all the graphics is smooth and nice. But if it is a full screen, then you can start to see the difference how it is rendered.
Question: What are the best practices to work with rich UI in JUCE to avoid render issues in big resolutions.

Thank you in advance!

UPDATE: What would be faster:

  • Draw a rectangle and FillRect with color.
  • Create a component with background picture with needed color and use it instead of rectangle, just changing its bounds in resize method.

Don’t create the font object for every paint call. Create it in your constructor and then use setFont when painting.

1 Like

Thank you.

Drawing images won’t be faster than fillRect.

Lots of simple components should be more or less the same speed as lots of simple drawing if you enable setPaintingIsUnclipped.

This is a good high-level summary:

4 Likes

In the linked thread (and elsewhere) it is wrote that the background component should be sibling (instead of at top) in the components tree, in order to avoid to be painted each time a child is repaint.
Is that worth the cost if the background’s paint method is just a color?

void paint (juce::Graphics& g) override
{
    g.fillAll (backgroundColour_.get());
}

There’s no immediate advantage to moving your graphics from a parent component to a separate child component, you won’t get any performance benefits from that alone.

The performance benefits come into play when the graphics you’re drawing take longer to render than drawing an image of the same size. In that case, you should call setBufferedToImage (true) on the component in question.

If the your background is just a solid colour then it’s always going to be quicker to just call paint() everytime, rather than using the cached image - so for that case you wouldn’t get any performance benefits from the dedicated component.

The main benefit you would get is consistency. I’ve now adopted a habit of classing all components as either a container, or a canvas. Containers have children and don’t do any drawing. Canvases do drawing but don’t have any children. Helps make clear the responsibility of the component.

1 Like

Thanks for the light. :+1:
In your approach the container component has an empty paint method thus?
How do you manage its size?

Yeah, typically my container classes don’t override paint() but do override resized(). And vice versa for canvases - override paint() but not resized().

2 Likes