Simple GUI with Python and TKinter

It would be nice to have a way to build quick-n-dirty GUIs so I can GUI-enable tools when that makes sense… but I’ve always just had a mental block about “going to that length”.

Yesterday though, I was flipping through Python in a Nutshell and I saw a GUI example there (p. 329) that was so simple I typed it in and tried it out :

import sys, Tkinter
Tkinter.Label(text="Welcome!").pack()
Tkinter.Button(text="Exit", command=sys.exit).pack()
Tkinter.mainloop()

That yields a simple little dialog:

hellotk-1

…that can be resized:

hellotk-2

I need to try some more of this!

playcd

Here is a simple CD player/pauser written in Python:

# Playcd.py - Play or pause an audio CD
# Author: Daniel S. Meyer
# Version 0.1
#
# Usage: python playcd.py
# (On Windows you can create a shortcut whose target is for example 
# C:\installs\python\python.exe c:\bin\playcd.py , and place it on
# your Windows desktop.  Then you can assign a shortcut key (say, 
# Ctrl+Alt+P) to that shortcut.  Now you can play and pause your
# CD by pressing the key combination.)
#
# TODOs: 
# - When saving the state, also save the list 
#   of tracks (or at least the number of tracks) so
#   we can detect if the CD is changed and not "resume"
#   in the middle of a different CD.
# - Add options for next/previous tracks
# - Detect if a track is an audio track before attempting to play it
# - Support playing a device other than the first one
# 

import pygame,os

def get_state_file_name():
    return os.environ['TEMP']+'/playcd-state.tmp'

pygame.cdrom.init()
cd0 = pygame.cdrom.CD(0)
cd0.init()
if cd0.get_busy():
    # Currently playing: pause it
    cd0.pause()

    # Save our state for later resume
    cdstate = open(get_state_file_name(),'w')
    cdstate.write(str(cd0.get_current()[0]) + '\n') # current track
    cdstate.write(str(cd0.get_current()[1])) # position within track
    cdstate.close()
else:
    # Not currently playing: try to resume from saved state
    try:
      cdstate = open(get_state_file_name(), 'r')
      curtrack = int(cdstate.readline())
      pos = float(cdstate.readline())
      cdstate.close()
      os.remove(get_state_file_name())
    except:
      # If anything goes wrong restoring our state,
      # just start playing at the beginning
      curtrack = 0
      pos = 0

    cd0.play(curtrack,pos,None)

    # Work around bug where only first track plays
    cd0.pause()
    cd0.resume()

cd0.quit()
pygame.cdrom.quit()

I set up the shortcut and shortcut key as described in the comments. Now I can play or pause an audio CD by pressing Ctrl+P.

(‘Course, I could have avoided this whole issue by getting a multimedia keyboard that has play and pause buttons on it… but then how would I learn Python? ;)

Link getter

As I learn Python, I’m writing some little helper scripts.  Here’s the latest, a script that prints all the .mp3 links referenced by a page (or pages) to standard output:

# mp3s.py
#
# Purpose: display all .mp3 links in the pages
#   pointed to by the given URLs
#
# Usage: python mp3s.py url [url2 [url3...]]
#
# Author: Daniel Meyer
# Date: Oct 20, 2009
import sys
import urllib2
from HTMLParser import HTMLParser

class LinkFinder(HTMLParser):
  def __init__(self):
    HTMLParser.__init__(self)
    self.links = []

  def handle_starttag(self, tag, attrs):
    if tag == 'a':
      for attr, value in attrs:
        if attr == 'href':
          self.links.append(value)

for url in sys.argv[1:] :
  page = urllib2.urlopen(url)
  linkFinder = LinkFinder()
  linkFinder.feed(page.read())
  linkFinder.close()

  for link in linkFinder.links:
    if link.find('.mp3') != -1:
      print link

Notice lines 15-17, which were required to initialize the links data member (since while still calling the base class constructor.

I’ve found this type of thing helpful when preparing to download conference audio where there are several individual mp3 links – I can then pipe the output through xargs to wget to download ’em:

python mp3s.py http://www.t4g.org/conference/t4g-2006/ | xargs wget