How to set the background color of a RichTextCtrl in wxPython

Hello, new to wxPython and trying to build a little chatbox.

I want to colour every entry in the RichTextCtrl with a background colour.

I got this class going:

from wx import Font, ID_ANY, TE_MULTILINE, TE_READONLY, DEFAULT, NORMAL, WHITE, Colour, BLACK, BORDER_DOUBLE
from wx.richtext import RichTextAttr, RichTextCtrl, TextBoxAttr, TextAttrDimension

class ChatDisplayer(RichTextCtrl):
    def __init__(self, *args, **kw):
        super().__init__(*args, **kw)

    def addMessage(self, message, red, green, blue):
        font = Font(12, DEFAULT, NORMAL, NORMAL, False)
        text_attr = RichTextAttr()
        text_attr.SetTextColour(WHITE)
        text_attr.SetFont(font)
        bg_color = Colour(red=red, green=green, blue=blue)
        text_attr.SetBackgroundColour(bg_color)

        self.BeginStyle(text_attr)
        self.AppendText(message)
        self.EndStyle()

when this is added to a grid, I can effectively add text to it, taking turns between sender and receiver, but nothing in the styling part will work, no text colour, no background colour.

This is what it looks like right now:

This ChatDisplayer class is then used in this class:

class ChatMessageGrid(FlexGridSizer):
    def __init__(self, panel):
        super().__init__(6, 2, 9, 25)
        
        chat_message_apikey_label = StaticText(panel, label="API key")
        chat_message_apikey_input = TextCtrl(panel)

        chat_displayer_label = StaticText(panel, label="Chat", pos=(1, 0))
        chat_displayer_input = ChatDisplayer(panel, ID_ANY, style=TE_MULTILINE|TE_READONLY)

        chat_message_system_label = StaticText(panel, label="System")
        chat_message_system_input = TextCtrl(panel)

        chat_message_label = StaticText(panel, label="your message")
        chat_message_text = TextCtrl(panel, style=TE_MULTILINE)
        chat_message_button = Button(panel, label="send")

        model_choice_label = StaticText(panel, label="model")
        model_choice_box = ComboBox(panel, value="gpt-4", choices=model_choices)

        self.AddMany(
            [
                chat_message_apikey_label,
                (chat_message_apikey_input, 1, EXPAND),
                chat_message_system_label,
                (chat_message_system_input, 1, EXPAND),
                (chat_displayer_label, 1, EXPAND),
                (chat_displayer_input, 1, EXPAND),
                (chat_message_label, EXPAND),
                (chat_message_text, 1, EXPAND),
                (model_choice_label, EXPAND),
                (model_choice_box, EXPAND),
                (chat_message_button, EXPAND),
            ]
        )

        self.AddGrowableRow(2, 1)
        self.AddGrowableRow(3, 1)
        self.AddGrowableCol(1, 1)

        chat_message_button.Bind(
            EVT_BUTTON,
            lambda event: self.onClick(
                event,
                chat_message_system_input,
                chat_message_apikey_input,
                chat_displayer_input,
                chat_message_text,
                model_choice_box,
                chat_message_button
            ),
        )
        
    def completeRequest(self, messages, model, apiKey, chat_displayer_input, message, button):
        # call the service
        client = ApiClient(apiKey)
        answer = client.complete(messages, model=model)

        messages.append({"role": "assistant", "content": answer})

        userMessage = "User: " + message + "\n"
        aiMessage = "Assistant: " + answer + "\n"

        # update the UI
        CallAfter(chat_displayer_input.addMessage, userMessage, 176, 210, 167)
        CallAfter(chat_displayer_input.addMessage, aiMessage, 176, 210, 167)

        # re enable the button
        button.Enable()

    def onClick(
        self,
        event,
        chat_message_system_input: TextCtrl,
        chat_message_apikey_input: TextCtrl,
        chat_message_historic_input: ChatDisplayer,
        chat_message_text: TextCtrl,
        model_choice_box: ComboBox,
        button: Button
    ):
        if not len(chat_message_apikey_input.GetValue().strip()):
            MessageBox("API key is empty!", "Error", OK | ICON_ERROR)
        elif not len(chat_message_text.GetValue().strip()):
            MessageBox("type something please!", "Error", OK | ICON_ERROR)
        else:
            #blabla
            button.Disable()

            # create a thread to run the API call
            t = threading.Thread(target=self.completeRequest, args=(messages, model_choice_box.GetValue(), apiKey, chat_message_historic_input, message, button))
            t.start()

lastly, this method is called in a basic main.

Can someone pinpoint me to the error here ? been trying to understand the documentation but didn’t find anything yet.
thank you

Hi,

When applying a style to some text in a RichTextCtrl using a RichTextAttr, you need to call the RichTextAttr object’s SetFlags() method to specify which elements of the attribute should be used.

e.g. if you are specifying the font size, text colour and background colour, you need to call:

text_attr.SetFlags(wx.TEXT_ATTR_FONT_SIZE | 
                   wx.TEXT_ATTR_TEXT_COLOUR | 
                   wx.TEXT_ATTR_BACKGROUND_COLOUR)

A full list of the flags can be found at: wx.TextAttrFlags — wxPython Phoenix 4.2.0 documentation