Another way to put a lot of wxPython widgets on a limited display area is to use a scrolled panel like the wx.lib.scrolledpanel.ScrolledPanel() widget ...

# testing wxPython's
# wx.lib.scrolledpanel.ScrolledPanel(parent, id, pos, size, style)
# allows for more space than the parent frame has

import wx
import  wx.lib.scrolledpanel as sp

class MyScrolledPanel(wx.lib.scrolledpanel.ScrolledPanel):
    def __init__(self, parent):
        # make the scrolled panel larger than its parent
        wx.lib.scrolledpanel.ScrolledPanel.__init__(self, parent,
            wx.ID_ANY, size=(800, 600), style=wx.TAB_TRAVERSAL)
        # scroll bars won't appear until required
        # default is SetupScrolling(scroll_x=True, scroll_y=True)
        self.SetupScrolling()
        self.SetBackgroundColour("blue")

        # this will take up plenty of space for the test
        self.createMultiLabel()

    def createMultiLabel(self):
        # things to put on the labels
        label_string = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ->UM'

        # wx.GridSizer(rows, cols, vgap, hgap)
        gsizer = wx.GridSizer(6, 5, 0, 0)

        # create a list of labels
        # acccess with self.labels[0], self.labels[1] etc.
        self.labels = []
        for c in label_string:
            self.labels.append(wx.StaticText(self, wx.ID_ANY,
                label=c, style=wx.ALIGN_CENTRE|wx.SUNKEN_BORDER))

        # iterate through the list of labels and set layout
        # also font and colour
        font = wx.Font(60, wx.MODERN, wx.NORMAL, wx.BOLD)
        for x in self.labels:
            x.SetFont(font)
            x.SetBackgroundColour("yellow")
            gsizer.Add(x, 0, flag=wx.ALL, border=20)  # |wx.EXPAND

        # set the sizer
        self.SetSizer(gsizer)


app = wx.App(0)
# create a frame, no parent, use default ID, set title, size
caption = "Multilabel display in a scrolled panel"
frame = wx.Frame(None, wx.ID_ANY, caption, size=(400, 300))
MyScrolledPanel(frame)
frame.Show(True)
app.MainLoop()
sneekula commented: interesting approach +4

Let's play around with the wx.BitmapButton() widget, simply a button with a picture on it. The picture can come from an image file. If you don't want to distribute your program with an extra image file, you can include the image in your code as a base64 encoded string ...

# playing with wxPython's
# wx.BitmapButton(parent, id, bitmap, pos, size, style)
# for small images it is best to embed them as base64 encoded strings

import wx
import cStringIO
import base64
import random

class MyFrame(wx.Frame):
    def __init__(self, parent, mytitle, data_stream):
        wx.Frame.__init__(self, parent, wx.ID_ANY, mytitle,
            size=(400, 300))

        # create a BitmapButton as an input widget
        # convert data_stream to a bitmap
        bmp = wx.BitmapFromImage(wx.ImageFromStream(data_stream))
        self.button = wx.BitmapButton(self, wx.ID_ANY, bitmap=bmp,
            pos=(10, 20),
            size=(bmp.GetWidth()+15, bmp.GetHeight()+15))
        # bind mouse click event to an action
        self.button.Bind(wx.EVT_BUTTON, self.onAction)
        # create an output widget
        self.label = wx.StaticText(self, wx.ID_ANY, "", pos=(10, 100))

    def onAction(self, event):
        """pick a colour at random"""
        colour_list = ['red', 'green', 'blue', 'yellow', 'white',
            'pink', 'brown', 'cyan', 'navy', 'magenta', 'plum']
        colour = random.choice(colour_list)
        self.label.SetLabel(colour)
        # establish new colour
        self.SetBackgroundColour(colour)
        # now clear old colour, set to new colour
        self.ClearBackground()


"""
# the base64 image string has been created with this short
# program, the resulting string is then copied and pasted

import base64

jpg_file = "Btn_rainbow.jpg"
jpg2base64string = base64.encodestring(open(jpg_file,"rb").read())
print "Btn_rainbow_jpg_b64='''\\\n" + jpg2base64string + "'''"
"""
Btn_rainbow_jpg_b64='''\
/9j/4AAQSkZJRgABAQEAyADIAAD/2wBDAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEB
AQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/2wBDAQEBAQEBAQEBAQEBAQEBAQEBAQEB
AQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/wAARCAAoACgDASIA
AhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQA
AAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3
ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWm
p6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEA
AwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSEx
BhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElK
U1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3
uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD+VL4J
/Aj4eeN/hNo+uan4a0mXWDo1pLNdNZQF7hvKh3TTOUP78f8ALWQk+aD1888+lfBf9lf4ceMvFF5p
d54Y0q4jt7wwpHJY28q7dkZx/qzwDz0681vfst/8kU0n/sCWn/pNDX0/+x/DFJ8RNW8xd/8AxNB9
7d/cTH06/wBM1/sn9Eb6OXhx4n/Rrx3FWeZHl9XPcuwuMl9fq4SlUrVVHGyp03Ko4cynCKUE1LVb
p2P6H/aG5/gfCD6O/AHFfC+QZTgs3x/AuU4vF4zB4HC4XE18T/ZWGnPEVKtKjGVStNyc6lWT5pyv
KTbk2fTnhX/glZ8DtU8Pw6hL8PPD8jyfxNpNmzen/Pv6cH2Ne5+Bf+COfwA1vQtQvrj4Z+G5JbeG
R1ZtHseqOh6/Z/6j9K/Wn4Z6bY/8IPZ/6LGPuddw/wCWa/T/ACOOOn2F8JdL0+P4f+JpFtY1kTT7
plbLfK29P85Nf8k/7TLxQ408GfF+XD3BvEOa5VgVi6tONHAYzEYakksTRhFOFKpBWtK2nTzZ/hX+
zk+mDx34wfSXwfBnF1JZnk08fmVOWExs44ihy0alKMIyp1YTi7KTsrW00Suz+H39v/8AYw+D37P3
w/8AFV54b8GaFY61BpN8YLiHTbWOSyZYZQsyhI/kuMY8mQ/6nAx+/A8or7I/4LJf8iV40/7Buof+
iJqK/p36HvEeecV+FNLOM+zTGZnmGIx7dTE42tPFVbfVqElCM6znKMIvaKdr3drtn/Q59M/IMi4e
4m8PMNkWT5dk+HxPAtDGV6OXYTD4SFbE1cwxHPXrKhSgqtVxjCHtJpz5IxjeysfnB+y3/wAkU0n/
ALAlp/6TQ19Sfsdf8lD1b/sJ/wDsiV8t/st/8kU0n/sCWn/pNDX0/wDsezRx/ETVtzqv/E16N3wi
Z6de3X+Vf9W/7PyUY/RK4h5pRing8Yk5O128wnZJvTvu1sfiH7WSMp/RS8M1GLk/+Ie5VpFNv/kU
YTokf1C/DH/kRrP6r/6LWvsT4Uf8k68Vf9gy6/8ARkdfGXwwvrP/AIQez/0iE/Mv8S/3E/z+fbNf
YXwlvrNvh/4ojWeFpDp10qr5i7mben5fX+Vf8NX7Y28/HxuKckswrXcU5JL67hm22lay9dvPQ/5m
P2R9GtD6YWAc6VSK/tTNneUJJf7xR0d4pLa+/wCtv5Qf+CyX/IleNP8AsG6h/wCiJqKP+CyX/Ile
NP8AsG6h/wCiJqK/sT6DX/JlcH/2Hf8AurQP+uz6c/8AyVnhr/2bzCf+p+JPx7+Cfx2+HXgj4TaP
oWq+JtIi1c6NaJNaNewB7aTyoh5Uyl8pOSP3qHmIg5GcgemfBP8Aam+GfgrxReanf+J9It45rzzl
kkv7dVZNiJ08zts+mc0UV/rd4cfSM8TeBvDpcEcO4/AYXInRr05U5YWtOvNVa3tJynUji6cJScnu
6VrJLlPxrx44rxHirwDw7wfxbleTYjJsoyDAZThYYbC4mlXeGw2Co0ISq1K2MxEJ1pwgnUnGnCEp
NtU4qyX6z+E/+CqvwH0nw/b6fJ8RfDaSx8bW1izV0yuP+eg7nHrnjqa908B/8Fj/ANnnQdB1DT7j
4m+GIZLmGSMK2tWS9WT/AKeD16+45oor/Kj6RfgnwV4zcUvP+No5piMxdWU3PB4rD0KfNOcKj9yv
g8U7c0U7c3kfxb4A+Cfhv4QeIlHjLgzh6hh87p1q9aNTGP29HnqzhKV6dGOGm1eKt+8uu5+Tn/BQ
X9s34NftBfD/AMVWvhfxroF7rU2k3629rb6naSNfN5MvyQoj/vJ/+eMf/Lf3uP8AWlFFfp/gnwLk
nh7wrU4fyCeO/s6ni/bU442vSrVISlThBwjOjQw8fZpU4uMXBuLbs0uVR/tLx98Q898Q8z4VzDPK
WXUK+V5DLKcOssoV8NTnhqOLlWpyrRr4rFOVZOrKLnCVOLhGPucycn//2Q==
'''

# convert to jpg image bytes
jpg_bytes = base64.b64decode(Btn_rainbow_jpg_b64)
# convert image bytes to data stream
data_stream = cStringIO.StringIO(jpg_bytes)

app = wx.App(0)
# create a MyFrame instance and show the frame
caption = 'testing the wx.BitmapButton() with b64 image'
MyFrame(None, caption, data_stream).Show()
app.MainLoop()

If you just want to play a wave sound file, wx.Sound() does the job ...

# playing a wave file with wxPython's wx.Sound()

import wx

class MyFrame(wx.Frame):
    def __init__(self, parent, mytitle, mysize):
        wx.Frame.__init__(self, parent, wx.ID_ANY, mytitle, size=mysize)
        self.SetBackgroundColour("red")

        # pick a .wav sound file you have ...
        sound = wx.Sound('anykey.wav')
        # wx.SOUND_SYNC --> sound plays completely through
        # wx.SOUND_ASYNC --> sound can be stopped or reset
        # wx.SOUND_ASYNC|wx.SOUND_LOOP --> loop until stopped
        # with sound.Stop()
        sound.Play(wx.SOUND_SYNC)


app = wx.App(0)
# create a MyFrame instance and show the frame
MyFrame(None, 'wx.Sound()', (300, 100)).Show()
app.MainLoop()

I took the idea of multiple buttons layout from vegaseat's little wxPython calculator ( http://www.daniweb.com/forums/post648463-31.html ) and applied it to form a periodic table. You can easily expand the element dictionary to pack more practical information into this program:

# create a Periodic Table with multiple wxButton() widgets

import wx

