My Tkinter Threading nightmare

half.italian at gmail.com half.italian at gmail.com
Wed Jan 24 21:47:46 EST 2007


Hi all,

I don't really understand how to properly use threading in my programs,
however I have managed to get by so far using them improperly.  Once
again I have come up to what I think is something that won't work
because of the way the program is set up.

I have a long running process running underneath a gui in a different
thread, and a progress bar that updates the status of the operation.
What I would like to do is use something like :

self.progressWindow.protocol('WM_DELETE_WINDOW', self.callback)

and setup the callback to kill the operation and then the window when
the user clicks on the X of the progress window.  I've implemented this
in my code, but clicking on the X does nothing until I kill the main
thread (i think), and then my callback is run.  I've also had problems
in the past of the gui not refreshing properly, which leads me to
believe that both of these are thread related.  Any help would be
immensely appreciated.

~Sean DiZazzo

~~~~~~~~~~~~~~~~~~~

import sys, os, time

libdir = "/usr/local/sw/lib"
sys.path.append(libdir)

import ProgressBarView, Folder, P

from Tkinter import *
from tkFileDialog import askopenfilenames
from tkMessageBox import showerror, showinfo
import pexpect, ssh_session

import P
import Pmw

rootWin = Tk()

class Window(Frame):
	label = None
	initialdir = "/"

	dest = "/tmp"
	folder = None
	logpath = "/tmp/Send.log"
	copyindex = 0
	files = []
	progressWindow = None
	session = None
	password = P.P()
	ssh = ssh_session.ssh_session("root", "XX.XX.XX.XX",
password.Decrypt(password.sean))

	timeout = 30

	def __init__(self, parent=None):
		Frame.__init__(self, parent)
		rootWin.title("Send to Blah")
		rootWin.resizable(width=0,height=0)
		self.pack()
		self.progress_and_log()
		f = Frame(self)
		openfunc = (lambda self=self, name=None: self.openfolder())
		Button(f, text="Choose", command=openfunc).pack(side="left")
		self.label = Label(f, text=' <--- Choose files', bg="grey", width=40,
justify='left', anchor='w')
		self.label.pack(side="left", anchor='w', padx=5)
		f.pack(padx=10, pady=10, side='left', fill='both', anchor='w')
		submitfunc = (lambda self=self, name=None: self.submit())
		b = Button(self, text="Send", command=submitfunc)
		b.pack(side="right", padx=5)


	def openfolder(self):
		self.files = []
		self.files_tuple = askopenfilenames(parent=rootWin, initialdir="/")

		for file in self.files_tuple:
			self.files.append(file)

		self.files.sort()

		label = "Click button to send files -->"
		self.st.configure(text_state = 'normal')
		self.st.clear()
		self.st.insert('end', "Files to be copied:\n")
		self.st.insert('end', "~~~~~~~~~~~~~~~~~~~\n")
		for file in self.files:
			self.st.insert('end', os.path.split(file)[-1] + "\n")
		self.st.insert('end', " \n \n")
		self.st.configure(text_state = 'disabled')
		self.label.config(text='Click to send files --->  ', justify='right',
anchor='e')

	def callback(self):
		"""Need to get the pid here and kill the running process"""

	def submit(self):
		files = self.files
		dest = Folder.Folder(self.dest)

		for file in files:
			if self.ssh.exists(os.path.join(dest.path,
os.path.split(file)[-1])):
				showerror("error", "The file '%s' already exists" %
os.path.join(dest.path, os.path.split(file)[-1]))
				return 0

		import threading
		geometry = None

		for file in files:
			self.progressWindow = Toplevel(rootWin)
			self.progressWindow.protocol('WM_DELETE_WINDOW', self.callback)
			self.progressWindow.geometry(geometry)
			self.progressWindow.title("Progress")
			self.progressWindow.resizable(width=0,height=0)

			self.proglabel = Label(self.progressWindow, text='Copying...',
anchor=NW, justify=LEFT, width=30)
			self.proglabel.pack(fill=X, expand=1)
			self.progressBar =
ProgressBarView.ProgressBarView(self.progressWindow)
			self.progressBar.pack(fill=X)

			threading.Thread(target=self.threadedCopy,args=(file, dest)).start()

			#grab the location from the first window
			if geometry is None:
				self.progressBar.updateProgress(0)
				geometry = self.progressWindow.geometry()

			self.incrementProgress(self.progressWindow, file, dest)

		self.label.config(text=" <--- Choose files", justify='left',
anchor='w')
		self.files=[]

	def progress_and_log(self):
		self.st = Pmw.ScrolledText(rootWin, borderframe = 1,
		usehullsize = 1,
                hull_width = 400,
                hull_height = 150,
                text_wrap='none',
                #text_font = fixedFont,
                text_padx = 4,
                text_pady = 4,
		)
		self.st.configure(text_state = 'disabled')

		self.st.pack(padx = 5, pady = 5, fill = 'both', expand = 1)


	def threadedCopy(self, file, dest):
		self.ssh.scp(file, os.path.join(dest.path, os.path.split(file)[1]))

	def appendToLog(self, src, dest):
		dest_size = self.ssh.size(dest.path)
		try:
			dest_size = float(dest_size)
		except:
			dest_size = 0

		if src.size == dest_size:
			status = "SUCCESS"
		else:
			status = "FAILED"
		entry = "%s - %s %s, %s\n" % (time.ctime(time.time()), status,
src.name, src.readableSize)

		f = open(self.logpath, 'a')
		f.write(entry)
		f.close()

		self.st.configure(text_state = 'normal')
		self.st.insert('end', entry)
		self.st.configure(text_state = 'disabled')


	def incrementProgress(self, window, file, dest):
		import File
		src = File.File(file)
		dest = File.File(os.path.join(dest.path, os.path.split(file)[-1]))
		start = time.time()


		p = 0
		last_dest = 0
		same_count = 0

		while  p < 100:
			d_size = self.ssh.size(dest.path)
			try:
				float(d_size)
			except:
				"Couldn't turn %s into a float" % d_size
				continue

			if last_dest == d_size and same_count == 40:
				showerror("error", "Error copying %s\nRemoving the partially
transferred file and continuing..." % dest.path)
				self.ssh.ssh("sudo rm %s" % dest.path)

			if d_size == None:
				d_size = 1000

			self.proglabel.config(text=src.name)

			p = (float(d_size) / float(src.size)) * 100.0

			d_size = self.ssh.size(dest.path)
			if last_dest == d_size:
				same_count = same_count +1

			print "P:", p
			self.progressBar.updateProgress(p)
			self.update_idletasks()
			time.sleep(0.25)
			last_dest = d_size

		self.appendToLog(src, dest)
		window.destroy()
		return 
		

if __name__ == "__main__":
	Window().mainloop()




More information about the Python-list mailing list