2

I am developing a GUI using python. When a button on one tab of the GUI is clicked, an executable is to be run in the background. While the executable is running, I would like to show a indeterminate progress bar oscillating on the input tab and when the subprocess is complete, the new tab should open up displaying the results from the text-files outputs of the subprocess.

However if I use thread function join(), the GUI freezes and the progress bar can't be shown. If I do not use join, the new tab opens, without waiting for the subprocess showing error since the output files do not exist.

I don't have a previous experience with threading and queues. I am not sure if I have understood the concepts properly. I would appreciate any help. This is a part of my code:

import Tkinter
from Tkinter import *
import subprocess

class myThread(threading.Thread):

    def __init__(self,thread_name,command):
        threading.Thread.__init__(self)
        self.thread_name=thread_name
        #self.queue=queue
        self.command=command

    def run(self):
        if self.thread_name=="Run":


           os.chdir( 'D:\\Projects\\' ) 
           subprocess.Popen( "executable.exe" ,shell=False)
           log.info('Execution started.')

class GUI(Frame):
    def __init__(self,parent):

    '''
    GUI design
    '''
        self.go_Button=Button(self.note,text="GO",command=self.submitted)
        self.go_Button.grid(row=13,column=4,pady=(20,10),in_=self.input_Tab)

    def submitted(self):
        #Defines the actions to be done after  the click of the GO button 
        #self.queue=Queue.Queue()
        self.go_Button.lower(self.input_Tab)
        progress=Progressbar(self.note,mode='indeterminate',length=500)
        progress.grid(row=13,columnspan=6,sticky=W+E,padx= (40,10),in_=self.input_Tab)

       self.t=myThread("Run",self.command)
       self.t.daemon=True
       self.t.start()
       progress.start()
       self.t.join() #waits for the thread to complete but freezes the tkinter GUI
       progress.stop()

       log.debug("Has finished the thread")
       self.note.select(self.output_Tab)
       self.uploadResults()
       progress.lower(self.input_Tab)
       self.go_Button.lift(self.input_Tab)

Thanks in advance..!

Athena
  • 69
  • 2
  • 13
  • http://stackoverflow.com/q/4995419/5226311 discusses solutions for PyGTK GUI. But I am using Tkinter. – Athena Sep 09 '15 at 07:18
  • [On Unix, you could use `SIGCHLD` handler, to avoid polling the process status periodically](http://stackoverflow.com/a/30281111/4279) (it is a complex solution, it is ok if you don't understand it at first). – jfs Sep 10 '15 at 13:15
  • unrelated: avoid commenting on own questions, put all necessary information into the question itself. – jfs Sep 10 '15 at 14:12

1 Answers1

0

There is no need to create a thread or spawn another process using multiprocessing module. I created a subprocess.Popen object from the mainloop and created a while loop which checks if the process is alive and updates the root widget if the executable is running. This ensures that the progress bar works until the subprocess is finished or killed.

self.progressBar=Progressbar(self.note,mode='indeterminate',length=500)
self.progressBar.grid(row=13,columnspan=6,sticky=W+E,padx=(40,10),in_=self.input_Tab)

os.chdir( 'D:\\Projects\\' ) 
self.proc=subprocess.Popen( "executable.exe" ,shell=False)
self.progressBar.start()

while self.proc.poll() is None:
      self.update()

self.progressBar.stop()
Athena
  • 69
  • 2
  • 13
  • you could [use `root.after()` instead of the`while` loop](https://gist.github.com/zed/4067619) – jfs Sep 10 '15 at 13:08