Another look at PyQT's canvas:

# pqt_drawtext2.py
# playing with PyQT's QPainter
# setPen, setBrush, setFont, drawRect and drawText

import sys
# simpler import
from PyQt4.QtCore import *
from PyQt4.QtGui import *

class DrawText(QWidget):
    def __init__(self, parent=None):
        QWidget.__init__(self, parent)
        # setGeometry(x_pos, y_pos, width, height)
        self.setGeometry(300, 300, 350, 150)
        self.setWindowTitle("Playing with PyQT's QPainter")

    def paintEvent(self, event):
        painter = QPainter()
        painter.begin(self)
        # PyQT has some color constants available
        # give the canvas blue background color
        painter.setBrush(QBrush(QColor("navy")))
        painter.drawRect(event.rect())
        # this will be the text color
        painter.setPen(QColor("orange"))
        # check the fonts available on your computer
        # for instance in C:\WINDOWS\Fonts
        painter.setFont(QFont('Comic Sans MS', 32))
        # drawText (x, y, QString s)
        painter.drawText(45, 90, "Hello World")
        painter.end()


app = QApplication(sys.argv)
dt = DrawText()
dt.show()
app.exec_()

Presenting data in the form of a table that can be sorted by column is slick, and relatively easy to do with PyQT's QTableView widget:

# use PyQT's QTableView and QAbstractTableModel
# to present tabular data (with column sort option)
# tested with Python 3.1 and PyQT 4.5
# Henri

import operator
import sys
from PyQt4.QtCore import *
from PyQt4.QtGui import *

class MyWindow(QWidget):
    def __init__(self, element_list, header, *args):
        QWidget.__init__(self, *args)
        # setGeometry(x_pos, y_pos, width, height)
        self.setGeometry(300, 200, 460, 300)
        self.setWindowTitle("Sorting PyQT's QTableView")

        self.header = header
        self.mydata = element_list
        # create table
        table = self.createTable()

        # use vbox layout
        layout = QVBoxLayout()
        layout.addWidget(table)
        self.setLayout(layout)

    def createTable(self):
        # create table view
        tview = QTableView()
        # set table model
        tmodel = MyTableModel(self, self.mydata, self.header)
        tview.setModel(tmodel)
        # set minimum size of table
        tview.setMinimumSize(450, 300)
        # hide grid
        tview.setShowGrid(False)
        # set font
        font = QFont("Courier New", 8)
        tview.setFont(font)
        # hide vertical header
        vh = tview.verticalHeader()
        vh.setVisible(False)
        # set horizontal header properties
        hh = tview.horizontalHeader()
        hh.setStretchLastSection(True)
        # set column width to fit contents
        tview.resizeColumnsToContents()
        # set all row heights
        nrows = len(self.mydata)
        for row in range(nrows):
            tview.setRowHeight(row, 18)
        # enable sorting
        tview.setSortingEnabled(True)
        return tview

class MyTableModel(QAbstractTableModel):
    def __init__(self, parent, mydata, header, *args):
        """
        mydata is list of tuples
        header is list of strings
        tuple length has to match header length
        """
        QAbstractTableModel.__init__(self, parent, *args)
        self.mydata = mydata
        self.header = header

    def rowCount(self, parent):
        return len(self.mydata)

    def columnCount(self, parent):
        return len(self.mydata[0])

    def data(self, index, role):
        if not index.isValid():
            return QVariant()
        elif role != Qt.DisplayRole:
            return QVariant()
        return QVariant(self.mydata[index.row()][index.column()])

    def headerData(self, col, orientation, role):
        if orientation == Qt.Horizontal and role == Qt.DisplayRole:
            return QVariant(self.header[col])
        return QVariant()

    def sort(self, col, order):
        """sort table by given column number col"""
        self.emit(SIGNAL("layoutAboutToBeChanged()"))
        self.mydata = sorted(self.mydata,
            key=operator.itemgetter(col))
        if order == Qt.DescendingOrder:
            self.mydata.reverse()
        self.emit(SIGNAL("layoutChanged()"))


# the test data is from one of vegaseat's codes
# so if there is a mistake don't blame Henri ...
header = [' Symbol ', ' Name ', ' Atomic Weight ',
    ' Melt (K) ', ' Boil (K) ']
# use numbers for numeric data to sort properly
element_list = [
('H', 'Hydrogen', 1.00794, 13.81, 20.28),
('He', 'Helium', 4.0026, 0.95, 4.216),
('Li', 'Lithium', 6.941, 453.7, 1615),
('Be', 'Beryllium', 9.0122, 1560, 3243),
('B', 'Boron', 10.811, 2365, 4275),
('C', 'Carbon', 12.011, 3825, 5100),
('N', 'Nitrogen', 14.0067, 63.15, 77.344),
('O', 'Oxygen', 15.9994, 54.8, 90.188),
('F', 'Fluorine', 18.9984, 53.65, 85.0),
('Ne', 'Neon', 20.1797, 24.55, 27.1),
('Na', 'Sodium', 22.98977, 371.0, 1156),
('Mg', 'Magnesium', 24.305, 922, 1380),
('Al', 'Aluminum', 26.9815, 933.5, 2740),
('Si', 'Silicon', 28.0855, 1683, 2630),
('P', 'Phosphorus', 30.9737, 317.3, 553),
('S', 'Sulfur', 32.066, 392.2, 717.62),
('Cl', 'Chlorine', 35.4527, 172.17, 239.18),
('Ar', 'Argon', 39.948, 83.95, 87.45),
('K', 'Potassium', 39.0983, 336.8, 1033),
('Ca', 'Calcium', 40.078, 1112, 1757),
('Sc', 'Scandium', 44.9559, 1814, 3109),
('Ti', 'Titanium', 47.88, 1935, 3560),
('V', 'Vanadium', 50.9415, 2136, 3650),
('Cr', 'Chromium', 51.996, 2130, 2945),
('Mn', 'Manganese', 54.938, 1518, 2235),
('Fe', 'Iron', 55.847, 1808, 3023),
('Co', 'Cobalt', 58.9332, 1768, 3143),
('Ni', 'Nickel', 58.6934, 1726, 3005),
('Cu', 'Copper', 63.546, 1356.6, 2840),
('Zn', 'Zinc', 65.39, 682.73, 1180),
('Ga', 'Gallium', 69.723, 302.92, 2478),
('Ge', 'Germanium', 72.61, 1211.5, 3107),
('As', 'Arsenic', 74.9216, 876.4, 876.3),
('Se', 'Selenium', 78.96, 494, 958),
('Br', 'Bromine', 79.904, 265.95, 331.85),
('Kr', 'Krypton', 83.8, 116, 120.85),
('Rb', 'Rubidium', 85.4678, 312.63, 961),
('Sr', 'Strontium', 87.62, 1042, 1655),
('Y', 'Yttrium', 88.9059, 1795, 3611),
('Zr', 'Zirconium', 91.224, 2128, 4683),
('Nb', 'Niobium', 92.9064, 2743, 5015),
('Mo', 'Molybdenum', 95.94, 2896, 4912),
('Tc', 'Technetium', 98, 2477, 4538),
('Ru', 'Ruthenium', 101.07, 2610, 4425),
('Rh', 'Rhodium', 102.9055, 2236, 3970),
('Pd', 'Palladium', 106.42, 1825, 3240),
('Ag', 'Silver', 107.868, 1235.08, 2436),
('Cd', 'Cadmium', 112.41, 594.26, 1040),
('In', 'Indium', 114.82, 429.78, 2350),
('Sn', 'Tin', 118.71, 505.12, 2876),
('Sb', 'Antimony', 121.757, 903.91, 1860),
('Te', 'Tellurium', 127.6, 722.72, 1261),
('I', 'Iodine', 126.9045, 386.7, 457.5),
('Xe', 'Xenon', 131.29, 161.39, 165.1),
('Cs', 'Cesium', 132.9054, 301.54, 944),
('Ba', 'Barium', 137.33, 1002, 2079),
('La', 'Lanthanum', 138.9055, 1191, 3737),
('Ce', 'Cerium', 140.12, 1071, 3715),
('Pr', 'Praseodymium', 140.9077, 1204, 3785),
('Nd', 'Neodymium', 144.24, 1294, 3347),
('Pm', 'Promethium', 145, 1315, 3273),
('Sm', 'Samarium', 150.36, 1347, 2067),
('Eu', 'Europium', 151.965, 1095, 1800),
('Gd', 'Gadolinium', 157.25, 1585, 3545),
('Tb', 'Terbium', 158.9253, 1629, 3500),
('Dy', 'Dysprosium', 162.5, 1685, 2840),
('Ho', 'Holmium', 164.9303, 1747, 2968),
('Er', 'Erbium', 167.26, 1802, 3140),
('Tm', 'Thulium', 168.9342, 1818, 2223),
('Yb', 'Ytterbium', 173.04, 1092, 1469),
('Lu', 'Lutetium', 174.967, 1936, 3668),
('Hf', 'Hafnium', 178.49, 2504, 4875),
('Ta', 'Tantalum', 180.9479, 3293, 5730),
('W', 'Tungsten', 183.85, 3695, 5825),
('Re', 'Rhenium', 186.207, 3455, 5870),
('Os', 'Osmium', 190.2, 3300, 5300),
('Ir', 'Iridium', 192.22, 2720, 4700),
('Pt', 'Platinum', 195.08, 2042.1, 4100),
('Au', 'Gold', 196.9665, 1337.58, 3130),
('Hg', 'Mercury', 200.59, 234.31, 629.88),
('Tl', 'Thallium', 204.383, 577, 1746),
('Pb', 'Lead', 207.2, 600.65, 2023),
('Bi', 'Bismuth', 208.9804, 544.59, 1837),
('Po', 'Polonium', 209, 527, 1235.15),
('At', 'Astatine', 210, 575, 610),
('Rn', 'Radon', 222, 202, 211.4),
('Fr', 'Francium', 223, 300, 950),
('Ra', 'Radium', 226.0254, 973, 1413),
('Ac', 'Actinium', 227, 1324, 3470),
('Th', 'Thorium', 232.0381, 2028, 5060),
('Pa', 'Proctactinium', 231.0359, 1845, 4300),
('U', 'Uranium', 238.029, 1408, 4407),
('Np', 'Neptunium', 237.0482, 912, 4175),
('Pu', 'Plutonium', 244, 913, 3505),
('Am', 'Americium', 243, 1449, 2880),
]

