1.11M Members

Python GUI Programming


Hey Henri, very nice widget tester for Pyside (for PyQt change imports). I just wanted to know if the list box would add a scroll-bar automatically for a long list. It does ...

# test PySide widgets
# load a list box

from PySide.QtCore import *
from PySide.QtGui import *

app = QApplication([])

# ----- start your widget test code ----

# Fnames.txt is a file of names, one each line
with open("Fnames.txt", "r") as fin:
    # remove trailing newline characters
    name_list = [name.strip() for name in fin]

# automatically adds vertical scrollbar for this long list
listbox = QListWidget()


# ---- end of widget test code -----

Attachments FNames.txt (5.59KB)

Some more explorations with Jython ...

view an image with Jython using the Java swing GUI toolkit
get the image from a webpage URL or any image file
tested with jython2.5.2  by  vegaseat

from pawt import swing
from java import net

def view_image(image):
    frame = swing.JFrame("Jython Image Viewer") 
    # allows frame corner x to exit properly
    frame.defaultCloseOperation = swing.JFrame.EXIT_ON_CLOSE
    frame.visible = True
    frame.setSize(500, 688)
    # show the image in a label

# get a URL based image from the internet
# the url was very long so I split it in half
part1 = "http://uploads.neatorama.com/wp-content/"
part2 = "uploads/2011/05/cogtrain-500x688.jpg"
url = part1 + part2
# now that is sweet ...
image = net.URL(url)

I coded the above Jython Image Viewer program with Python27 and PyQt, a little bit more complex ...

view an image with Python using the PyQt GUI toolkit
get the image from a webpage URL or any image file

note: urllib2 has changed in Python3

tested with Python27 and PyQt48

from PyQt4.QtCore import *
from PyQt4.QtGui import *
# Python2
import urllib2

app = QApplication([])
# create the window/frame
win = QWidget()
win.setGeometry(100, 50, 500, 688)
win.setWindowTitle("PyQt Image Viewer")

# get a URL based image from the internet
# the url was very long so I split it in half
part1 = "http://uploads.neatorama.com/wp-content/"
part2 = "uploads/2011/05/cogtrain-500x688.jpg"
url = part1 + part2
picture = urllib2.build_opener().open(url).read()

# save the image as a file
fname = "cogtrain-500x688.jpg"
fout = open(fname, "wb")

# load the picture back in a form PyQt can process
image = QPixmap(fname)

# use a label to display the image in
label = QLabel(win)



To allow for comparisons, here is the URL image viewer using Tkinter and PIL ...

view an image with Python using the Tkinter GUI toolkit
get the image from a webpage URL

note: urllib2 has changed in Python3

tested with Python 2.7 and PIL 1.1.7

import Tkinter as tk
from PIL import ImageTk
# Python2
import urllib2

root = tk.Tk()
root.title("Tkinter URL Image Viewer")

# get a URL based image from the internet
# the url was very long so I split it in half
part1 = "http://uploads.neatorama.com/wp-content/"
part2 = "uploads/2011/05/cogtrain-500x688.jpg"
url = part1 + part2
picture = urllib2.build_opener().open(url).read()

# use PIL to convert to a format Tkinter can handle
image_tk = ImageTk.PhotoImage(data=picture)

# put the image on a typical widget
label = tk.Label(root, image=image_tk)
label.pack(padx=5, pady=5)


The popular plotting module matplotlib works very well within Tkinter ...

embedding module matplotlib in a Tkinter GUI application
tested with Python 2.7 and matplotlib 1.0.1

import matplotlib

from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.backends.backend_tkagg import NavigationToolbar2TkAgg
from matplotlib.figure import Figure
import math
import Tkinter as tk

root = tk.Tk()
root.wm_title("Embedding matplotlib in Tkinter")

fig = Figure(figsize=(6, 5), dpi=100)
myplot = fig.add_subplot(111)

# brew up a simple sample plot
# create a list of floating point numbers
# this will be the x-axis data
float_list = [x/100.0 for x in range(300)]
# now create a list of sine values
# this will be the y-axis data
sine_list = [math.sin(2*math.pi*y) for y in float_list]
# optional labels
myplot.set_ylabel('y = sin(x)')
# then plot the two list's data in red
myplot.plot(float_list, sine_list, 'r')

# create a tk.DrawingArea
canvas = FigureCanvasTkAgg(fig, master=root)
canvas.get_tk_widget().pack(side='top', fill='both', expand=1)

