It is not very good idea to draw stuff outside MainLoop. You should setup your wx application so it is Event driven. The events EVT_PAINT and EVT_SIZE should be handled. The wx.Timer
can be used for basic movement.
import wx
#=============================================================================
class DrawPanelDB(wx.Panel):
def __init__(self, *args, **kwargs):
wx.Panel.__init__(self, *args, **kwargs)
self.ballPosition = [20, 20]
self.ballDelta = [1, 1]
self.timer = wx.Timer(self)
self.Bind(wx.EVT_TIMER, self.OnTime, self.timer)
self.timer.Start(20)
self.Bind(wx.EVT_PAINT, self.OnPaint)
self.Bind(wx.EVT_SIZE, self.OnSize)
self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground)
#-------------------------------------------------------------------------
def OnPaint(self, event):
dc = wx.BufferedPaintDC(self)
dc.SetBackground(wx.Brush(wx.BLACK))
dc.Clear()
dc.DrawCirclePoint(self.ballPosition, 20)
#-------------------------------------------------------------------------
def OnSize(self, event):
self.Refresh()
self.Update()
#-------------------------------------------------------------------------
def OnEraseBackground(self, event):
pass # Or None
#-------------------------------------------------------------------------
def OnTime(self, event):
self.ballPosition[0] += self.ballDelta[0]
self.ballPosition[1] += self.ballDelta[1]
w, h = self.GetClientSizeTuple()
if self.ballPosition[0] > w:
self.ballPosition[0] = w
self.ballDelta[0] *= -1
if self.ballPosition[1] > h:
self.ballPosition[1] = h
self.ballDelta[1] *= -1
if self.ballPosition[0] < 0:
self.ballPosition[0] = 0
self.ballDelta[0] *= -1
if self.ballPosition[1] < 0:
self.ballPosition[1] = 0
self.ballDelta[1] *= -1
self.Refresh()
#=============================================================================
class MainWindow(wx.Frame):
def __init__(self, *args, **kwargs):
wx.Frame.__init__(self, *args, **kwargs)
self.panel = DrawPanelDB(self)
self.Show()
#=============================================================================
app = wx.App(False)
win = MainWindow(None)
app.MainLoop()
Edit: Example with ScreenDC using xor function for non-destructible drawing.
import wx
#=============================================================================
class MainWindow(wx.Frame):
def __init__(self, *args, **kwargs):
wx.Frame.__init__(self, *args, **kwargs)
self.ballPosition = [20, 20]
self.lastPosition = None
self.ballDelta = [1, 1]
self.timer = wx.Timer(self)
self.Bind(wx.EVT_TIMER, self.OnTime, self.timer)
self.timer.Start(20)
#-------------------------------------------------------------------------
def OnTime(self, event):
self.ballPosition[0] += self.ballDelta[0]
self.ballPosition[1] += self.ballDelta[1]
w, h = wx.DisplaySize()
if self.ballPosition[0] > w:
self.ballPosition[0] = w
self.ballDelta[0] *= -1
if self.ballPosition[1] > h:
self.ballPosition[1] = h
self.ballDelta[1] *= -1
if self.ballPosition[0] < 0:
self.ballPosition[0] = 0
self.ballDelta[0] *= -1
if self.ballPosition[1] < 0:
self.ballPosition[1] = 0
self.ballDelta[1] *= -1
dc = wx.ScreenDC()
dc.StartDrawingOnTop()
dc.SetLogicalFunction(wx.XOR)
if self.lastPosition is not None:
dc.DrawRectangle(self.lastPosition[0], self.lastPosition[1], 15, 15)
self.lastPosition = (self.ballPosition[0], self.ballPosition[1])
dc.DrawRectangle(self.ballPosition[0], self.ballPosition[1], 15, 15)
dc.EndDrawingOnTop()
#=============================================================================
app = wx.App(False)
win = MainWindow(None)
app.MainLoop()
Edit: Another possibility is to keep backup copy of that part of the screen.
import wx
#=============================================================================
class MainWindow(wx.Frame):
def __init__(self, *args, **kwargs):
wx.Frame.__init__(self, *args, **kwargs)
self.ballPosition = [20, 20]
self.lastPosition = None
self.ballDelta = [1, 1]
self.patch = wx.EmptyBitmap(20, 20)
self.timer = wx.Timer(self)
self.Bind(wx.EVT_TIMER, self.OnTime, self.timer)
self.timer.Start(20)
#-------------------------------------------------------------------------
def OnTime(self, event):
self.ballPosition[0] += self.ballDelta[0]
self.ballPosition[1] += self.ballDelta[1]
w, h = wx.DisplaySize()
if self.ballPosition[0] > w:
self.ballPosition[0] = w
self.ballDelta[0] *= -1
if self.ballPosition[1] > h:
self.ballPosition[1] = h
self.ballDelta[1] *= -1
if self.ballPosition[0] < 0:
self.ballPosition[0] = 0
self.ballDelta[0] *= -1
if self.ballPosition[1] < 0:
self.ballPosition[1] = 0
self.ballDelta[1] *= -1
dc = wx.ScreenDC()
dc.StartDrawingOnTop()
bdc = wx.MemoryDC(self.patch)
if self.lastPosition is not None:
dc.Blit(self.lastPosition[0] - 2, self.lastPosition[1] - 2, 20, 20, bdc, 0, 0)
bdc.Blit(0, 0, 20, 20, dc, self.ballPosition[0] - 2, self.ballPosition[1] - 2)
self.lastPosition = (self.ballPosition[0], self.ballPosition[1])
dc.DrawRectangle(self.ballPosition[0], self.ballPosition[1], 15, 15)
dc.EndDrawingOnTop()
#=============================================================================
app = wx.App(False)
win = MainWindow(None)
app.MainLoop()