app = QApplication(sys.argv)
win = MyWindow(element_list, header)
win.show()
sys.exit(app.exec_())

Editor's Note:
With the advent of PyQT 4.6 the use of QVariant() should be avoided. So replace
return QVariant() with return None
return QVariant(self.header[col]) with return self.header[col]
and so on.

Exploring PyQT's QListView and QAbstractListModel. This little code pops up posssible words from word list as you type:

# using PyQT's QListView and QAbstractListModel
# to match partially typed word to words in list
# make matching case insensitive
# tested with Python 3.1 and PyQT 4.5
# Henri

import sys
from PyQt4.QtCore import *
from PyQt4.QtGui import *

class MyWindow(QWidget):
    def __init__(self, words, *args):
        QWidget.__init__(self, *args)
        # setGeometry(x_pos, y_pos, width, height)
        self.setGeometry(300, 300, 320, 250)
        self.setWindowTitle("Match words with PyQT's QListView")
        self.words = words

        # create objects
        self.label = QLabel("Start typing to match words in list:")
        #self.edit = MyLineEdit()
        self.edit = QLineEdit()
        self.lmodel = MyListModel(self, self.words)
        self.lview = QListView()
        self.lview.setModel(self.lmodel)

        # layout
        layout = QVBoxLayout()
        layout.addWidget(self.label)
        layout.addWidget(self.edit)
        layout.addWidget(self.lview)
        self.setLayout(layout)

        # one key has been pressed in edit
        self.connect(self.edit, SIGNAL("textChanged(QString)"),
                     self.update)

    def update(self):
        """
        updates the list of possible completions each time key
        is pressed, use lower() to make things case insensitive
        """
        p = str(self.edit.text()).lower()
        new_list = [w for w in self.words if w.lower().find(p)==0]
        self.lmodel.setAllData(new_list)


class MyListModel(QAbstractListModel):
    def __init__(self, parent, words, *args):
        """
        words is list of words
        """
        QAbstractListModel.__init__(self, parent, *args)
        self.words = words

    def rowCount(self, parent=QModelIndex()):
        return len(self.words)

    def data(self, index, role):
        if index.isValid() and role == Qt.DisplayRole:
            return QVariant(self.words[index.row()])
        else:
            return QVariant()

    def setAllData(self, new_list):
        """replace old list with new list"""
        self.words = new_list
        self.reset()


# this is just test list of words
state_list = [
'Mississippi', 'Oklahoma', 'Delaware', 'Minnesota',
'Arkansas', 'New Mexico', 'Indiana', 'Louisiana',
'Texas', 'Wisconsin', 'Kansas', 'Connecticut',
'California', 'West Virginia', 'Georgia', 'North Dakota',
'Pennsylvania', 'Alaska', 'Missouri', 'South Dakota',
'Colorado', 'New Jersey', 'Washington', 'New York',
'Nevada', 'Maryland', 'Idaho', 'Wyoming', 'Maine',
'Arizona', 'Iowa', 'Michigan', 'Utah', 'Illinois',
'Virginia', 'Oregon', 'Montana', 'New Hampshire',
'Massachusetts', 'South Carolina', 'Vermont', 'Florida',
'Hawaii', 'Kentucky', 'Rhode Island', 'Nebraska',
'Ohio', 'Alabama', 'North Carolina', 'Tennessee'
]

app = QApplication(sys.argv)
win = MyWindow(state_list)
win.show()
sys.exit(app.exec_())

Editor's Note:
With the advent of PyQT 4.6 the use of QVariant() should be avoided. So replace
return QVariant() with return None
return QVariant(self.words[index.row()]) with return self.words[index.row()]
and so on.

One more simple way to present data in table form:

# use PyQT's QTableWidget, QTableWidgetItem and setItem
# to show data in simple table format
# tested with Python 3.1 and PyQT 4.5
# Henri

import sys
# simplified import
from PyQt4.QtCore import *
from PyQt4.QtGui import *

class MyTable(QTableWidget):
    def __init__(self, data, rows, cols):
        QTableWidget.__init__(self, rows, cols)
        # setGeometry(x_pos, y_pos, width, height)
        self.setGeometry(300, 200, 280, 180)
        self.setWindowTitle("Simple QTableWidget")
        self.data = data
        self.set_data()

    def set_data(self):
        """self.data is list of (fname, sname, age) tuples"""
        row = 0
        for tup in self.data:
            col = 0
            for item in tup:
                newitem = QTableWidgetItem(item)
                self.setItem(row, col, newitem)
                col += 1
            row += 1


# fname, sname, age raw data for instance from file
staff = """\
Frank, Marco, 27
Henri, Poulong, 34
Gisela, Lang, 19
Lance, Handy, 46"""

# create list of (fname, sname, age) tuples
data = []
for line in staff.split('\n'):
    fname, sname, age = line.split(',')
    data.append((fname.strip(), sname.strip(), age.strip()))

app = QApplication(sys.argv)
rows = 5
cols = 3
table = MyTable(data, rows, cols)
table.show()
sys.exit(app.exec_())

Some options with a basic Tkinter window:

# set position and size of a Tkinter window

try:
    # for Python2
    import Tkinter as tk
except ImportError:
    # for Python3
    import tkinter as tk

#root = tk.Tk()
root = tk.Tk(className="My Title")  # sets title too
# or give it your title this way
#root.title("My Title")

w = 300
h = 200
x = 50
y = 100
# use width x height + x_offset + y_offset (no spaces!)
root.geometry("%dx%d+%d+%d" % (w, h, x, y))

# make Tk window not resizable, also disables the maximize button
#root.resizable(width=FALSE, height=FALSE)
# or ...
#root.resizable(0, 0)

# or make root window full screen
#root.state('zoomed')

# give it a colorful frame
frame = tk.Frame(root, bg='green')
frame.pack(fill='both', expand='yes')

