Very strange GUI-not-updating issue

I have a button which calls this function when I click it.

    public void openProfile() {
        updateGUI(); // can call twice here
        profileGO.SetActive(true);
        // and here - but no difference
    }

    public void updateGUI() {
        bool wasActive = profileGO.activeInHierarchy;
        profileGO.SetActive(true);
        // stuff happens, for example:
        friendsText.text = xyz.Replace("#numFriends#", ""+userProfile.friends.Count);
        activeSinceText.text = activeSinceText.text.Replace("#activeSince#", userProfile.pcd);
        profileGO.SetActive(wasActive);
    }

This button is the only code that can reach this updateGUI() function. When I debug the function, everything happens as expected, however in the editor I will not see the changes made to the text variables. I have to click the button a second time, no matter what. Even if I call updateGUI() twice before and even after SetActive(true). No matter what, I have to click the button a second time and seriously, I have no idea at all why this is so.
Can anyone help here?

This bit pops out at me:

I seem to vaguely recall that setting an object active/inactive multiple times in the same frame doesn’t work; it doesn’t fully change status until you give it a moment to react. Even if it did work, SetActive changes the value of activeSelf, but you are returning it to the old value of activeInHierarchy, so this isn’t the proper way to return it to its previous setting.

Also, I’m having trouble imagining what motivated you to try this in the first place, especially given that the openProfile() function is just calling SetActive(true) when you’re done.

Regarding your larger problem, I’m not understanding the details.

You contrast debugging with “in the editor”–are you only debugging standalone builds? Is the visible behavior different in standalone builds compared to running in the editor? Is the visible behavior different depending on whether you step through in a debugger versus letting it run uninterrupted?

You say you don’t see changes to variables, but you show code changing a property (technically not a variable) that should have visible effects on rendering the game screen. Are you checking the output by looking at the game screen, or by looking in the inspector window, or with Debug.Log calls, or what? (Consider doing all of the above, if you haven’t.)

Is profileGO active or inactive prior to you clicking the button for the first time? Are the results of the SetActive part visible immediately, even when the text is not? Does that object (or any of its children) have code in Awake, Start, or OnEnable that might directly or indirectly affect the text fields?

If none of those questions jars anything loose, I might Debug.Log the value of a text field right before you set it, right after you set it, and also every frame in an Update function somewhere. If everything were working correctly, you should see it output its old value before the set, and the new value after the set, and in every Update call thereafter. If that is what you actually do see, that suggests your data is being updated correctly and you have some sort of display problem. If you see something else, that points to a problem with your data either failing to change or being reset after you change it, which will narrow down where you should look for the bug.

2 Likes

I try to clarify :slight_smile:
When I debug this code, I see that it does what it is supposed to do.
I had to set the GO temporarily active because when it is inactive, I cannot find objects I want to find during this method.
There are other use cases in which I want to call updateGUI() without setting it active, so to find my objects, I need this saving of the old state. I am not debugging a standalone build, I am debugging while in the editor. It is the same whether or not I debug the code.
I am checking the output by looking at the game screen, yes.It wouldn’t be that bad if it took just 1 frame, but it doesnt update after 1 frame but only after a second call from the gui! Calling the method 4 times via scripting doesn’t improve the situation which I find totally strange.

The thing is, no other script changes anything on the Text Components you see in above code. It is only this piece of code which can alter the contents (for this usecase).

Is there another method instead of saving the enabled state when I want to find inactive objects? Did the Untiy team after so many years finally give a method to Find() inactive objects?

You seem kind of fixated on the fact that calling the function twice doesn’t fix things. This is not surprising to me. It just means that the problem is something other than “not working the first time”, which wouldn’t have been my first guess at the true problem anyway. I suggest you stop focusing on the work-around (i.e. pressing the button again) and instead focus on tracking down the root cause of the problem.

In most cases, it’s better to avoid using Find entirely (and second-choice would be to call it once in Start and save the result, so that you never need to call it again). My default way to get object references is to use public fields and drag references into them via the inspector.

Some versions of find are able to get inactive objects; e.g. this one has a flag for includeInactive. Not every variant of find has this ability, though.

Are you 100% sure that this “setting them temporarily active right before you search” trick that you’re doing even works? Because like I said earlier, I didn’t think that setting them active really “takes” until you wait a frame for them to react, and if I’m right, that could potentially explain your entire problem (your initial attempt to set the text fails because you aren’t able to find the objects, which aren’t fully active yet).

Although, if that were the problem, you should almost certainly be seeing error messages in the console, which I hope you would have already checked for, and mentioned if you found. (Checking for errors in the console should be close to the very first thing you do when any script has a problem.)

If nothing in this post solve your problem, please go back to my earlier post and look at the questions and suggestions you haven’t addressed yet.

Oh sh*t, you were right. There IS something in a Start() method. God I’m stupid.

So basically, these Text objects have a script attached “Translatable” which has a Start() function. The problem was that (and that’s why setActive kinda destroyed it) this Start was called after the updateGUI method.
I added a bool that states whether this Translatable was already changed by some other method setText() and then ignore what happens in Translatable.Start()

Thanks to your idea, I got this. Thank you :slight_smile: