DestroyChildren causing text color to be wrong

I am running on Windows 11 and the code below does not have the correct text color (white) if the text fits, i.e. does not wrap. If you resize the window, you can really see the effect. I have traced it down to the DestroyChildren function, because if I comment it out, it shows correctly, but then resizing does not work correctly.

import wx
import wx.grid


class RectanglePanel(wx.Panel):
    def __init__(self, parent, x, y, a, b, text, color):
        super().__init__(parent, size=(a, b), pos=(x, y))
        self.color = color
        self.SetBackgroundColour(self.color)
        # Create a StaticText widget to display the text
        self.text = wx.StaticText(self, label=text, size=(a-4, b-4), pos=(2, 2), style=wx.ALIGN_CENTRE_HORIZONTAL)
        # make the text white
        self.text.SetBackgroundColour(self.color)  # Set the background color to distinguish the rectangle
        self.text.SetForegroundColour(wx.WHITE)

        # Create a box sizer to center the text
        sizer = wx.BoxSizer(wx.HORIZONTAL)
        sizer.Add(self.text, 1, flag=wx.ALL | wx.EXPAND, border=0)

        self.SetSizer(sizer)
        # add a red border around the rectangle
        self.SetBackgroundStyle(wx.BG_STYLE_PAINT)
        self.Bind(wx.EVT_PAINT, self.OnPaint)

    def OnPaint(self, event):
        dc = wx.AutoBufferedPaintDC(self)
        dc.SetPen(wx.Pen(wx.RED, 2))
        dc.SetBrush(wx.Brush(wx.RED))
        dc.DrawRectangle(0, 0, self.GetSize().GetWidth(), self.GetSize().GetHeight())

class TL(wx.Frame):
    def __init__(self, data):
        super().__init__(parent=None, title="Test App", size=(1200, 500))

        self.data = data
        self.rectangle_ht = 40
        self.canvas = None

        # Creating the canvas
        self.createCanvas()
        self.update_plot()
        self.Layout()
        self.Show()

    def createCanvas(self):
        self.canvas = wx.Panel(self, -1, size=(1200, 500))
        self.canvas.Bind(wx.EVT_SIZE, self.on_window_resize)

    def update_plot(self):
        # This causes the text color to be incorrect for text that does not wrap
        self.canvas.DestroyChildren()

        canvas_width = self.canvas.GetSize().GetWidth()
        canvas_height = self.canvas.GetSize().GetHeight()

        # Calculate the size of the rectangles
        num_rectangles = len(self.data)
        rectangle_width = canvas_width // num_rectangles

        # Plot the main timeline
        y_pos_main = canvas_height // 2
        rectangle_height = self.rectangle_ht     # Set a fixed height for rectangles (change as needed)

        for i in range(len(self.data)):
            x_pos = i * rectangle_width
            # create a rectangle in wxPython
            rectangle = RectanglePanel(self.canvas, x_pos, y_pos_main - rectangle_height // 2, rectangle_width,
                                       rectangle_height, self.data[i], wx.Colour(64, 128, 255))



    def on_window_resize(self, event):
        # Update the plot when the window is resized
        size = self.GetSize()
        self.canvas.SetSize(size)
        self.update_plot()


if __name__ == "__main__":

    n = 3
    data = ["Short", "A bit longer", "This is a long text", "This is a very long text", "This is a very very long text"]

    app = wx.App()
    frame = TL(data * n)
    app.MainLoop()

well, the coding is very particular & to know the goal may help :sneezing_face: (or not)

The real application has other features where the dataset is much bigger and the user can zoom in/out and also “slide” to the left or right to see more data. I tried to come up with the minimal code that shows the issue. Of course, I could leave the text black, but it does not make sense to me why this is happening. It seems to be that the destroy is interfering with the new create.

that’s very good of you :partying_face:

  • lines 75/76 you may throw-out (then at start the intended view is given)

  • the rectangles don’t resize properly when the text is very long (height)

  • at the end of the init of the RectanglePanel a self.Refresh() may be an idea :wink:

Thanks for the suggestion of refresh. I played around and if I put self.canvas.Refresh() at the end of update_plot, it works!