Painting on a panel

Thank you for reading this.

I can paint on a frame but I’m at a complete loss when it come to painting on a panel. I’ll include the entire code in case there are multiple errors. I thought “self.MyPanel” might have been the answer, but it’s not.

import wx


class MyApp(wx.App):
    def __init__(self):
        super().__init__(clearSigInt=True
        )

        self.InitFrame()

    def InitFrame(self):
        frame = MyFrame(parent=None,
                        title="LED Class",
                        size=(300, 300),
                        pos=(100, 100))
        frame.Show()

class MyFrame(wx.Frame):
    def __init__(self, parent, title, size, pos):
        super().__init__(parent=parent, title=title, size=(300, 300), pos=pos)
        self.OnInit()

    def OnInit(self):
        panel = MyPanel(parent=self)

class MyPanel(wx.Panel):
    def __init__(self, parent):
        super().__init__(parent=parent)

        self.timer = wx.Timer(self)
        self.Bind(wx.EVT_TIMER, self.OnPaint)
        self.timer.Start(5000)

    def OnPaint(self, event):
        print('OnPaint')
        dc = wx.PaintDC(self)
       
        dc.SetPen(wx.Pen("green"))
        dc.DrawLine(10, 10, 50, 50)

        
if __name__ == "__main__":
    app = MyApp()
    app.MainLoop()

Traceback (most recent call last):
File ,line 36, in OnPaint
dc = wx.PaintDC(self)
wx._core.wxAssertionError: C++ assertion ““IsOk()”” failed at /home/wxpy/wxPython-4.1.1/ext/wxWidgets/src/common/dcgraph.cpp(436) in SetTextBackground(): wxGCDC(cg)::SetTextBackground - invalid DC

The documentation for PaintDC says: A wx.PaintDC must be constructed if an application wishes to paint on the client area of a window from within an EVT_PAINT() event handler.

However, you are trying to construct one in an EVT_TIMER() event handler.

If I replace:

        self.timer = wx.Timer(self)
        self.Bind(wx.EVT_TIMER, self.OnPaint)
        self.timer.Start(5000)

with:

        self.Bind(wx.EVT_PAINT, self.OnPaint)

it works for me on Python 3.8.10 + wxPython 4.1.1 gtk3 (phoenix) wxWidgets 3.1.5 + Linux Mint 20.2

What was the reason for using the timer?

Hi OverTheHill,
as Richard says, PaintDC is only used within a EVT_PAINT(), so bind your OnPaint to EVT_PAINT as he has suggested.

If you intend to redraw that line every time the Timer fires, just bind the EVT_TIMER to a function that refreshes the Panel.

self.Bind(wx.EVT_TIMER, self.OnTimer)

...

def OnTimer(self, event):
    self.Refresh()

Thank you RichardT and rucky,
Silly me for not realising that I was using the wrong event.