toolbar = NavigationToolbar2TkAgg( canvas, root )
canvas._tkcanvas.pack(side='top', fill='both', expand=1)

Attachments tk_matplot1.jpg 39.44KB

Since we are talking about plotting, often overlooked is VPython, that has quite a nice plotting feature. It is fairly simple to use, here is an example ...

""" vp_plot_bars1.py

use VPython to draw a bar chart

module visual (aka VPython) comes in Windows, Linux and Mac flavors

Windows download website:
pick the download for your version of Python
I used installer VPython-Win-Py2.7-5.41.exe

import visual.graph as vg

# set up the plot display
# if xmax, xmin, ymax, ymin are not specified, 
# then the default is auto scale
myplot = vg.gdisplay(x=80, y=50, width=680, height=350,
    title = 'widgets sold each day',
    ytitle='widgets sold',

draw_bars = vg.gvbars(delta=0.5, color=vg.color.red)

# list of data to be graphed
data = [30, 45, 80, 150, 220, 180, 110, 75, 50, 35, 20, 15, 10, 10]

for day, units in enumerate(data):
    draw_bars.plot(pos=(day+1, units))

You can use the Tkinter Entry() widget to enter a valid function_of_x string, evaluate it with eval(), and then plot it with VPython. Here is an example ...

using Tkinter to get the function of x input for a VPython plot
(console raw_input() does not work with VPython)
you can plot several functions, hence the random curve colors 
tested with Python27  by  vegaseat

import Tkinter as tk
import visual.graph as vg
import random
from math import *

class MyApp(tk.Tk):
    def __init__(self, prompt):
        # the root will be self
        self.title("Tkinter plotting with VPython")
        # set tk window x, y position below visual window
        self.prompt = prompt
        self.v = tk.StringVar()
        # set some initial functionx string
    def visual_plot(self):
        # optionally make curve color random
        color_list = [vg.color.cyan, vg.color.yellow, vg.color.green]
        curve_color = random.choice(color_list)
        curve = vg.gcurve(color=curve_color)
        for x, fx in self.plot_data:
            curve.plot(pos=(x, fx))
    def get_data(self, functionx):
        plot_data = []
        # create a range of x values from 0 to 9 in steps of 0.1
        # this might have to be changed via user entry
        for x in vg.arange(0, 9.1, 0.1):
            # evaluate string function of x
            fx = eval(functionx)
            #print(x, fx)  # test
            plot_data.append((x, fx))
        return plot_data
    def createWidgets(self):
        self.label = tk.Label(self, text=self.prompt)
        self.label.grid(row=0, column=0, padx=10, pady=1)
        self.enter = tk.Entry(self, textvariable=self.v, bg='yellow')
        self.enter.grid(row=1, column=0, padx=10, pady=1)
        self.button = tk.Button(self, text="plot the function of x",
        self.button.grid(row=2, column=0, padx=10, pady=1)

    def action(self):
        # function of x string from entry widget
        functionx = self.v.get()
        self.plot_data = self.get_data(functionx)
        #self['bg'] = 'green'  # test

prompt = """\
Please input a valid mathematical function of x
sin(2*x) * exp(0.5*x)
sqrt(x) + pi"""

app = MyApp(prompt)

PyQt, or in this case PySide, allows you to look at a given web page via PySide.QtWebKit.QWebView() ...

# PySide is the official LGPL-licensed version of PyQT
# You can download and use the Windows self-extracting installer
# PySide-1.0.0qt472.win32-py2.7.exe
# from: http://developer.qt.nokia.com/wiki/PySide_Binaries_Windows
# modified example from:
# http://www.pyside.org/docs/pyside/PySide/QtWebKit/
# tested with pyside472 and Python27
from PySide.QtCore import *
from PySide.QtGui import *
from PySide.QtWebKit import *
# create a Qt application
app = QApplication([])

# create a PySide.QtWebKit.QWebView() to display a web page
# (your computer needs to be connected to the internet)
view = QWebView()
url = "http://qt.nokia.com/"

# run the application event loop

What about an example of using the webbrowser as the frontend? I use some pen-testing suites that use html as the GUI.

Here is an example, kind of ugly since it is just to demonstrate what you can do.
Also, I am no web developer so the html was mostly pulled from w3schools.com.


import socket, webbrowser
#setup our socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
#set socket to reuse address, if you don't you will eventually get
#socket errors with repetitive access
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR,1)
#bind socket to localhost and port 44444

#I am not a web developer and most of this was from
page = """
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

<h1>GUI via web page</h1>

