Archive

Archive for March, 2012

Transparent static text in wxPython

March 15th, 2012 5 comments

For my non-geek friends, feel free to bail now.  This is a nerd post.

I’ve been spending a lot of time lately on a project that uses wxPython for its GUI.  Yesterday, I spent about five hours trying to figure out how to have a static text widget that would have a transparent background.  My application had a gradient background, and I wanted that to show through under the text.

After a bunch of Googling, I found lots of requests for such a widget, but I didn’t find any good explanations on how to do it.  Fortunately, I did figure it out, and as is often the case, the solution was straightforward in hindsight. In the hope that I’ll save somebody a headache, here’s some code for a transparent static text widget:

"""
Static text with transparent background
"""

import wx

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: First the style of the widget is wx.TRANSPARENT_WINDOW (all controls are windows).  Second, GCDC is used in on_paint(), because the normal DC doesn’t support transparency very well.

Unfortunately, many of the other widgets in wxPython have a similar lack of transparency support, so I ended up punting and redesigning without a gradient background. However, if I want to go back in the future and create more custom transparent widgets, this approach seems viable.