class MyFrame(wx.Frame):
    def __init__(self, parent, mytitle, list_pt1, list_pt2):
        wx.Frame.__init__(self, parent, wx.ID_ANY, mytitle, pos=(0,20),
        size=(640, 330))
        self.SetBackgroundColour('green')

        # main sizer
        vsizer = wx.BoxSizer(wx.VERTICAL)

        # wx.GridSizer(rows, cols, vgap, hgap)
        # sizer for standard periodic table elements
        gsizer1 = wx.GridSizer(8, 18)

        font = wx.Font(10, wx.MODERN, wx.NORMAL, wx.BOLD)
        self.buttons1 = []
        for ix, symbol in enumerate(list_pt1):
            # forms a list of button objects, make certain id is unique
            btn_id = 100 + ix
            label = symbol
            self.buttons1.append(wx.Button(self, btn_id, label))
            self.Bind(wx.EVT_BUTTON, self.clickedButton, id=btn_id)
            self.buttons1[ix].SetFont(font)
            if symbol == " ":
                self.buttons1[ix].SetBackgroundColour("green")
            else:
                self.buttons1[ix].SetBackgroundColour("yellow")
            # the gridsizer fills left to right one row at a time
            gsizer1.Add(self.buttons1[ix], 0, wx.ALL|wx.EXPAND, border=1)

        # sizer for Lanthanides and Actinides
        gsizer2 = wx.GridSizer(3, 15)

        self.buttons2 = []
        for ix, symbol in enumerate(list_pt2):
            # forms a list of button objects, make certain id is unique
            btn_id = 300 + ix
            label = symbol
            #print label, ix, btn_id  # testing
            self.buttons2.append(wx.Button(self, btn_id, label))
            self.Bind(wx.EVT_BUTTON, self.clickedButton, id=btn_id)
            self.buttons2[ix].SetFont(font)
            self.buttons2[ix].SetBackgroundColour("pink")
            self.buttons2[ix].ClearBackground()
            # the gridsizer fills left to right one row at a time
            gsizer2.Add(self.buttons2[ix], 0, wx.ALL|wx.EXPAND, border=1)

        vsizer.Add(gsizer1, 0, wx.EXPAND)
        # spacer
        vsizer.Add((0, 30), 0, wx.EXPAND)
        vsizer.Add(gsizer2, 0, wx.EXPAND)
        #self.SetSizerAndFit(vsizer)
        self.SetSizer(vsizer)

    def clickedButton(self, event):
        # get the event id and then the associated button label
        buttons = self.buttons1 + self.buttons2
        for btn in buttons:
            if btn.GetId() == event.GetId():
                btn_label = btn.GetLabel()
        if btn_label == " ":
            message = " "
        elif btn_label == "*":
            message = "Position for the Lanthanides"
        elif btn_label == "**":
            message = "Position for the Actinides"
        else:
            message = "You clicked " + element_dict.get(btn_label, btn_label)
        #print event.GetId(), btn.GetId(), btn_label  # testing
        self.SetTitle(message)


# standard periodic table elements (q symbolizes an empty space)
#  * --> Lanthanides
# ** --> Actinides
# 18 items per line
pt1 = """\
H,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,He,
Li,Be,q,q,q,q,q,q,q,q,q,q,B,C,N,O,F,Ne,
Na,Mg,q,q,q,q,q,q,q,q,q,q,Al,Si,P,S,Cl,Ar,
K,Ca,Sc,Ti,V,Cr,Mn,Fe,Co,Ni,Cu,Zn,Ga,Ge,As,Se,Br,Kr,
Rb,Sr,Y,Zr,Nb,Mo,Tc,Ru,Rh,Pd,Ag,Cd,In,Sn,Sb,Te,I,Xe,
Cs,Ba,*,Hf,Ta,W,Re,Os,Ir,Pt,Au,Hg,Ti,Pb,Bi,Po,At,Rn,
Fr,Ra,**,Rf,Db,Sg,Bh,Hs,Mt,Ds,Rg,q,q,q,q,q,q,q"""

# Lanthanides and Actinides ...
# 15 items per line
pt2 = """\
La,Ce,Pr,Nd,Pm,Sm,Eu,Gd,Tb,Dy,Ho,Er,Tm,Yb,Lu,
Ac,Th,Pa,U,Np,Pu,Am,Cm,Bk,Cf,Es,Fm,Md,No,Lr"""

# convert standard periodic table elements into a list
list_pt1 = pt1.replace('\n', "").replace('q', " ").split(",")

# convert Lanthanides and Actinides into a list
list_pt2 = pt2.replace('\n', "").split(",")

element_dict = \
{'Ru': 'Ruthenium', 'Re': 'Rhenium', 'Ra': 'Radium', 'Rb': 'Rubidium',
'Rn': 'Radon', 'Rh': 'Rhodium', 'Be': 'Beryllium', 'Ba': 'Barium',
'Bi': 'Bismuth', 'Br': 'Bromine', 'H': 'Hydrogen', 'P': 'Phosphorus',
'Os': 'Osmium', 'Hg': 'Mercury', 'Ge': 'Germanium', 'Gd': 'Gadolinium',
'Ga': 'Gallium', 'Pr': 'Praseodymium', 'Pt': 'Platinum',
'Pu': 'Plutonium', 'C': 'Carbon', 'Pb': 'Lead ', 'Pa': 'Proctactinium',
'Pd': 'Palladium', 'Cd': 'Cadmium', 'Po': 'Polonium', 'Pm': 'Promethium',
'Ho': 'Holmium', 'Hf': 'Hafnium', 'K': 'Potassium', 'He': 'Helium',
'Mg': 'Magnesium', 'Mo': 'Molybdenum', 'Mn': 'Manganese', 'O': 'Oxygen',
'S': 'Sulfur', 'W': 'Tungsten', 'Zn': 'Zinc', 'Eu': 'Europium',
'Zr': 'Zirconium', 'Er': 'Erbium', 'Ni': 'Nickel', 'Na': 'Sodium',
'Nb': 'Niobium', 'Nd': 'Neodymium', 'Ne': 'Neon', 'Np': 'Neptunium',
'Fr': 'Francium', 'Fe': 'Iron', 'B': 'Boron', 'F': 'Fluorine',
'Sr': 'Strontium', 'N': 'Nitrogen', 'Kr': 'Krypton', 'Si': 'Silicon',
'Sn': 'Tin', 'Sm': 'Samarium', 'V': 'Vanadium', 'Sc': 'Scandium',
'Sb': 'Antimony', 'Se': 'Selenium', 'Co': 'Cobalt', 'Cl': 'Chlorine',
'Ca': 'Calcium ', 'Ce': 'Cerium', 'Xe': 'Xenon', 'Lu': 'Lutetium',
'Cs': 'Cesium', 'Cr': 'Chromium', 'Cu': 'Copper', 'La': 'Lanthanum',
'Li': 'Lithium', 'Tl': 'Thallium', 'Tm': 'Thulium', 'Th': 'Thorium',
'Ti': 'Titanium', 'Te': 'Tellurium', 'Tb': 'Terbium', 'Tc': 'Technetium',
'Ta': 'Tantalum', 'Yb': 'Ytterbium', 'Dy': 'Dysprosium', 'I': 'Iodine',
'U': 'Uranium', 'Y': 'Yttrium', 'Ac': 'Actinium', 'Ag': 'Silver',
'Ir': 'Iridium', 'Am': 'Americium', 'Al': 'Aluminum', 'As': 'Arsenic',
'Ar': 'Argon', 'Au': 'Gold', 'At': 'Astatine', 'In': 'Indium'}


app = wx.App(0)
# create the MyFrame instance and then show the frame
caption = "A muliple buttons periodic table"
MyFrame(None, caption, list_pt1, list_pt2).Show(True)
app.MainLoop()

I was impressed with Sneekula's solvent grid, but wanted to be able to sort it by column, so you could easily find the highest boiling solvent, the lowest melting solvent, or the solvent with the least density. I had done a sorting program with a wx.ListCtrl() before, so I modified it using some of Snee's data.

When you sort a GUI list, you have to remember that you are dealing with numeric strings, and some special considerations have to be given to sort them properly as numbers ...

# using a wx.ListCtrl() to display common solvent information
# in columns and rows, added a sort by column feature

import wx
import operator

class MyFrame(wx.Frame):
    def __init__(self, parent, mytitle, solvents):
        wx.Frame.__init__(self, parent, wx.ID_ANY, mytitle,
            size=(500, 400))
        self.SetBackgroundColour("blue")
        # make data available to the instance
        self.solvents = solvents

        # create the list control
        self.lc = wx.ListCtrl(self, wx.ID_ANY,
            style=wx.LC_REPORT|wx.SUNKEN_BORDER|wx.LC_HRULES)

        # create and load the columns with header titles, set width
        self.lc.InsertColumn(0,"Solvent Name")
        self.lc.SetColumnWidth(0, 150)
        self.lc.InsertColumn(1,"BP (deg C)", wx.LIST_FORMAT_RIGHT)
        self.lc.SetColumnWidth(1, 100)
        self.lc.InsertColumn(2,"MP (deg C)", wx.LIST_FORMAT_RIGHT)
        self.lc.SetColumnWidth(2, 100)
        self.lc.InsertColumn(3,"Density (g/ml)", wx.LIST_FORMAT_RIGHT)
        self.lc.SetColumnWidth(3, 100)

        # load the rest of the list with data
        self.loadList()

        # create the sort buttons ...
        sort_solvent = wx.Button(self, wx.ID_ANY, "Sort by Solvent Name")
        sort_bp = wx.Button(self, wx.ID_ANY, "Sort by Boiling Point")
        sort_mp = wx.Button(self, wx.ID_ANY, "Sort by Melting Point")
        sort_density = wx.Button(self, wx.ID_ANY, "Sort by Density")
        # bind the button clicks ...
        self.Bind (wx.EVT_BUTTON, self.onSortSolvent, sort_solvent)
        self.Bind (wx.EVT_BUTTON, self.onSortBp, sort_bp)
        self.Bind (wx.EVT_BUTTON, self.onSortMp, sort_mp)
        self.Bind (wx.EVT_BUTTON, self.onSortDensity, sort_density)

        # use a vertical boxsizer as main sizer
        sizer_v = wx.BoxSizer(wx.VERTICAL)
        # use horizontal sizer for the buttons
        sizer_h = wx.BoxSizer(wx.HORIZONTAL)
        sizer_h.Add(sort_solvent, 1, flag=wx.ALL|wx.EXPAND, border=1)
        sizer_h.Add(sort_bp, 1, flag=wx.ALL|wx.EXPAND, border=1)
        sizer_h.Add(sort_mp, 1, flag=wx.ALL|wx.EXPAND, border=1)
        sizer_h.Add(sort_density, 1, flag=wx.ALL|wx.EXPAND, border=1)
        # add the rest + sizer_h to the vertical sizer
        sizer_v.Add(self.lc, 1, flag=wx.ALL|wx.EXPAND, border=10)
        sizer_v.Add(sizer_h, 0, flag=wx.ALL|wx.EXPAND, border=10)
        self.SetSizer(sizer_v)

    def loadList(self):
        # just in case clear the listctrl
        self.lc.DeleteAllItems()
        # load each data row
        for ix, line in enumerate(self.solvents):
            # set max_rows, change if need be
            max_rows = 100
            # also sets/updates row index starting at 0
            index = self.lc.InsertStringItem(max_rows, line[0])
            #print index
            self.lc.SetStringItem(index, 1, line[1])
            self.lc.SetStringItem(index, 2, line[2])
            self.lc.SetStringItem(index, 3, line[3])

    def cmp_float(self, s1, s2):
        """
        s1 and s2 are numeric strings in a list
        sort as floats low to high
        """
        if float(s1) > float(s2): return 1
        elif float(s1) < float(s2): return -1
        else: return 0

    def onSortSolvent(self, event):
        # solvent name is item 0
        index = operator.itemgetter(0)
        self.solvents.sort(key=index)
        self.loadList()

    def onSortBp(self, event):
        # bp is item 1
        index = operator.itemgetter(1)
        self.solvents.sort(key=index, cmp=self.cmp_float)
        self.loadList()

    def onSortMp(self, event):
        # mp is item 2
        index = operator.itemgetter(2)
        self.solvents.sort(key=index, cmp=self.cmp_float)
        self.loadList()

    def onSortDensity(self, event):
        # density is item 3
        index = operator.itemgetter(3)
        self.solvents.sort(key=index, cmp=self.cmp_float)
        self.loadList()