root.mainloop()

For those of you who want experience vegaseat's sweet Tinter tkk example at:
http://www.daniweb.com/forums/post921416-25.html
on your Linux machines, in my case Ubuntu (Python 3.1 is not in the repository yet), here is an easy installation of Python 3.1:

Download ActivePython-3.1.0.1-linux-x86.tar.gz via
http://downloads.activestate.com/ActivePython/linux/3.1/ActivePython-3.1.0.1-linux-x86.tar.gz
from:
http://www.activestate.com/activepython/python3/

Extract to the Desktop

In the terminal change to the proper directory:

cd ~/Desktop/ActivePython-3.1.0.1-linux-x86/

Then run:

sudo ./install.sh

As install directory I entered something easy like:

/home/dell/python/3.1

The installation takes a short time. Now create a symbolic link:

sudo ln -s /home/dell/python/3.1/bin/python3.1 /usr/local/bin/python3.1

Now you are ready to enjoy Python 3.1

# to run a scripts with Python3.1
# with the Geany IDE you can set 'Build'/'Set Includes and Arguments'
# 'Execute' to python3.1 "%f"

One nice graphical way to select calendar date is with the calendar widget. Here is the PyQT example:

# explore the PyQT QCalendarWidget widget
# tested with Python 3.1 and PyQT 4.5
# Henri

import sys
from PyQt4.QtCore import *
from PyQt4.QtGui import *

class MyCalendar(QWidget):
    def __init__(self, parent=None):
        QWidget.__init__(self, parent)
        # setGeometry(x_pos, y_pos, width, height)
        self.setGeometry(300, 300, 280, 220)
        self.setWindowTitle('Calendar')

        self.calendar = QCalendarWidget(self)
        self.calendar.setGridVisible(True)
        # use absolute layout (x_pos, y_pos) for widgets
        self.calendar.move(20, 20)
        self.connect(self.calendar, SIGNAL('selectionChanged()'),
            self.show_date)

        self.label = QLabel(self)
        self.label.move(120, 180)

        self.label2 = QLabel(self)
        self.label2.setGeometry(85, 200, 150, 20)

        # show initial date
        self.show_date()

    def show_date(self):
        date = self.calendar.selectedDate()
        # to get month/day/year like '8/13/2009' use ...
        s = "%s/%s/%s" % (date.month(), date.day(), date.year())
        self.setWindowTitle(s)  # test
        # date.toPyDate() gives year-month-day like '2009-8-13'
        self.label.setText(str(date.toPyDate()))
        # or you can use Qdate formatted string
        # to show something like 'Thursday August 13 2009'
        s2 = date.toString('dddd MMMM d yyyy')
        self.label2.setText(s2)


app = QApplication(sys.argv)
mc = MyCalendar()
mc.show()
app.exec_()

Quick look at PyQT's QListWidget, commonly called 'list box'. Also shows how to create multiple buttons with the for loop. Here is short example:

# pqt_listbox2.py
# explore PyQT's QListWidget (list box) actions
# tested with Python 3.1 and PyQT 4.5
# Henri

import sys
from PyQt4.QtCore import *
from PyQt4.QtGui import *

class MyFrame(QWidget):
    def __init__(self, coffee_list, parent=None):
        QWidget.__init__(self, parent)
        # setGeometry(x_pos, y_pos, width, height)
        self.setGeometry(100, 150, 420, 150)
        self.setWindowTitle('Things to do with QListWidget')

        self.coffee_list = coffee_list

        self.listbox = QListWidget()
        self.connect(self.listbox, SIGNAL("itemSelectionChanged()"),
            self.on_select)

        # use grid layout to position the widgets
        grid = QGridLayout(self)
        # addWidget(QWidget, row, column, rowSpan, columnSpan)
        grid.addWidget(self.listbox, 0, 0, 7, 2)

        # list of (btn_text, action_method) tuples
        btn_action = [
            ("Load", self.lb_load),
            ("Sort", self.listbox.sortItems),
            ("Move Down", self.lb_down),
            ("Move Up", self.lb_up),
            ("Remove Line", self.lb_remove),
            ("Add Line", self.lb_add),
            ("Edit Line", self.lb_edit)]
        # the standard button is the QPushButton widget
        # create multiple buttons using the for loop
        row = 0
        for text, action in btn_action:
            button = QPushButton(text)
            grid.addWidget(button, row, 2, 1, 1)
            self.connect(button, SIGNAL("clicked()"), action)
            row += 1
        self.setLayout(grid)


    def lb_load(self):
        """list box load"""
        # clear any existing data first
        self.listbox.clear()
        self.listbox.addItems(self.coffee_list)
        # start with first line selected (highlighted)
        self.listbox.setCurrentRow(0)

    def lb_down(self):
        """move selected item down one list box line"""
        row = self.listbox.currentRow()
        if row < self.listbox.count() - 1:
            item = self.listbox.takeItem(row)
            self.listbox.insertItem(row + 1, item)
            self.listbox.setCurrentItem(item)

    def lb_up(self):
        """move selected item up one list box line"""
        row = self.listbox.currentRow()
        if row >= 1:
            item = self.listbox.takeItem(row)
            self.listbox.insertItem(row - 1, item)
            self.listbox.setCurrentItem(item)

    def lb_remove(self):
        """remove selected item from the list box"""
        row = self.listbox.currentRow()
        item = self.listbox.takeItem(row)
        del item

    def lb_add(self):
        """add new line to list box above current line"""
        row = self.listbox.currentRow()
        title = "Add new coffee"
        text, ok = QInputDialog.getText(self, title, title)
        if ok and not text.isEmpty():
            self.listbox.insertItem(row, text)

    def lb_edit(self):
        """edit selected item via popup dialog window"""
        row = self.listbox.currentRow()
        item = self.listbox.item(row)
        if item is not None:
            title = "Edit the Coffee"
            text, ok = QInputDialog.getText(self, title, title,
                             QLineEdit.Normal, item.text())
            if ok and not text.isEmpty():
                item.setText(text)

    def on_select(self):
        """an item in the listbox has been clicked/selected"""
        try:
            selected_name =  self.listbox.selectedItems()[0].text()
            s = "selected = %s" % selected_name
            self.setWindowTitle(s)
        except:
            pass


coffee_list = ['Irish Coffee (Whisky)', 'Brandy Coffee (Brandy)',
'English Coffee (Gin)', 'Calypso Coffee (Kahlua and Rum)',
'Jamaican Coffee (Tia Maria and Rum)', 'Shin Shin Coffee (Rum)',
'Baileys Irish Cream Coffee', "Monk's Coffee (Benedictine)",
'Seville Coffee (Cointreau)', "Witch's Coffee (Strega)",
'Russian Coffee (Vodka)', 'Australian Coffee (Cask Wine/Goon)',
'Corfu Coffee (Koum Quat liquor)', 'Kaffee Fertig (Prune Schnaps)',
'Caffe corretto (grappa)']

app = QApplication(sys.argv)
frame = MyFrame(coffee_list)
frame.show()
sys.exit(app.exec_())

Sometimes it's nice to attach label to entry widget. One way to do this is with class object:

# pqt_EntryLab1.py
# create labeled data entry areas
# tested with Python 3.1 and PyQT 4.5
# Henri

import sys
from PyQt4.QtCore import *
from PyQt4.QtGui import *

