Search Unity

  1. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

TextMeshPro.SetText() method doesn't set text properly

Discussion in 'UGUI & TextMesh Pro' started by novaVision, Mar 3, 2020.

  1. novaVision

    novaVision

    Joined:
    Nov 9, 2014
    Posts:
    514
    This post is just informative, and I hope it will help someone to avoid 1 day of time wasting. I even couldn't imaging that text engine could have buggy behaviour in the main method.
    So, what's the case exactly?
    If you use TextMeshPro.SetText() method applying any value to the text component, it will change the view (visuals will be updated) but checking that text by TextMeshPro.text property you ALWAYS will get empty string (or string, which been applied before in inspector or using same TextMeshPro.text property) in any build. I been working on Standalone app, and this issue happened both Mac and Win.

    Here is a part of code from TMP_Text.cs
    Code (CSharp):
    1. public void SetText(string text, bool syncTextInputBox)
    2.         {
    3.             //if (text == old_text) return;
    4.  
    5.             //old_text = text;
    6.  
    7.             m_inputSource = TextInputSources.SetCharArray;
    8.  
    9.             StringToCharArray(text, ref m_TextParsingBuffer);
    10.  
    11.             #if UNITY_EDITOR
    12.             // Set the text in the Text Input Box in the Unity Editor only.
    13.             // TODO: Could revise to convert to string literal
    14.             if (syncTextInputBox)
    15.                 m_text = text;
    16.             #endif
    17.  
    18.             m_isInputParsingRequired = true;
    19.             m_havePropertiesChanged = true;
    20.             m_isCalculateSizeRequired = true;
    21.  
    22.             SetVerticesDirty();
    23.             SetLayoutDirty();
    24.         }
    As you see it will update m_text only in Editor.
    This behaviour is used in all currently official TMP versions. For Unity 2018 it's 1.4.1, for Unity 2019 it's 2.0.1
    In new preview versions they fixed it changing the method to simple

    Code (CSharp):
    1. public void SetText(string text, bool syncTextInputBox = true)
    2. {
    3.      this.text = text;
    4. }
    What makes it the same as TextMeshPro.text direct property change. Do I miss something or both version are pretty... weird...

    I hope this help. Would be great to get some response from TextMeshPro dev team with an explanation, how this part of code can be affected to such basic methods.
     
  2. Stephan_B

    Stephan_B

    Joined:
    Feb 26, 2017
    Posts:
    6,595
    The SetText() method was initially added to allow users to combine variables along with the text without allocations.

    For example : m_TextComponent.SetText("The value is: {0:1}.", 10.45f); which would result in "The value is: 10.5.".

    Since this SetText() function never internally set the .text property which to avoid allocations which left the Text Input Box in the Inspector empty, a change was made so that in the Editor Only, the .text property was set to match the SetText() with formatting content.

    At some other point in time, users requested the ability to user StringBuilder and as such
    public void SetText(StringBuilder text) was added as well as other variants of SetText().

    All along is was possible to use SetText() without formatting but that provided no benefits and also resulted in allocations in the Editor to set the .text property for the Inspector. So in order to avoid that, the plain SetText() with no formatting was simply replaced to set the .text property.

    There have been several threads about this over the years including this one from last week. This new thread includes a good suggestion from @Gladyon which I intend to explore when I have a chance.
     
    CPlusSharp22 likes this.
  3. TimHeijden2

    TimHeijden2

    Joined:
    Aug 11, 2016
    Posts:
    86
    I also ran into this and while I like the ability to avoid garbage allocation as you mentioned, right now the implications aren't obvious. As a result, it sounds like something people can run into often and specifically at inopportune times because most issues only happen in a build!

    My specific scenario is that I had my localization system use SetText(), and another script which would copy the text to another TextMeshProUGUI component. (which we do to work around this issue)

    A few suggestions I have for this:

    - Add documentation to the SetText() function, explicitly noting there is a difference in editor/build & explaining the use case. (something like along the lines of: "In order to avoid GC Alloc, the .text value is not updated. SetText() should only be used when you intend on only writing to the text, not reading")

    - Make the editor & build behave the same, though I'm not sure how hard this is to do. (I can imagine it being very difficult due to .text dependencies in-editor or smth)

    - Possibly rename SetText(0 to SetTextNonAlloc() to be more explicit in its purpose, though I understand that may not be a good idea due to legacy / package being distributed already.
     
    Arkade and CPlusSharp22 like this.
  4. jacobleaney_unity

    jacobleaney_unity

    Joined:
    Sep 6, 2018
    Posts:
    8
    I'm so glad I managed to find this, I was struggling for a solid 6-8 hours as to why my text was being processed differently in my build vs. the editor. Replacing 'TextMeshPro.SetText()' with 'TextMeshPro.text =' solved everything.
     
  5. tlatta

    tlatta

    Joined:
    Jul 22, 2019
    Posts:
    1
    Thank you guys for resolving this. For me it was 3 hours of searching in the dark...
    Replacing 'TextMeshPro.SetText()' with 'TextMeshPro.text =' solved everything for me aswell.
     
  6. Kamyker

    Kamyker

    Joined:
    May 14, 2013
    Posts:
    1,084
    In 3.0.3 it works fine for most of the functions but not for SetText(char[])...
     
  7. lulitha

    lulitha

    Joined:
    Feb 8, 2017
    Posts:
    11
    Code (CSharp):
    1. using TMPro;
    2.  
    3. public TMP_Text numberText;