# data to load the listctrl is in the form of a list of
# ['Solvent Name', 'BP (deg C)', 'MP (deg C)', 'Density (g/ml)'] lists
solvents = [
['ACETIC ACID', '117.9', '16.7', '1.049'],
['ACETIC ANHYDRIDE', '140.1', '-73.1', '1.087'],
['ACETONE', '56.3', '-94.7', '0.791'],
['ACETONITRILE', '81.6', '-43.8', '0.786'],
['ANISOLE', '154.2', '-37', '0.995'],
['BENZYL ALCOHOL', '205.4', '-15.3', '1.045'],
['BENZYL BENZOATE', '323.5', '19.4', '1.112'],
['BUTYL ALCOHOL NORMAL', '117.7', '-88.6', '0.81'],
['BUTYL ALCOHOL SEC', '99.6', '-114.7', '0.805'],
['BUTYL ALCOHOL TERTIARY', '82.2', '25.5', '0.786'],
['CHLOROBENZENE', '131.7', '-45.6', '1.111'],
['CYCLOHEXANE', '80.7', '6.6', '0.779'],
['CYCLOHEXANOL', '161.1', '25.1', '0.971'],
['CYCLOHEXANONE', '155.2', '-47', '0.947'],
['DICHLOROETHANE 1 2', '83.5', '-35.7', '1.246'],
['DICHLOROMETHANE', '39.8', '-95.1', '1.325'],
['DIETHYL ETHER', '34.5', '-116.2', '0.715'],
['DIMETHYLACETAMIDE', '166.1', '-20', '0.937'],
['DIMETHYLFORMAMIDE', '153.3', '-60.4', '0.944'],
['DIMETHYLSULFOXIDE', '189.4', '18.5', '1.102'],
['DIOXANE 1 4', '101.3', '11.8', '1.034'],
['DIPHENYL ETHER', '258.3', '26.9', '1.066'],
['ETHYL ACETATE', '77.1', '-83.9', '0.902'],
['ETHYL ALCOHOL', '78.3', '-114.1', '0.789'],
['ETHYL DIGLYME', '188.2', '-45', '0.906'],
['ETHYLENE CARBONATE', '248.3', '36.4', '1.321'],
['ETHYLENE GLYCOL', '197.3', '-13.2', '1.114'],
['FORMIC ACID', '100.6', '8.3', '1.22'],
['HEPTANE', '98.4', '-90.6', '0.684'],
['HEXAMETHYL PHOSPHORAMIDE', '233.2', '7.2', '1.027'],
['HEXANE', '68.7', '-95.3', '0.659'],
['ISO OCTANE', '99.2', '-107.4', '0.692'],
['ISOPROPYL ACETATE', '88.6', '-73.4', '0.872'],
['ISOPROPYL ALCOHOL', '82.3', '-88', '0.785'],
['METHYL ALCOHOL', '64.7', '-97.7', '0.791'],
['METHYL ETHYLKETONE', '79.6', '-86.7', '0.805'],
['METHYL ISOBUTYL KETONE', '116.5', '-84', '0.798'],
['METHYL T-BUTYL ETHER', '55.5', '-10', '0.74'],
['METHYLPYRROLIDINONE N', '203.2', '-23.5', '1.027'],
['MORPHOLINE', '128.9', '-3.1', '1'],
['NITROBENZENE', '210.8', '5.7', '1.208'],
['NITROMETHANE', '101.2', '-28.5', '1.131'],
['PENTANE', '36.1', ' -129.7', '0.626'],
['PHENOL', '181.8', '40.9', '1.066'],
['PROPANENITRILE', '97.1', '-92.8', '0.782'],
['PROPIONIC ACID', '141.1', '-20.7', '0.993'],
['PROPIONITRILE', '97.4', '-92.8', '0.782'],
['PROPYLENE GLYCOL', '187.6', '-60.1', '1.04'],
['PYRIDINE', '115.4', '-41.6', '0.978'],
['SULFOLANE', '287.3', '28.5', '1.262'],
['TETRAHYDROFURAN', '66.2', '-108.5', '0.887'],
['TOLUENE', '110.6', '-94.9', '0.867'],
['TRIETHYL PHOSPHATE', '215.4', '-56.4', '1.072'],
['TRIETHYLAMINE', '89.5', '-114.7', '0.726'],
['TRIFLUOROACETIC ACID', '71.8', '-15.3', '1.489'],
['WATER', '100', '0', '1'],
['XYLENES', '139.1', '-47.8', '0.86']
]


app = wx.App(0)
# create a MyFrame instance and show the frame
caption = "Common Solvent Information"
MyFrame(None, caption, solvents).Show()
app.MainLoop()

The wx.lib.filebrowsebutton.FileBrowseButton() makes it easy to select/browse one file and show or play it:

# exploring wxPython's
# wx.lib.filebrowsebutton.FileBrowseButton()
# use it to get wave sound file and play it

import wx
import wx.lib.filebrowsebutton

class MyFrame(wx.Frame):
    def __init__(self, parent, mytitle):
        wx.Frame.__init__(self, parent, wx.ID_ANY, mytitle, size=(500,100))
        self.SetBackgroundColour("green")
        panel = wx.Panel(self)

        self.fbb = wx.lib.filebrowsebutton.FileBrowseButton(panel,
            labelText="Selected WAVE file:", fileMask="*.wav")
        play_button = wx.Button(panel, wx.ID_ANY, ">>  Play")
        self.Bind(wx.EVT_BUTTON, self.onPlay, play_button)

        # setup the layout with sizers
        hsizer = wx.BoxSizer(wx.HORIZONTAL)
        hsizer.Add(self.fbb, 1, wx.ALIGN_CENTER_VERTICAL)
        hsizer.Add(play_button, 0, wx.ALIGN_CENTER_VERTICAL)
        # create border space
        border = wx.BoxSizer(wx.VERTICAL)
        border.Add(hsizer, 0, wx.EXPAND|wx.ALL, 15)
        panel.SetSizer(border)

    def onPlay(self, evt):
        filename = self.fbb.GetValue()
        self.sound = wx.Sound(filename)
        # error handling ...
        if self.sound.IsOk():
            self.sound.Play(wx.SOUND_ASYNC)
        else:
            wx.MessageBox("Missing or invalid sound file", "Error")


app = wx.App(True)
# create the MyFrame instance and show the frame
caption = "wx.lib.filebrowsebutton.FileBrowseButton()"
MyFrame(None, caption).Show(True)
app.MainLoop()

Just some wxPython code to show you how to draw a bar chart:

# using wxPython's
# wx.lib.plot.PlotCanvas() to show a colourful bar chart

import wx
import wx.lib.plot

class MyFrame(wx.Frame):
    def __init__(self, parent, mytitle, mysize):
        wx.Frame.__init__(self, parent, wx.ID_ANY, mytitle, size=mysize)

        # data values indicate upper value of each bar
        # bars are drawn as thick vertical lines
        # data set one
        data1 = [5, 8, 12, 9.5, 7, 5.5, 4.5, 3]
        # data set two
        data2 = [3, 7, 13.5, 9, 6, 3.5, 2, 1]

        plot_canvas = wx.lib.plot.PlotCanvas(self)

        # create list of bars for data1
        bar_colour = 'red'
        bars1 = []
        for x in range(len(data1)):
            x1 = 2*x
            y1 = data1[x]
            bars1.append(wx.lib.plot.PolyLine([(x1, 0), (x1, y1)],
                legend='1', colour=bar_colour, width=20))

        # create list of bars for data2
        bar_colour = 'blue'
        bars2 = []
        for x in range(len(data2)):
            x1 = 2*x+1
            y1 = data2[x]
            bars2.append(wx.lib.plot.PolyLine([(x1, 0), (x1, y1)],
                legend='', colour=bar_colour, width=20))

        # set up the graphics
        gc = wx.lib.plot.PlotGraphics(bars1 + bars2,
            '2007 Sales  Vista (red)  Linux (blue)',
            'X Axis (Sales Period)',
            'Y Axis (1000 Euro)')
        # then plot it
        plot_canvas.Draw(gc, xAxis=(-0.5, 15), yAxis=(0, 15))


app = wx.App(True)
# create the MyFrame instance and then show the frame
caption = "wx.lib.plot.PlotCanvas() Bar Chart"
MyFrame(None, caption, (500, 400)).Show(True)
app.MainLoop()

The wx.SplitterWindow() could have some interesting applications:

# testing wxPython's interesting
# wx.SplitterWindow(parent, id, pos, size, style)
# the size can be changed by dragging the interior borders
#
# style =
# wx.SP_3D  draws a 3D effect border and sash (default)
# wx.SP_BORDER   draws a standard border
# wx.SP_LIVE_UPDATE  resize the child windows immediately

import wx

class MyFrame(wx.Frame):
    def __init__(self, parent, mytitle, mysize):
        wx.Frame.__init__(self, parent, wx.ID_ANY, mytitle, size=mysize)

        self.splitter1 = wx.SplitterWindow(self, wx.ID_ANY,
            style=wx.CLIP_CHILDREN|wx.SP_LIVE_UPDATE|wx.SP_3D)
        self.splitter2 = wx.SplitterWindow(self.splitter1, wx.ID_ANY,
            style=wx.CLIP_CHILDREN|wx.SP_LIVE_UPDATE|wx.SP_3D)

        self.panel1 = wx.Panel (self.splitter1, wx.ID_ANY)
        self.panel1.SetBackgroundColour ("red")
        self.panel2 = wx.Panel (self.splitter2, wx.ID_ANY)
        self.panel2.SetBackgroundColour ("white")
        self.panel3 = wx.Panel (self.splitter2, wx.ID_ANY)
        self.panel3.SetBackgroundColour ("blue")

        # set splitters direction and content (top or left first)
        # and sash position
        self.splitter1.SplitVertically(self.panel1, self.splitter2, 200)
        self.splitter2.SplitHorizontally(self.panel2, self.panel3, 140)


app = wx.App(0)
# create a MyFrame instance and show the frame
MyFrame(None, 'test the wx.SplitterWindow()', (400, 300)).Show()
app.MainLoop()

