RichTextLabel.add_text doesn't work

Godot Version

v4.7

Question

This RichTextLabel is acting as an output feed for the player. “Outputs.comFeedGet()” will pop all of the items from the communication feed, an array of size-2 arrays representing speaker-text pairs like this: [[“PLAYER”, “Hello world”], [“ENEMY”, “I’m going to kill you now.”]] The _process function of the RichTextLabel just moves items from the communication feed into its own .text property. Or at least it’s supposed to. The code below throws no errors. It successfully executes the print() statement and the printed lines are correct. However, the add_textfunction appears to do nothing. The line is not loaded to the RTL’s body. If I replace that line with add_text(“test”), it works as expected, adding “test” to the body every frame.

var feed = Outputs.comFeedGet()
if feed.size() > 0: for x in feed.size():
		var line = feed[x][0] +": "+feed[x][1]+ "\n"
		print(line)
		add_text(line)

I also tried writing it a different way, but this doesn’t work either:

func _process(delta: float) → void:
var feed = Outputs.comFeedGet()
var item = [ ]
var line = “”
if feed.is_empty() == false:
>| item = feed.pop_front()
>| line = item[0] +": "+item[1]+ “\n”
if line != “”: print(line)
add_text(str(line))

add_text appends to the ‘tag stack’ it’s a lower level feature you probably don’t want to be using. Try text += line instead

Just tried it. That doesn’t work either. Exact same problem.

Can you share your updated code? Maybe more of it too, is there anywhere you are clearing the text of this label? What do your prints say?


Make sure to paste code between three ticks ``` or use the code button

This is the full text of communication_feed.gd, which is attached to an RTL. Note that clear() is not being used anywhere, and the RTL’s default text is “TEST” so I would know if it was being cleared.

extends RichTextLabel

# Called when the node enters the scene tree for the first time.
func _ready() -> void:
	var feed = Outputs.comFeedArchive
	for x in feed.size():
		self.add_text( feed[x][0] +": "+feed[x][1]+ "\n" )

# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta: float) -> void:
	var feed = Outputs.comFeedGet()
	var item = []
	var line = ""
	if feed.is_empty() == false:
		item = feed.pop_front()
		line = item[0] +": "+item[1]+ "\n"
	if line != "": print(line)
	text += str(line)
	
	
	#if feed.size() > 0: for x in feed.size():
		#var line = feed[x][0] +": "+feed[x][1]+ "\n"
		#print(line)
		#text += (line)
```
These are the relevant functions from Outputs.gd, an autoload:

```
@onready var communicationFeedQueue = []
@onready var communicationFeedReady = [["HANDLER",'900, can you hear me?'],["HANDLER","Your system has been compromised."]]
@onready var comFeedArchive = []

func comFeedAdd( speaker, string ):
	var composite = [speaker, string]
	communicationFeedQueue.push_back( composite )

func comFeedGet():
	var output = []
	if communicationFeedQueue.size() >0:
		for x in communicationFeedQueue.size():
			var item = communicationFeedQueue[x].duplicate()
			comFeedArchive.push_back( item )
			output.append( item )
		communicationFeedQueue.clear()
	return output
```

Finally, this is the function from Actions.gd (another autoload) which is called by input to trigger comFeedAdd(). Basically, every time the user presses the key, one line of dialogue should be moved into the feed.

func advanceCommunication():
	if Outputs.communicationFeedReady.size() >0:
		var item = Outputs.communicationFeedReady.pop_front()
		Outputs.comFeedAdd( item[0], item[1] )
		Audio.seMenuNav()
	else:
		Audio.seError()

I’m sure that it’s working properly right up to the “text +=” statement, because the output is correctly reading (only if I press tab twice):

"HANDLER: 900, can you hear me?

HANDLER: Your system has been compromised."

So this first line prints, but text doesn’t get appended? You still only see “TEST” on screen?

This appears in the output panel/console?

That’s correct. And if I instead write ```text += “TEST”```, it works as expected

works as expected meaning you see “TEST” appear multiple times in sequence like “TESTTESTTESTTEST”?

yeah, exactly

That is strange, maybe the str(line) cast is doing something? Since line is already a string you can just add text += line


Your code style is a pretty odd for Godot, maybe closest to old C-like. Your for loops do not need to iterate by index, for example this is equivalent to your ready block

var feed = Outputs.comFeedArchive
for f in feed:
	self.add_text( f[0] + ": " + f[1] + "\n" )

Personally I would rewrite it like so, using a lot more static typing can help with enigmatic cases.

func _process(_delta: float) -> void:
	var feed: Array[Array] = Outputs.comFeedGet()
	if feed.is_empty():
		return

	var item: Array = feed.pop_front()
	var line: String = "%s: %s\n" % [item[0], item[1]]
	print("New line found: ", line)
	text += line

If this never prints then it’s probably an issue with comFeedGet which is also a strange function duplicating parts of the array when I think just communicationFeedQueue.duplicate() would work

func comFeedGet():
	var output: Array[Array] = communicationFeedQueue.duplciate()
	communicationFeedQueue.clear()
	return output

Thanks so much for your help so far. I used your second two snippets to replace mine and I got this error on the first line of _process()

Trying to assign an array of type “Array” to a variable of type “Array[Array]”.

I forgot to add a type to comFeedGet, but arrays are finnicky with their typing it may be better to use Array instead of Array[Array] for now

func comFeedGet() -> Array[Array]:
	var output: Array[Array] = communicationFeedQueue.duplicate()
	communicationFeedQueue.clear()
	return output

Make a minimal reproduction example.

This returns the same error, I think because communicationFeedQueue is an array when empty, not an array-within-an-array.

I eventually solved this problem by deleting the whole system and rebuilding it from scratch. I found that RichTextLabel.clear() and .add_text were unnecessary and .text=“” and .text+=“blah blah blah” was a better system. Perhaps more importantly, I used static typing and ensured that the functions operating on my arrays could not return empty values. For example, the new getFeed() function will return a blank array in the proper format if the feed is empty.