Tkinter Does Not Suck

96
Tkinter doesn’t suck! Honest! Saturday, 7 November 2009

description

In which I attempt to convince the audience that Tkinter does not, in fact, suck.

Transcript of Tkinter Does Not Suck

Page 1: Tkinter Does Not Suck

Tkinter doesn’t suck!Honest!

Saturday, 7 November 2009

Page 2: Tkinter Does Not Suck

“What GUI toolkit should I use?”

– random poster in random forum

Saturday, 7 November 2009

Page 3: Tkinter Does Not Suck

wxWindows!

Saturday, 7 November 2009

Page 4: Tkinter Does Not Suck

import wx

class Application(wx.Frame): def __init__(self, parent): wx.Frame.__init__(self, parent, -1, 'My GUI', size=(300, 200)) panel = wx.Panel(self) sizer = wx.BoxSizer(wx.VERTICAL) panel.SetSizer(sizer) txt = wx.StaticText(panel, -1, 'Hello, world') sizer.Add(txt, 0, wx.TOP|wx.LEFT, 20) self.Centre() self.Show(True)

app = wx.App(0)Application(None)app.MainLoop()

Saturday, 7 November 2009

Page 5: Tkinter Does Not Suck

pyGTK

Saturday, 7 November 2009

Page 6: Tkinter Does Not Suck

import gtk

window = gtk.Window()label = gtk.Label("Hello, world")window.add(label)window.show_all()gtk.main()

Saturday, 7 November 2009

Page 7: Tkinter Does Not Suck

PyQt!

Saturday, 7 November 2009

Page 8: Tkinter Does Not Suck

import sysimport PyQt4.Qt as qt

a=qt.QApplication(sys.argv)w=qt.QLabel("Hello, world")w.show()a.exec_()

Saturday, 7 November 2009

Page 9: Tkinter Does Not Suck

“whatever you do...

Saturday, 7 November 2009

Page 10: Tkinter Does Not Suck

...don’t use Tkinter!”

Saturday, 7 November 2009

Page 11: Tkinter Does Not Suck

“Tkinter sucks!”

Saturday, 7 November 2009

Page 12: Tkinter Does Not Suck

import Tkinter as tk

root = tk.Tk()tk.Label(root, text="Hello, world").pack()root.mainloop()

Saturday, 7 November 2009

Page 13: Tkinter Does Not Suck

“yeah, OMG, Tkinter sucks!”

Saturday, 7 November 2009

Page 14: Tkinter Does Not Suck

I disagree

Saturday, 7 November 2009

Page 15: Tkinter Does Not Suck

1. it’s simple to use

- rich base widget set- which is not verbose- automatic packing

Saturday, 7 November 2009

Page 16: Tkinter Does Not Suck

2. it’s always there

on Windows & OS X

-- on Linuxes you might need to install an optional package

Saturday, 7 November 2009

Page 17: Tkinter Does Not Suck

3. it’s mature

first release 19918.0 released August 19998.5 released December 2007

Saturday, 7 November 2009

Page 18: Tkinter Does Not Suck

how I discovered thisI had this project that I wanted to be click-to-run, but needed to select a file

Looked for a cross-platform “file dialog” solution and found some hacks

Then I noticed a reference to Tkinter, and lo and behold...

Saturday, 7 November 2009

Page 19: Tkinter Does Not Suck

filename = tkFileDialog.askopenfilename(parent=root, filetypes=[('ReStructuredText Files', '.rst .txt'), ('All Files', '.*')], title='Select your presentation file')

Saturday, 7 November 2009

Page 20: Tkinter Does Not Suck

Saturday, 7 November 2009

Page 21: Tkinter Does Not Suck

well, if it can do that...

what about the program’s command-line options?

Saturday, 7 November 2009

Page 22: Tkinter Does Not Suck

Saturday, 7 November 2009

Page 23: Tkinter Does Not Suck

self.root = tk.Tk()frame = Tk.Frame(self.root)frame.pack()

Tk.Label(frame, text='Bruce, the Presentation Tool!').pack()

self.fullscreen = Tk.IntVar()Tk.Checkbutton(frame, text='Fullscreen?', variable=self.fullscreen).pack() # screen selectiondisplay = pyglet.window.get_platform().get_default_display()N = len(display.get_screens())self.screen = Tk.IntVar(0)if N > 1: for n in range(N): Tk.Radiobutton(frame, text="Display on screen %d"%(n+1), variable=self.screen, value=n).pack()

self.timer = Tk.IntVar()Tk.Checkbutton(frame, text='Show Timer?', variable=self.timer).pack()self.page_count = Tk.IntVar()Tk.Checkbutton(frame, text='Show Page Count?', variable=self.page_count).pack()self.bullet_mode = Tk.IntVar()Tk.Checkbutton(frame, text='Run in Bullet Mode?', variable=self.bullet_mode).pack()self.source = Tk.IntVar()Tk.Checkbutton(frame, text='Display source in console?', variable=self.source).pack()