class MyFrame(QWidget):
    def __init__(self, parent=None):
        QWidget.__init__(self, parent)
        # setGeometry(x_pos, y_pos, width, height)
        self.setGeometry(100, 150, 300, 150)
        self.setWindowTitle('data entry with attached label')

        # label to the 'left' side is default
        self.e_name = LEditLab(self, "Enter your name:")
        self.e_age = LEditLab(self, "Enter your age: ")
        self.e_job = LEditLab(self, "Enter your job: ")
        # display result 2 different ways, label on top
        self.e_result2 = LEditLab(self, "Result: ", 'top')
        self.e_result = EditLab(self, "Result:", 'top')

        self.b_done = QPushButton("Done")

        # use a grid layout to position the widgets
        # note that the grid is centered on the frame
        grid = QGridLayout(self)
        # addWidget(QWidget, row, column, rowSpan, columnSpan)
        grid.addWidget(self.e_name, 0, 0, 1, 3)
        grid.addWidget(self.e_age, 1, 0, 1, 3)
        grid.addWidget(self.e_job, 2, 0, 1, 3)
        grid.addWidget(self.b_done, 3, 1, 1, 1)
        grid.addWidget(self.e_result2, 4, 0, 1, 3)
        grid.addWidget(self.e_result, 5, 0, 1, 3)
        self.setLayout(grid)

        # connect the button click signal to an action
        self.connect(self.b_done, SIGNAL("clicked()"), self.action)

    def action(self):
        name = self.e_name.text()
        age = self.e_age.text()
        job = self.e_job.text()
        s2 = "%s, %s, %s" % (name, age, job)
        self.e_result2.setText(s2)
        s = "%s\n%s\n%s\n" % (name, age, job)
        self.e_result.setText(s)


class LEditLab(QWidget):
    """label QLineEdit data entry/display to the left or on top"""
    def __init__(self, parent, mytext=QString(), pos='left'):
        QWidget.__init__(self, parent)
        self.label = QLabel(mytext)
        self.edit = QLineEdit()
        label_pos = QBoxLayout.LeftToRight if pos == 'left' \
            else QBoxLayout.TopToBottom
        layout = QBoxLayout(label_pos)
        layout.addWidget(self.label)
        layout.addWidget(self.edit)
        self.setLayout(layout)

    def text(self):
        """create QLineEdit() like method to get text"""
        return self.edit.text()

    def setText(self, text):
        """create QLineEdit() like method to set text"""
        return self.edit.setText(text)


class EditLab(QWidget):
    """label QEdit data entry/display area to the left or on top"""
    def __init__(self, parent, mytext=QString(), pos='left'):
        QWidget.__init__(self, parent)
        self.label = QLabel(mytext)
        self.edit = QTextEdit()
        label_pos = QBoxLayout.LeftToRight if pos == 'left' \
            else QBoxLayout.TopToBottom
        layout = QBoxLayout(label_pos)
        layout.addWidget(self.label)
        layout.addWidget(self.edit)
        self.setLayout(layout)

    def setText(self, text):
        """create QTextEdit() like method to set text"""
        return self.edit.setText(text)

    def getText(self):
        """
        create method to get text
        use better syntax than QTextEdit()
        """
        return self.edit.toPlainText()


app = QApplication(sys.argv)
frame = MyFrame()
frame.show()
sys.exit(app.exec_())

Should work with Python2 versions too.

Exampled code for PyQT's multiline text entry widget:

# pqt_TextEdit1.py
# explore PyQT's QTextEdit multiline text entry box
# click right mouse button in edit area for popup menu
# Henri

import sys
from PyQt4.QtCore import *
from PyQt4.QtGui import *

class MyFrame(QWidget):
    def __init__(self, parent=None):
        QWidget.__init__(self, parent)
        # setGeometry(x_pos, y_pos, width, height)
        self.setGeometry(100, 50, 300, 180)
        self.setWindowTitle('QTextEdit() test')

        self.edit = QTextEdit(self)
        self.edit.append('just some text,\n you can append more')
        self.edit.append('well, here is more!!!')
        self.edit.append('click the right mouse button')
        self.edit.append('to get option popup menu\n')

        self.pbutton = QPushButton(self)
        self.pbutton.setText(' transfer text to label ')

        # label auto-adjusts to multiple lines
        self.label = QLabel(self)
        self.label.setText('label ...')

        # use grid layout manager
        grid = QGridLayout(self)
        # addWidget(QWidget, row, column, rowSpan, columnSpan)
        grid.addWidget(self.pbutton, 0, 0, 1, 1)
        grid.addWidget(self.edit, 1, 0, 1, 2)
        grid.addWidget(self.label, 2, 0, 1, 2)
        self.setLayout(grid)

        # bind the button clicked to action
        self.connect(self.pbutton, SIGNAL("clicked()"), self.action)

    def action(self):
        # get the text from self.edit
        text = self.edit.toPlainText()
        # put the text into self.label
        self.label.setText(text)


app = QApplication(sys.argv)
frame = MyFrame()
frame.show()
sys.exit(app.exec_())

Look at PyQT's progress bar widget and simple timer to drive it:

# pqt_progressbar1.py
# explore PyQT's progress bar and simple timer widgets
# Henri

import sys
from PyQt4.QtCore import *
from PyQt4.QtGui import *

class MyFrame(QWidget):
    def __init__(self, parent=None):
        QWidget.__init__(self, parent)
        # setGeometry(x_pos, y_pos, width, height)
        self.setGeometry(300, 300, 250, 150)
        self.setWindowTitle('QProgressBar')

        self.pbar = QProgressBar(self)
        self.pbar.setGeometry(30, 40, 200, 25)

        self.button = QPushButton('Start', self)
        self.button.setFocusPolicy(Qt.NoFocus)
        # absolute positioning
        self.button.move(40, 80)

        self.connect(self.button, SIGNAL('clicked()'), self.onStart)

        # QBasicTimer is simplified timer
        # use QTimer for more options and control
        self.timer = QBasicTimer()
        self.step = 0;

    def timerEvent(self, event):
        """preset method for timer widget"""
        if self.step >= 100:
            self.timer.stop()
            return
        self.step += 1
        self.pbar.setValue(self.step)

    def onStart(self):
        """toggle button action and label"""
        if self.timer.isActive():
            self.timer.stop()
            self.button.setText('Start')
        else:
            # timer interval of 100 milliseconds
            self.timer.start(100, self)
            self.button.setText('Stop')


app = QApplication(sys.argv)
frame = MyFrame()
frame.show()
app.exec_()

Put PyQT widgets on a color background using canvas:

# pqt_CanvasBackGround1.py
# use PyQT's paintEvent to create full frame canvas
# widgets will use the canvas as background
# Henri

import sys
from PyQt4.QtCore import *
from PyQt4.QtGui import *

class MyFrame(QWidget):
    def __init__(self):
        QWidget.__init__(self)
        # setGeometry(x_pos, y_pos, width, height)
        self.setGeometry(100, 150, 350, 200)
        self.setWindowTitle("paintEvent canvas as background")
        # specify the canvas background color (r, g, b)
        self.plum = QColor(221, 160, 221)

        # create some regular widgets
        # that will use the canvas as background
        btn_red = QPushButton("Red")
        btn_green = QPushButton("Green")
        btn_blue = QPushButton("Blue")
        # the label acts transparent, buttons do not
        label = QLabel(" 1 \n 2 \n 3 \n 4 \n 5 \n 6 \n")

        # use grid layout for the widgets
        grid = QGridLayout()
        # addWidget(widget, row, column, rowSpan=1, columnSpan=1)
        grid.addWidget(btn_red, 0, 0, 1, 1)
        grid.addWidget(btn_green, 0, 1, 1, 1)
        grid.addWidget(btn_blue, 1, 0, 1, 1)
        grid.addWidget(label, 2, 0, 1, 1)
        self.setLayout(grid)

    def paintEvent(self, event):
        """auto-create the painting canvas"""
        painter = QPainter()
        painter.begin(self)
        # use brush for rectangle background
        painter.setBrush(QBrush(self.plum))
        # set recangle to full frame size
        painter.drawRect(event.rect())
        painter.end()


app =  QApplication(sys.argv)
frame = MyFrame()
frame.show()
app.exec_()
commented: great, I have been looking for colors +13

I got inspired by Henri's nice PyQT studies, so here is my small contribution, an "almost IDE" ...

# pqt_RunPyFile2.pyw
# run a given Python script file with a given version of Python
# show the script and the result
# use with Python3 or change line 82 and 83
# tested with Python31 and PyQT45  by  vegaseat   05aug2009

import subprocess
import sys
from PyQt4.QtCore import *
from PyQt4.QtGui import *

