run a shell script from Python GUI - python

I've a GUI which will perform some functions when the buttons are pressed.
now i want to create a button in the GUI which will call and run a shell script in the background.
how can i achieve this ?

Not sure if your question is about how to call a shell script in Python, or how to make a button in your GUI. If the former, my comment above (recommending some research on subprocess.Popen) is the solution. Otherwise:
# assuming Python3
import tkinter as tk
import subprocess as sub
WINDOW_SIZE = "600x400"
root = tk.Tk()
root.geometry(WINDOW_SIZE)
tk.Button(root, text="Push me!", command=lambda: sub.call('path/to/script')).pack()

Python can run shell scripts using the supbprocess module. In order to run it in the background you can start it from a new thread.
To use the module
import subprocess
...
subprocess.call(['./yourScript.sh'])
For a good python threading resource you can try: How to use threading in Python?

Adding to what #lakesh said, below is the complete script :
import Tkinter
import subprocess
top = Tkinter.Tk()
def helloCallBack():
print "Below is the output from the shell script in terminal"
subprocess.call('./yourscript.sh', shell=True)
B = Tkinter.Button(top, text ="Hello", command = helloCallBack)
B.pack()
top.mainloop()
Please note that the shell script is in the same directory as that of the python script.
If needed, do chmod 777 yourscript.sh
subprocess.call('./yourscript.sh', shell=True)
and import Tkinter and not import tkinter solved the problems I was facing.

Use Tkinter to create a button. For more info, look at this video:http://www.youtube.com/watch?v=Qr60hWFyKHc
Example:
from Tkinter import *
root = Tk()
app = Frame(root)
app.grid()
button1 = Button(app,"Shell Script")
button1.grid()
root.mainloop()
To add the functionality:
change button1 line to:
button1 = Button(app,"Shell Script",command=runShellScript)
def runShellScript():
import subprocess
subprocess.call(['./yourScript.sh'])

Related

How to run two parallel scripts from tkinter?

With this code I was able to create a TK Inter pop-up with a button to run a Sample_Function.
This Sample_Function destroys the tk pop-up, runs another python file, and then opens itself (the first pop-up) again.
How can I run the other_python_file and pop-up 'itself' at the same time — so I can be able to trigger many functions before each one gets completed?
import sys, os
from tkinter import *
import tkinter as tk
root = Tk()
def Sample_Function():
root.destroy()
sys.path.insert(0,'C:/Data')
import other_python_file
os.system('python this_tk_popup.py')
tk.Button(text='Run Sample_Function', command=Sample_Function).pack(fill=tk.X)
tk.mainloop()
I think this will do close to what you want. It uses subprocess.Popen() instead of os.system() to run the other script and rerun the pop-up which doesn't block execution while waiting for them to complete, so they can now execute concurrently.
I also added a Quit button to get out of the loop.
import subprocess
import sys
from tkinter import *
import tkinter as tk
root = Tk()
def sample_function():
command = f'"{sys.executable}" "other_python_file.py"'
subprocess.Popen(command) # Run other script - doesn't wait for it to finish.
root.quit() # Make mainloop() return.
tk.Button(text='Run sample_function', command=sample_function).pack(fill=tk.X)
tk.Button(text='Quit', command=lambda: sys.exit(0)).pack(fill=tk.X)
tk.mainloop()
print('mainloop() returned')
print('restarting this script')
command = f'"{sys.executable}" "{__file__}"'
subprocess.Popen(command)

Make a box and store the input in a variable tkinter

I'm trying to make a ping tool with a GUI on tkinter. The thing is that i would like to create a box where you could enter a web domain and then click ping and ping to that web. right now I have to change the web to ping on the code (V1.0) but i really tried to make the changes mentioned above but they don`t seem to work.
This is the original code:
#Imports
from subprocess import Popen, PIPE, STDOUT
import Tkinter as tk
from Tkinter import Tk
from threading import Thread
def create_worker(target):
return Thread(target=target)
def start_worker(worker):
worker.start()
#Ping printed on tkinter window root
def commande():
cmd = 'ping -c 10 google.com'
p = Popen(cmd.split(), stdout=PIPE, stderr=STDOUT)
for line in iter(p.stdout.readline, ''):
result.configure(text=line)
#tkinter code
root = Tk()
root.title('PingTool')
root.geometry('450x70+400+400')
worker = create_worker(commande)
tk.Button(root, text='Ping', command=lambda:start_worker(worker)).pack()
result = tk.Label(root)
result.pack()
root.mainloop()
One not working version:
from subprocess import Popen, PIPE, STDOUT
import Tkinter as tk
from Tkinter import Tk
from threading import Thread
#intput on the console
u = input('Website to ping: ')
def create_worker(target):
return Thread(target=target)
def start_worker(worker):
worker.start()
def commande():
cmd = 'ping -c 10 ' + u
p = Popen(cmd.split(), stdout=PIPE, stderr=STDOUT)#
for line in iter(p.stdout.readline, ''): #changes the text printed instead of printing multiple times
result.configure(text=line)#
root = Tk()
root.title('PingTool')
root.geometry('450x70+400+400')
worker = create_worker(commande)
tk.Button(root, text='Ping', command=lambda: start_worker(worker)).pack()
result = tk.Label(root)
result.pack()
root.mainloop()
The 'not working version' has the 'problem' that the input is written on the console. The idea is to create a label and input the text there.
I know this might not be the best place to ask something like this because it seems that i just want the work done but trust me I've really tried.
Thank you
PD: I'm starting with tkinter.
subprocess.check_output should be enough for what you want to do https://pymotw.com/2/subprocess/index.html#module-subprocess A simple program follows that runs the command when the button is pressed, and prints the output. I'll leave something for you to do, i.e. configure the text on a Label http://effbot.org/tkinterbook/label.htm and also you should add some code for an entry that is not a valid website.
import sys
if sys.version_info[0] < 3:
import Tkinter as tk ## Python 2.x
else:
import tkinter as tk ## Python 3.x
import subprocess
def button_callback():
ent_contents=ent.get()
output=subprocess.check_output("ping -c 10 "+ent_contents,
shell=True)
print "*****after", output, "\n"
root=tk.Tk()
ent=tk.Entry(root)
ent.grid(row=0, column=0)
ent.focus_set()
tk.Button(root, text="ping website", bg="lightblue",
command=button_callback).grid(row=1, column=0)
tk.Button(root, text="Exit Program", bg="orange",
command=root.quit).grid(row=2, column=0)
root.mainloop()