Information can be presented as a tree branching into more and more details. The wx.TreeCtrl() widget does that, just take a look at this short example ...

# testing wxPython's
# wx.TreeCtrl(parent, id, pos, size, style)
# presents information as a hierarchy,
# with items that may be expanded to show further items
# style =
# wx.TR_HAS_BUTTONS  show + and - buttons to the left of parent items (default)
# wx.TR_NO_BUTTONS  no buttons are to be drawn
# wx.TR_HIDE_ROOT  suppress the display of the root node
# wx.TR_EDIT_LABELS  user to be able to edit labels in the tree control

import wx

class MyFrame(wx.Frame):
    def __init__(self, parent, mytitle, mysize):
        wx.Frame.__init__(self, parent, wx.ID_ANY, mytitle, size=mysize)
        self.SetBackgroundColour("yellow")

        self.tree = wx.TreeCtrl(self)

        # you can only have one root
        root = self.tree.AddRoot("Computer")

        # these form subroots
        os = self.tree.AppendItem(root, 'Systems')
        tk = self.tree.AppendItem(root, 'Toolkits')

        # add 3 items to os
        os_items = ["Windows", "Solaris", "Linux"]
        for item in os_items:
            self.tree.AppendItem(os, item)

        # add 3 items to tk
        tk_items = ["Tkinter", "wxPython", "Qt"]
        for item in tk_items:
            self.tree.AppendItem(tk, item)

        # bind mouse clicks to an action
        self.Bind(wx.EVT_TREE_ITEM_EXPANDED, self.onItemExpanded, self.tree)
        self.Bind(wx.EVT_TREE_ITEM_COLLAPSED, self.onItemCollapsed, self.tree)
        self.Bind(wx.EVT_TREE_SEL_CHANGED, self.onSelChanged, self.tree)
        self.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self.onActivated, self.tree)

        # start with root expanded
        #self.tree.Expand(root)

        # create an output widget
        self.label = wx.StaticText(self, wx.ID_ANY, "click on a node or item")

        # use a vertical boxsizer for the widget placement
        sizer_v = wx.BoxSizer(wx.VERTICAL)
        sizer_v.Add(self.tree, 1, flag=wx.ALL|wx.EXPAND, border=10)
        sizer_v.Add(self.label, 0, flag=wx.ALL|wx.EXPAND, border=10)
        self.SetSizer(sizer_v)

    def onItemExpanded(self, event):
        item_text = self.tree.GetItemText(event.GetItem())
        s = "onItemExpanded: " + item_text
        self.label.SetLabel(s)

    def onItemCollapsed(self, event):
        item_text = self.tree.GetItemText(event.GetItem())
        s = "onItemCollapsed: " + item_text
        self.label.SetLabel(s)

    def onSelChanged(self, event):
        item_text = self.tree.GetItemText(event.GetItem())
        s = "onSelChanged: " + item_text
        self.label.SetLabel(s)

    def onActivated(self, event):
        """item has been double clicked"""
        item_text = self.tree.GetItemText(event.GetItem())
        s = "onActivated: " + item_text
        self.label.SetLabel(s)


app = wx.App(0)
# create a MyFrame instance and show the frame
MyFrame(None, 'wx.TreeCtrl() testing', (400, 300)).Show()
app.MainLoop()

Using the wx.ToggleButton to play with wxPython's colours:

# testing the wxPython widgets ...
# wx.ToggleButton(parent, id, label, pos, size, style)
# wx.Dialog(parent, id, title, pos, size, style)
# note: id wx.ID_ANY is the same as -1
# also: if a button stays toggled the colours will mix

import wx

class MyDialog(wx.Dialog):
    def __init__(self, parent, mytitle):
        # use a simple dialog box rather than a frame
        wx.Dialog.__init__(self, parent, wx.ID_ANY, mytitle, 
            size=(300, 200))

        # wx.Colour(red, green, blue, alpha=wx.ALPHA_OPAQUE)
        # r, g, or b colour intensity can be 0 to 255
        self.colour = wx.Colour(0, 0, 0)  # black
        #print str(self.colour)  # (0, 0, 0, 255)

        tb1 = wx.ToggleButton(self, wx.ID_ANY, 'red', pos=(20, 20))
        tb2 = wx.ToggleButton(self, wx.ID_ANY, 'green', pos=(20, 60))
        tb3 = wx.ToggleButton(self, wx.ID_ANY, 'blue', pos=(20, 100))

        self.panel  = wx.Panel(self, wx.ID_ANY, pos=(150, 20), 
            size=(110, 110), style=wx.SUNKEN_BORDER)
        self.panel.SetBackgroundColour('black')

        self.Bind(wx.EVT_TOGGLEBUTTON, self.ToggleRed, tb1)
        self.Bind(wx.EVT_TOGGLEBUTTON, self.ToggleGreen, tb2)
        self.Bind(wx.EVT_TOGGLEBUTTON, self.ToggleBlue, tb3)
        
        # create a label to show result
        self.label = wx.StaticText(self, wx.ID_ANY, "click a button",
            pos=(20, 140))

        self.Centre()
        self.ShowModal()
        self.Destroy()

    def ToggleRed(self, event):
        green = self.colour.Green()
        blue = self.colour.Blue()
        if  self.colour.Red():
            self.colour.Set(0, green, blue)
        else:
            self.colour.Set(255, green, blue)
        self.panel.SetBackgroundColour(self.colour)
        # clear old colour, set to new colour
        self.panel.ClearBackground()
        s = self.colour.GetAsString()
        self.label.SetLabel(s)

    def ToggleGreen(self, event):
        red = self.colour.Red()
        blue = self.colour.Blue()
        if  self.colour.Green():
            self.colour.Set(red, 0, blue)
        else:
            self.colour.Set(red, 255, blue)
        self.panel.SetBackgroundColour(self.colour)
        self.panel.ClearBackground()
        s = self.colour.GetAsString()
        self.label.SetLabel(s)

    def ToggleBlue(self, event):
        red = self.colour.Red()
        green = self.colour.Green()
        if  self.colour.Blue():
            self.colour.Set(red, green, 0)
        else:
            self.colour.Set(red, green, 255)
        self.panel.SetBackgroundColour(self.colour)
        self.panel.ClearBackground()
        s = self.colour.GetAsString()
        self.label.SetLabel(s)


app = wx.App(0)
MyDialog(None, 'wx.ToggleButton()')
app.MainLoop()

Also a good example how to use the simpler wx.Dialog instead of the wx.Frame.

To create a window or frame with wxPython you use wx.Frame. There are some basic things you can do with a frame and I tried to put them in one spot:

# a few things you can do with wxPython's wx.Frame
# wx.Frame(parent, id, title, pos, size, style, name)
# set/change colour, cursor, position, size, title, tooltip
# blow the frame to full size and return to normal  

import wx

class MyFrame(wx.Frame):
    """inherits wx.Frame, self is the instance of the frame"""
    def __init__(self):
        # create a frame/window, no parent, default to id=wxID_ANY
        # note that id=wxID_ANY is the same as id=-1 
        # position is overwritten by Center()
        wx.Frame.__init__(self, None, wx.ID_ANY, 'original title', 
            pos=(100, 150), size=(400, 350))
        # show the frame during the creation of the instance
        # default is True, False would hide the frame
        self.Show(True)
        
        # wait just a moment, 4.5 seconds to be exact
        wx.Sleep(4.5)
        
        # this allows you to change the frame title
        self.SetTitle('changed title, colour, and cursor')
        # optionally change the cursor
        self.SetCursor(wx.StockCursor(wx.CURSOR_MAGNIFIER))
        # change the frame's colour 
        # notice British spelling of Colour
        self.SetBackgroundColour('green')
        # now clear old color, set to new color
        self.ClearBackground()
        self.Show()
        
        wx.Sleep(4.5)
        self.SetTitle('center wx.Frame horizontal')
        # optionally center the frame on the display screen
        # notice British spelling of Centre
        # wx.HORIZONTAL, wx.VERTICAL or wx.BOTH (default)
        self.Centre(wx.HORIZONTAL)
        self.Show()
        
        wx.Sleep(4.5)
        cap = 'now center wx.Frame vertical too and change size'
        self.SetTitle(cap)
        #self.Update()
        # change the size of the frame
        width, height = self.GetSize()
        # needs tuple
        self.SetSize((width+200, height-100))
        # in this case assumes same position as wx.BOTH
        # since we already did the horizontal centering
        self.Centre(wx.wx.VERTICAL)
        self.Show()
        
        wx.Sleep(4.5)
        # go full screen, will over-rule SetMaxSize
        # no border etc.
        self.ShowFullScreen(True, style=wx.FULLSCREEN_ALL)
        
        wx.Sleep(4.5)
        self.SetTitle("wowee sowee!")
        # optionally set  tooltip
        self.SetToolTip(wx.ToolTip('click corner x to exit'))
        # and reset to previous size and style again
        self.ShowFullScreen(False)


app = wx.App(0)

# create an instance of class MyFrame
frame = MyFrame()

# you can also fix the max/min size of the frame
frame.SetMaxSize((600, 400))
frame.SetMinSize((300, 100))

# optional info
print "frame size (width, height)   =", frame.GetSize()
print "display size (width, height) =", wx.DisplaySize()

# start the event loop
app.MainLoop()
commented: very nice basics +4

I was trying to create an alternative calculator using some of wxPython's input widgets like wx.Choice and wx.TextCtrl. This turned out to be a good example for the wx.GridBagSizer too. The basic workings are there, but as always there is room for improvement:

# do some simple math operations with
# wx.Choice(parent,id,pos,size,choices,style)

import wx
from math import *

