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.