Tkinter threading and return to text widget

I've read some post on stack overflow,Issues intercepting subprocess output in real time, Redirect command line results to a tkinter GUI, i know i have to use threading and queue in tkinter, but I am still can't do the same thing because I am a beginner in program,please help.
The goal: When press a button, getting the 'top' command output and realtime display in tkinter text widget
The issue: I've tried to follow the code, but still cannot get the output, but I have not idea how to make it work.
from tkinter import *
import tkinter as tk
import subprocess
from threading import Thread
from queue import Queue
window = tk.Tk()
window.title('realtime')
window.geometry('800x400')
text = tk.Text(window)
text.pack()
button = tk.Button(window, text= 'Press')
button.pack()
window.mainloop()
This is only the gui outlook, please help
top refreshes itself now and then and I'm guessing that's the behavior you want to capture with threading and whatnot. However in this case it would be much easier to ask top to only run once, and have tkinter do the timing and refreshing:
import tkinter as tk
from sh import top
def update_text():
text.delete(0.0, tk.END)
text.insert(0.0, top('-b', n=1))
window.after(1000, update_text) # call this function again in 1 second
window = tk.Tk()
window.title('realtime')
window.geometry('800x400')
text = tk.Text(window)
text.pack()
button = tk.Button(window, text= 'Press', command=update_text)
button.pack()
window.mainloop()
You may need to install sh to run top like I did, or use subprocess.check_output if you want.
text.insert(0.0, subprocess.check_output(['top', '-b', '-n 1']))

Why always have to force quit python launcher after running Tkinter on Mac?

I'm using jupyter notebook on mac, recently I need to write interactive dialog box, so after google, I use Tkinter to make an interactive window.
But I was bothered by this problem couples day ,and still can't find a solution way.
Fisrt example:
from Tkinter import *
from tkFileDialog import askopenfilename
import sys
import os,time
def callback():
name= askopenfilename()
print name
errmsg = 'Error!'
Button(text='File Open', command=callback).pack(fill=X)
mainloop()
Second example:
from Tkinter import *
import sys,os
class YourApp(Tk):
def quit_and_close(self):
app.quit()
#os._exit(0)
#sys.exit(1)
#exit(0)
app = YourApp()
app.title('example')
app.geometry('400x300+200+200')
b = Button(app, text = "quit", command = app.quit_and_close)
b.pack()
app.mainloop()
And the third one:
import Tkinter as tk
import tkMessageBox
def ask_quit():
if tkMessageBox.askokcancel("Quit", "You want to quit now? *sniff*"):
root.destroy()
root = tk.Tk()
root.protocol("WM_DELETE_WINDOW", ask_quit)
root.mainloop()
After running those above code, always need have to force quit python launcher.
It is very weird, and annoying because after forcing quit, I will got the error:
Is it necessary to use python launcher as default window?
Is there possible to set another window to open ?
or is there proper way to close the launcher without causing programming crash?
p.s Even I try to use wxpython, it still open python launcher and got the same problem.

Tkinter program runs button command on startup?

So I have a program that is basically supposed to have a button that opens a file dialog in the (username) folder. But when I run the program it opens without even pushing the button. What's more, the button doesn't even show up. So in addition to that problem I have to find a way to turn the selected directory into a string.
import tkinter
import tkinter.filedialog
import getpass
gui = tkinter.Tk()
user = getpass.getuser()
tkinter.Button(gui, command=tkinter.filedialog.askopenfilename(initialdir='C:/Users/%s' % user)).pack()
gui.mainloop()
Regarding your first issue, you need to put the call to tkinter.filedialog.askopenfilename in a function so that it isn't run on startup. I actually just answered a question about this this morning, so you can look here for the answer.
Regarding your second issue, the button isn't showing up because you never placed it on the window. You can use the grid method for this:
button = tkinter.Button(gui, command=lambda: tkinter.filedialog.askopenfilename(initialdir='C:/Users/%s' % user))
button.grid()
All in all, your code should be like this:
import tkinter
import tkinter.filedialog
import getpass
gui = tkinter.Tk()
user = getpass.getuser()
button = tkinter.Button(gui, command=lambda: tkinter.filedialog.askopenfilename(initialdir='C:/Users/%s' % user))
button.grid()
gui.mainloop()
You forgot to use a geometry manager on the button:
button = tkinter.Button(window, command=test)
button.pack()
If you don't do it, the button won't be drawn. You might find this link useful: http://effbot.org/tkinterbook/pack.htm.
Note that to pass the command to handler you have to write only the name of the function (Like it's descibed in the other answer).
This is an old question, but I just wanted to add an alternate method of preventing Tkinter from running methods at start-up. You can use Python's functools.partial (doc):
import tkinter
import tkinter.filedialog
import getpass
import functools
gui = tkinter.Tk()
user = getpass.getuser()
button = tkinter.Button(
gui,
command=functools.partial(
tkinter.filedialog.askopenfilename,
initialdir='C:/Users/%s' % user)
)
button.grid()
gui.mainloop()

Categories

Resources