class MyFrame(wx.Frame):
    def __init__(self, parent, title, operation_list):
        wx.Frame.__init__(self, parent, wx.ID_ANY, title, size=(350, 270))
        self.SetBackgroundColour('green')

        # create choice widget for the math operations
        self.choice = wx.Choice(self, wx.ID_ANY, choices=operation_list)
        # select item 0 (first item) in choices list to show
        self.choice.SetSelection(0)
        self.choice.SetToolTip(wx.ToolTip('select one math operation'))
        # bind the checkbox events to action
        self.choice.Bind(wx.EVT_CHOICE, self.onAction)
        
        edit_label1 = wx.StaticText(self, wx.ID_ANY, 'enter x')
        self.edit1 = wx.TextCtrl(self, wx.ID_ANY, value="1",
            size=(200, 20))
        
        edit_label2 = wx.StaticText(self, wx.ID_ANY, 'enter y')
        self.edit2 = wx.TextCtrl(self, wx.ID_ANY, value="1",
            size=(200, 20))
            
        edit_label3 = wx.StaticText(self, wx.ID_ANY, 'result')
        self.edit3 = wx.TextCtrl(self, wx.ID_ANY, value="",
            size=(200, 20))
        self.edit3.SetToolTip(wx.ToolTip('double click to move data to x'))
        self.edit3.Bind(wx.EVT_LEFT_DCLICK, self.onDoubleClick)
        
        self.button = wx.Button(self, wx.ID_ANY, label='Calculate')
        # bind mouse event to action
        self.button.Bind(wx.EVT_BUTTON, self.onAction)
        
        # hgap is between columns, vgap between rows
        sizer = wx.GridBagSizer(vgap=0, hgap=0)
        # pos=(row, column)
        sizer.Add(edit_label1, pos=(0,0), flag=wx.ALL|wx.EXPAND, border=10)
        sizer.Add(self.edit1, pos=(0,1), flag=wx.ALL|wx.EXPAND, border=10)
        sizer.Add(edit_label2, pos=(1,0), flag=wx.ALL|wx.EXPAND, border=10)
        sizer.Add(self.edit2, pos=(1,1), flag=wx.ALL|wx.EXPAND, border=10)
        # span=(rowspan, columnspan)
        sizer.Add(self.choice, pos=(2,0), span=(1, 2),
            flag=wx.ALL|wx.EXPAND, border=10)
        sizer.Add(self.button, pos=(3,0), span=(1, 2),
            flag=wx.ALL|wx.EXPAND, border=10)
        sizer.Add(edit_label3, pos=(4,0), flag=wx.ALL|wx.EXPAND, border=10)
        sizer.Add(self.edit3, pos=(4,1), flag=wx.ALL|wx.EXPAND, border=10)
        self.SetSizerAndFit(sizer)

    def onAction(self, event):
        op = self.choice.GetStringSelection()
        x = float(self.edit1.GetValue())
        y = float(self.edit2.GetValue())
        if y == 0.0 and op == 'x / y' :
            result = 'division by zero error'
        else:
            result = eval(op)
        #print result, type(result)
        self.edit3.SetValue(str(result))
        
    def onDoubleClick(self, event):
        """
        if edit3 has been doubleclicked, transfer value to edit1
        """
        val = self.edit3.GetValue()
        self.edit1.ChangeValue(val)


# list of math operations Python understands
# x and/or y values are pulled from the edit boxes
operation_list = [
'x + y',
'x - y',
'x * y',
'x / y',
'x**y',
'sqrt(x)',
'exp(x)', 
'log(x)', 
'log10(x)', 
'degrees(x)',
'radians(x)',
'sin(x)',
'cos(x)',
'tan(x)',
'asin(x)',
'acos(x)',
'atan(x)'
]

app = wx.App(0)
# create the MyFrame instance and show it
MyFrame(None, 'do math stuff', operation_list).Show()
app.MainLoop()
commented: nice code snee +9

Another example of wxPython's grid widget. This time we are setting up the grid with the help of a table class that inherits from wx.grid.PyGridTableBase. Once the grid is set up and loaded with data, let's select a range of data for processing ...

# a simple wxPython wx.grid.Grid()
# load grid via a '(row, col): value' dictionary and a table class
# for info on wx.grid.PyGridTableBase() check:
# http://wxpython.org/docs/api/wx.grid.GridTableBase-class.html
# select a range of cells and show values

import wx
import wx.grid

class MyTable(wx.grid.PyGridTableBase):
    def __init__(self, data_dict):
        wx.grid.PyGridTableBase.__init__(self)
        self.data = data_dict

    def GetNumberRows(self):
        """actually sets number of rows"""
        return 10

    def GetNumberCols(self):
        """actually sets number of cols"""
        return 10

    def IsEmptyCell(self, row, col):
        return self.data.get((row, col)) is not None

    def GetValue(self, row, col):
        """actually sets value of each (row, col)"""
        value = self.data.get((row, col))
        if value is not None:
            return value
        else:
            return ''

    def SetValue(self, row, col, value):
        self.data[(row,col)] = value


class MyFrame(wx.Frame):
    def __init__(self, data_dict):
        wx.Frame.__init__(self, None, title="Grid Table",
            size=(600, 250))
        # get row and column numbers
        self.rows = max(data_dict.keys())[0] + 1
        self.cols = max(data_dict.keys())[1] + 1

        self.grid = wx.grid.Grid(self)
        self.grid.SetDefaultColSize(50)  # sets all col width
        table = MyTable(data_dict)
        self.grid.SetTable(table, True)

        # select a cell or range of cells with a mouse drag
        self.Bind(wx.grid.EVT_GRID_RANGE_SELECT, self.onCellRangeSelect)

    def onCellRangeSelect(self, event):
        """create a list of values from the selected range"""
        self.select_list = []
        for row in range(self.rows):
            for col in range(self.cols):
                if self.grid.IsInSelection(row, col):
                    val = self.grid.GetCellValue(row, col)
                    self.select_list.append(val)
        print self.select_list  # testing ...
        # now you can do something with the selected data
        # for example assume all data are integers ...
        sel_data = [int(x) for x in self.select_list]
        print sel_data, sum(sel_data), len(sel_data)
        print 'average =', 1.0*sum(sel_data)/len(sel_data)


# convert raw data to a dictionary with (row, col):value pairs
raw_data = """\
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 1 1 1 1 0 0 0 0
0 0 1 1 1 1 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 1 1 0 1 1 1 1 0 0
0 1 1 0 1 1 1 1 0 0
0 1 1 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0"""

data_list = []
for line in raw_data.split('\n'):
    line_list = line.split(' ')
    data_list.append(line_list)

#print data_list  # testing

data_dict = {}
for row, item in enumerate(data_list):
    #print row, item
    for col, value in enumerate(item):
        data_dict[(row, col)] = value

#print data_dict  # testing

app = wx.PySimpleApp(0)
MyFrame(data_dict).Show()
app.MainLoop()

The question came up in the forum how to overlap playing cards in wxPython. Here is one way to do it, using a wx.PaintDC() paint canvas and Blit() to handle the card images on the canvas:

# draw card images on a paint canvas and overlap the cards
# note: the name of the card matches the image file

import wx
import random

class CardPanel(wx.Panel):
    """ create a panel with a canvas"""
    def __init__(self, parent):
        wx.Panel.__init__(self, parent, wx.ID_ANY)

        # the subdirectory containing the card image files
        self.image_dir = "./cards/"
        # create the card list
        self.card_list = self.create_cards()

        self.button = wx.Button(self, wx.ID_ANY, label='deal a hand',
            pos=(10, 120))
        # bind mouse event to an action
        self.button.Bind(wx.EVT_BUTTON, self.draw_hand)

        # set up a paint event on a PaintDC canvas
        wx.EVT_PAINT(self, self.on_paint)

    def create_cards(self):
        """
        create a list of 52 cards
        suit: club=C, diamond=D, heart=H spade=S
        rank: ace=A, 10=T, jack=J, queen=Q, king=K, numbers=2..9
        ace of spade would be SA, 8 of heart would be H8 and so on ...
        """
        return [suit + rank for suit in "CDHS" for rank in "A23456789TJQK"]

    def shuffle_cards(self):
        """random shuffle a list of cards"""
        # make a copy of the original list
        card_list1 = self.card_list[:]
        random.shuffle(card_list1)
        return card_list1

    def pick_5cards(self):
        """pick five cards from the shuffled list"""
        return self.card_list_shuffled[:5]

    def on_paint(self, event=None):
        # create the paint canvas
        self.canvas_dc = wx.PaintDC(self)
        # color the game table top
        self.canvas_dc.SetBrush(wx.Brush('dark green'))
        # DrawRectangle(x, y, width, height)
        self.canvas_dc.DrawRectangle(0, 0, 320, 200)
        # pick and draw a random hand of five cards
        self.draw_hand()

    def draw_hand(self, event=None):
        """
        suit: club=C, diamond=D, heart=H spade=S
        rank: ace=A, 10=T, jack=J, queen=Q, king=K, numbers=2..9
        the ace of spade would be image file SA.gif,
        the 8 of heart would be H8.gif and so on ...
        """
        # shuffle the card list and pick a hand of 5 cards
        self.card_list_shuffled = self.shuffle_cards()
        self.hand = self.pick_5cards()
        print self.hand  # testing

        posx = 5
        for card in self.hand:
            # make sure the card image file path is correct
            dc_card = wx.MemoryDC(wx.Bitmap(self.image_dir+card+".gif"))
            # card image is width=71  height=96
            self.canvas_dc.Blit(posx, 5, 71, 96, dc_card, 0, 0)
            # move x to the right to overlap cards
            posx += 30


app = wx.App(redirect=False)  # stderr/stdout --> console
# create window/frame
frame = wx.Frame(None, wx.ID_ANY, "Cards", size=(320, 200))
# create the panel instance
CardPanel(frame)
# show the frame
frame.Show(True)
# start the GUI event loop
app.MainLoop()

For the card images extract the attached Cards_gif.zip file into a subdirectory /Cards

Some of the stuff came from an earlier suggestion by vegaseat.

A splash screen comes up in the beginning of a program for a short time, usually showing some attractive graphics image with the programs name and author on it. Here is an example:

# a wxPython splash screen example using
# wx.SplashScreen(bitmap, splashStyle, milliseconds, parent,
#    id, pos=wx.DefaultPosition, size=wx.DefaultSize,
#    style=wxSIMPLE_BORDER|wxFRAME_NO_TASKBAR|wxSTAY_ON_TOP)
# splashStyle:
#    wx.SPLASH_CENTRE_ON_PARENT
#    wx.SPLASH_CENTRE_ON_SCREEN
#    wx.SPLASH_NO_CENTRE
#    wx.SPLASH_TIMEOUT
#    wx.SPLASH_NO_TIMEOUT
# ene

import wx

class MySplash(wx.SplashScreen):
    def __init__(self, parent, duration=2000):
        # pick a splash image file you have in the working folder
        image_file = 'CloudSplash.jpg'
        bmp = wx.Bitmap(image_file)
        # covers the parent frame
        wx.SplashScreen(bmp, wx.SPLASH_CENTRE_ON_PARENT|wx.SPLASH_TIMEOUT,
            duration, parent, wx.ID_ANY)


class MyFrame(wx.Frame):
    def __init__(self, parent, mytitle, mysize):
        wx.Frame.__init__(self, parent, wx.ID_ANY, mytitle, size=mysize)
        self.panel = wx.Panel(self, wx.ID_ANY, style=wx.SUNKEN_BORDER)

        # now make up your regular GUI stuff
        self.panel.SetBackgroundColour('yellow')
        s = "How did you like the 5 second splash screen?"
        self.label = wx.StaticText(self.panel, wx.ID_ANY, s, pos=(130, 100))


app = wx.App(0)
# create a MyFrame instance and show the frame
frame = MyFrame(None, 'wx.SplashScreen() test', (640, 480))
frame.Show()
# bring up a temporary splash screen lasting 5000 milliseconds
MySplash(frame, duration=5000)
app.MainLoop()

I was doing exercises and came up with Idea to post something for very begginers. I'm not experienced in pythoning but I post as my contributing to my fellow programmers in Py! Any suggestion correction and Addition is highly appreciated.
Thanks alot
Steve.

NOTE: Don't forget to start new thread for Questions! Thanks for your understanding!

