0

I am making a Tkinter app, which is copying files from user's system to a FTP server. I want to include a determinate progress bar which will show the % progress of the file copied over the server. But the progress bar isn't working as the window hangs while copying. I have used threads and indeterminate mode for the progress bar, but its proving of no use. Please check the below code and suggest suitable additions/modifications.

from Tkinter import *
from ftplib import FTP
import ttk,threading,os,time,tkMessageBox

main_window=Tk()

def onCopy_buttonClick():                                   

    def ok_button_click():
        i=0
        global list1        
        for item in files:
            if(list1[i].get()==1):              
                Ftp=FTP_Entry.get()
                Ftp=Ftp.split("/",1)
                site=FTP(Ftp[0])
                site.login(User_Entry.get(),Password_Entry.get())
                site.cwd(Ftp[1])
                copy_window.withdraw()
                progress_window=Toplevel(copy_window)
                p_label=Label(progress_window,text="Please wait while the files are being copied..").pack()

                progressbar=ttk.Progressbar(progress_window,length=300,orient='horizontal',mode='determinate')
                progress=StringVar()
                progresslabel=Label(textvariable=progress).pack()
                progress.set("0 KBps")
                progressbar.pack()

                result=True

                for file in site.nlst():
                    if item==file:
                        result=tkMessageBox.askyesno("Warning !",item+" is already present. If you select Yes, item will be replaced.")

                if result==True:                    
                    def foo():
                        with open(item,"rb") as f:
                            site.storbinary("STOR "+item,f,blocksize=33554432)                              
                    def start_foo_thread():
                        foo_thread = threading.Thread(target=foo)
                        foo_thread.start()                          
                        size=int(os.path.getsize(item)) #item can be in GB's
                        copied=0        
                        '''while(copied!=size):
                            copied=int(site.size(item)) #doesn't get size till copying is done
                            progressbar['value']=round(copied/size)
                            progress.set(" KBps") #how?
                            time.sleep(1000)'''
                        while(True):
                            if foo_thread.is_alive()==False:
                                progressbar.stop()
                                break

                start_foo_thread()
            i=i+1   
        progress_window.destroy()
        copy_window.destroy()
        main_window.deiconify()

    os.chdir(Path_Entry.get())  
    copy_window=Toplevel(main_window)   
    main_window.withdraw()
    files=os.listdir(os.getcwd())
    global list1
    list1=[]
    for i in range(0,len(files)):
        list1.append("0")
        list1[i]=IntVar()
    i=0 
    for item in files:
        if os.path.isfile(item):
            c = Checkbutton(copy_window,variable=list1[i],text=item)
            c.pack()
        i=i+1
    ok_button=Button(copy_window,text="OK",command=ok_button_click).pack()


Path_Label=Label(text="Enter File path : ").grid(row=0,column=0)
Path_Entry=Entry()
Path_Entry.grid(row=0,column=1)
FTP_Label=Label(text="FTP Path : ").grid(row=1,column=0)
FTP_Entry=Entry()
FTP_Entry.grid(row=1,column=1)
User_Label=Label(text="Username : ").grid(row=2,column=0)
User_Entry=Entry()
User_Entry.grid(row=2,column=1)
Password_Label=Label(text="Password : ").grid(row=3,column=0)
Password_Entry=Entry()
Password_Entry.grid(row=3,column=1)
Copy_button=Button(text="START COPYING",command=onCopy_buttonClick)
Copy_button.grid(row=4,columnspan=2)
main_window.mainloop()

I have now edited the code and this is how it looks, it serves my purpose. Any suggestions are welcome.

def ok_button_click():
        i=0
        global list1        
        for item in files:
            if(list1[i].get()==1):              
                Ftp=FTP_Entry.get()
                Ftp=Ftp.split("/",1)
                site=FTP(Ftp[0])
                site.login(User_Entry.get(),Password_Entry.get())
                site.cwd(Ftp[1])
                copy_window.withdraw()
                progress_window=Toplevel(copy_window)
                p_label=Label(progress_window,text="Please wait while the files are being copied..").pack()

                progressbar=ttk.Progressbar(progress_window,length=300,orient='horizontal',mode='determinate')              
                progressbar.pack()
                progress=StringVar()
                progresslabel=Label(progress_window,textvariable=progress)
                progresslabel.pack()
                progress.set("0 % Copied")

                result=True

                for file in site.nlst():
                    if item==file:
                        result=tkMessageBox.askyesno("Warning !",item+" is already present. If you select Yes, item will be replaced.")

                if result==True:    

                    def callback(block):
                        global sizewritten
                        sizewritten += 8388608                      
                    def foo():
                        with open(item,"rb") as f:
                            site.storbinary("STOR "+item,f,8388608,callback)    
                    def start_foo_thread():
                        filesize=int(os.path.getsize(item))
                        progressbar["maximum"] = filesize
                        foo_thread = threading.Thread(target=foo)
                        foo_thread.start()                      
                        while(True):
                            progressbar["value"]=sizewritten
                            percent=str(int(sizewritten/float(filesize)*100))
                            if (int(percent)>100):
                                percent="100"
                            progress.set(percent+" % Copied")   
                            progress_window.update()
                            if foo_thread.is_alive()==False:
                                progressbar.stop()
                                break

                start_foo_thread()
            i=i+1   
        progress_window.destroy()
        copy_window.destroy()
        main_window.deiconify()
Pranjal
  • 11
  • 6
  • 1
    I don't entirely understand your code, but I have some general advice. `while` loops inside Tkinter programs tend to lock up the interface, because as long as the loop continues, no window events can be processed by the system. It may be better to create a function which updates the progress bar a single time without looping, and then use Tkinter's [`after`](http://effbot.org/tkinterbook/widget.htm#Tkinter.Widget.after-method) to make that function execute every X milliseconds. This will give Tkinter the required spare time to handle window events. – Kevin Jul 30 '14 at 12:21
  • @Pranjal you have made a pretty easy mistake by combining `.pack()` and `.grid()` in one Tkinter window, this may be the reason that the progressbar isn't working how you want it to - heres why: http://stackoverflow.com/questions/17267140/python-pack-and-grid-methods-together – W1ll1amvl Jul 30 '14 at 22:46
  • 1
    @W1ll1amvl : .grid() is for main_window and .pack() is for progress_window. I have issues only with progress_window, as it hangs while copying files, which I tried to counter by using thread, but in vain. – Pranjal Jul 31 '14 at 04:44
  • Ok I can see that now, what is copy_window for? You could try to use only grid maybe it would help? – W1ll1amvl Jul 31 '14 at 07:56
  • once we click Copy_button on main_window, copy_window appears on which names of files in chose folder comes. We check the files to copy and press ok_button to open progress_window which starts copying files. – Pranjal Aug 01 '14 at 09:15
  • @Kevin : I applied while loop because I didn't want next task to be executed till the copying was completed. For now, I have made changes in the code but retained while loop and it works fine. I couldn't figure out where and how to use after in this code. Maybe you could suggest some changes. PS : If you have access to any FTP server, you could copy paste and run this code to check. Thanks – Pranjal Aug 01 '14 at 09:26

1 Answers1

1

Quick suggestion without reading all of that code, but I skimmed and didn't see it. Try updating your root window after every time your progress bar is supposed to increase.

marshmallow
  • 158
  • 1
  • 11