Search code examples
pythonwxpythonwxwidgets

Persistent drawing + temporary overlay with wx.PaintDC


I'm trying to make something of a Microsoft Paint-esque app using wxPython.

Currently, the app 'draws' onto the screen with a circular brush during a mouse left-down event. This is great, and the desired behavior. But I also need a circle of the same radius to 'follow' the mouse, without it drawing persistently onto wx.PaintDC.

That is, a circle of some radius follows the mouse around the screen, but only when the left mouse button is held, should the circle be 'permanently' drawn onto the buffer.

The approaches I've taken either (1) have a circle following the mouse around, but draw onto the PaintDC instance regardless of mouse-down, (2) follow the mouse around but never draw persistently onto the PaintDC instance, or (3) do not follow the mouse around, but appear and are drawn persistently on left-mouse down (see the example below).

Thank you!

import wx

class MyPanel(wx.Panel):
    def __init__(self, parent):
        wx.Panel.__init__(self, parent, -1)

        self.draw = False
        self.radius = 50

        self.Bind(wx.EVT_PAINT, self.OnPaint)
        self.Bind(wx.EVT_MOTION, self.Draw)
        self.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown)
        self.Bind(wx.EVT_LEFT_UP, self.OnLeftUp)

    def OnPaint(self, event):
        dc = wx.PaintDC(self)

    def Draw(self, event):

        if self.draw == True:
            x = event.GetX()
            y = event.GetY()
            dc = wx.ClientDC(self)

            pen = wx.Pen(wx.Colour(192,192,192,128), 2)
            brush = wx.Brush(wx.Colour(192,192,192,128))

            dc.SetPen(pen)
            dc.SetBrush(brush)
            dc.DrawCircle(x,y,self.radius)

    def OnLeftDown(self, event):
        self.draw = True

    def OnLeftUp(self, event):
        self.draw = False


class MyForm(wx.Frame):

    def __init__(self):
        wx.Frame.__init__(self, None, wx.ID_ANY, "Test",style=wx.DEFAULT_FRAME_STYLE,size=wx.Size(400, 300))
        self.main_panel = MyPanel(self)

if __name__ == "__main__":
    app = wx.App(False)
    frame = MyForm()
    frame.Show()
    app.MainLoop()

Solution

  • There is the wx.Overlay class that does a pretty good job assisting with drawing temporary things on top of more permanent stuff. See the Overlay sample in the demo: https://github.com/wxWidgets/Phoenix/blob/master/demo/Overlay.py