import wx
ID_EXIT = 12
class MainWindow(wx.Frame):
    def __init__ (self, parent, id, title):
        wx.Frame.__init__(self, parent, id, title)
        
        #Add simple menu with quit item only
        #define menubar and menu
        menubar = wx.MenuBar()
        # attach menubar to the frame
        self.SetMenuBar(menubar)
        #define menus
        filemenu = wx.Menu()
        #Append file menu to menubar
        menubar.Append(filemenu, "&File")
        # Append items    
        filemenu.Append(ID_EXIT, "&Exit", "Close Application")        
        #---You can add as many Menu and Its items as you want
        #-----------------------------------------
        # Define Event handlers
        #also you can bind event using any of the methods below; I prefer the latter
        #self.Bind(wx.EVT_MENU, self.OnExit, id = ID_EXIT)
        wx.EVT_MENU (self, ID_EXIT, self.OnExit)
        #Add a panel
        Panel = wx.Panel(self, -1)
        
        #Add status bar
        self.CreateStatusBar()
        # Add text to status bar
        self.SetStatusText("Press F1 for help")
        
        # Add all your widgets here
        #--------------------------------
        #Add text are with mutliline capability
        Text = wx.TextCtrl(Panel, -1, style= wx.TE_MULTILINE)
        #Text.SetValue("Type your text here!")
        # Add three buttons that need to be equal in size
        yes = wx.Button(Panel, -1, "Yes")
        no = wx.Button(Panel, -1, "No")
        cancel = wx.Button(Panel, -1, "Cancel")
        # After adding all widget stuffs, add them to sizers
        #declare sizers
        main = wx.BoxSizer(wx.VERTICAL)
        grid = wx.GridSizer(1, 3, 4, 4) # grid with 1 row 3 column and vertical/horizontal spacing 4 pixs
        
        #add Text widget to main sizer
        main.Add(Text, proportion = 1, flag = wx.EXPAND |wx.LEFT | wx.RIGHT | wx.BOTTOM, border = 5)
        # Add buttons to a row of Grid sizer
        grid.AddMany([
            (yes, 0, wx.EXPAND),
            (no, 0, wx.EXPAND),
            (cancel, 0, wx.EXPAND)
        ])
        
        
        
        #add grid to main sizer
        #use min button size i.e no expand/ centering the grid sizer (with all its widgets)
        main.Add(grid, 0, flag = wx.CENTER| wx.BOTTOM, border = 5)
        # Attach sizer to panel
        Panel.SetSizer(main)
        Panel.Layout()
        #--------------------------------
        # End of all widgets here
        
        # Center your windows
        self.Center()
        # show your windows - unless you put below line, your window will be there but invisible!
        self.Show(True)
        
    # Start event handlers
    def OnExit (self, event):
        self.Close()
        
# Create application       
app = wx.App()
# Define your app window
MainWindow(None, -1, "Python GUI - Box Sizers and Grid Sizers")
# Start application loop
app.MainLoop()

Using wx.StaticBitmap() to show an image. Here we position the image in the center of the frame. Actually, the center of the panel that fills the frame:

# show a .jpg .png ,gif .bmp image using a wx.StaticBitmap()
# wx.StaticBitmap(parent, id, label, pos, size, style)
# calculate pos so image is in center

import wx

class ImagePanel(wx.Panel):
    """ create a panel with a wx.StaticBitmap """
    def __init__(self, parent):
        wx.Panel.__init__(self, parent, wx.ID_ANY)

        # pick an image file you have in the working folder
        # (can be a .jpg .png ,gif or .bmp image file)
        image_file = 'chemist.gif'
        bmp = wx.Bitmap(image_file)
        # get the width and height of the image
        wi, hi = bmp.GetSize()
        # get the width and height of the frame
        wf, hf = parent.GetSize()
        # calculate position so image is centered
        px = wf/2 - wi/2
        # 15 is estimated height of frame's title bar
        py = hf/2 - hi/2 - 15
        # show the static bitmap
        wx.StaticBitmap(self, wx.ID_ANY, bmp, pos=(px, py))

        # optionally show some image information
        info = "%s  %dx%d" % (image_file, bmp.GetWidth(), bmp.GetHeight())
        # the parent is the frame
        parent.SetTitle(info)


app = wx.App(redirect=False)  # stderr/stdout --> console
# create window/frame
frame = wx.Frame(None, wx.ID_ANY, size = (640, 480))
# create the panel instance
ImagePanel(frame)
# show the frame
frame.Show(True)
# start the GUI event loop
app.MainLoop()

Sometimes you want to change the colour of the widget as the mouse pointer moves over it. Here is the wx.Button() code example:

# change the color of the button as the mouse pointer moves over it

import wx

class MyFrame(wx.Frame):
    def __init__(self, parent, title):
        wx.Frame.__init__(self, parent, wx.ID_ANY, title, size=(300, 100))
        # panel needed to size the single button properly
        panel = wx.Panel(self, wx.ID_ANY)

        self.button = wx.Button(panel, wx.ID_ANY, 
            'move the mouse pointer over the button',
            pos=(10, 10), size=(-1, -1))
        self.button.SetBackgroundColour('green')

        # bind mouse events to actions
        self.button.Bind(wx.EVT_ENTER_WINDOW, self.mouse_over)
        self.button.Bind(wx.EVT_LEAVE_WINDOW, self.mouse_not_over)
        self.button.Bind(wx.EVT_BUTTON, self.button_clicked)

    def mouse_over(self, event):
        self.button.SetBackgroundColour( 'yellow')
        #self.button.Refresh()

    def mouse_not_over(self, event):
        self.button.SetBackgroundColour( 'green')
        #self.button.Refresh()
    
    def button_clicked(self, event):
        self.SetTitle("button has been clicked")


app = wx.App(0)
MyFrame(None, 'show mouse-over event').Show()
app.MainLoop()

The wx.ToggleButton() widget changes its value between True and False each time it is clicked:

# testing wxPython's
# wx.ToggleButton(parent, id, label, pos, size, style)

import wx

class MyFrame(wx.Frame):
    def __init__(self, parent, mytitle, mysize):
        wx.Frame.__init__(self, parent, wx.ID_ANY, mytitle, size=mysize)
        # use panel so single button behaves
        panel = wx.Panel(self, wx.ID_ANY)

        self.tbtn = wx.ToggleButton(panel, 1, 'Toggle Off', (20, 25))
        # bind mouse event to an action
        self.tbtn.Bind(wx.EVT_TOGGLEBUTTON, self.onToggle)

    def onToggle(self, event):
        #print self.tbtn.GetValue()  # test True or False
        if self.tbtn.GetValue():
            self.tbtn.SetLabel('Toggle On')
        else:
            self.tbtn.SetLabel('Toggle Off')
        pass


app = wx.App(0)
# create a MyFrame instance and then show the frame
MyFrame(None, 'test the wx.ToggleButton', (300, 100)).Show()
app.MainLoop()

You may never have guessed it, but I do have a passion for colour. Here is another way to present colourful text with wxPython's wx.html.HtmlWindow() widget ...

# using wxPython's wx.html.HtmlWindow() to display
# colourful text via simple html code

import wx
import wx.html

class MyFrame(wx.Frame):
    def __init__(self, parent, title):
        wx.Frame.__init__(self, parent, wx.ID_ANY, title,
            size=(350, 220))

        htmlwin = wx.html.HtmlWindow(self, wx.ID_ANY, style=wx.NO_BORDER)
        htmlwin.SetPage(html_code)


html_code = """\
<HTML>
  <HEAD>
    <TITLE>
      Hello large color
    </TITLE>
  </HEAD>
  <BODY bgcolor="#008000">
    <B>
	  <FONT size="+4">
	  <FONT color="#00ffff">hello world</FONT>
	  <BR>
      <FONT color="#0004bc">bonjour tout le monde</FONT>
	  <BR>
      <FONT color="#f2fd29">hola mundo</FONT>
	  <BR>
      <FONT color="#ff0fb5">ciao a tutti</FONT>
  	  <BR>
      <FONT color="#fca736">hello wereld</FONT>
	  </FONT>
	</B>
  </BODY>
</HTML>
"""

app = wx.App(0)
frame = MyFrame(None, 'Multilingual Hello')
frame.Show(True)
frame.Center()
app.MainLoop()

You can use an xml based resource file to specify widgets for wxPython. Here is an example ...

# use an xml resource file to create widgets
# you can create .xrc files with something like wxGlade
# from: http://wxglade.sourceforge.net/

import  wx
import  wx.xrc  as  xrc

class MyXml(wx.Frame):
    def __init__(self, parent, id, title):
        wx.Frame.__init__(self, parent, id, title, size=(300, 100))
        self.toggle = True

        # load the xml resource file
        # should be in your working folder or use full path
        res = xrc.XmlResource('resource.xrc')

        '''
        # or you can use a resource string directly
        res = xrc.EmptyXmlResource()
        res.LoadFromString(xml_resource)
        '''

        self.panel = res.LoadPanel(self, 'MyPanel')
        print self.panel

        # bind mous click to the button in the resource
        self.Bind(wx.EVT_BUTTON, self.onClick,
            id=xrc.XRCID('ColourButton'))

    def onClick(self, event):
        """do something with the button click"""
        if self.toggle:
            self.panel.SetBackgroundColour('green')
            self.toggle = False
        else:
            self.panel.SetBackgroundColour('red')
            self.toggle = True
        self.panel.Refresh()


# this is an xml resource file
# here a simple panel with one button
xml_resource = """\
<?xml version="1.0" ?>
<resource>
  <object class="wxPanel" name="MyPanel">
   <bg>#E6E6FA</bg>
   <object class="wxButton" name="ColourButton">
    <bg>#F0E68C</bg>
    <label>Click me!</label>
    <pos>15,10</pos>
   </object>
  </object>
</resource>
"""

# for the test save the xml code as resource.xrc
fout = open('resource.xrc', "w")
fout.write(xml_resource)
fout.close()

app = wx.App(0)
MyXml(None, -1, 'xml resource to create widgets').Show()
app.MainLoop()

As you look through the tags of the xml code, you can easily change a few things like bg colour, button label and position. Give it a try.

If you want to display an image, but not attach an image file, you can appropriate one from an internet website you like ...

# display an image from an internet webpage
# using wxPython

import wx
import urllib2
import cStringIO

class ImagePanel(wx.Panel):
    """ create a panel with a wx.StaticBitmap """
    def __init__(self, parent, bmp, image_name):
        wx.Panel.__init__(self, parent, wx.ID_ANY)
        self.SetBackgroundColour('brown')

        # show the static bitmap
        wx.StaticBitmap(self, wx.ID_ANY, bmp, pos=(50, 40))

        # optionally show some image information
        info = "name = %s   image size = %dx%d" % \
            (image_name, bmp.GetWidth(), bmp.GetHeight())
        # the parent is the frame
        parent.SetTitle(info)


# find yourself a picture on a web page you like and then
# right click on the picture, look under properties and copy the URL
# (right click only tested on a Windows machine)
image_url = "http://www.google.com/intl/en/images/logo.gif"

# extract the picture's name (optional)
image_name = image_url.split('/')[-1]

# open the image url and read bytes it into a variable
opener = urllib2.build_opener()
image_bytes = opener.open(image_url).read()

# convert image bytes to data stream
data_stream = cStringIO.StringIO(image_bytes)

