Fixed transparency issues in Windows by using a GraphicsContext. Changed background to white.

- The white background is a workaround for not being able to set the
exact color of gray for the XY/Z widgets.
master
Duane Johnson 2011-11-08 09:37:35 -06:00
parent 39a99314b3
commit 50d340f900
5 changed files with 44 additions and 74 deletions

View File

@ -1,6 +1,6 @@
""" """
BufferedCanvas -- Double-buffered, flicker-free canvas widget BufferedCanvas -- flicker-free canvas widget
Copyright (C) 2005, 2006 Daniel Keep Copyright (C) 2005, 2006 Daniel Keep, 2011 Duane Johnson
To use this widget, just override or replace the draw method. To use this widget, just override or replace the draw method.
This will be called whenever the widget size changes, or when This will be called whenever the widget size changes, or when
@ -46,16 +46,12 @@ import wx
class BufferedCanvas(wx.Panel): class BufferedCanvas(wx.Panel):
""" """
Implements a double-buffered, flicker-free canvas widget. Implements a flicker-free canvas widget.
Standard usage is to subclass this class, and override the Standard usage is to subclass this class, and override the
draw method. The draw method is passed a device context, which draw method. The draw method is passed a device context, which
should be used to do your drawing. should be used to do your drawing.
Also, you should NOT call dc.BeginDrawing() and dc.EndDrawing() --
these methods are automatically called for you, although you still
need to manually clear the device context.
If you want to force a redraw (for whatever reason), you should If you want to force a redraw (for whatever reason), you should
call the update method. This is because the draw method is never call the update method. This is because the draw method is never
called as a result of an EVT_PAINT event. called as a result of an EVT_PAINT event.
@ -77,16 +73,12 @@ class BufferedCanvas(wx.Panel):
# Bind events # Bind events
self.Bind(wx.EVT_PAINT, self.onPaint) self.Bind(wx.EVT_PAINT, self.onPaint)
self.Bind(wx.EVT_SIZE, self.onSize)
# Disable background erasing (flicker-licious) # Disable background erasing (flicker-licious)
def disable_event(*pargs,**kwargs): def disable_event(*pargs,**kwargs):
pass # the sauce, please pass # the sauce, please
self.Bind(wx.EVT_ERASE_BACKGROUND, disable_event) self.Bind(wx.EVT_ERASE_BACKGROUND, disable_event)
# Ensure that the buffers are setup correctly
self.onSize(None)
## ##
## General methods ## General methods
## ##
@ -97,27 +89,11 @@ class BufferedCanvas(wx.Panel):
""" """
pass pass
def flip(self):
"""
Flips the front and back buffers.
"""
self.buffer,self.backbuffer = self.backbuffer,self.buffer
self.Refresh()
def update(self): def update(self):
""" """
Causes the canvas to be updated. Causes the canvas to be updated.
""" """
dc = wx.MemoryDC() self.Refresh()
width,height = self.getWidthHeight()
self.backbuffer = wx.EmptyBitmapRGBA(width,height,alpha=0)
dc.SelectObject(self.backbuffer)
dc.BeginDrawing()
self.draw(dc)
dc.EndDrawing()
self.flip()
def getWidthHeight(self): def getWidthHeight(self):
width,height = self.GetClientSizeTuple() width,height = self.GetClientSizeTuple()
@ -133,15 +109,9 @@ class BufferedCanvas(wx.Panel):
def onPaint(self, event): def onPaint(self, event):
# Blit the front buffer to the screen # Blit the front buffer to the screen
dc = wx.BufferedPaintDC(self, self.buffer) w, h = self.GetClientSizeTuple()
if not w or not h:
return
def onSize(self, event): else:
# Here we need to create a new off-screen buffer to hold dc = wx.BufferedPaintDC(self)
# the in-progress drawings on. self.draw(dc, w, h)
w, h = self.getWidthHeight()
self.buffer = wx.EmptyBitmapRGBA(w, h, alpha=0)
self.backbuffer = wx.EmptyBitmapRGBA(w, h, alpha=0)
# Now update the screen
self.update()

View File

@ -120,6 +120,7 @@ class PronterWindow(wx.Frame,pronsole.pronsole):
self.starttime=0 self.starttime=0
self.curlayer=0 self.curlayer=0
self.cur_button=None self.cur_button=None
self.SetBackgroundColour("white")
def startcb(self): def startcb(self):
self.starttime=time.time() self.starttime=time.time()