Tk.Button(frame, text='Play Presentation', command=self.go).pack()

Saturday, 7 November 2009

Page 24: Tkinter Does Not Suck

specific Tkinter gripes

Saturday, 7 November 2009

Page 25: Tkinter Does Not Suck

1. it’s not pretty

Saturday, 7 November 2009

Page 26: Tkinter Does Not Suck

1. it’s not pretty1. it doesn’t look native,2. fonts are not anti-aliased

Saturday, 7 November 2009

Page 27: Tkinter Does Not Suck

2. extending is tricky

Saturday, 7 November 2009

Page 28: Tkinter Does Not Suck

native look and feel(since Tk 8.0, 1999)

Saturday, 7 November 2009

Page 29: Tkinter Does Not Suck

native look and feel(since Tk 8.0, 1999)

(much improved in Tk 8.5, 2008)

Saturday, 7 November 2009

Page 30: Tkinter Does Not Suck

native look and feel(since Tk 8.0, 1999)

(much improved in Tk 8.5, 2008)

(“less ugly but not perfect”)

Saturday, 7 November 2009

Page 31: Tkinter Does Not Suck

Saturday, 7 November 2009

Page 32: Tkinter Does Not Suck

Saturday, 7 November 2009

Page 33: Tkinter Does Not Suck

truetype / opentype fonts

(since Tk 8.5)

Saturday, 7 November 2009

Page 34: Tkinter Does Not Suck

1. Simple to use

Saturday, 7 November 2009

Page 35: Tkinter Does Not Suck

Widgets

Saturday, 7 November 2009

Page 36: Tkinter Does Not Suck

import Tkinter as tk

root = tk.Tk()tk.Label(root, text="Hello, world").pack()root.mainloop()

demo image display

label properties: foreground, background, font, ???

Saturday, 7 November 2009

Page 37: Tkinter Does Not Suck

import Tkinter as tk

root = tk.Tk()tk.Label(root, text="Hello, world").pack()root.mainloop()

No point showing the other three lines in other examples

Saturday, 7 November 2009

Page 38: Tkinter Does Not Suck

from PIL import Image, ImageTkimage = ImageTk.PhotoImage(Image.open('kitten.jpg'))tk.Label(root, image=image).pack()

Saturday, 7 November 2009

Page 39: Tkinter Does Not Suck

def pressed(): print 'You pressed me!'

tk.Button(root, text='Press me!', command=pressed).pack()

Saturday, 7 November 2009

Page 40: Tkinter Does Not Suck

entry = tk.Entry(root)entry.pack()entry.insert(0, 'some text')

Saturday, 7 November 2009

Page 41: Tkinter Does Not Suck

value = tk.IntVar()tk.Checkbutton(root, text='Checked?', variable=value).pack()

Saturday, 7 November 2009

Page 42: Tkinter Does Not Suck

value = tk.IntVar()for n in range(4): tk.Radiobutton(root, value=n text="Selection %d"%(n+1), variable=value).pack()

Saturday, 7 November 2009

Page 43: Tkinter Does Not Suck

value = tk.StringVar(value='One')tk.OptionMenu(root, value, 'One', 'Two', 'Three').pack()

10 minutes

Saturday, 7 November 2009

Page 44: Tkinter Does Not Suck

listbox = tk.Listbox(root)listbox.pack()listbox.insert(tk.END, "a list entry")for item in ‘one two three four’.split(): listbox.insert(tk.END, item)

Saturday, 7 November 2009

Page 45: Tkinter Does Not Suck

text = tk.Text(root)text.pack()text.insert(tk.END, '''some textmore text''')

also allows:- embedding of images and widgets- searching- tagging (identification, useful for properties)- styles

Saturday, 7 November 2009

Page 46: Tkinter Does Not Suck

scale = tk.Scale(root, from_=0, to=100)scale.pack()

Saturday, 7 November 2009

Page 47: Tkinter Does Not Suck

w = tk.Canvas(root, width=200, height=100)w.pack()w.create_line(0, 0, 200, 100)w.create_line(0, 100, 200, 0, fill="red", dash=(4, 4))w.create_rectangle(50, 25, 150, 75, fill="blue")

- line (with arrows), arc, image, oval, polygon, rectangle, text, widgets- outline, fill- scrollable (limitable)- picking (with closest)

Saturday, 7 November 2009

Page 48: Tkinter Does Not Suck

1. Simple to use

Saturday, 7 November 2009

Page 49: Tkinter Does Not Suck

Packing