class MyWindow(QWidget):
    def __init__(self, python_path, initial_dir, *args):
        QWidget.__init__(self, *args)
        # setGeometry(x_pos, y_pos, width, height)
        self.setGeometry(300, 200, 640, 400)
        s = "Run a Python script file with %s" % python_path
        self.setWindowTitle(s)
        self.python_path = python_path
        self.initial_dir = initial_dir

        self.show_fname = QLineEdit()
        self.show_fname.setToolTip("press enter key")
        self.show_script = QTextEdit()
        self.show_result = QTextEdit()

        # use a vertical boc layout
        layout = QVBoxLayout(self)
        layout.addWidget(self.show_fname)
        layout.addWidget(self.show_script)
        layout.addWidget(self.show_result)
        self.setLayout(layout)

        self.file_dialog()
        self.load_script()

        # press return key in show_fname to start run_command()
        # allows you to add commandline args
        self.connect(self.show_fname, SIGNAL("returnPressed(void)"),
                     self.run_command)

    def run_command(self):
        """use subprocess.Popen to run the command line"""
        py_file = str(self.show_fname.text())
        self.setWindowTitle(py_file)
        py_exe = self.python_path
        option = "-u"
        py_script = py_file
        p = subprocess.Popen([py_exe, option, py_script], 
            bufsize=2048, shell=True, stdin=subprocess.PIPE, 
            stdout=subprocess.PIPE, close_fds=False)
        # write additional args to the external program
        #p.stdin.write("args")
        # allow external program to work
        p.wait()
        result_str = p.stdout.read()
        # the result is a bytearray in Python3
        if type(result_str) != str:
            # decode <class 'bytes'> to string
            result_str = result_str.decode("utf8")
        s = "my result -->\n%s" % result_str
        self.show_result.setText(s)

    def file_dialog(self):
        """get the Python script file's mname"""
        #getOpenFileName (parent, caption, dir, filter, 
        #    selectedFilter, options)
        self.filename = QFileDialog.getOpenFileName(self, 
            'Open file', self.initial_dir, 
            "Python files (*.py *.pyw)")        
        self.show_fname.setText(self.filename)

    def load_script(self):
        # PyQT needs this elaborate process 
        # to deal with loading text ...
        try:
            fh = QFile(self.filename)
            if not fh.open(QIODevice.ReadOnly):
                raise IOError(str(fh.errorString()))
            stream = QTextStream(fh)
            stream.setCodec("UTF-8")
            self.show_script.setPlainText(stream.readAll())
        except IOError as e:  # Python3
        #except IOError, e:  # Python2
            QMessageBox.warning(self, "Load Error",
                    "Failed to load %s: %s" % (self.filename, e))
        finally:
            if fh is not None:
                fh.close()
        

# modify for correct path and Operating System syntax
python_path = "D:/Python31/Python.exe"
initial_dir = "./"

app = QApplication(sys.argv)
win = MyWindow(python_path, initial_dir)
win.show()
sys.exit(app.exec_())

PyGame isn't the only toolkit you can use for animation. If you use Python 3.1 and still wait for PyGame to be available, you can use Tinter for some simple animations:

# Tk_CanvasMove1.py
# explore Tkinter animation via canvas.move()
# Henri

import time
try:
    # for Python2
    import Tkinter as tk
except ImportError:
    # for Python3
    import tkinter as tk

root = tk.Tk()
root.title("canvas.move() test")

canvas = tk.Canvas(root, width=400, height=380)
canvas.pack()

# canvas.create_rectangle(x0, y0, x1, y1, option, ... )
# x0, y0, x1, y1 are corner coordinates of ulc to lrc diagonal
rc1 = canvas.create_rectangle(20, 260, 120, 360,
    outline='white', fill='blue')
rc2 = canvas.create_rectangle(20, 10, 120, 110,
    outline='white', fill='red')

# initial delay to view setting
canvas.update()
time.sleep(0.7)

for x in range(50):
    y = x = 5
    time.sleep(0.025)
    # canvas.move(obj, xAmount, yAmount)
    # objects are rectangles rc1 and rc2
    canvas.move(rc1, x, -y)
    canvas.move(rc2, x, y)
    canvas.update()

time.sleep(0.7)

# reverse move
for x in range(50, 0, -1):
    y = x = -5
    time.sleep(0.025)
    # canvas.move(obj, xAmount, yAmount)
    # objects are rectangles rc1 and rc2
    canvas.move(rc1, x, -y)
    canvas.move(rc2, x, y)
    canvas.update()


root.mainloop()
commented: nicely done +13
commented: yes! +13

In the previous example I meant 'Tkinter' rather than 'Tinter'. This however is PyQT example looking at the tooltip widget and some colored text:

# pqt_tooltip1.py
# exploring PyQT's tooltip and color text (html)
# Henri

import sys
from PyQt4.QtCore import *
from PyQt4.QtGui import *

class Tooltip(QWidget):
    def __init__(self, parent=None):
        QWidget.__init__(self, parent)
        # setGeometry(x_pos, y_pos, width, height)
        self.setGeometry(300, 300, 250, 150)
        self.setWindowTitle('Tooltip')

        btn_hello = QPushButton("Push Button")
        btn_hello.setToolTip('Press <b>me</b> for the greeting')
        self.connect(btn_hello, SIGNAL("clicked()"), self.on_click)

        self.label = QLabel()

        grid = QGridLayout()
        grid.addWidget(btn_hello, 0, 0, 1, 1)
        grid.addWidget(self.label, 1, 0, 1, 3)
        self.setLayout(grid)


    def on_click(self):
        s = "<font size=6 color='red'>Hello stranger!</font>"
        self.label.setText(s)


app = QApplication(sys.argv)
tooltip = Tooltip()
tooltip.show()
app.exec_()

Retrieve the text from Tkinter Text widget line by line:

# explore the Tkinter Text() widget
# getting text 'line by line' from the widget
# use ctrl+c to copy, ctrl+x to cut selected text,
# ctrl+v to paste, and ctrl+/ to select all
# Henri

try:
    # for Python2
    import Tkinter as tk
except ImportError:
    # for Python3
    import tkinter as tk

def get_text(event):
    """get text widget contents of given line n (firstline=1)"""
    # retrieve the line number from button text
    n = int(event.widget.cget("text"))
    # set up start and end of the line
    start = "%d.0" % n
    end = "%d.end" % n
    # get the line text
    s = text.get(start, end)
    # show it in the label
    label['text'] = s

# test data
mw = """\
Na Sodium 22.98977
Mg Magnesium 24.305
Al Aluminum 26.98154
Si Silicon 28.0855
P Phosphorus 30.97376
S Sulfur 32.066
Cl Chlorine 35.4527
Ar Argon 39.948"""

root = tk.Tk()
root.title('get text line by line')

# text field, width=width chars, height=lines text
text = tk.Text(root, width=30, height=8, bg='yellow')
text.insert('insert', mw)
text.pack(pady=5)

# create buttons to call each line by number
for n, data in enumerate(mw.split('\n')):
    # first line in text is 1
    s = str(n+1)
    btn = tk.Button(root, text=s)
    btn.bind("<Button-1>", get_text)
    btn.pack(side='left', pady=5, padx=2)

# width/height in char size
label = tk.Label(root, text="", width=30, height=2)
label.pack(side='top', pady=5)

root.mainloop()

Here is an example of a scrolled Tkinter canvas to display a series of drawn objects or pictures:

# example of a Tkinter scrolled canvas class
# snee

try:
    # for Python2
    import Tkinter as tk
except ImportError:
    # for Python3
    import tkinter as tk

class ScrolledCanvas(tk.Frame):
    def __init__(self, parent=None, color='brown'):
        tk.Frame.__init__(self, parent)
        self.pack(expand='yes', fill='both')
        self.parent = parent
        
        canvas = tk.Canvas(self, bg=color, relief='sunken')
        #canvas.config(width=300, height=200)
        canvas.config(scrollregion=(0, 0, 300, 1000))
        canvas.config(highlightthickness=0)

        sbar = tk.Scrollbar(self)
        # vertical scrollbar
        sbar.config(command=canvas.yview)
        canvas.config(yscrollcommand=sbar.set)
        sbar.pack(side='right', fill='y')
        canvas.pack(side='left', expand='yes', fill='both')

        # put in some text for testing ...
        for k in range(10):
            s = 'now calling #' + str(k)
            canvas.create_text(150, 50+(k*100), text=s, fill='beige')
        # for testing canvas (x, y)
        canvas.bind('<Double-1>', self.onDoubleClick)
        self.canvas = canvas
        
    def onDoubleClick(self, event):
        """show location (x, y) of double click on canvas"""
        #print( event.x, event.y )
        x = self.canvas.canvasx(event.x)
        y = self.canvas.canvasy(event.y)
        s = "x = %s  y = %s" % (x, y)
        self.parent.title(s)

