setVisible() problem


#1

So this is what i'm experiencing.
All three components here are simple components created by me in introjucer.
I have a simple parent component with a png as a background.
I add a child component that only has a png as a background.
The parent component also has a button i created, which has two pngs, signifying the state of a switch.
In the parent component i have the function below.

void parent_component::buttonClicked( Button* btn_clicked )
{
    if ( btn_clicked== &btn1 )
    {
        if ( bool_flag )
        {
            child_component.setVisible(false);
        }
        else
        {
            child_component.setVisible(true);
        }
        bool_flag= !bool_flag;
        this->repaint();
    }
}

The problem is that when i make the child_component invisible for the first time, it doesn't become visible again.
But...
When i'm in debugging mode and enable breakpoints in the setVisible blocks, this works fine.
Any ideas why this is happening?


#2

Hi, I'm almost positive this is not going to fix your code, but I've streamlined it a little bit.  If bool_flag is already a boolean value, then just use it as your setVisiable parameter... This gets rid of the entire if else block.   Of course this is only valid if I'm not missing something and or you were not going to put more code in that if/else block.  smiley


void parent_component::buttonClicked( Button* btn_clicked )
{
    if( btn_clicked == &btn1 )
    {
        child_component.setVisible( bool_flag );
        bool_flag = !bool_flag;
        this->repaint( );
    }
}


#3

While we're refactoring, why not eliminate bool_flag altogether:

child_component.setVisible( !child_component.isVisible() );

Getting back to the OP's question...

We're going to need to see your constructors, specifically, for (1) the parent_component class and (2) whatever class child_component is of.

STYLE: consider using an initial capital letter for class names so that we can distinguish the difference between a class and a variable. It will make it easier for us to read your code on this forum. In your code, parent_component is a class name, but child_component is an object--this is confusing.


#4

The easiest way to figure this out is to step through the code with the debugger. Then you'll soon see what's going on :)


#5

So this is the code in question. I've posted whichever function i thought was essential.

Class of parent_component:

Parent_component::Parent_component ()
{
    cachedImage_Parent_back_png = ImageCache::getFromMemory (Parent_back_png, Parent_back_pngSize);

    //[UserPreSize]
    //[/UserPreSize]

    setSize (885, 640);

    //[Constructor] You can add your own custom stuff here..
    bool_flag= true;
    
    addAndMakeVisible(btn1, ++id_components);
    btn1.setTopLeftPosition(610, 65);
    btn1.addMouseListener(this, true);
    btn1.addListener(this);

    addAndMakeVisible(child_component, ++id_components);
    child_component.setTopLeftPosition(313, 226 );
    child_component.addMouseListener(this, true);

    //[/Constructor]
}

void Parent_component::buttonClicked( Button* btn_clicked )
{
    if ( btn_clicked== &btn1 )
    {
        bool_flag= !bool_flag;
        child_component.setVisible(bool_flag);
        this->repaint();
    }
}

Next is the switch's code. btn1 is of class Simple_switch which in turn inherits ImageButton.

Could the inheritance from ImageButton be the problem?


Simple_switch::Simple_switch ()
{
    image_painted= cachedImage_simple_switch_st1_png = ImageCache::getFromMemory (simple_switch_st1_png, simple_switch_st1_pngSize);
    image_painted_Size= simple_switch_st1_pngSize;
    cachedImage_simple_switch_st2_png= ImageCache::getFromMemory (simple_switch_st2_png, simple_switch_st2_pngSize);
    //[UserPreSize]
    btn_state= true;
    //[/UserPreSize]

    setSize (116, 28);

    //[Constructor] You can add your own custom stuff here..
    //[/Constructor]
}
void Simple_switch::paint (Graphics& g)
{
    //[UserPrePaint] Add your own custom painting code here..
    //[/UserPrePaint]

    g.drawImage (image_painted,
        0, 0, 116, 28,
        0, 0, image_painted.getWidth(), image_painted.getHeight());

    //[UserPaint] Add your own custom painting code here..
    //[/UserPaint]
}

void Simple_switch::mouseDown( const MouseEvent& e )
{
    if ( btn_state )
    {
        image_painted= cachedImage_simple_switch_st2_png;
    }
    else
    {
        image_painted= cachedImage_simple_switch_st1_png;
    }
    btn_state= !btn_state;
    this->repaint();
}

And finally the Child_component class:


Child_component::Child_component ()
{
    cachedImage_child_component_bg_png = ImageCache::getFromMemory (child_component_bg_png, child_component_bg_pngSize);

    //[UserPreSize]
    //[/UserPreSize]

    setSize (500, 111);

    //[Constructor] You can add your own custom stuff here..
    //[/Constructor]
}