View File

@ -14,6 +14,7 @@ class MyFrame(wx.Frame):
sizer.Add(self.z, flag=wx.ALIGN_CENTER) sizer.Add(self.z, flag=wx.ALIGN_CENTER)
self.SetSizer(sizer) self.SetSizer(sizer)
self.SetBackgroundColour("white")
def moveXY(self, x, y): def moveXY(self, x, y):
print "got x", x, 'y', y print "got x", x, 'y', y

View File

@ -13,7 +13,7 @@ class XYButtons(BufferedCanvas):
keypad_positions = { keypad_positions = {
0: (126, 126), 0: (126, 126),
1: (100, 100), 1: (100, 100),
2: (78, 78), 2: (80, 80),
3: (60, 60) 3: (60, 60)
} }
concentric_circle_radii = [15, 55, 86, 117, 142] concentric_circle_radii = [15, 55, 86, 117, 142]
@ -101,7 +101,7 @@ class XYButtons(BufferedCanvas):
def mouseOverKeypad(self, mpos): def mouseOverKeypad(self, mpos):
for idx, kpos in XYButtons.keypad_positions.items(): for idx, kpos in XYButtons.keypad_positions.items():
rect = wx.Rect(kpos[0], kpos[1], 44, 32) rect = wx.Rect(kpos[0], kpos[1], self.keypad_bmp.GetWidth(), self.keypad_bmp.GetHeight())
if rect.Contains(mpos): if rect.Contains(mpos):
return idx return idx
return None return None
@ -144,28 +144,19 @@ class XYButtons(BufferedCanvas):
self.concentric = None self.concentric = None
self.update() self.update()
def drawPartialPie(self, dc, center, r1, r2, angle1, angle2): def drawPartialPie(self, gc, center, r1, r2, angle1, angle2):
parts = 64 parts = 64
angle_dist = angle2 - angle1 angle_dist = angle2 - angle1
angle_inc = angle_dist / parts angle_inc = angle_dist / parts
p1 = wx.Point(center.x + r1*math.cos(angle1), center.y + r1*math.sin(angle1)) p1 = wx.Point(center.x + r1*math.cos(angle1), center.y + r1*math.sin(angle1))
p2 = wx.Point(center.x + r2*math.cos(angle1), center.y + r2*math.sin(angle1))
p3 = wx.Point(center.x + r2*math.cos(angle2), center.y + r2*math.sin(angle2))
p4 = wx.Point(center.x + r1*math.cos(angle2), center.y + r1*math.sin(angle2))
points = [p1, p2]
points.extend([wx.Point(
center.x + r1*math.cos(angle1+i*angle_inc),
center.y + r1*math.sin(angle1+i*angle_inc)) for i in range(0, parts)])
# points.extend([p3]) path = gc.CreatePath()
path.MoveToPoint(p1.x, p1.y)
points.extend([wx.Point( path.AddArc(center.x, center.y, r1, angle1, angle2, True)
center.x + r2*math.cos(angle1+i*angle_inc), path.AddArc(center.x, center.y, r2, angle2, angle1, False)
center.y + r2*math.sin(angle1+i*angle_inc)) for i in range(parts, 0, -1)]) path.AddLineToPoint(p1.x, p1.y)
dc.DrawPolygon(points) gc.DrawPath(path)
def distanceToLine(self, pos, x1, y1, x2, y2): def distanceToLine(self, pos, x1, y1, x2, y2):
xlen = x2 - x1 xlen = x2 - x1
@ -174,7 +165,7 @@ class XYButtons(BufferedCanvas):
pylen = y1 - pos.y pylen = y1 - pos.y
return abs(xlen*pylen-ylen*pxlen)/math.sqrt(xlen**2+ylen**2) return abs(xlen*pylen-ylen*pxlen)/math.sqrt(xlen**2+ylen**2)
def highlightQuadrant(self, dc, quadrant, concentric): def highlightQuadrant(self, gc, quadrant, concentric):
assert(quadrant >= 0 and quadrant <= 3) assert(quadrant >= 0 and quadrant <= 3)
assert(concentric >= 0 and concentric <= 3) assert(concentric >= 0 and concentric <= 3)
@ -197,21 +188,24 @@ class XYButtons(BufferedCanvas):
r1 = XYButtons.concentric_circle_radii[concentric] r1 = XYButtons.concentric_circle_radii[concentric]
r2 = XYButtons.concentric_circle_radii[concentric+1] r2 = XYButtons.concentric_circle_radii[concentric+1]
self.drawPartialPie(dc, center, r1-inner_ring_radius, r2-inner_ring_radius, a1+fudge, a2-fudge)
def draw(self, dc): self.drawPartialPie(gc, center, r1-inner_ring_radius, r2-inner_ring_radius, a1+fudge, a2-fudge)
def draw(self, dc, w, h):
dc.Clear()
gc = wx.GraphicsContext.Create(dc)
center = wx.Point(XYButtons.center[0], XYButtons.center[1]) center = wx.Point(XYButtons.center[0], XYButtons.center[1])
dc.SetPen(wx.Pen(wx.Colour(100,100,100,172), 4)) gc.DrawBitmap(self.bg_bmp, 0, 0, self.bg_bmp.GetWidth(), self.bg_bmp.GetHeight())
dc.SetBrush(wx.Brush(wx.Colour(0,0,0,128)))
dc.DrawBitmap(self.bg_bmp, 0, 0)
if self.quadrant != None and self.concentric != None: if self.quadrant != None and self.concentric != None:
self.highlightQuadrant(dc, self.quadrant, self.concentric) gc.SetPen(wx.Pen(wx.Colour(100,100,100,172), 4))
gc.SetBrush(wx.Brush(wx.Colour(0,0,0,128)))
self.highlightQuadrant(gc, self.quadrant, self.concentric)
if self.keypad_idx >= 0: if self.keypad_idx >= 0:
pos = XYButtons.keypad_positions[self.keypad_idx] pos = XYButtons.keypad_positions[self.keypad_idx]
dc.DrawBitmap(self.keypad_bmp, pos[0], pos[1]) gc.DrawBitmap(self.keypad_bmp, pos[0], pos[1], self.keypad_bmp.GetWidth(), self.keypad_bmp.GetHeight())
return True return True