Saturday, 7 November 2009

Page 50: Tkinter Does Not Suck

rows or columns

the pack manager packs into rows or columns

the default is column, centered.

Saturday, 7 November 2009

Page 51: Tkinter Does Not Suck

in the beginning there is a container, and it is empty

we’re going to pack this container at the default tk.TOP

Saturday, 7 November 2009

Page 52: Tkinter Does Not Suck

pack a button

tk.Button(root, text='Press me!').pack()

Saturday, 7 November 2009

Page 53: Tkinter Does Not Suck

pack a button

tk.Button(root, text='Press me!').pack()tk.Button(root, text='Press me too!').pack()

Saturday, 7 November 2009

Page 54: Tkinter Does Not Suck

pack a button

tk.Button(root, text='Press me!').pack()tk.Button(root, text='Press me too!').pack()tk.Button(root, text='And me!').pack()

Saturday, 7 November 2009

Page 55: Tkinter Does Not Suck

pack on tk.LEFT instead

tk.Button(root, text='Press me!').pack(side=tk.LEFT)tk.Button(root, text='Press me too!').pack(side=tk.LEFT)tk.Button(root, text='And me!').pack(side=tk.LEFT)

Saturday, 7 November 2009

Page 56: Tkinter Does Not Suck

pack on tk.RIGHT instead

tk.Button(root, text='Press me!').pack(side=tk.RIGHT)tk.Button(root, text='Press me too!').pack(side=tk.RIGHT)tk.Button(root, text='And me!').pack(side=tk.RIGHT)

Saturday, 7 November 2009

Page 57: Tkinter Does Not Suck

more complex packing?

Saturday, 7 November 2009

Page 58: Tkinter Does Not Suck

tk.Button(root, text='Press me!').pack()horizontal = tk.Frame(root)horizontal.pack()tk.Button(horizontal, text='Press me too!').pack(side=tk.LEFT)tk.Button(horizontal, text='Press me too!').pack(side=tk.LEFT)

Saturday, 7 November 2009

Page 59: Tkinter Does Not Suck

grids

Saturday, 7 November 2009

Page 60: Tkinter Does Not Suck

tk.Button(root, text='Press me!').grid(row=0, column=0)tk.Message(root, text='Press\nme\ntoo!').grid(row=1, column=0)tk.Button(root, text='And me!').grid(row=1, column=1)

those are tk.CENTER “sticky”

other options are the 9 points of the compass

pack() also allows the sticky side to be specified

see I snuck in the multiline “Message” widget there?

Saturday, 7 November 2009

Page 61: Tkinter Does Not Suck

... or place

Saturday, 7 November 2009

Page 62: Tkinter Does Not Suck

Widget values

Saturday, 7 November 2009

Page 63: Tkinter Does Not Suck

widgets with a variablevariable = tk.IntVar()value = variable.get()variable.set(value)

Saturday, 7 November 2009

Page 64: Tkinter Does Not Suck

text widgetsentry = tk.Entry()value = entry.get()entry.delete(0, tk.END)entry.insert(0, value)

Saturday, 7 November 2009

Page 65: Tkinter Does Not Suck

list boxeslistbox = tk.Listbox(root)listbox.pack()for item in ‘one two three four’.split(): listbox.insert(tk.END, item)selected = list.curselection()

Saturday, 7 November 2009

Page 66: Tkinter Does Not Suck

Styling

Saturday, 7 November 2009

Page 67: Tkinter Does Not Suck

2 methods:1. direct2. themed (py2.6+, py3k+)

Saturday, 7 November 2009

Page 68: Tkinter Does Not Suck

tk.Label(root, text="Hello, world!", background='black', foreground='white', font='Courier').pack()

Saturday, 7 November 2009

Page 69: Tkinter Does Not Suck

tk.Button(root, text="Hello, world!", background='black', foreground='white', font='Courier').pack()

some limitations (sometimes depending on your theme)

Saturday, 7 November 2009

Page 70: Tkinter Does Not Suck

Option 2: Themed

Saturday, 7 November 2009

Page 71: Tkinter Does Not Suck

from [tT]kinter import ttk

lower-case “t” in py3k+

If you want it earlier you can install the tile extension

Saturday, 7 November 2009

Page 72: Tkinter Does Not Suck

complementary

Though the themed widget commands work similarly to the originals, there are important differences.

Themed widgets are not a drop-in replacement.

In particular, themed widgets generally provide less options for customizing their appearance than regular Tk widgets (e.g. they will often not have options like "-background").

Such changes, if needed (and they should be needed much less often) must be done by defining new widget styles, using the facilities offered by the themed widget package.

Saturday, 7 November 2009

Page 73: Tkinter Does Not Suck

Implementsbutton, checkbutton, entry, label, menubutton, radiobutton, scale,