app = wx.App(0)
# convert data_stream to a bitmap
bmp = wx.BitmapFromImage(wx.ImageFromStream(data_stream))
# calculate width and height needed to set the frame
# plus a little extra for the border
width = bmp.GetWidth() + 100
height = bmp.GetHeight() + 100
# create window/frame instance
frame = wx.Frame(None, wx.ID_ANY, size=(width, height))
# create the panel instance
ImagePanel(frame, bmp, image_name)
# show the frame
frame.Show(True)
# start the GUI event loop
app.MainLoop()

If you are playing with the pygame module, you may find a few things that pygame can do very well. Well, you can use the pygame module from within a wxPython program. Here is an embryonic example ...

# running Pygame (SDL based) from within wxPython (wxWindow based)
# module pygame is imported in class PG_panel
# pygame is free from: http://www.pygame.org/
# original concept by Riccardo Trocca
# tested with wxPython28, pygame18 on Windows XP

import wx
import os
import thread

class PG_thread(object):
    global pygame
    def __init__(self, screen):
        self.pg_keepgoing = self.pg_running = False
        # pick an image you have (.bmp  .jpg  .png  .gif)
        # if the image file is not in the working folder,
        # use the full pathname like "C:/Images/gifs/Froggy.jpg"
        image_file = "Froggy.jpg"

        # RGB color tuple used by pygame
        black = (0, 0, 0)
        white = (255, 255, 255)
        screen.fill(black)

        # load the image from a file
        image = pygame.image.load(image_file).convert()

        # this will rotate the image using angle and zoom using scale
        # pygame.transform.rotozoom(surface, angle, scale)
        angle = 45.5
        scale = 1.5
        image = pygame.transform.rotozoom(image, angle, scale)

        # draw image, position the image ulc at x=15, y=5
        screen.blit(image, (15, 5))
        # nothing gets displayed until one updates the screen
        pygame.display.flip()

    def start(self):
        self.pg_keepgoing = self.pg_running = True
        thread.start_new_thread(self.run, ())

    def stop(self):
        self.pg_keepgoing = False

    def isRunning(self):
        return self.pg_running

    def run(self):
        """run the pygame event loop"""
        # start event loop and wait until
        # the user clicks on the window corner x
        while self.pg_keepgoing:
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    raise SystemExit


class PG_panel(wx.Panel):
    def __init__(self,parent, mysize):
        # pygame is imported in this class
        # make it globally available
        global pygame
        wx.Panel.__init__(self, parent, wx.ID_ANY, size=mysize)
        #self.Fit()

        # pygame uses SDL, set the environment variables
        os.environ['SDL_WINDOWID'] = str(self.GetHandle())
        os.environ['SDL_VIDEODRIVER'] = 'windib'

        # do the pygame stuff after setting the environment variables
        import pygame
        pygame.display.init()
        # create the pygame window/screen
        screen = pygame.display.set_mode(mysize)
        # start the thread instance
        self.thread = PG_thread(screen)
        self.thread.start()

    def __del__(self):
        self.thread.stop()


class MyFrame(wx.Frame):
    def __init__(self, parent, mytitle, mysize):
        wx.Frame.__init__(self, parent, wx.ID_ANY, mytitle, size=mysize)
        self.pg_panel = PG_panel(self, mysize)


app = wx.App(0)
title = "load a picture, rotate and enlarge it using pygame"
mysize = (450,460)
MyFrame(None, title, mysize).Show()
app.MainLoop()

I played around with the wx.MiniFrame() widget that brings up a simpler frame. To make it do something useful I added the LEDNumberCtrl and made it a digital clock:

# use wxPython's wx.MiniFrame(), wx.gizmos.LEDNumberCtrl() and
# wx.Timer() to create a digital LED 24 hour clock

import wx
import wx.gizmos
import time

class MyMiniFrame(wx.MiniFrame):
    def __init__(self, parent, mytitle, mysize):
        wx.MiniFrame.__init__(self, parent, wx.ID_ANY, mytitle,
            size=mysize, style=wx.DEFAULT_FRAME_STYLE)

        self.led = wx.gizmos.LEDNumberCtrl(self, wx.ID_ANY,
            style=wx.gizmos.LED_ALIGN_CENTER)  #, pos, size, style)
        # default colours are green on black
        self.led.SetBackgroundColour("blue")
        self.led.SetForegroundColour("yellow")
        # start right away
        self.onTimer(None)
        # then let the timer kick in
        self.timer = wx.Timer(self, wx.ID_ANY)
        # update clock digits every second (1000ms)
        self.timer.Start(1000)
        self.Bind(wx.EVT_TIMER, self.onTimer)

    def onTimer(self, event):
        # get current time from your computer
        current = time.localtime(time.time())
        # time string can have characters 0..9, -, period, or space
        ts = time.strftime("%H-%M-%S ", current)
        self.led.SetValue(ts)


app = wx.App(0)
# create a MyMiniFrame instance and then show the frame
mframe = MyMiniFrame(None, 'a digital led clock', (350, 100))
mframe.Show()
app.SetTopWindow(mframe)
app.MainLoop()

This code example uses the wx.lib.scrolledpanel.ScrolledPanel() widget to show off wxPython's list of colours by name, #RRGGBB hexstring, and then a small panel of the actual colour:

# show the colours in wxPython's wx.lib.colourdb
# use a wx.lib.scrolledpanel.ScrolledPanel and wx.GridSizer

import wx
import wx.lib.scrolledpanel
import wx.lib.colourdb

class MyScrolledPanel(wx.lib.scrolledpanel.ScrolledPanel):
    def __init__(self, parent):
        # make the scrolled panel larger than its parent
        wx.lib.scrolledpanel.ScrolledPanel.__init__(self, parent, wx.ID_ANY,
            size=(600, 450), style=wx.TAB_TRAVERSAL|wx.SUNKEN_BORDER)
        # scroll bars won't appear until required
        # default is SetupScrolling(scroll_x=True, scroll_y=True)
        self.SetupScrolling()
        self.SetBackgroundColour("white")

        wx.lib.colourdb.updateColourDB()
        # create a list of all the colours in the colour data base
        #colours = wx.lib.colourdb.getColourList()
        colours = wx.lib.colourdb.getColourInfoList()

        # main sizer
        vsizer = wx.BoxSizer(wx.VERTICAL)

        # wx.GridSizer(rows, cols, vgap, hgap)
        gsizer = wx.GridSizer(len(colours), 3, 2, 2)

        n = 1
        for line in colours:
            #print line,  # eg. line = ('SNOW', 255, 250, 250)
            hexstr = "#%02X%02X%02X" % tuple(line[1:])
            s = "%3d  %s" % (n, line[0])
            t = wx.StaticText(self, wx.ID_ANY, s)
            gsizer.Add(t, 0, wx.ALL, border=2)
            t = wx.StaticText(self, wx.ID_ANY, hexstr)
            gsizer.Add(t, 0, wx.ALL, border=2)
            p = wx.Panel(self, wx.ID_ANY)
            p.SetBackgroundColour(hexstr)
            gsizer.Add(p, 0, wx.ALL|wx.EXPAND, border=2)
            n += 1

        # now add the whole thing to the main sizer and set it
        vsizer.Add(gsizer, 0, wx.ALL|wx.EXPAND, 10)
        self.SetSizer(vsizer)


app = wx.App(0)
# create a frame, no parent, default ID, title, size
caption = "all the colours in wx.lib.colourdb"
frame = wx.Frame(None, wx.ID_ANY, caption, size=(600, 450))
MyScrolledPanel(frame)
frame.Show(True)
app.MainLoop()

An oldy but goody, drawing a simple bar graph using thick lines for the bars. The wxPython canvas created with wx.ClientDC() makes this project look easy:

# a simple bar graph using a thick line
# the wx.ClientDC surface is wxPython's canvas
# use wx.ClientDC() without the wx.PaintEvent

import wx

class MyFrame(wx.Frame):
    def __init__(self, parent, title):
        wx.Frame.__init__(self, parent, wx.ID_ANY, title, size=(360, 320))
        self.SetBackgroundColour('white')

        # data to be graphed
        self.data = [30, 45, 80, 150, 220, 180, 110, 75, 50, 35, 25, 15]
        # call bargraph() 10 ms after the window has been created
        # this small delay is needed
        wx.FutureCall(10, self.bargraph)

    def bargraph(self):
        """draw a simple bar graph"""
        # does not use a wx.PaintEvent
        dc = wx.ClientDC(self)
        # set line colour and thickness (pixels)
        dc.SetPen(wx.Pen('black', 2))
        # DrawLine(x1, y1, x2, y2) from point (x1,y1) to (x2,y2)
        # draw the baseline
        dc.DrawLine(20, 260, 340, 260)

        # set up the bars
        thick = 20
        dc.SetPen(wx.Pen('red', thick))
        delta = thick + 5
        x = 20
        for y in self.data:
            y1 = 255
            y2 = y1 - y
            # draw each bar
            dc.DrawLine(x, y1, x, y2)
            # add values to the top of each bar
            s = str(y)
            dc.DrawText(s, x-8, y2-25)
            x += delta


app = wx.App()
MyFrame(None, 'draw a simple bar graph').Show(True)
app.MainLoop()

Just thought I crash the wxPython coding party to show you one way to make drawings transparent ...

# use wxPython's wx.PaintDC() and wx.GCDC() to
# create transparent shapes, overlap shapes for effect

import wx

class MyPanel(wx.Panel):
    def __init__(self, parent):
        wx.Panel.__init__(self, parent, wx.ID_ANY)
        self.SetBackgroundColour('white')
        self.Bind(wx.EVT_PAINT, self.onPaint)

    def onPaint(self, evt):
        pdc = wx.PaintDC(self)
        pdc.DrawText("A text layer under the rectangles", 90, 80)
        try:
            # gives realistic transparency
            dc = wx.GCDC(pdc)
        except:
            dc = pdc

        # wx.Rect(x, y, w, h)
        # basic rectangle for all rectangles
        rect = wx.Rect(0, 0, 220, 200)

        alpha1 = 250
        alpha2 = 125

        r, g, b = (220, 30, 30)
        pos = (10, 10)
        pencolour = wx.Colour(r, g, b, alpha1)
        brushcolour = wx.Colour(r, g, b, alpha2)
        # the border in this case
        # wx.Pen(colour, width=1, style=wx.SOLID)
        dc.SetPen(wx.Pen(pencolour))
        # the fill in this case
        dc.SetBrush(wx.Brush(brushcolour))
        rect.SetPosition(pos)
        # corners are quarter-circles using a radius of 8
        dc.DrawRoundedRectangleRect(rect, 8)

        r, g, b = (30, 140, 220)   #35)
        pos = (150, 50)
        pencolour = wx.Colour(r, g, b, alpha1)
        brushcolour = wx.Colour(r, g, b, alpha2)
        dc.SetPen(wx.Pen(pencolour))
        dc.SetBrush(wx.Brush(brushcolour))
        rect.SetPosition(pos)
        dc.DrawRoundedRectangleRect(rect, 8)


app = wx.App(0)
caption = "using wx.GCDC() to improve transparency"
frame = wx.Frame(None, wx.ID_ANY, caption, size=(400, 310))
MyPanel(frame)
frame.Show(True)
app.MainLoop()

Zoe's bar graph example made me look a little closer at wx.Pen() -->

