Hi. This is an issue on both GTK and Windows - the following code will create a new bitmap of th x/y positions of the mouse cursor. Drag the grey area of the window to resize the bitmap, and there is noticeable tearing/flickering.
#!/usr/bin/python
import os
import wx
CANVAS_BORDER = 15 # pixels in size
RIGHT = 1
DIAGONAL = 2
BOTTOM = 3
class GUI(wx.Frame):
def __init__(self, parent):
wx.Frame.__init__(self, parent, size=(1024, 786))
tabs = wx.Notebook(self)
tabs.AddPage(DrawingPanel(tabs), "Tab 1")
class DrawingPanel(wx.ScrolledWindow):
def __init__(self, tab): wx.ScrolledWindow.__init__(self, tab, style=wx.NO_FULL_REPAINT_ON_RESIZE | wx.CLIP_CHILDREN)
self.canvas_size = (1000, 1000)
self.area = (self.canvas_size[0] - 200, self.canvas_size[1] - 200)
self.SetVirtualSizeHints(2, 2)
self.SetVirtualSize(self.canvas_size)
self.SetScrollRate(1, 1)
self.SetBackgroundColour('Grey')
self.buffer = wx.EmptyBitmap(*self.area)
self.resizing = False
self.resize_direction = False
self.Bind(wx.EVT_ERASE_BACKGROUND, self.on_erase)
self.Bind(wx.EVT_LEFT_DOWN, self.left_down)
self.Bind(wx.EVT_LEFT_UP, self.left_up)
self.Bind(wx.EVT_MOTION, self.left_motion)
self.Bind(wx.EVT_PAINT, self.on_paint)
def convert_coords(self, event):
return self.CalcUnscrolledPosition(event.GetX(), event.GetY())
def left_down(self, event):
x, y = self.convert_coords(event)
if os.name == "nt":
self.CaptureMouse()
if self.check_canvas_resize(x, y): # start resizing
self.resizing = True
def left_motion(self, event):
x, y = self.convert_coords(event)
if self.resizing:
self.resize_canvas((x, y), self.resize_direction)
else:
direction = self.check_canvas_resize(x, y)
if direction:
if not self.resize_direction:
self.resize_direction = direction
if direction != self.resize_direction:
self.resize_direction = direction
def left_up(self, event):
if os.name == "nt":
self.ReleaseMouse()
if self.resizing:
self.resizing = False
def on_paint(self, event=None):
if os.name == "nt" and self.resizing:
dc = wx.ClientDC(self)
dc.SetBrush(wx.GREY_BRUSH)
dc.Clear()
wx.BufferedPaintDC(self, self.buffer, wx.BUFFER_VIRTUAL_AREA)
def on_erase(self, event=None):
event.Skip()
def check_canvas_resize(self, x, y):
if x > self.area[0] and y > self.area[1]:
return DIAGONAL
elif x > self.area[0]:
return RIGHT
elif y > self.area[1]:
return BOTTOM
return False
def resize_canvas(self, size, direction=None):
""" Resizes the canvas. Size = (w, h) tuple """
if size[0] < 1 or size[1] < 1:
return
if direction == RIGHT:
size = (size[0] + CANVAS_BORDER, self.area[1])
self.Scroll(size[0], -1)
elif direction == BOTTOM:
size = (self.area[0], size[1])
self.Scroll(-1, size[1] + CANVAS_BORDER)
else:
self.Scroll(*size)
self.buffer = wx.EmptyBitmap(*size)
self.area = size
size = (size[0] + CANVAS_BORDER, size[1] + CANVAS_BORDER)
self.SetVirtualSize(size)
self.Refresh() # I need to force a paint in this sample
# -----------------------------------------------------------
class TestApp(wx.App):
def OnInit(self):
frame = GUI(None)
frame.Show(True)
return True
if __name__ == '__main__':
app = TestApp(redirect=True)
app.MainLoop()
I also have an issue with Windows. Previously, I was using self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM) to prevent flickering. However, if I use that style, the background colour of grey is not applied.
So, if I keep the call to self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM), I can then draw the grey background myself in EVT_PAINT. Doing this works fine, until the window is minimised/another window dragged on top of it - then the background area isn't repainted. I've tried binding EVT_ERASE_BACKGROUND, and calling Skip(), and just NOP'ing the event, but neither work here.
Another approach I tried to combat flickering, was to remove the call to SetBackgroundStyle and Bind to EVT_ERASE_BACKGROUND. If I call event.skip() then, the window gets repainted properly when re-exposed. However, drawing flicker is brought in again. If I use pass instead of event.Skip, then the flicker is fixed, but the repainting issue comes back again!
I can't think of the correct mixture of these solutions!
resizing_canvas.py (3.67 KB)
···
--
Steven Sproat, BSc
http://www.basicrpg.com/