最近玩 wxPython 3時覺得沒有透明元件覺得就用不下去了, 所以設計了些個簡單的透明元件.
TPanel
TStaticText
TButton
但是寫完之後, 發現還很多元件待寫...等有用到再寫了...囧
#-------------------------------------------------------------------------------
# Name: ExtComponent
# Purpose: simple transparent components for Python 2.7
#
# Author: nanoha
#
# Created: 01/01/3000
# Copyright: (c) nanoha 3000
# Licence: no licence
#-------------------------------------------------------------------------------
import wx
################################################################################
class TPanel(wx.Panel):
def __init__(self, parent, id=-1, image=None, pos=wx.DefaultPosition,
size=wx.DefaultSize, style=wx.TAB_TRAVERSAL, name="panel"):
style |= (wx.CLIP_CHILDREN | wx.TRANSPARENT_WINDOW)
wx.Panel.__init__(self, parent, id, pos, size, style, name)
self.SetBackedImage(image)
self.Bind(wx.EVT_PAINT,self.OnPaint)
self.Bind(wx.EVT_SIZE, self.OnSize)
# 設定背景圖片
def SetBackedImage(self, image=None):
if image is not None:
self.BackedImage = image
tmpImg = self.BackedImage.Copy()
W, H = self.GetClientSize()
tmpImg.Rescale(W, H)
self.BackedBmp = tmpImg.ConvertToBitmap()
else:
self.BackedBmp = None
self.BackedImage = None
self.Refresh()
def OnPaint(self,event):
event.Skip()
(width, height) = self.GetClientSizeTuple()
dc = wx.PaintDC(self)
self.DrawBackedImage(dc, width, height)
def DrawBackedImage(self, dc, width, height):
# 建立繪圖緩衝區
bmp = wx.EmptyBitmap(width, height)
memDC = wx.MemoryDC()
memDC.SelectObject(bmp)
# 塗滿透明色
memDC.SetPen(wx.Pen('#010101'))
memDC.SetBrush(wx.Brush('#010101'))
memDC.DrawRectangle(0, 0, width, height)
# 加入父窗口背景
Parent = self.GetParent()
if Parent:
# 加入父窗口背景色
ParentClr = Parent.GetBackgroundColour()
memDC.SetPen(wx.Pen(ParentClr))
memDC.SetBrush(wx.Brush(ParentClr))
memDC.DrawRectangle(0, 0, width, height)
# 加入父窗口背景圖
if hasattr(Parent, 'BackedBmp'):
if Parent.BackedBmp:
# get position
scr_x,scr_y = self.GetScreenPositionTuple()
x,y = Parent.ScreenToClientXY(scr_x,scr_y)
pbmp_W = Parent.BackedBmp.GetWidth()
pbmp_H = Parent.BackedBmp.GetHeight()
w1 = pbmp_W-x
if width < w1:
w1 = width
h1 = pbmp_H-y
if height < h1:
h1 = height
if w1>0 and h1>0:
pbackDC = wx.MemoryDC(Parent.BackedBmp)
memDC.Blit(0, 0, w1, h1, pbackDC, x, y)
pbackDC.SelectObject(wx.NullBitmap)
# 加入自帶背景
if self.BackedBmp:
bmp_W = self.BackedBmp.GetWidth()
bmp_H = self.BackedBmp.GetHeight()
backDC = wx.MemoryDC(self.BackedBmp)
memDC.Blit(0, 0, bmp_W, bmp_H, backDC, 0, 0)
backDC.SelectObject(wx.NullBitmap)
memDC.SelectObject(wx.NullBitmap)
# 設定透明色
mask = wx.Mask(bmp, wx.Colour(1,1,1))
bmp.SetMask(mask)
# 畫下去
dc.DrawBitmap(bmp, 0, 0, True)
# 將背景圖填滿 panel
def OnSize(self,event):
if self.BackedImage is None:
return
W, H = self.GetClientSize()
if W == 0 or H == 0:
return
bmp_W = self.BackedBmp.GetWidth()
bmp_H = self.BackedBmp.GetHeight()
if W != bmp_W or H != bmp_H:
tmpImg = self.BackedImage.Copy()
tmpImg.Rescale(W, H)
self.BackedBmp = tmpImg.ConvertToBitmap()
self.Refresh()
################################################################################
TST_TEXT_LEFT = 0
TST_TEXT_CENTER = 1
TST_TEXT_RIGHT = 2
class TStaticText(wx.StaticText):
def __init__(self,parent,id,label='',
pos=wx.DefaultPosition,
size=wx.DefaultSize,
style=0,
labelpos=TST_TEXT_LEFT,
name = 'TPStaticText'):
style |= wx.TRANSPARENT_WINDOW
wx.StaticText.__init__(self,parent,id,label,pos,size,style=style)
self.labelpos=labelpos
self.Bind(wx.EVT_PAINT,self.OnPaint)
def OnPaint(self,event):
event.Skip()
(width, height) = self.GetClientSizeTuple()
# 建立繪圖緩衝區
bmp = wx.EmptyBitmap(width, height)
memDC = wx.MemoryDC()
memDC.SelectObject(bmp)
# 塗滿透明色
memDC.SetPen(wx.Pen('#010101'))
memDC.SetBrush(wx.Brush('#010101'))
memDC.DrawRectangle(0, 0, width, height)
# 加入父窗口背景
Parent = self.GetParent()
if Parent:
# 加入父窗口背景色
ParentClr = Parent.GetBackgroundColour()
memDC.SetPen(wx.Pen(ParentClr))
memDC.SetBrush(wx.Brush(ParentClr))
memDC.DrawRectangle(0, 0, width, height)
# 加入父窗口背景圖
if hasattr(Parent, 'BackedBmp'):
if Parent.BackedBmp:
# get position
scr_x,scr_y = self.GetScreenPositionTuple()
x,y = Parent.ScreenToClientXY(scr_x,scr_y)
pbmp_W = Parent.BackedBmp.GetWidth()
pbmp_H = Parent.BackedBmp.GetHeight()
w1 = pbmp_W-x
if width < w1:
w1 = width
h1 = pbmp_H-y
if height < h1:
h1 = height
if w1>0 and h1>0:
pbackDC = wx.MemoryDC(Parent.BackedBmp)
memDC.Blit(0, 0, w1, h1, pbackDC, x, y)
pbackDC.SelectObject(wx.NullBitmap)
# 加入文字
textXpos = textYpos = 0
textWidth, textHeight = self.GetTextExtent(self.GetLabel())
textYpos = (height-textHeight)/2
if self.labelpos == TST_TEXT_CENTER:
textXpos = (width-textWidth)/2
elif self.labelpos == TST_TEXT_RIGHT:
textXpos = width-textWidth
memDC.SetFont(self.GetFont())
#if self.IsEnabled():
memDC.SetTextForeground(self.GetForegroundColour())
#else:
# memDC.SetTextForeground(wx.SystemSettings.GetColour(wx.SYS_COLOUR_GRAYTEXT))
memDC.DrawText(self.GetLabel(), textXpos, textYpos)
memDC.SelectObject(wx.NullBitmap)
# 設定透明色
mask = wx.Mask(bmp, wx.Colour(1,1,1))
bmp.SetMask(mask)
# 畫下去
dc = wx.PaintDC(self)
dc.DrawBitmap(bmp, 0, 0, True)
################################################################################
class TButtonEvent(wx.PyCommandEvent):
def __init__(self, eventType, id):
wx.PyCommandEvent.__init__(self, eventType, id)
self.isDown = False
self.theButton = None
def SetIsDown(self, isDown):
self.isDown = isDown
def GetIsDown(self):
return self.isDown
def SetButtonObj(self, btn):
self.theButton = btn
def GetButtonObj(self):
return self.theButton
################################################################################
TBB_IMAGE_CENTER = 0
TBB_IMAGE_LEFT = 1
TBB_IMAGE_RIGHT = 2
TBB_IMAGE_TOP = 3
TBB_IMAGE_BOTTOM = 4
TBB_LABEL_CENTER = 0
TBB_LABEL_LEFT = 1
TBB_LABEL_RIGHT = 2
TBB_LABEL_TOP = 3
TBB_LABEL_BOTTOM = 4
class TBitmapButton(wx.PyControl):
def __init__(self, parent=None, id=-1, image=None, label='',
pos = wx.DefaultPosition, size = wx.DefaultSize,
style=0, imagepos = TBB_IMAGE_CENTER,
labelpos = TBB_LABEL_CENTER,
validator = wx.DefaultValidator,
name = "Nanohabutton"):
cstyle = style# | wx.BORDER_NONE
wx.PyControl.__init__(self, parent, id, pos, size, cstyle, validator, name)
self.up = True
self.hasFocus = False
self.style = cstyle
if cstyle & wx.BORDER_NONE:
self.bezelWidth = 0
self.useFocusInd = False
else:
self.bezelWidth = 2
self.useFocusInd = True
self.ImagePos = imagepos
self.LabelPos = labelpos
self.BackedBmp = None
if image is not None:
self.BackedBmp = image.ConvertToBitmap()
self.MaskClr = wx.Colour(1,1,1)
self.SetLabel(label)
self.InheritAttributes()
self.SetInitialSize(size)
self.InitColours()
self.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown)
self.Bind(wx.EVT_LEFT_UP, self.OnLeftUp)
self.Bind(wx.EVT_LEFT_DCLICK, self.OnLeftDown)
self.Bind(wx.EVT_MOTION, self.OnMotion)
self.Bind(wx.EVT_SET_FOCUS, self.OnGainFocus)
self.Bind(wx.EVT_KILL_FOCUS, self.OnLoseFocus)
self.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown)
self.Bind(wx.EVT_KEY_UP, self.OnKeyUp)
self.Bind(wx.EVT_PAINT, self.OnPaint)
self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackgound)
self.Bind(wx.EVT_SIZE, self.OnSize)
def SetInitialSize(self, size=None):
if size is None:
size = wx.DefaultSize
wx.PyControl.SetInitialSize(self, size)
SetBestSize = SetInitialSize
def DoGetBestSize(self):
w, h, useMin = self._GetLabelSize()
if self.style & wx.BU_EXACTFIT:
width = w + 2 + 2 * self.bezelWidth + 4 * int(self.useFocusInd)
height = h + 2 + 2 * self.bezelWidth + 4 * int(self.useFocusInd)
else:
defSize = wx.Button.GetDefaultSize()
width = 12 + w
if useMin and width < defSize.width:
width = defSize.width
height = 11 + h
if useMin and height < defSize.height:
height = defSize.height
width = width + self.bezelWidth - 1
height = height + self.bezelWidth - 1
return (width, height)
def AcceptsFocus(self):
return self.IsShown() and self.IsEnabled()
def GetDefaultAttributes(self):
return wx.Button.GetClassDefaultAttributes()
def ShouldInheritColours(self):
return False
def Enable(self, enable=True):
if enable != self.IsEnabled():
wx.PyControl.Enable(self, enable)
self.Refresh()
def SetBezelWidth(self, width):
self.bezelWidth = width
def GetBezelWidth(self):
return self.bezelWidth
def SetUseFocusIndicator(self, flag):
self.useFocusInd = flag
def GetUseFocusIndicator(self):
return self.useFocusInd
def InitColours(self):
faceClr = self.GetBackgroundColour()
r, g, b = faceClr.Get()
fr, fg, fb = min(255,r+32), min(255,g+32), min(255,b+32)
self.faceDnClr = wx.Colour(fr, fg, fb)
sr, sg, sb = max(0,r-32), max(0,g-32), max(0,b-32)
self.shadowPenClr = wx.Colour(sr,sg,sb)
hr, hg, hb = min(255,r+64), min(255,g+64), min(255,b+64)
self.highlightPenClr = wx.Colour(hr,hg,hb)
self.focusClr = wx.Colour(hr, hg, hb)
def SetBackgroundColour(self, colour):
wx.PyControl.SetBackgroundColour(self, colour)
self.InitColours()
def SetForegroundColour(self, colour):
wx.PyControl.SetForegroundColour(self, colour)
self.InitColours()
def SetDefault(self):
tlw = wx.GetTopLevelParent(self)
if hasattr(tlw, 'SetDefaultItem'):
tlw.SetDefaultItem(self)
def _GetLabelSize(self):
w, h = self.GetTextExtent(self.GetLabel())
if not self.BackedBmp:
return w, h, True
w_bmp = self.BackedBmp.GetWidth() + 2
h_bmp = self.BackedBmp.GetHeight() + 2
height = h + h_bmp + 12
if w_bmp > w:
width = w_bmp
else:
width = w
return width, height, True
def Notify(self):
evt = ExtButtonEvent(wx.wxEVT_COMMAND_BUTTON_CLICKED, self.GetId())
evt.SetIsDown(not self.up)
evt.SetButtonObj(self)
evt.SetEventObject(self)
self.GetEventHandler().ProcessEvent(evt)
def DrawBezel(self, dc, x1, y1, x2, y2):
# draw the upper left sides
if self.up:
dc.SetPen(wx.Pen(self.highlightPenClr, 1, wx.SOLID))
else:
dc.SetPen(wx.Pen(self.shadowPenClr, 1, wx.SOLID))
for i in range(self.bezelWidth):
dc.DrawLine(x1+i, y1, x1+i, y2-i)
dc.DrawLine(x1, y1+i, x2-i, y1+i)
# draw the lower right sides
if self.up:
dc.SetPen(wx.Pen(self.shadowPenClr, 1, wx.SOLID))
else:
dc.SetPen(wx.Pen(self.highlightPenClr, 1, wx.SOLID))
for i in range(self.bezelWidth):
dc.DrawLine(x1+i, y2-i, x2+1, y2-i)
dc.DrawLine(x2-i, y1+i, x2-i, y2)
def DrawBackedImage(self, dc, width, height, dx=0, dy=0):
x1 = y1 = 0
# 建立繪圖緩衝區
bmp = wx.EmptyBitmap(width, height)
memDC = wx.MemoryDC()
memDC.SelectObject(bmp)
# 塗滿透明色
memDC.SetPen(wx.Pen(self.MaskClr))
memDC.SetBrush(wx.Brush(self.MaskClr))
memDC.DrawRectangle(0, 0, width, height)
# 加入父窗口背景
Parent = self.GetParent()
if Parent:
# 加入父窗口背景色
ParentClr = Parent.GetBackgroundColour()
memDC.SetPen(wx.Pen(ParentClr))
memDC.SetBrush(wx.Brush(ParentClr))
memDC.DrawRectangle(0, 0, width, height)
# 加入父窗口背景圖
if hasattr(Parent, 'BackedBmp'):
if Parent.BackedBmp:
# get position
scr_x,scr_y = self.GetScreenPositionTuple()
x,y = Parent.ScreenToClientXY(scr_x,scr_y)
pbmp_W = Parent.BackedBmp.GetWidth()
pbmp_H = Parent.BackedBmp.GetHeight()
w1 = pbmp_W-x
if width < w1:
w1 = width
h1 = pbmp_H-y
if height < h1:
h1 = height
if w1>0 and h1>0:
pbackDC = wx.MemoryDC(Parent.BackedBmp)
memDC.Blit(0, 0, w1, h1, pbackDC, x, y)
pbackDC.SelectObject(wx.NullBitmap)
# 加入自帶背景
if self.BackedBmp:
bmp_W = self.BackedBmp.GetWidth()
bmp_H = self.BackedBmp.GetHeight()
backDC = wx.MemoryDC(self.BackedBmp)
# 背景位置
if TBB_IMAGE_LEFT == self.ImagePos:
x1 = dx
y1 = (height-bmp_H)/2+dy
elif TBB_IMAGE_RIGHT == self.ImagePos:
x1 = width-bmp_W+dx
y1 = (height-bmp_H)/2+dy
elif TBB_IMAGE_TOP == self.ImagePos:
x1 = (width-bmp_W)/2+dx
y1 = dy
elif TBB_IMAGE_BOTTOM == self.ImagePos:
x1 = (width-bmp_W)/2+dx
y1 = height-bmp_H+dy
else:
x1 = (width-bmp_W)/2+dx
y1 = (height-bmp_H)/2+dy
memDC.Blit(x1, y1, bmp_W, bmp_H, backDC, 0, 0)
backDC.SelectObject(wx.NullBitmap)
self.DrawBackedImage2(memDC, dx, dy)
# 邊框
x1 = y1 = 0
x2 = width-1
y2 = height-1
self.DrawBezel(memDC, x1, y1, x2, y2)
# 加入文字
memDC.SetFont(self.GetFont())
if self.IsEnabled():
memDC.SetTextForeground(self.GetForegroundColour())
else:
memDC.SetTextForeground(wx.SystemSettings.GetColour(wx.SYS_COLOUR_GRAYTEXT))
label = self.GetLabel()
tw, th = memDC.GetTextExtent(label)
# 文字位置
if TBB_LABEL_LEFT == self.LabelPos:
x1 = dx
y1 = (height-th)/2+dy
elif TBB_LABEL_RIGHT == self.LabelPos:
x1 = width-tw+dx
y1 = (height-th)/2+dy
elif TBB_LABEL_TOP == self.LabelPos:
x1 = (width-tw)/2+dx
y1 = dy
elif TBB_LABEL_BOTTOM == self.LabelPos:
x1 = (width-tw)/2+dx
y1 = height-th+dy
else:
x1 = (width-tw)/2+dx
y1 = (height-th)/2+dy
memDC.DrawText(label, x1, y1)
# 加入Focus效果
if self.hasFocus and self.useFocusInd:
self.DrawFocusIndicator(memDC, width, height)
memDC.SelectObject(wx.NullBitmap)
# 設定透明色
mask = wx.Mask(bmp, self.MaskClr)
bmp.SetMask(mask)
# 畫下去
hasMask = bmp.GetMask() is not None
dc.DrawBitmap(bmp, 0, 0, hasMask)
def DrawBackedImage2(self, dc, dx=0, dy=0):
pass
def DrawFocusIndicator(self, dc, w, h):
bw = self.bezelWidth
textClr = self.GetForegroundColour()
focusIndPen = wx.Pen(textClr, 1, wx.USER_DASH)
focusIndPen.SetDashes([1,1])
focusIndPen.SetCap(wx.CAP_BUTT)
if wx.Platform == "__WXMAC__":
dc.SetLogicalFunction(wx.XOR)
else:
focusIndPen.SetColour(self.focusClr)
dc.SetLogicalFunction(wx.INVERT)
dc.SetPen(focusIndPen)
dc.SetBrush(wx.TRANSPARENT_BRUSH)
dc.DrawRectangle(bw+2,bw+2, w-bw*2-4, h-bw*2-4)
dc.SetLogicalFunction(wx.COPY)
def OnPaint(self, event):
(width, height) = self.GetClientSizeTuple()
dx = dy = 0
if not self.up:
dx = dy = 1
dc = wx.PaintDC(self)
#dc.SetBackground(wx.TRANSPARENT_BRUSH)
#dc.Clear()
self.DrawBackedImage(dc, width, height, dx, dy)
def OnSize(self, event):
self.Refresh()
event.Skip()
def OnEraseBackgound(self, event):
pass
def OnLeftDown(self, event):
if not self.IsEnabled():
return
self.up = False
self.CaptureMouse()
self.SetFocus()
self.Refresh()
event.Skip()
def OnLeftUp(self, event):
if not self.IsEnabled() or not self.HasCapture():
return
if self.HasCapture():
self.ReleaseMouse()
if not self.up: # if the button was down when the mouse was released...
self.Notify()
self.up = True
if self: # in case the button was destroyed in the eventhandler
self.Refresh()
event.Skip()
def OnMotion(self, event):
if not self.IsEnabled() or not self.HasCapture():
return
if event.LeftIsDown() and self.HasCapture():
x,y = event.GetPositionTuple()
w,h = self.GetClientSizeTuple()
if self.up and x<w and x>=0 and y<h and y>=0:
self.up = False
self.Refresh()
return
if not self.up and (x<0 or y<0 or x>=w or y>=h):
self.up = True
self.Refresh()
return
event.Skip()
def OnGainFocus(self, event):
self.hasFocus = True
self.Refresh()
self.Update()
def OnLoseFocus(self, event):
self.hasFocus = False
self.Refresh()
self.Update()
def OnKeyDown(self, event):
if self.hasFocus and event.GetKeyCode() == ord(" "):
self.up = False
self.Refresh()
event.Skip()
def OnKeyUp(self, event):
if self.hasFocus and event.GetKeyCode() == ord(" "):
self.up = True
self.Notify()
self.Refresh()
event.Skip()
################################################################################
沒有留言:
張貼留言