DrawableButton setButtonText crashes


#1

Hi,

 

I have a drawablebutton created: "DrawableButton* UserSelect = new DrawableButton ("User", DrawableButton::ImageAboveTextLabel);", that at a certain situation i need to put the button text, not when painting.

The situation is that i use the function "UserSelect->setButtonText("Text to put");" and the application crashes giving access violation and opens the header "juce_CharPointer_UTF8.h";

What am i'm doing wrong ?

On normal button i can setButtonText anytime without any problem.

Thanks,

Paulo


#2

at a certain situation

Can you post some code?


#3

Sure I can:

LoginClass::LoginClass (int menuOptionID) {

setName ("LoginComponent");

DrawableImage down, up, clicked;
down.setImage (ImageCache::getFromMemory (BinaryData::person_png, BinaryData::person_pngSize));
down.setOverlayColour (Colours::black.withAlpha (0.3f));
up.setImage (ImageCache::getFromMemory (BinaryData::person_png, BinaryData::person_pngSize));
up.setOverlayColour (Colours::white.withAlpha (0.3f));
clicked.setImage (ImageCache::getFromMemory (BinaryData::person_png, BinaryData::person_pngSize));
clicked.setOverlayColour (Colours::blue.withAlpha (0.3f));

DrawableButton* UserSelect = new DrawableButton ("UserButton", DrawableButton::ImageAboveTextLabel);
UserSelect->setName(TRANS("Unknown"));
UserSelect->setButtonText(TRANS("Unknown"));
UserSelect->setImages(&up, &down, &clicked);
UserSelect->setBounds(32, 90, 111, 104);
UserSelect->setTooltip(TRANS("Click to choose your user"));
UserSelect->setColour(DrawableButton::backgroundColourId, Colours::lightgrey);

addAndMakeVisible(UserSelect);

 

then bellow i have a function that gets some data from a database and i need to update to text and image on the button:

String NameOfUser = "";
...
UserSelect->setButtonText(NameOfUser);

 

Paulo

 


#4

Please consider using the Styles dropdown to mark your code so it looks like this:

String NameOfUser = "";
...
UserSelect->setButtonText(NameOfUser);

It will make it easier for people to read your post.

Also you are posting code fragments--these don't mean much without context. If you want anyone to be able to help you, you'll have to give them context by letting them know what function, class, thread, etc you are executing the function from.

Try removing all of the other button images except the normalImage. Remove any other unnecessary code, too. Try to create the smallest program possible that both (1) compiles and (2) replicates your issue.

On a different note, how are you managing the lifetime of this object?

DrawableButton* UserSelect = new DrawableButton ("UserButton", DrawableButton::ImageAboveTextLabel);

#5

I removed all DrawableButton definitions and make it simple like this:

LoginClass::LoginClass () {

setName ("LoginComponent");

DrawableImage up;

up.setImage (ImageCache::getFromMemory (BinaryData::person_png, BinaryData::person_pngSize));
up.setOverlayColour (Colours::white.withAlpha (0.3f));

DrawableButton* UserSelect = new DrawableButton ("UserButton", DrawableButton::ImageAboveTextLabel);
UserSelect->setImages(&up, &up, &up);
UserSelect->setBounds(32, 90, 111, 104);
addAndMakeVisible(UserSelect);

And on the function i call, i am using trying the same way:

String NameOfUser = "";

...

UserSelect->setButtonText(NameOfUser);

Error is the same, it crashes saying:
"Unhandled exception at 0x007A60EF in MyApp.exe: 0xC0000005: Access violation reading location 0x00000084."

And it crashes on juce_CharPointer_UTF7.h, on line 66:

inline bool operator== (CharPointer_UTF8 other) const noexcept { return data == other.data; }

Cannot understand why this is happening.

Your question about lifetime of this object i cannot understand, sorry, but i explain what i have done.

This DrawableButton makes part of a component that is used for login on my application, and when i destroy the component, i have it declared as a "ScopedPointer<DrawableButton> UserSelect" and i do UserSelect = nullptr when "destroying" the component.

Hope this helps.

Thanks,

Paulo


#6

0xC000005 indicates you’re trying to access an object which doesn’t exist… So check to make sure that UserSelect != nullptr before you try to use it.

… Then check the lifetime if your objects are what you expect them to be.

Rail


#7

Are you saying that you have a member variable in your class like

private:
    ScopedPointer<DrawableButton> UserSelect;

An then in your constructor you have this line:

DrawableButton* UserSelect = new DrawableButton ("UserButton", DrawableButton::ImageAboveTextLabel);

If you declare a local variable with the same name as a member variable it will take precedence over it. What you're actually doing is creating a new pointer, assigning it your newly created object and never acually touching your member variable. So when try to use your UserSelect member later on it doesn't actually contain a valid object.

To fix it, don't re-declare the UserSelect identifier, just assign it. E.g. the line above becomes:

UserSelect = new DrawableButton ("UserButton", DrawableButton::ImageAboveTextLabel);

Better still, unless this object needs to be created and deleted dynamically make it a member object, not a pointer. That way you know it will always be vailid and you won't have to assign it an object or de-reference the pointer each time you use it.

 

Try turning up your warning levels, there should be one to highlight this issue.

Also it's a good style idea to not start your variable names with a capital letter, it makes it hard to distinguish what is a variable and what is a class name, especially on forums where there is no syntax highlighting.


#8

Your question about lifetime of this object i cannot understand

Yeah, I think this might be the problem.

When you say something like this,

DrawableButton* UserSelect = new DrawableButton(...);

You are implying that you are going to handle calling delete by yourself in your destructor. Don't let jules see this. He'll blow a gasket.

Hopefully, you have something like this in your class declaration:

class LoginClass : public Component
{
    ...
private:
    ScopedPointer<DrawableButton> UserSelect;

You should use UserSelect like this in your constructor:

addAndMakeVisible(UserSelect = new DrawableButton ("UserButton", DrawableButton::ImageAboveTextLabel));
UserSelect->setImages(&up, &up, &up);
UserSelect->setBounds(32, 90, 111, 104); 

What you have done is redefine a local variable with the type DrawableButton* in your constructor. This is a local override, meaning, it is a different variable than the variable with the same name that has the type ScopedPointer<DrawableButton>. As you have it, you aren't changing the variable ScopedPointer<DrawableButton> UserSelect, which by default contains a null pointer to a DrawableButton. So when you go to use it, the operator->() will return a null pointer. It's important to distinguish that UserSelect itself won't actually be null if you've declared it to be a ScopedPointer in your class declaration. Note, however, that the operator==() and operator!=() have been overloaded so that you can check to see if the pointer managed by ScopedPointer is nullptr.

ScopedPointer<> helps you manage the "birth" and "death" or lifetime of the object in a safe way.


#9

Exactly! dave96, you beat me to it.


#10

Hi Dave,

yes you were right, i do not know why i have declared it that way, but the lifetime of the component was short. I removed it and now works perfectly.

You and matty are really expert. Just wish i have 1% of your skills.

I have another issue that is breaking my head completly, that is regarding addAndMakeVisible components, acting like son and father.

I have nested components that occupy full app width and height, and for sure i am making things in a wrong way.

Should i post this question here or create a new one ?

Thanks again to all.

Paulo


#11

Thanks Rail for the tip


#12

I'm no expert, I'm just trying to help a fellow JUCE fan along ;)

the lifetime of the component was short

Exactly the opposite! What happened was that you created a new object on the heap in your constructor. Then once the constructor exited, that object still existed on the heap, but the pointer to that object on the heap fell out of scope, so you no longer had access to the object it pointed to. So the object stayed on the heap until your program exited or was terminated by the OS. This is called a "dangling pointer" and it resulted in a memory leak. This is not what caused your crash, though!

I'm glad it's working for you now.