if __name__ == '__main__':
    root = tk.Tk()
    # use width x height + x_offset + y_offset (no spaces!)
    root.geometry("%dx%d+%d+%d" % (350, 250, 100, 80))
    root.title('testing the scrolled canvas')
    ScrolledCanvas(root).mainloop()

The Tkinter version that comes with the Python 3.1 installation includes expansion module ttk. This module includes a couple of widgets missing from Tkinter, like a tabbed notebook. As usual, actual examples are totally missing from the Python manual, so I give you at least a hint of its use ...

# ttk_notebook1.py
# exploring the Tkinter expansion module ttk notebook
# tested with Python 3.1 and Tkinter 8.5   by  vegaseat

import tkinter as tk
import tkinter.ttk as ttk

root = tk.Tk()
# use width x height + x_offset + y_offset (no spaces!)
root.geometry("%dx%d+%d+%d" % (300, 200, 100, 50))
root.title('test the ttk.Notebook')

nb = ttk.Notebook(root)
nb.pack(fill='both', expand='yes')

# create a child wdget for each page
f1 = tk.Frame(bg='red')
f2 = tk.Frame(bg='blue')
f3 = tk.Frame(bg='green')

# create the pages
nb.add(f1, text='page1')
nb.add(f2, text='page2')
nb.add(f3, text='page3')

# put a button widget on child f1
btn1 = tk.Button(f1, text='button1')
btn1.pack(side='left', anchor='nw', padx=3, pady=5)

root.mainloop()

And here is the combobox, a combination of drop down listbox and entrybox ...

# ttk_combobox2.py
# exploring the Tkinter expansion module ttk combobox
# tested with Python 3.1 and Tkinter 8.5   by  vegaseat

import tkinter as tk
import tkinter.ttk as ttk

def action(event):
    """
    a combo box item has been selected, do some action
    """
    label['bg'] = combo.get()


root = tk.Tk()

# create a label
label = tk.Label(text='select a color', bg='white')

# create the combo box
combo = ttk.Combobox()
combo.bind('<<ComboboxSelected>>', action)

colors = ['red', 'green', 'magenta', 'yellow']
# load the combo box with the colors list
combo['values'] = colors

# set the initial color
combo.set('yellow')
label['bg'] = combo.get()

# pack the widgets vertically in this order
label.pack(fill='both', expand='yes')
combo.pack()

root.mainloop()
commented: finally an actual example +8

Here is a basic template of a window, 2 buttons and a label using the pygtk toolkit:

# a very basic pygtk window template
# with two buttons and one label
# snee

import pygtk
pygtk.require('2.0')
import gtk

class MyWindow(object):
    def __init__(self):
        # type=gtk.WINDOW_TOPLEVEL is default
        self.window = gtk.Window()
        # pygtk needs this
        # attach destroy signal to terminate application properly
        self.window.connect("destroy", lambda w: gtk.main_quit())
        # title bar caption
        self.window.set_title("gtk.Window template")
        # put upper left corner on display coordinates (x, y)
        self.window.move(100, 80)
        # resize(width, height)
        self.window.resize(350, 150)
        
        # create 2 button widgets and a label widget
        button1 = gtk.Button("Button 1")
        # connect mouse click to a callback
        button1.connect("clicked", self.callback, "Tom")
        button2 = gtk.Button("Button 2")
        # connect mouse click to a callback
        button2.connect("clicked", self.callback, "Frank")
        self.label = gtk.Label("Hello!")

        # create a vertical box to pack the widgets into
        box_v = gtk.VBox(False, 0)
        self.window.add(box_v)
        # now pack the widgets into the box (top to bottom order)
        box_v.pack_start(button1, False, False, 0)
        box_v.pack_start(button2, False, False, 0)
        box_v.pack_start(self.label, True, True, 0)

        # now show all the widgets including the window
        button1.show()
        button2.show()
        self.label.show()
        box_v.show()
        self.window.show()

    def callback(self, widget, data=None):
        s = "You clicked %s's button" % data
        self.window.set_title(s)
        if data == "Tom":
            self.label.set_text("Major Tom")
        else:
            self.label.set_text("Major Frank Burns")
        

MyWindow()
gtk.main()

If you have young children at home, or are yourself a young child at heart, there is a delightful Python module called frog, that does turtle like drawings and more:

# frog is a somewhat advanced turtle graphics module
# get frog-1.0.1.zip from:
# http://www.zahlenfreund.de/python/frog.html
# see also:
# http://pypi.python.org/pypi/frog/1.0.0
# unzip and copy frog.py into the Python lib folder
# or use it in the working folder
# works with Python2 and Python3

import frog

# pond forms the canvas
pond = frog.Pool()
pond.title = "Watch the frog move and draw"
pond.bgcolor = "lightblue"
# kermit forms the drawing pen
kermit = frog.Frog(pond)
kermit.shape = "frog"
kermit.bodycolor = "green"
# kermit draws a square 
# starts at the center of the pond
for n in range(4):
    kermit.move(100)
    kermit.turn(90)
# turn kermit in the other direction
kermit.turn(180)
for n in range(4):
    kermit.move(100)
    kermit.turn(90)
pond.ready()

Just a little more for the fun of it:

# get frog-1.0.1.zip from:
# http://www.zahlenfreund.de/python/frog.html
# unzip and copy frog.py into the Python lib folder
# or use it in the working folder
# works with Python2 and Python3

import frog

canvas = frog.Pool()
canvas.setbgcolor('green')
# use the default triangle shape
pen = frog.Frog(canvas)
pen.color = "red"
# pen normally starts in the canvas center
# make it jump (no drawing) left and then down
pen.jump(-50)
pen.turn(90)
pen.jump(-25)
pen.turn(270)
# the pen draws a number of 'pentagon shapes' 
# starts at the center and forms a star
for n in range(9):
    pen.move(100)
    pen.turn(80)
canvas.ready()

The Tkinter drawing canvas can be fun. Here are two short programs that can be used by an artist for creative things:

# draw a circle with center (x, y) and fixed radius at
# each mouse (x, y) click point

try:
    # Python2
    import Tkinter as tk
except ImportError:
    # Python3
    import tkinter as tk

def draw_circle(event):
    '''
    draw a circle with given radius and its center
    at the mouse click position
    '''
    x = event.x
    y = event.y
    radius = 40
    # to draw a circle you need to get the upper left
    # and lower right corner coordinates of a square
    rect = get_square(x, y, radius)
    # draw the cicle that fits into the rect/square
    circle = cv.create_oval(rect)

def get_square(x, y, radius):
    '''
    given the center=(x, y) and radius
    calculate the square for a circle to fit into
    return x1, y1, x2, y2 of the square's ulc=(x1, y1) and
    lrc=(x2, y2) diagonal corner coordinates
    '''
    x1 = x - radius
    y1 = y - radius
    x2 = x + radius
    y2 = y + radius
    return x1, y1, x2, y2

# create the basic window, let's call it 'root'
root = tk.Tk()
# only set x=100, y=80 position of root upper left corner
root.geometry("+%d+%d" % (100, 80))
root.title("click the mouse on the green area")

# create a canvas to draw on
cv = tk.Canvas(root, width=600, height=600, bg='green')
# position the canvas
cv.grid()

# respond to the mouse as it is clicked
root.bind("<Button-1>", draw_circle)

# start the event loop
root.mainloop()

Just a little more involved:

# explore Tkinter's tag_bind of a canvas draw object
# draw a 10x10 pattern of circles on a canvas and
# turn each circle red as mouse goes across it

