Introduction
Martijn wrote:
I was unable to create good native flat buttons on windows. If it is possible , I would love to know how.
This example subclasses some buttons in wx.lib.buttons to create native looking flat buttons on win32.
Eric O added: Try ThemedGenButton (as of wxPython 2.8.4.0)
from wx.lib.buttons import ThemedGenButton button = ThemedGenButton(self, id=-1, label="foo", style=wx.NO_BORDER)
(either wx.NO_BORDER or wx.BORDER_NONE... both appear to work, creating a native flat button. What I found not to work is wx.BU_EXACTFIT...)
What Objects are Involved
Subclassed from wx.lib.buttons:
New classes:
GenWinFlatButton
Process Overview
Emulates a win32 flat button
Default-state:border=0
hover:border=1
down:do not change colour
Special Concerns
Todo:
- Disabled buttons should be greyed out,not masked grey.
- Add Toggle buttons.
Code
import wx
from wx.lib.buttons import *
import wx.lib.colourdb
class _WinFlatMixin:
"""
Emulates a win32 flat button
Default-state:border=0
hover:border=1
down:do not change colour
"""
def __init__(self):
self.useFocusInd = False
self.bezelWidth = 0
self.Bind(wx.EVT_ENTER_WINDOW ,self.OnMouseEnter)
self.Bind(wx.EVT_LEAVE_WINDOW ,self.OnMouseLeave)
def OnMouseEnter(self,event):
self.bezelWidth = 1
self.Refresh()
def OnMouseLeave(self,event):
self.bezelWidth = 0
self.Refresh()
def OnPaint(self, event):
"""
copy&paste from GenButton with 1 minor change(colour on down)
"""
(width, height) = self.GetClientSizeTuple()
x1 = y1 = 0
x2 = width-1
y2 = height-1
dc = wx.BufferedPaintDC(self)
brush = None
if True: #was:if self.up
colBg = self.GetBackgroundColour()
brush = wx.Brush(colBg, wx.SOLID)
if self.style & wx.BORDER_NONE:
myAttr = self.GetDefaultAttributes()
parAttr = self.GetParent().GetDefaultAttributes()
myDef = colBg == myAttr.colBg
parDef = self.GetParent().GetBackgroundColour() == parAttr.colBg
if myDef and parDef:
if wx.Platform == "__WXMAC__":
brush.MacSetTheme(1) # 1 == kThemeBrushDialogBackgroundActive
elif wx.Platform == "__WXMSW__":
if self.DoEraseBackground(dc):
brush = None
elif myDef and not parDef:
colBg = self.GetParent().GetBackgroundColour()
brush = wx.Brush(colBg, wx.SOLID)
else:
brush = wx.Brush(self.faceDnClr, wx.SOLID)
if brush is not None:
dc.SetBackground(brush)
dc.Clear()
self.DrawBezel(dc, x1, y1, x2, y2)
self.DrawLabel(dc, width, height)
if self.hasFocus and self.useFocusInd:
self.DrawFocusIndicator(dc, width, height)
class GenWinFlatButton(_WinFlatMixin,GenButton):
def __init__(self,*arg,**kwarg):
GenButton.__init__(self,*arg,**kwarg)
_WinFlatMixin.__init__(self)
class GenWinFlatBitmapButton(_WinFlatMixin,GenBitmapButton):
def __init__(self,*arg,**kwarg):
GenBitmapButton.__init__(self,*arg,**kwarg)
_WinFlatMixin.__init__(self)
class GenWinFlatBitmapTextButton(_WinFlatMixin,GenBitmapTextButton):
def __init__(self,*arg,**kwarg):
GenBitmapTextButton.__init__(self,*arg,**kwarg)
_WinFlatMixin.__init__(self)
class MyFrame(wx.Panel):
def __init__(self, parent, ID):
wx.Panel.__init__(self, parent, ID, wx.DefaultPosition)
bmp = wx.ArtProvider.GetBitmap(wx.ART_HELP) #need an image..
self.btn1 = GenWinFlatButton(self, -1, "GenWinFlatButton", pos = (20,20), size=(-1, -1))
self.btn2 = GenWinFlatBitmapButton(self, -1, bmp,pos = (20,50))
self.btn3 = GenWinFlatBitmapTextButton(self, -1, bmp,"GenWinFlatBitmapTextButton"
,pos = (20,100),size=(200,40))
if __name__ == '__main__':
class MyApp(wx.App):
def OnInit(self):
wx.lib.colourdb.updateColourDB()
frame = wx.Frame(None, -1, "InteractiveButton", wx.DefaultPosition, wx.Size(300,300))
myframe = MyFrame(frame, -1)
frame.Centre()
frame.Show(True)
self.SetTopWindow(frame)
return True
app = MyApp(0)
app.MainLoop()
Comments
Catching of enter/leave was taken,learned from InteractiveButton.