View File

@ -38,7 +38,7 @@ class ZButtons(BufferedCanvas):
idx += 1 idx += 1
return None return None
def highlight(self, dc, rng, dir): def highlight(self, gc, rng, dir):
assert(rng >= -1 and rng <= 3) assert(rng >= -1 and rng <= 3)
assert(dir >= -1 and dir <= 1) assert(dir >= -1 and dir <= 1)
@ -49,7 +49,8 @@ class ZButtons(BufferedCanvas):
k = 1 if dir > 0 else 0 k = 1 if dir > 0 else 0
y = ZButtons.center[1] - (dir * ZButtons.button_ydistances[rng+k]) y = ZButtons.center[1] - (dir * ZButtons.button_ydistances[rng+k])
h = ZButtons.button_ydistances[rng+1] - ZButtons.button_ydistances[rng] h = ZButtons.button_ydistances[rng+1] - ZButtons.button_ydistances[rng]
dc.DrawRectangle(x, y, w, h) gc.DrawRoundedRectangle(x, y, w, h, 4)
# gc.DrawRectangle(x, y, w, h)
# self.drawPartialPie(dc, center, r1-inner_ring_radius, r2-inner_ring_radius, a1+fudge, a2-fudge) # self.drawPartialPie(dc, center, r1-inner_ring_radius, r2-inner_ring_radius, a1+fudge, a2-fudge)
def getRangeDir(self, pos): def getRangeDir(self, pos):
@ -78,13 +79,16 @@ class ZButtons(BufferedCanvas):
self.direction = None self.direction = None
self.update() self.update()
def draw(self, dc): def draw(self, dc, w, h):
dc.SetPen(wx.Pen(wx.Colour(100,100,100,172), 4)) dc.Clear()
dc.SetBrush(wx.Brush(wx.Colour(0,0,0,128))) gc = wx.GraphicsContext.Create(dc)
dc.DrawBitmap(self.bg_bmp, 0, 0) gc.SetPen(wx.Pen(wx.Colour(100,100,100,172), 4))
gc.SetBrush(wx.Brush(wx.Colour(0,0,0,128)))
gc.DrawBitmap(self.bg_bmp, 0, 0, self.bg_bmp.GetWidth(), self.bg_bmp.GetHeight())
if self.range != None and self.direction != None: if self.range != None and self.direction != None:
self.highlight(dc, self.range, self.direction) self.highlight(gc, self.range, self.direction)
return True return True