I'm currently trying to write a Python
program that starts a Tkinter
GUI. One of the features of the GUI is, that it runs a shell command after clicking a button. For this I use the subprocess
module.
Since the shell command takes a while to complete, I use a thread so the GUI does not freeze.
So far, this all works, but now I would like to add another button, that can kill the shell command. If I run the command without my Python GUI, I just use ctrl-c
. How can I do that within my GUI, at the click of an button? I'd Imagine that this is a fairly common and easy thing to do, but I just didn't find anything that would work for me ...
Here is a minimal version of my code:
import subprocess
import Tkinter as tk
from threading import Thread
import signal
class GUI:
def __init__(self,master):
self.master = master
master.title('Program')
#Button to Run command
self.button_idarun = tk.Button(master,text="Run",command=self.Runthread)
self.button_idarun.grid(row = 0, column = 0)
#Button to terminate command
self.button_terminate = tk.Button(master, text = "Stop", command = self.terminate)
self.button_terminate.grid(row = 1, column =0)
#Function that runs command.
def Run(self):
self.p = subprocess.Popen("cd IDA/trunk;./job_sge", stdout=subprocess.PIPE, stderr=subprocess.STDOUT,shell=True)
for line in iter(self.p.stdout.readline,''):
print line
#Function that calls Run in a thread, so other buttons can still be pressed ...
#Probably not the correct way to do this(?)
def Runthread(self):
self.thread = Thread(target=self.Run)
self.thread.start()
#Function that terminates the process started in RUN
#This is the part that does not work.
def terminate(self):
self.p.send_signal(signal.SIGINT)
root = tk.Tk()
gui = GUI(root)
root.mainloop()
Thanks in advance for any help you guys can offer, and sorry for my bad coding. I'm trying my best here :-/
Edit:
So I now tried an even simpler version of my code and replaced the command that I actually want to run with a simple ping. So the function Run
looks now like this:
def Run(self):
self.p = subprocess.Popen("ping 8.8.8.8", stdout=subprocess.PIPE, stderr=subprocess.STDOUT,shell=True)
for line in iter(self.p.stdout.readline,''):
print line
With the Ping, my Program works without problems. When I click Run
, it starts continuously pinging, until I click Stop
, when it stops.
So the Problem seems to be the command ./job_sge
that I am running. Though I do not understand why this would make a difference. If I execute it from the shell directly, I can kill it with ctrl-c
, isn't that the same thing signal.SIGINT
does?
Edit 2:
Ok, so I think I found the problem. Appearently, it doesn't work, if you send two commands at once. For example, with the ping command above it works, but when I click the Run button twice, it doesn't anymore.
Same if I cange the Run
command for example to
def Run(self):
self.p = subprocess.Popen("cd ..;ping 8.8.8.8", stdout=subprocess.PIPE, stderr=subprocess.STDOUT,shell=True)
for line in iter(self.p.stdout.readline,''):
print line
then the stop button does not work anymore either.
The problem now is that my command ./job_sge
is a bash script that itself runs several other commands. So even if I change cd IDA/trunk;./job_sge
to <Full Path>/job_sge
, I still can not stop the command ...