In the version of JUCE you are using not all opaque components are guaranteed to always prevent another component from drawing. There are a couple of reasons for this including where the components are in the component tree relative to each other, if a component is using setPaintingIsUnclipped (true), and even if a component has children.
However, if you check out the develop branch you should see that opaque components should now always prevent other components they obscure from drawing. That being said you need to weigh up the costs of drawing vs the costs of checking if an opaque component obscures another component.
In the version of JUCE you are using components always checked if they were being covered by an opaque component (with some caveats as mentioned above). This meant the price for checking for opaque components always existed so using setOpaque() was a no-brainer, it was unlikely to ever make performance noticeably worse.
In the latest version this cost will only be paid once a component is marked opaque, this cost is paid by all the components that need to check if they are covered by the opaque component(s). This means every component that is potentially* behind an opaque component will need to perform a check to see if they have been obscured. Therefore the savings of preventing a component being drawn need to be greater than the cost of all the combined checks, otherwise setOpaque() isn’t worth it.
As a rule of thumb if the component you are hiding is inexpensive to draw don’t use setOpaque (true). If it’s expensive to draw, first check you can’t implement some better/more informed logic to set the visibility of the component. If setOpaque() is the only option, and your UI does not consist of many components, it’s probably fine to use setOpaque(), otherwise measure that it is actually improving performance of the whole app as the cost of the checks will be paid for by potentially lots of other components. Another aspect to consider is how often the component(s) will be covered. If a component is only obscured occasionally you may still be paying for the checks on every paint call.
*A component is potentially behind another component if it has a lower z-order. This might be a sibling, or child of a sibling with a lower z-order, or a parent, sibling of a parent, or child of a sibling of a parent, with a lower z-order.
isVisible() returns a value mirroring that of setVisible().
isShowing() checks the value of isVisible() on this component and all it’s parents. Although a good indication of if a component is showing, actually checking all the conditions required to know if a component is on screen is significantly more complicated than that and could be a potentially time consuming task if there are enough components.