Reputation: 93
I'm writing a wxPython app that needs to match the appearance of an existing Windows application. I'm trying to put Static Text and Button controls on a panel with a gradient background. Here are the ways I've found, but I can't help feeling that I'm missing something. How should I draw static text and custom controls and let the background show through?
msw.window.no-clip-children
to let the background show through?2 seems easiest but I wonder if it's turned off for a reason. Are there any performance implications to turning on the no-clip-children globally? Is there any way to turn it on just for the windows I want?
edit: Sample code and screnshots
Sorry if this is starting to look like an answer in a question. I want to know if there is a right way to do this.
#!/usr/bin/python
import wx
class GradientPanel(wx.Panel):
def __init__(self,*args,**kwargs):
wx.Panel.__init__(self,*args,**kwargs)
self.Bind(wx.EVT_PAINT,lambda e: self.paintBackground())
self.Bind(wx.EVT_ERASE_BACKGROUND,lambda e: None)
self.t=wx.StaticText(self,pos=(30,20),label="wxStaticText. Looks bad on MSW")
self.t2=MyStaticText(self,pos=(30,50), size=(300,25), label="MyStaticText. Needs ClipChildren turned off")
self.t3=MyStaticTextWithCustomBackground(self,pos=(30,80),size=(300,25), label="This Control touches up its own background",paintBackgroundToDC=self.paintBackgroundToDC)
def paintBackground(self):
dc=wx.PaintDC(self)
self.paintBackgroundToDC(self,dc)
def paintBackgroundToDC(self,ofWindow,dc=None):
r=self.GetScreenRect()
r.SetTopLeft(ofWindow.ScreenToClient(r.GetTopLeft()))
dc.GradientFillLinear(r,wx.Colour(240,240,240),wx.Colour(128,128,255),wx.SOUTH)
class MyStaticText(wx.Window):
def __init__(self,parent,label,**kwargs):
wx.Window.__init__(self,parent,**kwargs)
self.label=label
self.Bind(wx.EVT_PAINT,lambda e: self.repaint())
self.Bind(wx.EVT_ERASE_BACKGROUND,lambda e: None)
def repaint(self):
self.repaintToDC(wx.PaintDC(self))
def repaintToDC(self,dc):
dc.DrawText(self.label,0,0)
class MyStaticTextWithCustomBackground(MyStaticText):
def __init__(self,parent,label,paintBackgroundToDC=None,**kwargs):
self.paintBackgroundToDC=paintBackgroundToDC
MyStaticText.__init__(self,parent,label,**kwargs)
def repaint(self):
dc=wx.PaintDC(self)
if self.paintBackgroundToDC:
self.paintBackgroundToDC(self,dc)
MyStaticText.repaintToDC(self,dc)
if __name__ == "__main__":
#wx.SystemOptions.SetOptionInt('msw.window.no-clip-children',1)
app=wx.PySimpleApp()
frame=wx.Frame(None,title="Transparent Controls")
panel=GradientPanel(frame)
frame.Show()
app.MainLoop()
Upvotes: 3
Views: 3188
Reputation: 66
I ran into this exact problem the other day: how to display static text with a transparent background using wxPython. Here's what I came up with:
class TransparentText(wx.StaticText):
def __init__(self, parent, id=wx.ID_ANY, label='', pos=wx.DefaultPosition,
size=wx.DefaultSize, style=wx.TRANSPARENT_WINDOW, name='transparenttext'):
wx.StaticText.__init__(self, parent, id, label, pos, size, style, name)
self.Bind(wx.EVT_PAINT, self.on_paint)
self.Bind(wx.EVT_ERASE_BACKGROUND, lambda event: None)
self.Bind(wx.EVT_SIZE, self.on_size)
def on_paint(self, event):
bdc = wx.PaintDC(self)
dc = wx.GCDC(bdc)
font_face = self.GetFont()
font_color = self.GetForegroundColour()
dc.SetFont(font_face)
dc.SetTextForeground(font_color)
dc.DrawText(self.GetLabel(), 0, 0)
def on_size(self, event):
self.Refresh()
event.Skip()
A couple of key things:
I have noticed occasional problems where the parent panel's background does not get invalidated when the content of the TransparentText control gets updated. It's not consistent, and it usually works well.
Upvotes: 5