from functools import partial
try:
    # Python2
    import Tkinter as tk
except ImportError:
    # Python3
    import tkinter as tk

def circle_enter(circle, event=None):
    """turn each circle red as mouse goes across it"""
    canvas.itemconfig(circle, fill='red')


root = tk.Tk()
# only set x, y position of root
root.geometry("+%d+%d" % (100, 80))
root.title("Move mouse over circles")

canvas = tk.Canvas(root, width=480, height=460, bg='white')
canvas.pack()

# create a 10x10 pattern of circles evenly spaced on the canvas
circles = []
for x in range(420, 20, -40):
    for y in range(50, 450, 40):
        circle = canvas.create_oval(x+10, y+10, x-10, y-10,
            fill='white', outline='grey', tag='circle')
        circles.append(circle)
        canvas.tag_bind(circle, '<Enter>',
            partial(circle_enter, circle))

root.mainloop()

Inspired by Sneekula's exploration of the Python module frog, I came up with this little frog code (actually frog uses Tkinter under the hood, or should I say under that green skin) ...

# according to Snee get frog-1.0.1.zip from:
# http://www.zahlenfreund.de/python/frog.html
# unzip and copy frog.py into the Python lib folder
# or use it in the working folder
# tested with Python 3.1 on a Windows XP computer

import frog

canvas = frog.Pool()
canvas.title = "module frog draws 2 circles"
canvas.setbgcolor("yellow")
# use the default triangle shape
pen = frog.Frog(canvas)
pen.color = "blue"
# pen normally starts in the canvas center facing right
# pen draws a circle of radius 50 going counterclockwise 
pen.circle(50)

# do some text, something scientific like
# giving the circumference of the blue circle drawn
s = "the blue pen has moved %0.3f pixels" % pen.way
pen.jumpto(-170, 110)
pen.font = "Arial",8,"bold"
pen.write(s)
# jump back to center position
pen.jumpto(0, 0)

pen.color = "red"
# fill this lower circle with green
pen.fillcolor = "green"
pen.fill = True
# this circle goes into the opposite direction
# or clockwise
pen.circle(-50)

# make the pen wait for 1000 milliseconds = 1 second
pen.wait(1000)
pen.shape = "frog"

for k in range(3):
    # use a wave sound file you have
    pen.sing("boing.wav")
    pen.wait(200)

canvas.ready()

I have to admit, frog is a very capable fun module for any age!

Just a basic text editor written with the Tkinter GUI toolkit:

# a very simple Tkinter editor
# shows you how to create a menu and
# use the file dialog to read and write files of text data
# snee

try:
    # Python2
    import Tkinter as tk
    import tkFileDialog as tkfd
except ImportError:
    # Python3
    import tkinter as tk
    import tkinter.filedialog as tkfd

class MyEditor(object):
    def __init__(self, master):
        frame = tk.Frame(master)
        frame.pack()
        self.text = tk.Text(bg='white')
        self.text.pack()
        
        menu = tk.Menu(master)
        root.config(menu=menu)
        # file menu
        filemenu = tk.Menu(menu, tearoff=0)
        menu.add_cascade(label="File", menu=filemenu)
        filemenu.add_command(label="New", command=self.new_text)
        filemenu.add_command(label="Open", command=self.file_open)
        filemenu.add_command(label="SaveAs", command=self.file_saveas)
        filemenu.add_separator()
        filemenu.add_command(label="Exit", command=self.do_exit)
        
        # start with cursor in the editor area
        self.text.focus()
        
    def new_text(self):
        """clear the text area so you can start new text"""
        self.text.delete(0.0, 'end')
    
    def file_open(self):
        """open a file to read"""
        # the filetype mask (default is all files)
        mask = \
        [("Text and Python files","*.txt *.py *.pyw"),
        ("HTML files","*.htm *.html"),
        ("All files","*.*")]
        fin = tkfd.askopenfile(filetypes=mask, mode='r')
        text = fin.read()
        if text != None:
            # delete any old text first
            self.text.delete(0.0, 'end')
            self.text.insert('end', text)

    def file_saveas(self):
        """get a filename and save your text to it"""
        # default extension is optional, will add .txt if missing
        fout = tkfd.asksaveasfile(mode='w', defaultextension=".txt")
        text2save = str(self.text.get(0.0, 'end'))
        fout.write(text2save)
        fout.close()

    def do_exit(self):
        root.destroy()

root = tk.Tk()
# use width x height + x_offset + y_offset (no spaces!)
root.geometry("%dx%d+%d+%d" % (500, 300, 120, 80))
root.title("my very simple editor")
myed = MyEditor(root)
root.mainloop()

A nice template you make improvements on.

Just another look at the PyQT canvas, this time we fill it with a colorful radial gradient ...

# pqt_canvasgradient2.py
# use PyQT's paintEvent to create a full frame canvas
# with a radial color gradient, works best with a square
# tested with Python 3.1 and PyQT 4.5  by  vegaseat

import sys
from PyQt4.QtCore import *
from PyQt4.QtGui import *

class MyFrame(QWidget):
    def __init__(self):
        QWidget.__init__(self)
        # setGeometry(x_pos, y_pos, width, height)
        self.setGeometry(100, 150, 350, 350)
        self.setWindowTitle("paintEvent creates a canvas")

        # color tuple (red, green, blue), values are 0 to 255
        self.red = QColor(255, 0, 0)
        self.blue = QColor(0, 0, 255)

    def paintEvent(self, event):
        """auto-create the painting canvas"""
        # needed by QRadialGradient widget
        outer = self.width()//2
        self.set_gradient(outer)

        painter = QPainter()
        painter.begin(self)
        # use the brush for background
        painter.setBrush(QBrush(self.gradient))
        painter.drawRect(event.rect())
        painter.end()

    def set_gradient(self, outer):
        """gradient radiates from center point on out"""
        center = QPointF(outer, outer)
        # (QPointF center, float radius, QPointF focalPoint)
        self.gradient = QRadialGradient(center, outer, center)
        # (float pos, QColor color), pos min 0.0 to max 1.0
        self.gradient.setColorAt(0.2, self.red)
        self.gradient.setColorAt(1.0, self.blue)


app =  QApplication(sys.argv)
frame = MyFrame()
frame.show()
app.exec_()

This small code shows how to change the Tkinter button color when the button is pressed ...

# change Tkinter button color when pressed

try:
    # Python2
    import Tkinter as tk
except ImportError:
    # Python3
    import tkinter as tk

def show_pressed(btn): 
    btn.config(activebackground='red') 

  
root = tk.Tk()
# optional color for the root window
root.config(bg='beige')
 
btn1 = tk.Button(root, text='Button1', bg='yellow') 

# change button color when pressed, procedure 1
btn1.bind('<ButtonPress-1>', lambda event: show_pressed(btn1))
btn1.pack(side='left', padx=10, pady=5) 

# change button color when pressed, procedure 2 (simpler)
btn2 = tk.Button(root, text='Button2', activebackground='cyan',
        bg='green') 
btn2.pack(padx=10, pady=5) 

root.mainloop()

It's like putting single image on PyGame "liquid canvas" giving an eerie visual effect. Here is short code:

# PyGame liquid effect on single image
# just old PyGame example modified
# module pygame free from: http://www.pygame.org

import pygame as pg
import math

pg.init()
# set width and height of pygame window
w = 600
h = 400
screen = pg.display.set_mode((w, h), pg.HWSURFACE|pg.DOUBLEBUF)
pg.display.set_caption('Animation of single image')

# load image file you have
# if not in the working folder, add full path
image_file = 'PythonHand3.jpg'
bitmap = pg.image.load(image_file)
# double the image size
#bitmap = pg.transform.scale2x(bitmap)

# put image and screen into the same format
if screen.get_bitsize() == 8:
    screen.set_palette(bitmap.get_palette())
else:
    bitmap = bitmap.convert()

increment = 0.0
x_list = range(0, w, 10)
y_list = range(0, h, 10)
while True:
    for event in pg.event.get():
        if event.type == pg.QUIT:
            raise SystemExit
    increment += 0.08
    for x in x_list:
        xpos = (x + (math.sin(increment + x*0.01)*15)) + 20
        for y in y_list:
            ypos = (y + (math.sin(increment + y*0.01)*15)) + 20
            screen.blit(bitmap, (x, y), (xpos, ypos, 20, 20))
    pg.display.flip()

