Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

I am trying to remove an image that has been placed at some random point on a panel. This solution works but it is dependent upon the colour scheme that I am using. Is there a better way of doing this?

import wx
from PIL import Image
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):
    """Create a panel class to contain screen widgets."""
    def __init__(self, frame):
        wx.Panel.__init__(self, frame)
        self.Bind(wx.EVT_PAINT, self._on_paint)
        cmd_refresh = wx.Button(self, wx.ID_REFRESH)
        cmd_refresh.Bind(wx.EVT_BUTTON, self._on_cmd_refresh_click)
        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.x_pos = random.randint(0, 100)
        self.y_pos = random.randint(0, 100)

    def _on_paint(self, event):
        bitmap = self._get_image()
        self._draw_image(bitmap)

    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):
        dc = wx.ClientDC(self)
        dc.DrawBitmap(bitmap, self.x_pos, self.y_pos, True)

    def _on_cmd_refresh_click(self, event):
        del event
        colour = (212, 212, 212)
        blank_image = Image.new('RGB', (self.image_width, self.image_height), colour)
        bitmap = wx.Bitmap.FromBuffer(self.image_width, self.image_height, blank_image.tobytes())
        self._draw_image(bitmap)


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

[EDIT 29 Dec 17: change wx.PaintDC to wx.ClientDC]

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
122 views
Welcome To Ask or Share your Answers For Others

1 Answer

You only need to Refresh your Panel without redrawing the bitmap. You will get your Panel background style in the place of the picture. This would work for your current code (fixed-size Panel) but not for a Frame that could be resized because this would produce and EVT_PAINT and you will have again your bitmap drawn. To solve this, you can use a flag to tell when you want a Refresh without bitmap.

Example of code could be:

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, 1, wx.EXPAND)     # I made the panel expandable sizable
        self.SetSizerAndFit(sizer)
        self.Centre()
        self.Show()

class MainPanel(wx.Panel):
    """Create a panel class to contain screen widgets."""
    def __init__(self, frame):
        wx.Panel.__init__(self, frame)
        self.Bind(wx.EVT_PAINT, self._on_paint)
        cmd_refresh = wx.Button(self, wx.ID_REFRESH)
        cmd_refresh.Bind(wx.EVT_BUTTON, self._on_cmd_refresh_click)
        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.x_pos = random.randint(0, 100)
        self.y_pos = random.randint(0, 100)
        self.refresh = False            # flag to control drawing of  bitmap

    def _on_paint(self, event):
        if self.refresh: return         # for a clean background, return
        bitmap = self._get_image()
        self._draw_image(bitmap)

    def _get_image(self):
        bitmap = wx.Bitmap()
        bitmap.LoadFile("mypng.PNG", wx.BITMAP_TYPE_ANY)
        return bitmap

    def _draw_image(self, bitmap):
        dc = wx.ClientDC(self)
        dc.DrawBitmap(bitmap, self.x_pos, self.y_pos, True)

    def _on_cmd_refresh_click(self, event):
        self.refresh = True        # forget the bitmap
        self.Refresh()             # and refresh the screen

Another option is to create a Bitmap of size 0 to replace the original one. Note that for this you have to decouple the _on_paint call from the reading of the bitmap. Otherwise you will re-read the original picture each time you resize your window:

class MainPanel(wx.Panel):
    """Create a panel class to contain screen widgets."""
    def __init__(self, frame):
        wx.Panel.__init__(self, frame)
        self.Bind(wx.EVT_PAINT, self._on_paint)
        cmd_refresh = wx.Button(self, wx.ID_REFRESH)
        cmd_refresh.Bind(wx.EVT_BUTTON, self._on_cmd_refresh_click)
        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.x_pos = random.randint(0, 100)
        self.y_pos = random.randint(0, 100)

        self._get_image()

    def _on_paint(self, event):
        self._draw_image()

    def _get_image(self):
        self.bitmap = wx.Bitmap()
        self.bitmap.LoadFile("mypng.PNG", wx.BITMAP_TYPE_ANY)

    def _draw_image(self):
        dc = wx.ClientDC(self)
        dc.DrawBitmap(self.bitmap, self.x_pos, self.y_pos, True)

    def _on_cmd_refresh_click(self, event):
        self.bitmap = wx.Bitmap(0,0)
        self._draw_image()
        self.Refresh()

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
...