1

I programmed a GUI that calls a .cmd file several times (with different parameters)

class App:
    def process(self):
        for filename in os.listdir(path):
            subprocess.call(['script.cmd', filename])
            self.output('processed ' + filename)

    def output(self, line):
        self.textarea.config(state = NORMAL)
        self.textarea.tag_config("green", background="green", foreground="black")
        self.textarea.insert(END, line, ("green"))
        self.textarea.yview(END)
        self.textarea.config(state = DISABLED)
        self.textarea.update_idletasks()

root = Tk()
app = App()
app.build_gui(root)
app.pack_gui(root)

root.mainloop()

process() is called when pressing a button

I also tried subprocess.Popen() and the old os.spawnv() It's always the same. The GUI is not reacting when processing the files. Only after all files have been processed, the GUI is updated with all the 'processed XYZ' messages.

Shouldn't update_idletasks() update the GUI after every subprocess call?

Thank you

edit: I narrowed the problem to this simple code:

from Tkinter import *
import subprocess

file_list = ['file1', 'file2', 'file3', 'file4', 'file5']

def go():
    labeltext.set('los')
    for filename in file_list:
        labeltext.set('processing ' + filename + '...')
        label.update_idletasks()

        proc = subprocess.call(["C:\\test\\process.exe", filename])
    labeltext.set('all done!')


root = Tk()

Button(root, text="Go!", command=go).pack(side=TOP)

labeltext = StringVar()
labeltext.set('Press button to start')

label = Label(root, textvariable=labeltext)
label.pack(side=TOP)

root.mainloop()

Now it depends on the process.exe if the script works properly. If I write a simple C program with busy-looping (e.g. source code of process.exe: int i=0; while(i<1e9){ i++; }), the GUI is updated with every file1-5. When I call the original .exe-file I wanted to use, it displays "processing file1" and switches to "processing file2" but then freezes until program termination ("all done!").

I dont really understand whats up here. Obviously it has something to do with the process called. Does anyone have an idea?

Timedog
  • 51
  • 1
  • 5
  • The update of the textarea should be enough. One question thought: maybe it's a copy-paste error, but why is `app = App()` not referring to `root`? Could you paste your complete code? – Joël Oct 18 '11 at 11:06
  • Thanks for your answer. Unfortunately it seems to be not enough. The GUI is not updating during the processing. App() is not referring to root since I don't have a constructor function. It this neccessary? The complete code is pretty long but I think the most important parts are included in the first post. – Timedog Oct 19 '11 at 17:53
  • MMh, I've got no real idea why this is not refreshing, but looking to http://infohost.nmt.edu/tcc/help/pubs/tkinter/universal.html, I'm not sure that updating the label text is a so-called idle task. Could you make a test without using a `StringVar`, so using directly the following command: `label.configure(text="processing ")`? – Joël Oct 20 '11 at 07:15
  • Thanks but it's still the same. It switches to "processing file1" and "processing file2" but then freezes until "all done!". Is it somehow possible that the .exe is not terminating correctly? – Timedog Oct 20 '11 at 16:26
  • You can check ending of execution by checking if returncode of the executable is as expected: `subprocess.call` returns it, so you may compare it to `0` or the expected value. – Joël Oct 20 '11 at 16:36
  • Ok. The process always terminated with return code 0. So that should be fine. The problem continues. But I found a dirty solution. I call root.update() before every subprocess.call(). To make sure that no buttons are pressed during processing (that seems to be a problem with root.update() according to a quick google search), I disable them all before the subprocesses are started. – Timedog Oct 20 '11 at 19:54
  • Normally yes, 0 should be fine (but I'm working with one weird tool, that returns 1 if execution was correct...). For your way to make your script work, it would be fine if you could make an answer on your own, and accept it as resolution of your question: this will trace the solution for anyone that needs it. – Joël Oct 21 '11 at 06:27

1 Answers1

4

I found a dirty solution: I call root.update() before every subprocess.call().

To make sure that no buttons are pressed during processing (that seems to be a problem with root.update() according to a quick google search), I disable them all before the subprocesses are started

like this:

from Tkinter import *
import subprocess

file_list = ['file1', 'file2', 'file3', 'file4', 'file5']

def button():
    b_process.configure(state=DISABLED)
    go()
    b_process.configure(state=NORMAL)

def go():
    for filename in file_list:
        label.configure(text="processing " + filename)
        root.update()

        proc = subprocess.call(["C:\\DTNA\\stat\\run.exe", filename])
        print 'process terminated with return code ' + str(proc)     
    label.configure(text="all done!")

root = Tk()

b_process = Button(root, text="Go!", command=button)
b_process.pack(side=TOP)

label = Label(root, text='Press button to start')
label.pack(side=TOP)

root.mainloop()
Timedog
  • 51
  • 1
  • 5