scrollbar, frame, labelframe, panedwindow

Saturday, 7 November 2009

Page 74: Tkinter Does Not Suck

Addedcombobox, notebook, progressbar, separator,

sizegrip

Saturday, 7 November 2009

Page 75: Tkinter Does Not Suck

Not presentcanvas, listbox,

menu, spinbox, text

these aren’t really needed

Saturday, 7 November 2009

Page 76: Tkinter Does Not Suck

“classes” and “styles”>>> from tkinter import ttk>>> l = ttk.Label('hello, world!')>>> l.winfo_class()'TLabel'>>> l['style']''

Saturday, 7 November 2009

Page 77: Tkinter Does Not Suck

layout example (button)

Saturday, 7 November 2009

Page 78: Tkinter Does Not Suck

>>> style = ttk.Style()>>> style.layout('TButton')[("Button.border", {"children": [("Button.focus", {"children": [("Button.spacing", {"children": [("Button.label", {"sticky": "nswe"})], "sticky": "nswe"})], "sticky": "nswe"})], "sticky": "nswe", "border": "1"})]

Saturday, 7 November 2009

Page 79: Tkinter Does Not Suck

element options>>> style = ttk.Style()>>> style.element_options('Button.label')('-compound', '-space', '-text', '-font', '-foreground', '-underline', '-width', '-anchor', '-justify', '-wraplength', '-embossed', '-image', '-stipple', '-background')

Saturday, 7 November 2009

Page 80: Tkinter Does Not Suck

style = ttk.Style()style.configure("Red.TLabel", foreground="red", font="Courier 32")ttk.Label(text="Test Styled", style="Red.TLabel").pack()ttk.Label(text="Test Unstyled").pack()

Saturday, 7 November 2009

Page 81: Tkinter Does Not Suck

switching themesstyle = ttk.Style()current_theme = style.theme_use()new_theme = style.theme_create(...)style.theme_use(new_theme)

Saturday, 7 November 2009

Page 82: Tkinter Does Not Suck

Events

Saturday, 7 November 2009

Page 83: Tkinter Does Not Suck

bind(), unbind()def callback(event): print "clicked at", event.x, event.y

frame = Frame(root, width=100, height=100)frame.bind("<Button-1>", callback)

Saturday, 7 November 2009

Page 84: Tkinter Does Not Suck

<modifier-type-detail>

Saturday, 7 November 2009

Page 85: Tkinter Does Not Suck

mouse event types

mouse button <Button-1>, <Button-2>, <Button-3>

mouse drag <B1-Motion>

mouse release <ButtonRelease-1>, ...

double click <Double-Button-1>, ...

triple click <Triple-Button-1>, ...

mouse entered <Enter>

mouse left <Leave>

Saturday, 7 November 2009

Page 86: Tkinter Does Not Suck

keyboard event types

focus <FocusIn>, <FocusOut>

specific keys <Enter>, <Delete>, <Left>, <Right>, ...

any key <Key>

any text a, b, 1, 2, ...

modified keys <Shift-Up>, <Alt-Enter>, <Control-Tab>, ...

Saturday, 7 November 2009

Page 87: Tkinter Does Not Suck

special event types

configuration <Configure>

The widget changed size (or location, on some platforms). The new size is provided in the width and height attributes of the event object passed to the callback.

Saturday, 7 November 2009

Page 88: Tkinter Does Not Suck

Canvas

w = tk.Canvas(root, width=400, height=300)w.pack()

Saturday, 7 November 2009

Page 89: Tkinter Does Not Suck

w.create_line(0, 0, 400, 300)

Saturday, 7 November 2009

Page 90: Tkinter Does Not Suck

w.create_line(0, 300, 400, 0,fill="red", dash=(4, 4))

Saturday, 7 November 2009

Page 91: Tkinter Does Not Suck

w.create_rectangle(150, 125, 250, 175, outline="green", fill="blue")

specify corders, outline and fill colors

Saturday, 7 November 2009

Page 92: Tkinter Does Not Suck

w.create_arc(50, 50, 200, 200, outline="blue", fill="green")

Saturday, 7 November 2009

Page 93: Tkinter Does Not Suck

w.create_oval(200, 200, 250, 250, outline="blue", fill="green")

Saturday, 7 November 2009

Page 94: Tkinter Does Not Suck

from PIL import Image, ImageTkimage = ImageTk.PhotoImage(Image.open('kitten.jpg'))w.create_image((0, 0), image=image, anchor=tk.NW)

Saturday, 7 November 2009

Page 95: Tkinter Does Not Suck

Tips

Saturday, 7 November 2009

Page 96: Tkinter Does Not Suck

self.attributes('-topmost', True)

Saturday, 7 November 2009