<p>Some examples of using html for a GUI</p>

<li>Element 1</li>
<li>Element 2</li>
<li>So on..</li>
<li>And so on.</li>

<form name="input" action="html_form_action.asp" method="get">
First name: <input type="text" name="firstname" /><br />
Last name: <input type="text" name="lastname" /><br />

Password: <input type="password" name="pwd" /><br />

<input type="radio" name="sex" value="male" /> Male<br />
<input type="radio" name="sex" value="female" /> Female<br />

<input type="checkbox" name="vehicle" value="Bike" /> I have a bike<br />
<input type="checkbox" name="vehicle" value="Car" /> I have a car<br />

Username: <input type="text" name="user" /><br />

<input type="submit" value="Submit" />



car_page = """
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">



I have a car too, it is a Scion tC!



bike_page = """
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">



I don't have a bike....



loggedin_page = """
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">


Logged in

You are now logged in, welcome.



started = 0

while 1:
    #listen for connection
    #check an see if this is the first time running
    #if so, open the default browser to our server
    #not needed, added for convince 
    if started == 0:
        started = 1
        #accept connection and create objects to handle it
        conn, addr = s.accept()
        #get data from browser
        data = conn.recv(10000)
        print data
        #check and see if the browser POSTed data to us
        if "html_form_action.asp?" in data:
            #look for stuff from forms and send appropreate page
            if "Bike" in data:
            elif "Car" in data:
        #close connection so we can get more data if sent

PySide is out for Python32, here is a little test program ...

# explore multiple QFrame() in a QGridLayout()
# also change the color of the frames
# tested with PySide 474 and Python32

from PySide.QtCore import *
from PySide.QtGui import *

class FrameTester(QWidget):
    def __init__(self, title, width, height, parent=None):
        # create the window (this will be instance self)
        QWidget.__init__(self, parent)
        # setGeometry(x_pos, y_pos, width, height)
        self.setGeometry(100, 150, width, height)
    def make_frame(self):
        self.frame1 = QFrame(self)
        self.frame2 = QFrame(self)

        self.frame3 = QFrame(self)
        grid = QGridLayout()
        # addWidget(QWidget, row, column, rowSpan, columnSpan)
        # span 2 rows and 1 column each
        grid.addWidget(self.frame1, 1, 1, 2, 1)
        grid.addWidget(self.frame2, 1, 2, 2, 1)
        # span 1 row and 2 columns
        # note that you occupy row 3 now
        grid.addWidget(self.frame3, 3, 1, 1, 2)
        # put a button on frame1
        self.button = QPushButton("Change colors", self.frame1)
        self.button.resize(150, 30)  # alternate size
        self.button.move(20, 20)
        # bind the button click
    def changeFrameColor(self):
        # color is a string in #RRGGBB format
        red = "#ff0000"
        blue = "#0000ff"
        yellow = "#ffff00"        
        style_str = "QFrame {background-color: %s}"            
        # use style sheet to set background colors of frames
        self.frame1.setStyleSheet(style_str % yellow)
        self.frame2.setStyleSheet(style_str % red)
        self.frame3.setStyleSheet(style_str % blue)        

# create the Qt Application
app = QApplication([])

title = "3 frames in a grid layout"
width = 800
height = 600
tester = FrameTester(title, width, height)

# run the main Qt event loop

A test code for a PySide button with an image and text next to it:

# test PySide widgets
# button with image and text

from PySide.QtCore import *
from PySide.QtGui import *

app = QApplication([])

# ----- start your widget test code ----

# the image file can be a .jpg, .png, ,gif, .bmp image file
# if not in the working directory, give the full path
image_file = "down.gif"
image = QPixmap(image_file)

text = "my down arrow"
# put an image and a text on the button
button = QPushButton(image, text)

# ---- end of widget test code -----

Attachments down.gif 0.59KB

This shows you how simple it is to use PySide to display an image:

# test PySide widgets
# label with an image on it

from PySide.QtCore import *
from PySide.QtGui import *

app = QApplication([])

# ----- start your widget test code ----

# the image file can be a .jpg, .png, ,gif, .bmp image file
# if not in the working directory, give the full path
image_file = "PorscheBoxster.jpg"
image = QPixmap(image_file)

label = QLabel()

# ---- end of widget test code -----

Attachments PorscheBoxster.jpg 30.26KB

Just playing around with PySide and the QT Designer. The example is a popular program that matches words with words on a list as you type. Rewritten using the Designer's XML .ui file and a Python ui-loader program:


example using PySide's QListView and QAbstractListModel
to match a partially typed word to words in a list

the visible GUI part was generated with PySide's Designer
the Designer's XML file was saved as "ps_listview_match2.ui"

it contains a QWidget form with a QLabel, a QLineEdit and
a QListView stacked into a QVBoxLayout()

this program is a simple loader for the .ui XML file and also
does the connection of the widget's signals

PySide is the official LGPL-licensed version of PyQT
I downloaded the 32 bit version for Python 2.7 from:
The Windows self installer is called:
this also installs the Designer program

from PySide.QtCore import *
from PySide.QtGui import *
from PySide.QtUiTools import QUiLoader

class MyWindow():
    def __init__(self, words, *args):
        # create the ui loader
        loader = QUiLoader()
        # and load the form's ui file created by Designer
        self.widget = loader.load("ps_listview_match2.ui")

        # create the label, edit and list objects
        # (for correct names check the .ui file)
        self.label = self.widget.findChild(QLabel, 'label')
        self.edit = self.widget.findChild(QLineEdit, 'lineEdit')
        self.lview = self.widget.findChild(QListView, 'listView')

        # create model objects
        # words is a list of words
        self.lmodel = MyListModel(self.widget, words)

        self.words = words

        # act on the key pressed in edit

    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]

class MyListModel(QAbstractListModel):
    def __init__(self, parent, words, *args):
        QAbstractListModel.__init__(self, parent, *args)
        # words is a list of words
        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 self.words[index.row()]
            return None

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

# just a 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([])
win = MyWindow(state_list)
# run the application event loop

For those of you who are curious, here is the XML code file "ps_listview_match2.ui" the Designer generated:

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <widget class="QWidget" name="Form">
  <property name="geometry">
  <property name="windowTitle">
   <string>Match words with a list</string>
  <widget class="QWidget" name="verticalLayoutWidget">
   <property name="geometry">
   <layout class="QVBoxLayout" name="verticalLayout">
     <widget class="QLabel" name="label">
      <property name="text">
       <string>Start typing to match words in list:</string>
     <widget class="QLineEdit" name="lineEdit"/>
     <widget class="QListView" name="listView"/>

Select multiple items from a Tkinter list box:

# a simple Tkinter Listbox example
# press the shift or ctrl key to select multiple items

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

def get_list():
    function to read the listbox selection(s)
    (mutliple lines can be selected)
    and put the result(s) in a label
    # tuple of line index(es)
    sel = listbox.curselection()
    # get the text, might be multi-line
    seltext = '\n'.join([listbox.get(x) for x in sel])

root = tk.Tk()
# used for label text
label_text = tk.StringVar(root)

# extended mode allows CTRL or SHIFT mouse selections
listbox = tk.Listbox(root, selectmode=tk.EXTENDED)

# click the button to show the selection(s)
button = tk.Button(root, text="Get Selection(s)", command=get_list)

# used to display selection(s)
label = tk.Label(root, textvariable=label_text)

# load some datalines into the listbox
items = ["one", "two", "three", "four", "five", "six"]
for item in items:
    listbox.insert(tk.END, item)

# highlight/preselect line 3 of listbox (starts with zero)
# lb.selection_set(first, last=None) can preselect more than 1 line


Thanks for sharing, only how listbox(3) chooses third if the lines are numbered 0 based as per comment?


You can use PyQT or PySide to do a similar thing:

# explore the PyQT or PySide QListWidget

from PySide.QtCore import *
from PySide.QtGui import *

class MyWindow(QWidget):
    def __init__(self, title, width, height, parent=None):
        # create the window (this will be instance self)
        QWidget.__init__(self, parent)
        # setGeometry(x_pos, y_pos, width, height)
        self.setGeometry(100, 150, width, height)

        # create a test list of characters 'a' to 'z'
        test_list = [chr(p) for p in range(0x0061,  0x007b)]
        # create the listbox and position and size it
        self.listbox = QListWidget(self)
        self.listbox.setGeometry(20, 10, 200, 200)
        # load the listbox with the test list
        # automatically adds vertical scrollbar if list is long
        # now show the listbox
        # new connect style, needs PyQt 4.5+

    def on_select(self):
        """an item in the listbox has been clicked/selected"""
        selected_item = self.listbox.currentItem().text()

# create the Qt Application
app = QApplication([])

title = "select listbox item"
width = 240
height = 220
window = MyWindow(title, width, height)

# run the main Qt event loop

Tkinter is still refreshingly simple to use:

# display GMT time with Tkinter

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

def update_gmt():
    gmt_string.set(time.strftime("%H:%M:%S", time.gmtime()))
    # update every second recursively
    app.after(1000, update_gmt)

def main():
    myfont = ('times', 48, 'bold')
    gmt_label = tk.Label(app, textvariable=gmt_string,
        font=myfont, fg='red', bg='yellow')

app = tk.Tk()

gmt_string = tk.StringVar()



Nice, only to correct after call comment, that is not recursive call, as after setting the timed call the function exits and function is not running until the timer fires the scheduled call.

So, I would call it scheduled call.


A little more involved, and shows how to draw lines on an image with the mouse pointer. The picture is in an earlier post if you want to use it.

draw lines across an image

PySide is the official LGPL-licensed version of PyQT
downloaded and used the Windows self-extracting installer
from: http://developer.qt.nokia.com/wiki/PySide_Binaries_Windows
tested with pyside474 and Python27

from PySide.QtCore import *
from PySide.QtGui import *

class MyQGraphicsView(QGraphicsView):
    def __init__(self,scene, parent=None):
        super(MyQGraphicsView, self).__init__(scene, parent=parent)
        self.parent = parent
        self.scene  = scene
        self.startPunkt = None
        self.endPunkt = None

    def mouseReleaseEvent(self, event):
        if event.button() == Qt.LeftButton:
          self.endPunkt = event.pos()

    def mousePressEvent(self, event):
        if (event.buttons() & Qt.LeftButton):
          self.startPunkt = event.pos()

    def paintme(self):
        if self.endPunkt and self.startPunkt:
            pen = QPen()
            # set pen color
            self.startPunkt = self.mapToScene(QPoint(self.startPunkt.x(),
            self.endPunkt = self.mapToScene(QPoint(self.endPunkt.x(),
            self.startPunkt = None
            self.endPunkt = None

class MainWindow(QMainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()
        self.setWindowTitle('draw lines on an image (click/drag pointer)')
        # setGeometry(x_pos, y_pos, width, height)
        self.setGeometry(100, 100, 800, 500)

    def setup_ui(self):
        self.scene = QGraphicsScene(self)
        self.scene.setSceneRect(0, 0, 800, 500)

        loaded_image = QImage()
        # pick an image file you have in the working folder or give full path
        image_file = "PorscheBoxster.jpg"
        load_error = "%s not found!" % image_file
        if not loaded_image.load(image_file):
        self.image = loaded_image

        self.view = MyQGraphicsView(self.scene, self)

    def paintEvent(self, event):

app = QApplication([])
win = MainWindow()

A little pygame code to show you how to create the effect of soap bubbles floating:

make bubble circles float up the screen

exploring the Python module pygame
pygame free from: http://www.pygame.org/
or: http://www.lfd.uci.edu/~gohlke/pythonlibs/
pygame is available for Python27 or Python32

import pygame as pg
import random

def draw(screen, background, width, height):
    # create a few random values
    x = random.randint(10, width)
    y = random.randint(100, height)
    radius = random.randint(20, 50)
    # random (r, g, b) color, avoid black (0, 0, 0)
    r = random.randint(20, 255)
    g = random.randint(20, 255)
    b = random.randint(20, 255)
    # bubble up until circle center (x, y) reaches top
    while y > 0:
        # draw.circle(Surface, color, pos, radius, width)
        # width of 0 (default) fills the circle
        pg.draw.circle(background, (r, g, b), (x, y), radius, 3)
        y -= 1
        # put the circle on the screen
        screen.blit(background, (0, 0))
        # update screen

def main():
    # create the pg window, give it a caption and bg color
    width = 680
    height = 460
    screen = pg.display.set_mode((width, height))
    pg.display.set_caption(' random bubbles')
    background = pg.Surface(screen.get_size())
    clock = pg.time.Clock()
    # the pg event loop ...
    while True:
        # quit when window corner x is clicked
        # there is a small delay
        for event in pg.event.get():
            if event.type == pg.QUIT:
                raise SystemExit
        draw(screen, background, width, height)
        # use a frame rate of 30 to avoid flickering

if __name__ == "__main__":
Isn't it about time forums rewarded their contributors?

Earn rewards points for helping others. Gain kudos. Cash out. Get better answers yourself.

It's as simple as contributing editorial or replying to discussions labeled or OP Kudos

This is an OP Kudos discussion and contributors may be rewarded
Start New Discussion
View similar articles that have also been tagged: