Python Tkinter scripts
(August 2005)

Table of contents

A scrolled canvas

A dialog window for renaming many digital pictures

A scrolled canvas

This script has been tested with Python 2.3.3 on a Linux operating system.

Main features:
Here is the python script:
#!/usr/bin/python

from Tkinter import *

class display(Frame) :
	def __init__(self, parent, **options) :
		Frame.__init__(self, parent, options)

		# creation of internal widgets (scrollbars, canvas)
		self.xscrollbar = Scrollbar(self, orient=HORIZONTAL)
		self.yscrollbar = Scrollbar(self)
		self.canvas = Canvas(self, background="#888")

		# connect srollbars
		self.canvas.config(
			xscrollcommand = self.xscrollbar.set,
			yscrollcommand = self.yscrollbar.set )
		self.xscrollbar.config(command=self.canvas.xview)
		self.yscrollbar.config(command=self.canvas.yview)
		self.items = []
		self.max_item_width = 0
		self.max_item_height = 0

		self.bind("<Configure>", self.resize)
		self.update_idletasks()
		self.draw()

	def resize(self, w) :
		self.draw()

	def add(self, message) :
		widget = Label(self.canvas, background="#0F8", text=message)
		self.items.append(widget)
		self.max_item_width = max(self.max_item_width, widget.winfo_reqwidth())
		self.max_item_height = max(self.max_item_height, widget.winfo_reqheight())
		self.draw()

	def draw_items(self) :
		x_border = 10
		y_border = 10
		# compute the number of columns
		w = self.winfo_width()
		n_col = w/(x_border+self.max_item_width)
		if n_col == 0 : n_col = 1
		n = 0
		self.canvas.delete("all")

		x = x_border
		y = y_border
		for item in self.items :
			id = self.canvas.create_window(x, y, window=item, anchor=NW, tags=("all",))
			n = n+1
			if n % n_col == 0 :
				x = x_border
				y = y+self.max_item_height+y_border
			else :
				x = x+self.max_item_width+x_border

		self.canvas.config(scrollregion=self.canvas.bbox(ALL))
	
	def draw_scrollbars(self) :
		w = self.winfo_width()
		h = self.winfo_height()
		bbox = self.canvas.bbox(ALL)
		if bbox != None :
			bb_x0, bb_y0, bb_x1, bb_y1 = bbox
		else :
			# no scrollbar needed
			self.yscrollbar.place_forget()
			self.xscrollbar.place_forget()
			return w, h

		if h > bb_y1-bb_y0 :
			# no y scrollbar needed
			self.yscrollbar.place_forget()
			if w < bb_x1-bb_x0 :
				# x scrollbar needed
				delta_y = self.xscrollbar.winfo_reqheight()
				self.xscrollbar.place(anchor=SW, rely=1.0, relwidth=1)
				h = h-delta_y
				if h > bb_y1-bb_y0 :
					# y scrollbar need finally
					self.yscrollbar.place(anchor=NE, relx=1.0, relheight=1, height=-delta_y)

		else :
			# y scrollbar needed
			delta_x = self.yscrollbar.winfo_reqwidth()
			w = w-delta_x
			if w < bb_x1-bb_x0 :
				# x scrollbar needed
				delta_y = self.xscrollbar.winfo_reqheight()
				self.xscrollbar.place(anchor=SW, rely=1.0, relwidth=1, width=-delta_x)
				h = h - delta_y
			else :
				delta_y = 0
				self.xscrollbar.place_forget()

			self.yscrollbar.place(anchor=NE, relx=1.0, relheight=1, height=-delta_y)
		return w, h

	def draw(self) :
		self.draw_items()
		w, h = self.draw_scrollbars()
		self.canvas.place(width=w, height=h)

	def delete_all(self) :	
		self.canvas.delete("all")
		self.items = []
		self.draw()
		

def add_cb() :
	global my_display, n, root
	my_display.add("hello world %d" % n)
	n = n+1

# main part of the program
root = Tk()
n = 0
my_display = display(root, width=100, height=100)
button_panel = Frame(root)
button_panel.pack()
add_button = Button(button_panel, command=add_cb, text="add")
add_button.pack(side=LEFT)
del_button = Button(button_panel, command=my_display.delete_all, text="delete all")
del_button.pack(side=LEFT)

