Tkinter Does Not Suck

Preview:

DESCRIPTION

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

Citation preview

Tkinter doesn’t suck!Honest!

Saturday, 7 November 2009

“What GUI toolkit should I use?”

– random poster in random forum

Saturday, 7 November 2009

wxWindows!

Saturday, 7 November 2009

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

pyGTK

Saturday, 7 November 2009

import gtk

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

Saturday, 7 November 2009

PyQt!

Saturday, 7 November 2009

import sysimport PyQt4.Qt as qt

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

Saturday, 7 November 2009

“whatever you do...

Saturday, 7 November 2009

...don’t use Tkinter!”

Saturday, 7 November 2009

“Tkinter sucks!”

Saturday, 7 November 2009

import Tkinter as tk

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

Saturday, 7 November 2009

“yeah, OMG, Tkinter sucks!”

Saturday, 7 November 2009

I disagree

Saturday, 7 November 2009

1. it’s simple to use

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

Saturday, 7 November 2009

2. it’s always there

on Windows & OS X

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

Saturday, 7 November 2009

3. it’s mature

first release 19918.0 released August 19998.5 released December 2007

Saturday, 7 November 2009

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

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

Saturday, 7 November 2009

Saturday, 7 November 2009

well, if it can do that...

what about the program’s command-line options?

Saturday, 7 November 2009

Saturday, 7 November 2009

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

specific Tkinter gripes

Saturday, 7 November 2009

1. it’s not pretty

Saturday, 7 November 2009

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

Saturday, 7 November 2009

2. extending is tricky

Saturday, 7 November 2009

native look and feel(since Tk 8.0, 1999)

Saturday, 7 November 2009

native look and feel(since Tk 8.0, 1999)

(much improved in Tk 8.5, 2008)

Saturday, 7 November 2009

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

Saturday, 7 November 2009

Saturday, 7 November 2009

truetype / opentype fonts

(since Tk 8.5)

Saturday, 7 November 2009

1. Simple to use

Saturday, 7 November 2009

Widgets

Saturday, 7 November 2009

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

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

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

Saturday, 7 November 2009

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

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

Saturday, 7 November 2009

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

Saturday, 7 November 2009

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

Saturday, 7 November 2009

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

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

10 minutes

Saturday, 7 November 2009

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

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

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

Saturday, 7 November 2009

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

1. Simple to use

Saturday, 7 November 2009

Packing

Saturday, 7 November 2009

rows or columns

the pack manager packs into rows or columns

the default is column, centered.

Saturday, 7 November 2009

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

pack a button

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

Saturday, 7 November 2009

pack a button

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

Saturday, 7 November 2009

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

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

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

more complex packing?

Saturday, 7 November 2009

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

grids

Saturday, 7 November 2009

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

... or place

Saturday, 7 November 2009

Widget values

Saturday, 7 November 2009

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

Saturday, 7 November 2009

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

Saturday, 7 November 2009

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

Styling

Saturday, 7 November 2009

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

Saturday, 7 November 2009

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

Saturday, 7 November 2009

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

some limitations (sometimes depending on your theme)

Saturday, 7 November 2009

Option 2: Themed

Saturday, 7 November 2009

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

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

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

scrollbar, frame, labelframe, panedwindow

Saturday, 7 November 2009

Addedcombobox, notebook, progressbar, separator,

sizegrip

Saturday, 7 November 2009

Not presentcanvas, listbox,

menu, spinbox, text

these aren’t really needed

Saturday, 7 November 2009

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

Saturday, 7 November 2009

layout example (button)

Saturday, 7 November 2009

>>> 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

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

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

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

Saturday, 7 November 2009

Events

Saturday, 7 November 2009

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

<modifier-type-detail>

Saturday, 7 November 2009

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

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

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

Canvas

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

Saturday, 7 November 2009

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

Saturday, 7 November 2009

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

Saturday, 7 November 2009

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

specify corders, outline and fill colors

Saturday, 7 November 2009

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

Saturday, 7 November 2009

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

Saturday, 7 November 2009

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

Tips

Saturday, 7 November 2009

self.attributes('-topmost', True)

Saturday, 7 November 2009

Recommended