An enlightening look at Tkinter's grid layout manager:

# looking at the Tkinter grid() layout manager
#
# The size of a grid cell in a given row or column is
# determined by its largest widget.
#
# If you give a grid layout more space than it needs,
# it will fill this space from its center on out.
# A way around this is to use place() with a frame and
# then grid() within this frame.
#
# Grid does not have an anchor positioner like pack().
#
# You can use place() and grid(), but not pack() and grid()
# within the same container widget.
#
# You can put a child grid into a parent grid.
# Ene

try:
    # Python2
    import Tkinter as tk
except ImportError:
    # Python3
    import tkinter as tk

root = tk.Tk()
root.title('Grid layout')
root['bg'] = 'yellow'

b1 = tk.Button(root, text="Button1")
b2 = tk.Button(root, text="Button2", bg='green')
b3 = tk.Button(root, text="Button3")
b4 = tk.Button(root, text="Button4")
b5 = tk.Button(root, text="Button5")
b6 = tk.Button(root, text="Button6")
b7 = tk.Button(root, text="Button7", bg='blue')
# button b8 has a 3 row text
b8 = tk.Button(root, text="\nButton8\n", bg='red')

b1.grid(row=0, column=1)
# use sticky=tk.E+tk.W or sticky='ew'
b2.grid(row=1, column=0, columnspan=3, sticky='ew')
b3.grid(row=2, column=0, pady=5)
b4.grid(row=2, column=1)
# gives the entire column=2 padx=10 padding!
b5.grid(row=2, column=2, padx=10)
b6.grid(row=3, column=2)
# forces button b7 to take up padded space too
b7.grid(row=4, column=2, ipadx=10)
# button b8 has a 3 row text, so give it rowspan=3
b8.grid(row=5, column=0, rowspan=3, columnspan=3, sticky='ew')

# dictionary of grid info for button b8
print( b8.grid_info() )
# specific info about b8
print( b8.grid_info()['row'] )  # 5

# optional, but interesting
# get the size of the root (root.update is needed!)
root.update()
width = root.winfo_width()  # 158
print(width)
height = root.winfo_height()  # 174
print(height)

root.mainloop()

A quick look at Tkinter's radio and check buttons:

# exploring multiple Tkinter radio buttons
# radio buttons only allow one item to be selected/checked
# ene

try:
    # Python2
    import Tkinter as tk
except ImportError:
    # Python3
    import tkinter as tk

def rb_selected():
    # show checked/selected radio button item
    ix = rb_v.get()
    label['text'] = 'you selected %s' % mylist[ix]

root = tk.Tk()

# used by the radio buttons as index
rb_v  = tk.IntVar()

mylist = [
'apple',
'orange',
'banana',
'pear',
'apricot'
]

# list(range()) needed for Python3
rb = list(range(len(mylist)))
for ix, text in enumerate(mylist):
    # command is optional and responds to any rb changes
    rb[ix] = tk.Radiobutton(root, text=text, value=ix,
        variable=rb_v, command=rb_selected)
    rb[ix].grid(row=ix, column=0, sticky='w')

label = tk.Label(root, width=20)
label.grid(row=ix+1, column=0, pady=5, sticky='w')

# you can preset one radio button
# default is first button (ix=0)
rb_v.set(2)
# show initial selection
rb_selected()

root.mainloop()
# exploring multiple Tkinter check buttons
# check buttons allow more than one item to be selected/checked
# ene

try:
    # Python2
    import Tkinter as tk
except ImportError:
    # Python3
    import tkinter as tk

def cb_checked():
    # show checked check button item(s)
    label['text'] = ''
    for ix, item in enumerate(cb):
        if cb_v[ix].get():
            label['text'] += '%s is checked' % item['text'] + '\n'


root = tk.Tk()

mylist = [
'apple',
'orange',
'banana',
'pear',
'apricot'
]

# list(range()) needed for Python3
cb = list(range(len(mylist)))
cb_v = list(range(len(mylist)))
for ix, text in enumerate(mylist):
    # IntVar() tracks checkbox status (1=checked, 0=unchecked)
    cb_v[ix] = tk.IntVar()
    # command is optional and responds to any cb changes
    cb[ix] = tk.Checkbutton(root, text=text,
        variable=cb_v[ix], command=cb_checked)
    cb[ix].grid(row=ix, column=0, sticky='w')

label = tk.Label(root, width=20)
label.grid(row=ix+1, column=0, sticky='w')

# you can preset check buttons (1=checked, 0=unchecked)
cb_v[3].set(1)
# show initial selection
cb_checked()

root.mainloop()

Editor's note: changed to list(range()) to make it work with Python2 and Python3 upon Ene's request

Adding an item to a PyQT list box is used to take a look at PyQT programming styles ...

# add an item to a PyQT list box with a button click
# shows newer connect style and uses no 'import sys'
# tested with PyQT 4.5.2 and Python 3.1.1

from PyQt4.QtCore import *
from PyQt4.QtGui import *

class MyWindow(QWidget):
    def __init__(self):
        QWidget.__init__(self)
        self.setWindowTitle("click button")
        self.count = 1

        layout = QVBoxLayout(self)
        self.list = QListWidget(self)
        layout.addWidget(self.list)

        s = 'add an item to the list box'
        self.button = QPushButton(s, self)
        layout.addWidget(self.button)

        # old connect style for PyQt < 4.5
        #self.connect(self.button, SIGNAL('clicked()'), self.addItem)
        # new connect style for PyQt 4.5+
        self.button.clicked.connect(self.addItem)

    def addItem(self):
        s = 'Item #%d' % self.count
        self.list.addItem(s)
        self.count += 1


app = QApplication([])
window = MyWindow()
window.show()
app.exec_()

Note:
You may want to be careful with this interim release of PyQT:
PyQt-Py3.1-gpl-4.6rc1-1.exe
It gives me a QVariant() error with some of my code.

Thanks vegaseat for the newer PyQT style info. Here is a relatively simple way to display tabular data using a function to create an html coded table:

# PyQT's QLabel widget can display html formatted text
# used here to display data in a nice table
# tested with Python 3.1.1 and PyQT 4.5.2
# ene

from PyQt4.QtCore import *
from PyQt4.QtGui import *

class MyForm(QWidget):
    def __init__(self, html_table):
        QWidget.__init__(self)
        # setGeometry(x_pos, y_pos, width, height)
        # widget will expand to fit lable size
        self.setGeometry(100, 150, 1, 1)
        self.setWindowTitle("html formatted data table")

        label = QLabel(html_table)

        # use the grid layout manager
        grid = QGridLayout()
        # addWidget(widget, row, column, rowSpan=1, columnSpan=1)
        grid.addWidget(label, 0, 0)
        self.setLayout(grid)


def make_html_table(data_list):
    """
    use a list of data tuples and create the html code
    of a html formatted table containing the data items
    """
    rows = len(data_list)
    columns = len(data_list[0])
    # color is in hex format "#RRGGBB"
    html = '<table border="5" bordercolor="#0000cc" cellspacing="5" '
    html += 'cellpadding="5" width="5" bgcolor="#ffff66">\n'
    for row in range(rows):
        html += '<tr>\n'
        for col in range(columns):
            item = data_list[row][col]
            html += "    %s%s%s\n" % ('<td>', item, '</td>')
        html += '</tr>\n'
    html += '</table>\n'
    return html


# a list of (name, age, weight) tuples
# the first tuple is the header
data_list = [
('Name', 'Age', 'Weight'),
('Heidi Kalumpa', '36', '127'),
('Frank Maruco', '27', '234'),
('Larry Pestraus', '19', '315'),
('Serge Romanowski', '59', '147'),
('Carolus Arm', '94', '102'),
('Michel Sargnagel', '21', '175')
]

html_table = make_html_table(data_list)

#print(html_table)  # for test only

app =  QApplication([])
form = MyForm(html_table)
form.show()
app.exec_()
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.