0

I'm trying to make a function that runs a ttk progressbar until a file is created. It seems that Widget.after is causing the APPCRASH but I don't know why. Please help!

def FilePgBar(title, file):
    if root:
        root.withdraw()
        boxRoot = Toplevel(master=root)
        boxRoot.withdraw()
    else:
        boxRoot = Tk()
        boxRoot.withdraw()

    boxRoot.protocol('WM_DELETE_WINDOW', denyWindowManagerClose )
    boxRoot.title(title)
    boxRoot.iconname('Dialog')
    boxRoot.geometry(rootWindowPosition)
    boxRoot.minsize(400, 100)
    pgBar = ttk.Progressbar(boxRoot, orient=HORIZONTAL, length=300, mode='indeterminate')
    pgBar.grid(row=1, column=0)
    pgBar.pack()
    pgBar.start()
    def checkfile():
        if os.path.exists(file):
            pgBar.stop()
            pgBar.destroy()
            boxRoot.deiconify()
            boxRoot.mainloop()
            boxRoot.destroy()
            if root: root.deiconify()
        else:
            boxRoot.after(100, checkfile)

    checkfile()

I want to call this function from others scripts, so I'm not sure about using a class

EDIT: I edited the code. I no longer get an APPCRASH, but nothing happens when I run the program.

Luke Dinkler
  • 731
  • 5
  • 16
  • 36

1 Answers1

1

Python evaluates the arguments before passing them to a function. So when it encounters

boxRoot.after(100, checkfile(file))

it evaluates checkfile(file) -- calling checkfile -- and replaces checkfile(file) with the value returned by the function before calling boxRoot.after.

Since checkfile(file) has no return statement, None is returned by default. Thus

boxRoot.after(100, None)

gets called. This raises an error since the second argument to boxRoot.after should be a callable.


Instead, pass the function object checkfile itself:

def checkfile():
    if os.path.exists(file):
        pgBar.stop()
        pgBar.destroy()     
        boxRoot.destroy()
        if root: root.deiconify()
    else:
        # You need to update the progress bar            
        boxRoot.after(100, checkfile)

This allows the boxRoot.after function to call the function from within boxRoot.after instead of before after is called.


You might do something like this:

import os
import Tkinter as tk
import ttk

class App(object):
    def __init__(self, master, *args, **kwargs):
        self.master = master
        self.button = tk.Button(master, text='Stop', command=self.stop)
        self.button.pack()
        self.progress = ttk.Progressbar(master, orient="horizontal", 
                                        length=200, mode="determinate")
        self.progress.pack()
        self.progress["value"] = 0
        self.progress["maximum"] = 100
        self.filename = '/tmp/out'
        if os.path.exists(self.filename):
            os.unlink(self.filename)
        self.checkfile()

    def checkfile(self):
        self.progress["value"] += 1
        if (not os.path.exists(self.filename) 
            and self.progress["value"] < self.progress["maximum"]):
            self.master.after(100, self.checkfile)

    def stop(self):
        with open(self.filename, 'w') as f: pass

root = tk.Tk()
app = App(root)
root.mainloop()
unutbu
  • 842,883
  • 184
  • 1,785
  • 1,677
  • I'm not sure how this helps. Where is the `file` argument for checkfile? – Luke Dinkler Dec 21 '14 at 20:12
  • Yes, but now it says that `checkfile()` is missing the 1 required argument, `file`! – Luke Dinkler Dec 21 '14 at 20:15
  • Look again. My `def checkfile()` has no argument. – unutbu Dec 21 '14 at 20:16
  • Oh! Ok, now I checked it and nothing happens when I run it! – Luke Dinkler Dec 21 '14 at 20:19
  • Wait, what do I call after I define the `checkfile` function? – Luke Dinkler Dec 21 '14 at 20:21
  • Nothing is happening because you need to update the progress bar. See http://stackoverflow.com/q/7310511/190597 for a runnable example. One thing you'll need to decide is the maximum value, `pgBar['maximum']`. I don't know how you plan to do that if you are simply waiting for a file to exist. (i.e., how do you know when the wait is half over?) – unutbu Dec 21 '14 at 20:29
  • I have looked at the link, but I still don't understand. It doesn't say anything about updating the progressbar – Luke Dinkler Dec 21 '14 at 20:32
  • `self.progress["value"] = self.bytes` updates the progress bar. The progress bar is drawn based on the ratio of `self.progress['value']` and `self.progress['maximum']`. – unutbu Dec 21 '14 at 20:33
  • But I'm not using a class, so I can't use `self`! – Luke Dinkler Dec 21 '14 at 20:40
  • I don't know if I have said this, but I don't want to use a class because the whole reason for the function is to call it from different programs. And I am simply waiting for the file to exist. I don't need to worry about the bytes. – Luke Dinkler Dec 21 '14 at 20:42
  • Still not sure what to do. Could you possibly show me how I can use the class in one program in another? – Luke Dinkler Dec 22 '14 at 13:44