Search code examples
gdiwxpython

How to remove image in wxPython using DC.Clear()


I am trying to remove an image that has been placed at some random point on a panel. I have previously tried to find a solution to this here, but no one has been able to help.

I have made some progress using wx.DC. However, the documentation of the DC class for the Clear method says:

Clear   Clears the device context using the current background brush.

I have tried this in the following program, however the cleared region is not quite the same colour as the panel background colour. Can anyone please suggest how to set the brush colour to the panel background colour?

import wx
import random


class MainFrame(wx.Frame):
    def __init__(self):
        wx.Frame.__init__(self, None, -1, "Remove image")
        panel = MainPanel(self)
        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(panel)
        self.SetSizerAndFit(sizer)
        self.Centre()
        self.Show()

class MainPanel(wx.Panel):
    def __init__(self, frame):
        wx.Panel.__init__(self, frame)
        self.Bind(wx.EVT_PAINT, self._on_paint)
        self.frame = frame

        # Button
        cmd_refresh = wx.Button(self, wx.ID_REFRESH)
        cmd_refresh.Bind(wx.EVT_BUTTON, self._on_cmd_refresh_click)

        # Main sizer
        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add((500, 300))
        sizer.Add(cmd_refresh, flag=wx.ALL|wx.ALIGN_CENTER, border=10)
        self.SetSizer(sizer)
        self.started = False

    def _on_paint(self, event):
        del event
        if not self.started:
            bitmap = self._get_image()
            self._draw_image(bitmap)
            self._draw_image(bitmap)
            self.started = True

    def _get_image(self):
        bitmap = wx.Bitmap()
        bitmap.LoadFile("red.png", wx.BITMAP_TYPE_ANY)
        self.image_width = bitmap.GetWidth()
        self.image_height = bitmap.GetHeight()
        return bitmap

    def _draw_image(self, bitmap):
        self.x_pos = random.randint(0, self.frame.GetSize()[0]-self.image_width)
        self.y_pos = random.randint(0, self.frame.GetSize()[1]-self.image_height)
        dc = wx.PaintDC(self)
        dc.DrawBitmap(bitmap, self.x_pos, self.y_pos, True)

    def _on_cmd_refresh_click(self, event):
        del event
        dc = wx.ClientDC(self)
        points = (self.x_pos, self.y_pos, self.image_width, self.image_height)
        dc.DestroyClippingRegion()
        dc.SetClippingRegion(points)
        dc.Clear()


if __name__ == '__main__':
    screen_app = wx.App()
    main_frame = MainFrame()
    screen_app.MainLoop()

Solution

  • I have a work-around for this

    I have placed the two lines

        dc = wx.ClientDC(self)
        panel.SetBackgroundColour(dc.GetBackground().Colour)
    

    in the init method of the MainFrame class. It works but it is unsatisfactory because the panel colour is no longer that defined by the theme (in my case (225, 225, 225) instead of (212, 212, 212)).

    This might not seem significant, but

    1. it detracts from the unity of applications using the theme and that seems very untidy;
    2. the colour selected is outside my control. I wonder where this arbitrary colour comes from?
    3. The original works perfectly under Windows but not Ubuntu. So it means having OS dependent code.