Ping a website with output to Tkinter - python

I try to ping a website and display the output in real-time to a Label. Problem : the command makes an infinite loop (nom_mp4 = tk.Label(root, text=line) and the code stop before nom_mp4.pack().
Someone has an idea to make it work?
This is my code :
from subprocess import Popen, PIPE, STDOUT
import Tkinter as tk
from Tkinter import *
def commande():
cmd = 'ping www.wikipedia.com'
p = Popen(cmd.split(), stdout=PIPE, stderr=STDOUT)
for line in iter(p.stdout.readline,''):
nom_mp4 = tk.Label(root, text=line)
nom_mp4.pack()
root = Tk()
root.geometry('300x190+400+400')
browsebutton2 = tk.Button(root,text='Ping',command=commande) #le bouton browse
browsebutton2.pack()
root.mainloop()

One solution is to use threading.
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()
def commande():
cmd = 'ping www.wikipedia.com'
p = Popen(cmd.split(), stdout=PIPE, stderr=STDOUT)
for line in iter(p.stdout.readline, ''):
nom_mp4 = tk.Label(root, text=line)
nom_mp4.pack()
root = Tk()
root.geometry('300x190+400+400')
worker = create_worker(commande)
tk.Button(root, text='Ping', command=lambda: start_worker(worker)).pack()
root.mainloop()

cmd = 'ping www.wikipedia.com'
This will run infinite. You need to define how many times you want it to run. And maybe not ping a website when you are testing. For example:
cmd = 'ping -c 10 localhost'
-c 10 tells ping to run 10 times. localhost is just pinging your own machine, replace with URL when you have it working as intended.
You should also move the creation of the tk.Label outside of the for-loop. You don't need to create a new label each time, you just need to change the text value of the label. If you create and pack it after the tk.Button, it will appear below the button in the window.
To update the text of a tk.Label, you can do something like:
nom_mp4.configure(text=new_value_here)
The window will not be updated while the for-loop runs, and it will be "locked" until the loop has finished. To have it update you can put this at the end of the for-loop:
root.update_idletasks()
The window will still be locked though. To fix this I belive you will have to look into threading or something similar.

It works ! I have changed the code with your suggestions. I didn't put the -c option on the ping command because I wanted ping to work on its own without blocking the program. I changed the position of the pack outside of the loop as suggested by Oystein-hr and update the text with a configure. I also insert a threading with the example of Josh Leeb-du Toit.
Thanks guys.
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()
def commande():
cmd = 'ping localhost'
p = Popen(cmd.split(), stdout=PIPE, stderr=STDOUT)
for line in iter(p.stdout.readline, ''):
result.configure(text=line)
root = Tk()
root.geometry('600x80+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()

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()

Need help interacting with Python GUI while there is a process being run

I am developing an application that will run a batch of a test when you press a Start Button on the GUI. The problem is that once that subprocess to run the test is called, the Python GUI freezes until the subprocess is finished executing. I am using Python 2.7 by the way.
I would like to interact with the GUI while the test is running, have different buttons that can be pressed, etc. without interrupting the test.
Here is an excerpt of what I have for this part:
import Tkinter
import tkMessageBox
import subprocess
top = Tkinter.Tk()
def batchStartCallBack():
tkMessageBox.showinfo("Batch Application", "Batch STARTED!")
for x in range(0, 3):
p = subprocess.call('batch path', stdout = None, stderr = None, shell=False)
def batchStopCallBack():
tkMessageBox.showinfo("Batch Application", "Batch Stopped!")
# STOP BATCH
StartButton = Tkinter.Button(top, text = "Start Batch", command = batchStartCallBack, width = 8, height = 2)
StopButton = Tkinter.Button(top, text = "Stop Batch", command = batchStopCallBack, width = 8, height = 2)
StartButton.pack()
StopButton.pack()
top.mainloop()
You should use subprocess.Popen which is non-blocking. Calls to subprocess.call will make the current script wait until the subprocess has finished. In a gui, an endless loop is run checking for input and this means your gui will unresponsive as you have seen. It may be possible to initialise a subprocess pool and use a separate subprocess for the gui and another for the run...

run a shell script from Python GUI

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'])

How do I use Tkinter and allow my application to keep the focus?

I have a small application that the user can interact with as a command line. I want the user to be able to copy to the Windows clipboard information that the application has just displayed on-screen. Obviously, the user can do this manually, but it takes several steps: right-click on the window, select "Mark", select the rectangle of text, and press Enter to copy it. I want to allow the user to do this automatically by typing a short command like "cb" or "copy".
Per this answer, an easy way to get clipboard functionality is using the tkinter library. This does indeed work well. However, I find that when my application starts up, it loses the focus. It seems that a hidden window (opened by Tk() and then hidden by withdraw()) has it. The act of hiding the window with withdraw() did not give focus back to my application. This is inconvenient, because having opened the application, the user has to manually switch back to it rather than being able to just begin typing.
I want to create a tkinter object and either give the focus back to my application after I hide the new window, or have my application not lose focus in the first place. How can I do this?
There are various questions already relating to tkinter and focus, but they seem generally to relate to giving focus to the windows that tkinter itself opens, whereas I want to keep focus on the original window of my application, and deny it to the tkinter window.
I'm working at a Windows 8 machine.
Pastebin http://pastebin.com/6jsasiNE
On Windows NT, Windows Server 2003, and Windows 7+
You don't need to use Tkinter at all to achieve your goal.
clip.py:
import subprocess
def write_to_clipboard(string):
p = subprocess.Popen(['clip'], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
p.communicate(input=string)
This code just calls the standard windows clip.exe utility, pasting whatever passed in the string variable.
Usage:
from clip import write_to_clipboard
try:
while True:
write_to_clipboard(raw_input())
except KeyboardInterrupt:
pass
On Windows 95, 98, ME, and XP
Those versions of windows don't come with clip.exe, so here's a python only version:
clip.py:
import subprocess
def write_to_clipboard(string):
p = subprocess.Popen(['python', __file__], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
p.communicate(input=string)
if __name__ == "__main__":
import sys
from Tkinter import Tk
r = Tk()
r.withdraw()
r.clipboard_clear()
r.clipboard_append(sys.stdin.read())
r.update()
r.destroy()
This will work on all version of windows and in face any OS supporting TK.
Note that you must run the Tk code in a separate process like this, because even though we call r.destroy(), Tk seems to "lock" the clipboard (no other process can access the clipboard until this process has exited).
Reading and Writing Clipboard
If you want to be able to read from the clipboard as well as write to it, this is the solution.
clip.py:
import subprocess
def write(string):
p = subprocess.Popen(['python', __file__, 'write'], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
p.communicate(input=string)
def read():
p = subprocess.Popen(['python', __file__, 'read'], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
return p.communicate()[0]
if __name__ == "__main__":
import sys
from Tkinter import Tk
if len(sys.argv) != 2:
sys.exit(1)
r = Tk()
try:
r.withdraw()
if sys.argv[1] == "write":
r.clipboard_clear()
r.clipboard_append(sys.stdin.read())
r.update()
elif sys.argv[1] == "read":
sys.stdout.write(r.clipboard_get()),
else:
sys.exit(1)
finally:
r.destroy()
Usage:
import clip
print "clipboard contains: %s" % clip.read()

Categories

Resources