473,388 Members | 1,340 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,388 software developers and data experts.

My Tkinter Threading nightmare

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.progressWindo w)
self.progressBar.pack(fill=X)

threading.Thread(target=self.threadedCopy,args=(fi le, 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()

Jan 25 '07 #1
5 4223
ha**********@gmail.com writes:
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.
That was more code than I was willing to sit and read, but basically
the tkinter thread blocks unless there's tkinter events. The usual
trick for what you're trying to do is to set up a tk.after event to
run every 20 msec or so. That can check for commands on a queue to
launch operations, kill windows, or whatever. In your Window class
you'd have something like (this is pseudocode, I don't remember the
exact params and args off the top of my head so you'll have to check
them):

def __init__(self, ...):
...
self.after(20, self.idle)

def idle(self):
# read and execute any commands waiting on the queue
while True:
try:
func, args, kw = self.cmd_queue.get(block=False)
except QueueEmpty:
return
func (*args, **kw)

cmd_queue is a queue that you set up ahead of time, and you use it to
send commands into your gui thread from other threads, such as window
kill. Don't call gui functions directly as tkinter is not
thread-safe.
Jan 25 '07 #2
Paul Rubin <http://ph****@NOSPAM.invalidwrites:
def idle(self):
# read and execute any commands waiting on the queue
while True:
try:
func, args, kw = self.cmd_queue.get(block=False)
except QueueEmpty:
return
func (*args, **kw)
Whoops, I forgot, you have to set up the after event again at the end
of this:

def idle(self):
# read and execute any commands waiting on the queue
while True:
try:
func, args, kw = self.cmd_queue.get(block=False)
except QueueEmpty:
return
func (*args, **kw)
self.after(20, self.idle)
Jan 25 '07 #3

On Jan 24, 7:35 pm, Paul Rubin <http://phr...@NOSPAM.invalidwrote:
Paul Rubin <http://phr...@NOSPAM.invalidwrites:
def idle(self):
# read and execute any commands waiting on the queue
while True:
try:
func, args, kw = self.cmd_queue.get(block=False)
except QueueEmpty:
return
func (*args, **kw)Whoops, I forgot, you have to set up the after event again at the end
of this:

def idle(self):
# read and execute any commands waiting on the queue
while True:
try:
func, args, kw = self.cmd_queue.get(block=False)
except QueueEmpty:
return
func (*args, **kw)
self.after(20, self.idle)
Thanks Paul. That has made more sense than all of my scrounging
combined, but I still need to mess around with the idea and code some.
How can I put something like the window delete into the command queue?
Isn't window.protocol() just binding the close window button to a
function?

I'll look deeper and experiment and try to make sense of it once again
tomorrow. :)

~Sean

Jan 25 '07 #4
ha**********@gmail.com writes:
try:
func, args, kw = self.cmd_queue.get(block=False)
except QueueEmpty:
return
func (*args, **kw)
>
Thanks Paul. That has made more sense than all of my scrounging
combined, but I still need to mess around with the idea and code some.
How can I put something like the window delete into the command queue?
Isn't window.protocol() just binding the close window button to a
function?
self.progressWindow.protocol('WM_DELETE_WINDOW', self.callback)

becomes

gui.cmd_queue.put(self.progressWindow.protocol,
('WM_DELETE_WINDOW', self.callback))

where gui is the Window object containing your gui.

I think there are some recipes like this in ASPN, that give more
detail about how to do this stuff.
Jan 25 '07 #5
In article <7x************@ruckus.brouhaha.com>,
Paul Rubin <http://ph****@NOSPAM.invalidwrote:
>
self.progressWindow.protocol('WM_DELETE_WINDOW', self.callback)

becomes

gui.cmd_queue.put(self.progressWindow.protocol,
('WM_DELETE_WINDOW', self.callback))

where gui is the Window object containing your gui.

I think there are some recipes like this in ASPN, that give more
detail about how to do this stuff.
You can find a simple example at http://pythoncraft.com/ in the threads
tutorial.
--
Aahz (aa**@pythoncraft.com) <* http://www.pythoncraft.com/

Help a hearing-impaired person: http://rule6.info/hearing.html
Jan 25 '07 #6

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

0
by: Bruce Davis | last post by:
I'm having a problem on windows (both 2000 and XP) with a multi-threaded tkinter gui application. The problem appears to be a deadlock condition when a child thread pops up a Pmw dialog window in...
2
by: Michael Zhang | last post by:
My project uses Python-2.3.4 + Tkinter + PIL-1.1.4 to retrieve images from server and display those images. I created a thread (also a separate toplevel window) for displaying images and another...
8
by: Erik Johnson | last post by:
I am looking for some input on GUI libraries. I want to build a Python-driven GUI, but don't really understand the playing field very well. I have generally heard good things about wxPython. I...
2
by: Mark English | last post by:
Is there a safe way to run tkinter in a multithreaded app where the mainloop runs in a background thread ? Here's some test code demonstrating the problem. I'm running Python2.4 under Windows...
3
by: Philippe C. Martin | last post by:
Hi, I need to pop-up in a "modless" manner some windows from an existing Tkinter loop. The following code works OK under Linux: the second window opens, shows the information, and quits cleanly...
9
by: Tuvas | last post by:
I am building a tkinter program. A part of this program is to read data from an incoming interface, and depending on the data, will display a bit of text on the tk dialog, it decodes this data, so...
14
by: Hendrik van Rooyen | last post by:
Hi, I get the following: hvr@LINUXBOXMicrocorp:~/Controller/libpython display.py UpdateStringProc should not be invoked for type font Aborted and I am back at the bash prompt - this is...
2
by: Kevin Walzer | last post by:
I'm trying to decide whether I need threads in my Tkinter application or not. My app is a front end to a command-line tool; it feeds commands to the command-line program, then reads its output and...
13
by: Daniel Fetchinson | last post by:
Was looking at PEP 3108, http://www.python.org/dev/peps/pep-3108/ , Is it just me or others also think that it would be a major loss to remove tkinter from the python core? PEP 3108 starts off...
0
by: taylorcarr | last post by:
A Canon printer is a smart device known for being advanced, efficient, and reliable. It is designed for home, office, and hybrid workspace use and can also be used for a variety of purposes. However,...
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.