# the wx.PaintDC surface is wxPython's drawing canvas
# a closer look at wx.Pen(colour, width=1, style=wx.SOLID)
"""
pen styles:
wx.SOLID
wx.DOT
wx.LONG_DASH
wx.SHORT_DASH
wx.DOT_DASH
wx.TRANSPARENT

SetJoin style options:
wx.JOIN_MITER  --> default
wx.JOIN_BEVEL
wx.JOIN_ROUND

SetCap style options:
wx.CAP_ROUND
wx.CAP_PROJECTING
wx.CAP_BUTT  --> default
"""

import wx

class MyFrame(wx.Frame):
    def __init__(self, parent, title):
        wx.Frame.__init__(self, parent, wx.ID_ANY, title, size=(400, 300))
        self.SetBackgroundColour('white')
        self.Bind(wx.EVT_PAINT, self.on_paint)

    def on_paint(self, event):
        "create the canvas and draw on it"
        dc = wx.PaintDC(self)

        # wx.Pen(colour, width, style)
        # wx.SOLID is actually the default
        pen = wx.Pen('blue', 10, wx.SOLID)

        pen.SetJoin(wx.JOIN_MITER)
        dc.SetPen(pen)
        dc.DrawRectangle(10, 10, 110, 70)
        dc.DrawText('JOIN_MITER', 20, 20)

        pen.SetJoin(wx.JOIN_BEVEL)
        dc.SetPen(pen)
        dc.DrawRectangle(140, 10, 110, 70)
        dc.DrawText('JOIN_BEVEL', 150, 20)

        pen.SetJoin(wx.JOIN_ROUND)
        dc.SetPen(pen)
        dc.DrawRectangle(270, 10, 110, 70)
        dc.DrawText('JOIN_ROUND', 280, 20)

        # comes in handy if you want to use thick lines
        # for instance for a bar graph
        pen.SetCap(wx.CAP_BUTT)
        dc.SetPen(pen)
        dc.DrawLine(30, 150,  150, 150)
        dc.DrawText('CAP_BUTT', 170, 140)

        pen.SetCap(wx.CAP_PROJECTING)
        dc.SetPen(pen)
        dc.DrawLine(30, 190,  150, 190)
        dc.DrawText('CAP_PROJECTING', 170, 180)

        pen.SetCap(wx.CAP_ROUND)
        dc.SetPen(pen)
        dc.DrawLine(30, 230,  150, 230)
        dc.DrawText('CAP_ROUND', 170, 220)

        # base lines
        pen2 = wx.Pen('red')
        dc.SetPen(pen2)
        dc.DrawLine(30, 130, 30, 250)
        dc.DrawLine(150, 130, 150, 250)
        dc.DrawLine(155, 130, 155, 250)


app = wx.App(0)
MyFrame(None, 'wx.Pen() options').Show()
app.MainLoop()

Just some fun with colours, using wxPython's wx.PaintDC() canvas and dc.GradientFillLinear(). Can be used as a gradient background and so on:

# using dc.GradientFillLinear() on a wxPython canvas
# cosmetic but fun

import wx

class MyFrame(wx.Frame):
    def __init__(self, parent, title):
        wx.Frame.__init__(self, parent, wx.ID_ANY, title, size=(300, 300))
        self.SetBackgroundColour('#FFE4C4')   # bisque
        self.Bind(wx.EVT_PAINT, self.on_paint)

    def on_paint(self, event):
        dc = wx.PaintDC(self)

        # wx.Rect(x, y, w, h)
        # basic rectangle for all rectangles
        rect = wx.Rect(0, 0, 250, 50)

        rect.SetPosition((20, 20))
        dc.GradientFillLinear(rect, 'blue', 'white', wx.NORTH)
        dc.DrawText("blue to white going north", 30, 40)
        rect.SetPosition((20, 80))
        dc.GradientFillLinear(rect, 'blue', 'white', wx.SOUTH)
        rect.SetPosition((20, 140))
        dc.GradientFillLinear(rect, 'blue', 'yellow', wx.WEST)
        dc.DrawText("blue to yellow going west", 30, 160)
        rect.SetPosition((20, 200))
        dc.GradientFillLinear(rect, 'blue', 'yellow', wx.EAST)

        # pretty much froms a horizontal line
        rect = wx.Rect(0, 0, 250, 5)
        rect.SetPosition((20, 10))
        dc.GradientFillLinear(rect, 'red', 'green', wx.WEST)
        rect.SetPosition((20, 255))
        dc.GradientFillLinear(rect, 'red', 'green', wx.EAST)


app = wx.App(0)
MyFrame(None, 'dc.GradientFillLinear()').Show()
app.MainLoop()

Amongst other things, you can assign an image to wx.Brush(). Since the image is small, you can include it in the code as a base64 encoded image string. This has been done in previous sample codes in this thread, so here is a closer look at wxPython's canvas brush:

# a closer look at wx.Brush(colour, style=wx.SOLID)
# ene
"""
brush styles:
wx.TRANSPARENT       transparent (no fill)
wx.SOLID             solid (default)
wx.BDIAGONAL_HATCH   backward diagonal hatch
wx.CROSSDIAG_HATCH   cross-diagonal hatch
wx.FDIAGONAL_HATCH   forward diagonal hatch
wx.CROSS_HATCH       cross hatch
wx.HORIZONTAL_HATCH  horizontal hatch
wx.VERTICAL_HATCH    vertical hatch
wx.STIPPLE           stippled using a bitmap
wx.STIPPLE_MASK_OPAQUE  stippled using a bitmap's mask
"""

import wx
# to handle the base64 brush image
import cStringIO
import base64


class MyFrame(wx.Frame):
    def __init__(self, parent, title, data_stream):
        wx.Frame.__init__(self, parent, wx.ID_ANY, title, size=(370, 310))
        self.SetBackgroundColour('white')
        # convert data_stream to bitmap
        self.bmp = wx.BitmapFromImage(wx.ImageFromStream(data_stream))
        self.Bind(wx.EVT_PAINT, self.on_paint)

    def on_paint(self, event):
        # wx.PaintDC() creates a drawing canvas
        dc = wx.PaintDC(self)

        # wx.Brush(colour, style)
        dc.SetBrush(wx.Brush('red', wx.CROSS_HATCH))
        dc.DrawRectangle(10, 15, 90, 60)

        # wx.SOLID is the default style
        dc.SetBrush(wx.Brush('red', wx.SOLID))
        dc.DrawRectangle(130, 15, 90, 60)

        dc.SetBrush(wx.Brush('red', wx.BDIAGONAL_HATCH))
        dc.DrawRectangle(250, 15, 90, 60)

        dc.SetBrush(wx.Brush('red', wx.CROSSDIAG_HATCH))
        dc.DrawRectangle(10, 105, 90, 60)

        dc.SetBrush(wx.Brush('red', wx.FDIAGONAL_HATCH))
        dc.DrawRectangle(130, 105, 90, 60)

        dc.SetBrush(wx.Brush('blue', wx.HORIZONTAL_HATCH))
        dc.DrawRectangle(250, 105, 90, 60)

        dc.SetBrush(wx.Brush('blue', wx.VERTICAL_HATCH))
        dc.DrawRectangle(10, 195, 90, 60)

        dc.DrawRectangle(130, 195, 90, 60)
        dc.SetBrush(wx.Brush('yellow', wx.TRANSPARENT))
        dc.DrawRectangle(150, 205, 90, 60)

        # a way to set up a wall-papered background
        brush_bmp = wx.BrushFromBitmap(self.bmp)
        dc.SetBrush(brush_bmp)
        dc.DrawRectangle(250, 195, 90, 60)


# a base64 encoded image string
Lips_jpg_b64 = '''\
/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAoHBwgHBgoICAgLCgoLDhgQDg0NDh0VFhEYIx8lJCIf
IiEmKzcvJik0KSEiMEExNDk7Pj4+JS5ESUM8SDc9Pjv/2wBDAQoLCw4NDhwQEBw7KCIoOzs7Ozs7
Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozv/wAARCAAgADIDASIA
AhEBAxEB/8QAGwAAAQUBAQAAAAAAAAAAAAAABgADBAUHAQL/xAAvEAABBAAGAQMCBAcAAAAAAAAB
AgMEEQAFBhIhMUETIlEUYUJxkfAVIyQyUoGh/8QAGAEAAwEBAAAAAAAAAAAAAAAABAUGAwL/xAAn
EQABAwIEBQUAAAAAAAAAAAABAAIDBBEFEzFBEiFRgdEiMmFxkf/aAAwDAQACEQMRAD8AMsUWaapY
iPuQ4jLkmUkhNpSS2hRvhRHPABNAeK+ajap1KzBSrL48hTcoqAdUlJHpoNE+7wSD2Aa/OsZ29MbS
N7jh3klSlLPf75/XAk05B4WKgw7DGPbnVHIbDTv9ItXrDMg26oy4u5S1BpDTR4TsUAqyDQ3AEAiy
e6Haka1zVxCAgRoyHUinUIKyhQ4N3x2LqiQFDs9ikJv+JV6eYZdGQeSuXLQ2Oz+G918fH3+Lso+l
80zFt9zK5mUziwfciNLKlXzXgDmjV1eMRnpi52GAgWBt8eNUTRdXy47rYmttymFBe1cdshxaUi/U
omqPN9VSuttYLI0lmZHRIjuBxpwWlQ84yKY1OyOWhE9kRZC+Wj6oJBSRyCkmj+/vi40zqZOVvIZd
IRDWv+YEoKuard3fYHXdn7Y7jmc02eh6vDoJ4zJS2uNhv26rScLHELQ4hLjagtCgClSTYI+RhYOU
togXWejlSXnc0g/ULU6pIcYZHR6KwAefFiibJN4DY2SZdIoSJL/CLKlELCiLPHIrigO+cbbgXzHQ
eXyXC5AdVAUpVrSlO9B7JpJIo8jo0AOsDSRO1YU7oq6CwZVNvbQ+RuqaBkkKJAMZGpHWGNhWCm0A
fhse/aU7lC/J2kA3uxEcykMPlpvUTqpbzIk0g+xS9vAK9/Bof3GuCP8ATUnSOfxC7/RB9CE36jLi
VBXFmkkhR+OvyxEZyTN5DqWm8qmBSrre0W0jj/JQAH64FIkGyeMdRuFxILdk9munMpkMvTF5yZr5
JAWUkKWQKAsnkUPnik8HcDiHluQJl5u1Bhypcpt1O5ajSfTBq1H7JNeRfQ7Bxf5foXNJW5U1xEEC
wAacUTxRpJqu/N8decHOX5ZDythTMJn0m1r3qG4qs0BfJPgDG0ccjvdyCX1dbSQg5Pqf1HL9tqvc
GN9Fl8eJv3+g0lvdVbqAF/8AMLD+Fg1TJJJuV//Z
'''

# convert to jpg image bytes
jpg_bytes = base64.b64decode(Lips_jpg_b64)
# convert jpg bytes to data stream
data_stream = cStringIO.StringIO(jpg_bytes)

app = wx.App(0)
MyFrame(None, 'wx.Brush() styles', data_stream).Show()
app.MainLoop()
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.