Components and changing background colors


#1

Hi,

I’ll begin by saying I’m relatively new to Juce.

I have some parent component (currently just a Component, nothing more specific) that contains a TextEditor and a ComboBox.
When hovered, the parent component’s background should change from white to, say, red.

On mouseMove() I set the TextEditor’s background to red, but what about the dead space under the ComboBox? How can I set it to red also?
Which parent components fits my needs in this case? I know Component and Viewport don’t have backgroundColourId…

Note: This parent component should appear multiple times, one on top of the other…

Thanks!


#2

In your parent component overwrite the paint() with something like this:

void ParentComponent::paint(Graphics& g)
{
  g.fillAll(Colours::red);
}

(or use a Colour member variable if you want to switch colours)

Chris


#3

[quote=“ckk”][quote]
but what about the dead space under the ComboBox? How can I set it to red also?
[/quote]
In your parent component overwrite the paint() with something like this:

void ParentComponent::paint(Graphics& g)
{
  g.fillAll(Colours::red);
}

(or use a Colour member variable if you want to switch colours)

Chris[/quote]

Nice, thanks.

But how do I combine it with the hovering?

I mean, calling repaint from mouseMove doesn’t really help me because its not instant…


#4

If I understood correctly your question,

http://www.rawmaterialsoftware.com/juce/api/classComponent.html#a335d0fe3153768962c91c91f38e6e520

Override mouseEnter and mouseExit in the same way you overrided paint. Just use a global variable to store the current state (e.g. bool isMouseIn) and then call repaint,
which should be now rewritten like

if(isMouseIn) g.fillAll(Colours::red); else g.fillAll(Colours::green);


#5

[quote=“masshacker”]If I understood correctly your question,

http://www.rawmaterialsoftware.com/juce/api/classComponent.html#a335d0fe3153768962c91c91f38e6e520

Override mouseEnter and mouseExit in the same way you overrided paint. Just use a global variable to store the current state (e.g. bool isMouseIn) and then call repaint,
which should be now rewritten like

if(isMouseIn) g.fillAll(Colours::red); else g.fillAll(Colours::green);[/quote]

I wrote this:

[code]void Comment::mouseEnter (const MouseEvent&)
{
repaint();
}

void Comment::mouseExit (const MouseEvent&)
{
repaint();
}[/code]

But when the cursor is over the ComboBox it doesn’t trigger it… Works for the TextEditor tho…


#6

Do you mean

[code]void Comment::mouseEnter (const MouseEvent&)
{
isMouseIn = true;
repaint();
}

void Comment::mouseExit (const MouseEvent&)
{
isMouseIn = false;
repaint();
}[/code]

?


#7

[quote=“masshacker”]Do you mean

[code]void Comment::mouseEnter (const MouseEvent&)
{
isMouseIn = true;
repaint();
}

void Comment::mouseExit (const MouseEvent&)
{
isMouseIn = false;
repaint();
}[/code]

?[/quote]

Well, since I need the mouse logic inside paint() (to change the background color), I thought I’d do it only inside paint():

void Comment::paint(Graphics& g) { if (isMouseOver(true)) { g.fillAll(Colour::fromRGB(238, 238, 238)); } else { g.fillAll(Colours::white); } }

Notice I’m using isMouseOver(true) (true means check for children also).

But when the cursor enters my components through the ComboBox the g.fillAll() in paint() doesn’t change the background color, its like this Graphics isn’t for the parent component…


#8

Maybe you should add a new Component on top of the others, making it cover the whole area and invisible, and put the hovering logic inside it.


#9

I can, but I’m sure there’s a way solve it in an elegant way…


#10

I can, but I’m sure there’s a way solve it in an elegant way…[/quote]

masshacker’s solution is elegant enough. The Juce Component class API is particularly robust and perfectly suited to handle your situation. There is nothing wrong with having a Component overlaid on your existing controls, whose sole purpose is to process a mouse enter for itself or its children (using the mouse listener system), and trigger painting behaviors in other components.

There is no “perfect” user interface system that is completely reusable, flexible enough to handle all cases, and especially elegant. Juce comes pretty close. Use the facilities that are there to solve your problem, and move on to the next aspect of your project.


#11

To address the original post, I would use setColour() to make the background colour of the combo box and edit box transparent (alpha = 0) and then just paint the background myself in the parent component, with appropriate colour changes to reflect the mouse-enter state.


#12

I had set the background colors of the ComboBox and TextEditor to be transparent.

My problem is that when the mouse is on the ComboBox itself, the paint(g) in the parent component affects only the ComboBox (its background does change, but not the background of the entire component).

Its like the Graphics given contains only The ComboBox graphics…


#13

In the parent component, call addMouseListener and pass true for wantsEventsForAllNestedChildComponents. When you receive mouse enter and exit messages in the parent, set a flag indicating if the mouse is inside the parent or one of the children and use an AsyncUpdater to trigger the repaint.

The reason we use the AsyncUpdater is due to the way that is wantsEventsForAllNestedChildComponents implemented you will see the mouseExit first, and then the mouseEnter for the child. There is no way to know, at the point of the mouseExit, that you will receive the mouseEnter for the child (versus the mouse exiting the parent completely and going to an unrelated Component). The AsyncUpdater allows you to defer the final resolution of all the mouse movements until the Component logic is done sending messages.

If your repaint is only affecting the ComboBox probably you are calling repaint on the child. You need to call repaint() on the parent component. Also, don’t use setOpaque(true) in the children if you are setting background colours to transparent.


#14

Well probably you have “invalidate entire component on mouse enter” set on the ComboBox, the mouse is going inside, and a repaint for just the ComboBox is being triggered. The clip region on the Graphics will be set to include only the ComboBox.

As I said in my previous post you need to add some logic in your parent component so it can detect when the mouse is inside itself, or any child. When the mouse is inside itself, or any child, you want to repaint the entire parent component so that everything changes colour.


#15

Give me a few minutes I will try to collect my code that does what you want into something general purpose, and post it.


#16

Okay here is the class:

MouseEnterGroup

To use it for your scenario do the following:

  1. Add this class in the list of bases of your parent object

  2. in your paint() method, call isMouseInsideGroup() to determine the color to use for painting the background

  3. override onMouseEnterGroup() and onMouseExitGroup() and call repaint() inside each


#17

[quote=“TheVinn”]Okay here is the class:

MouseEnterGroup

To use it for your scenario do the following:

  1. Add this class in the list of bases of your parent object

  2. in your paint() method, call isMouseInsideGroup() to determine the color to use for painting the background

  3. override onMouseEnterGroup() and onMouseExitGroup() and call repaint() inside each[/quote]

Well, it does the trick - I’ll make sure I understand what it does exactly :stuck_out_tongue:

Thanks!


#18

Edit: Managed to post a reply instead of creating a seperate thread...