void Child_component::paint (Graphics& g)
{
    //[UserPrePaint] Add your own custom painting code here..
    //[/UserPrePaint]

    g.drawImageWithin (cachedImage_child_component_bg_png,
                       0, 0, 500, 111,
                       RectanglePlacement::centred,
                       false);

    //[UserPaint] Add your own custom painting code here..
    //[/UserPaint]
}

Thank you all for the suggestions on the bool flag.


#6
Parent_component::Parent_component () 
{ 
    ...
    addAndMakeVisible(btn1, ++id_components); 
    btn1.setTopLeftPosition(610, 65); 
    btn1.addMouseListener(this, true);  // XXX why do you need this?
    btn1.addListener(this);             // this is okay; you need this
addAndMakeVisible(child_component, ++id_components); 
child_component.setTopLeftPosition(313, 226 ); 

child_component.addMouseListener(this, true); // XXX why do you need this?
}

If I'm reading your code correctly, you shouldn't need the above lines (marked in bold).

When you click on btn1, you should get a callback to Simple_switch::mouseDown(). That should toggle your images. You don't need to add a mouse listener for this.

Now because you've added a button listener for btn1 by calling btn1.addListener(this), you will get a callback to Parent_component::buttonClicked(). This is probably all you need.

My guess is that somehow the mouse events are getting duplicated or mixed up, hence why you are seeing different behavior when you step through with a debugger. Try removing those lines and see what happens.


#7

I created a supe super simple version of all codes.

I created components that have no images. simply a background color.

So, empty components and nothing interferes.

And i 've noticed something. What i did is push the btn, then i took away the focus from the vst and pressed the btn again. And it worked fine.

Hence the fact that while debugging and setting breakpoints it worked ok. My code editor gained the focus during breakpoints.

After the

setVisible(bool_f);

call, i added

unfocusAllComponents();

and then worked like a charm, without having to focus outside the vst.

But i'm guessing this is not a solution.


#8

Any thoughts on what is mentioned above?


#9

My thoughts are that you shouldn't have to hack it like this to make it work. You're not doing something right. The JUCE library can handle doing what you are trying to do with ease. It's a matter of getting the details right.

Did you try my suggestion? Why do you need those calls to addMouseListener in your code?


#10

Matty sorry but i thought the problem is, most likely, not in the Listeners.

Yes I have cleared up my code and clearly no mixup can occur since MouseListener is allready a Listener. So what if I did the Listener assignment twice to my switch component.
As i mentioned the new version of the code is very simple. I even took out the Listener assignment for my Child_component class. Honestly i can't answer your question on what i need the MouseListener for my child_component. I simply do. UI requires interaction. And my components will be used by users for doing things, especially with the mouse.

The question remains.

Create a simple VST, with 3 GUI components, A, B and C created in Introjucer.

A containing B and C.

B being a child class of ImageButton(or ToggleButton if you wish).

The sole purpose and functionality of this VST would be this: when you press on component B, component C must change between visible state and invisible.

What i'm worried about is the B component being a button of some sort(Image or Toggle). Because, I need it to work like a button. So i need a buttonListener to capture the mousebutton press of the user. Yes i could handle this with a simple MouseDown event, but shouldn't i be capable to create a class that triggers a button click event?


#11

Honestly i can't answer your question on what i need the MouseListener for my child_component. I simply do. UI requires interaction.

My question was not "why do you need to use the mouse." In the code you've showed us so far, you aren't doing anything that requires additional MouseListeners. Component already inherits MouseListener. Button inherits Component.

when you press on component B, component C must change between visible state and invisible.

I've created your scenario one-handed in 7 min while eating breakfast:

class ParentComponent : public Component,
                        public ButtonListener
{
...
private:
    ScopedPointer<ToggleButton> toggleButton;
    ScopedPointer<Label> label;
...
};

ParentComponent::ParentComponent ()
{
    addAndMakeVisible (toggleButton = new ToggleButton ("new toggle button"));
    toggleButton->setButtonText (TRANS("Hide Label"));
    toggleButton->addListener (this);

    addAndMakeVisible (label = new Label ("new label",
        TRANS("Check the toggle button to show or hide me!")));
    ...
}

void ParentComponent::buttonClicked (Button* buttonThatWasClicked)
{
    if (buttonThatWasClicked == toggleButton)
    {
        label->setVisible(!label->isVisible());
    }
}

Is this what you're trying to do?