my_display.pack(expand=1, fill=BOTH)

root.mainloop()

A dialog window for renaming many digital pictures

This script has been tested with Python 2.4 on a Linux operating system.

Main features:
shell> ren_view *.jpg
There is the script:
#!/usr/bin/python

import string
from Tkinter import *
import Image
import ImageTk
import os
import re

THUMBNAIL_WIDTH = 300
THUMBNAIL_HEIGHT = 300
automatic_suffix=True
filelist = sys.argv
filelist.pop(0) # removal of the first element which is the name of the program
current_file = None
thumbnail_id = None
photo = None

def display_next_file() :
	global thumbnail_id, photo, current_file, automatic_suffix
	if thumbnail_id != None : thumbnail_canvas.delete(thumbnail_id)
	if len(filelist) == 0 : sys.exit(0)
	current_file = filelist.pop(0)
	if automatic_suffix :
		suffix = re.sub(".*\.", ".", current_file)
		suffix_entry.delete(0, END)
		suffix_entry.insert(END, suffix)
	filename_label.config(text=current_file)
	im = Image.open(current_file)
	#im = im.resize((THUMBNAIL_WIDTH, THUMBNAIL_HEIGHT))
	im.thumbnail((THUMBNAIL_WIDTH, THUMBNAIL_HEIGHT))
	print im.size
	photo = ImageTk.PhotoImage(im)
	thumbnail_id = thumbnail_canvas.create_image(10+THUMBNAIL_WIDTH/2, 10+THUMBNAIL_HEIGHT/2, anchor=CENTER, image=photo)

def rename(current, new) :
	dir = os.path.dirname(current)
	full_new_path = os.path.join(dir, new)
	if os.path.exists(full_new_path) :
		i=1
		prefix = os.path.join(dir, prefix_entry.get())
		user_text = user_entry.get()
		suffix = suffix_entry.get()
		format = "%s%s.%02d%s"
		while os.path.exists(format % (prefix, user_text, i, suffix)) :
			i = i+1
		full_new_path = format % (prefix, user_text, i, suffix)

	print "rename", current, "->", full_new_path
	os.rename(current, full_new_path)

def validate(event) :
	if user_entry.get() != "" :
		rename(current_file, new_name())
	user_entry.delete(0, END)
	display_next_file()

def new_name() :
	prefix = prefix_entry.get()
	user_text = user_entry.get()
	suffix = suffix_entry.get()
	return user_convert(prefix+user_text+suffix)

def user_convert(str) :
	return string.replace(str, " ", "_")

def update_result(event) :
	result_label.config(text="Resulting file name: "+new_name())

root = Tk()
title_label = Label(root, text="Rename your pictures", font=("Helvetica","14"))
title_label.grid(row=0, columnspan=4, sticky=W)

# prefix
prefix_label = Label(root, text="Prefix:")
prefix_label.grid(row=1, column=0, sticky=W)
prefix_entry = Entry(width=20)
prefix_entry.grid(row=1, column=1)
prefix_entry.bind("<KeyRelease>", update_result)

# suffix
suffix_label = Label(root, text="Suffix:")
suffix_label.grid(row=1, column=2, sticky=W)
suffix_entry = Entry(width=20)
suffix_entry.grid(row=1, column=3)
suffix_entry.bind("<KeyRelease>", update_result)

thumbnail_canvas = Canvas(root, height=THUMBNAIL_HEIGHT+20, width=THUMBNAIL_WIDTH+20)
thumbnail_canvas.grid(row=2, columnspan=4)

filename_label = Label(root, text="(void)")
filename_label.grid(row=3, columnspan=4)

# short description
description = Message(root, text="Enter a description to be used in the filename (leave blank if no change is to be made):", aspect=1200)
description.grid(row=4, columnspan=4, sticky=W)

# user entry
user_entry = Entry(width=30)
user_entry.bind("<Return>", validate)
user_entry.bind("<KeyRelease>", update_result)
user_entry.grid(row=5, columnspan=4);
user_entry.focus_set()

#
result_label = Label(root)
result_label.grid(row=6, columnspan=4)

display_next_file()

root.mainloop()
Points of interest: