[Tkinter] How to get the result of a ping to show in tkinter? - Printable Version +- Python Forum (https://python-forum.io) +-- Forum: Python Coding (https://python-forum.io/forum-7.html) +--- Forum: GUI (https://python-forum.io/forum-10.html) +--- Thread: [Tkinter] How to get the result of a ping to show in tkinter? (/thread-18983.html) |
How to get the result of a ping to show in tkinter? - jacklee26 - Jun-09-2019 Do anyone knows how to let ping to print in the tkinter GUI, not on the terminal i had tried many methods and find on the net just couldn't find a method to solve it. Many resource mention on subprocess or thread related methods. Could anyone help me, please? Thanks and really appreciate. import sys import os from tkinter import * def ping(): myinptext = entry.get() os.system("ping "+entry.get()+" -n 2" ) myGui = Tk() entry = StringVar() myGui.geometry('300x300') myGui.title("Get output inside GUI") mylabel = Label(myGui,text="Enter target IP or host as required.").pack() mybutton = Button(myGui,text ="Ping Test",command = ping).pack() myEntry = Entry(myGui,textvariable=entry) myEntry.insert(-1,"8.8.8.8") myEntry.pack() myGui.mainloop() RE: How to get the result of a ping to show in tkinter? - Yoriz - Jun-09-2019 This is quite a tricky task as calling ping can block the GUI mainloop. The code below uses the technique from the following forum tutorial. https://python-forum.io/Thread-Tkinter-How-to-deal-with-code-that-blocks-the-mainloop-freezing-the-gui import functools import os import tkinter as tk from concurrent import futures thread_pool_executor = futures.ThreadPoolExecutor(max_workers=1) def tk_after(target): @functools.wraps(target) def wrapper(self, *args, **kwargs): args = (self,) + args self.after(0, target, *args, **kwargs) return wrapper def submit_to_pool_executor(executor): def decorator(target): @functools.wraps(target) def wrapper(*args, **kwargs): return executor.submit(target, *args, **kwargs) return wrapper return decorator class MainFrame(tk.Frame): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.master.geometry('500x350') self.master.title("Get output inside GUI") self.entry = tk.StringVar() label = tk.Label( self.master, text="Enter target IP or host as required.") label.pack() entry = tk.Entry(self.master, textvariable=self.entry) entry.insert(-1, "8.8.8.8") entry.pack() self.button = tk.Button( self.master, text="Ping Test", command=self.on_button) self.button.pack() self.text = tk.Text(self.master) self.text.config(state=tk.DISABLED) self.text.pack(padx=5, pady=5) @tk_after def button_state(self, enabled=True): state = tk.NORMAL if not enabled: state = tk.DISABLED self.button.config(state=state) @tk_after def clear_text(self): self.text.config(state=tk.NORMAL) self.text.delete(1.0, tk.END) self.text.config(state=tk.DISABLED) @tk_after def insert_text(self, text): self.text.config(state=tk.NORMAL) self.text.insert(tk.END, text) self.text.config(state=tk.DISABLED) def on_button(self): self.ping() @submit_to_pool_executor(thread_pool_executor) def ping(self): self.button_state(False) self.clear_text() self.insert_text('Starting ping request') result = os.popen("ping "+self.entry.get()+" -n 2") for line in result: self.insert_text(line) self.insert_text('ping request finished') self.button_state(True) if __name__ == '__main__': app = tk.Tk() main_frame = MainFrame() app.mainloop() RE: How to get the result of a ping to show in tkinter? - DeaD_EyE - Jun-09-2019 Hm, I like the idea about using decorators for that. Previous I made an example, but was not willing to show it. It's too complex. I guess the OP will have problems to understand everything. The main problem in a GUI application is, that blocking calls, blocks the guis eventloop and then the gui is freezing for this time. Those kind of blocking calls should run in another thread or process, if it's a cpu intensive calculation. For io stuff a thread or threadpool is ok. import sys import socket from queue import Queue from ipaddress import ip_address from threading import Thread from subprocess import check_output from tkinter.ttk import ( Label, Entry, ) from tkinter import ( Tk, Button, Text, StringVar, END, Toplevel, BOTH ) # from tkinter.messagebox import showinfo # we need to make our own showinfo widget def validate_ip(ip): """ Validate an ip address if the address is a valid ipv4 or ipv6 address the functions returns True, otherwise it returns False """ try: ip_address(ip) except: return False else: return True class Showinfo(Toplevel): """ Spawns a new Toplevel window. """ def __init__(self, *, title, msg, width, height): super().__init__(width=width, height=height) self.title(title) Label(self, text=msg).pack(fill=BOTH) Button(self, text="Ok", command=self.destroy).pack(fill=BOTH) class App(Tk): def __init__(self): super().__init__() self.title('My Ping GUI') #self.geometry('500x400') self.ping_active = False self.validation_queue = Queue() self.validation_loop() self.ip = StringVar(self) self.ip.trace_add("write", self.validate) self.setup() def setup(self): Label(self, text="Enter target IP or host as required.").pack() Entry(self, textvariable=self.ip).pack() ping_button = Button(self, text="Ping Test", command=self.ping) ping_button.pack() self.ping_button = ping_button self.textbox = Text(self, width=150, height=10) self.textbox.pack(fill=BOTH) Button(self, text="Exit", command=self.destroy).pack() def validate(self, *args): self.validation_queue.put(self.ip.get()) def validation_loop(self): self._validation_loop = Thread(target=self._validation_worker, daemon=True) self._validation_loop.start() def set_ping_color(self, color): self.ping_button['activebackground'] = color self.ping_button['bg'] = color self.ping_button['highlightbackground'] = color def _validation_worker(self): while True: ip_or_host = self.validation_queue.get() is_ip = validate_ip(ip_or_host) if is_ip: self.set_ping_color("green") else: self.set_ping_color("red") # is useful if you want to join a queu # then join blocks, until all tasks are done self.validation_queue.task_done() def ping(self): if not self.ping_active: self.ping_active = True self.textbox.delete(1.0, END) ip = self.ip.get() thread = Thread(target=self.ping_thread) thread.start() def ping_thread(self): # code tested on linux # ping on windows has different options stdout = check_output(['ping', '-c', '3', self.ip.get()], encoding="utf8") # print(stdout) self.textbox.insert(END, stdout) Showinfo(title='Results', msg=stdout, width=500, height=100) self.ping_active = False App().mainloop() RE: How to get the result of a ping to show in tkinter? - jacklee26 - Jun-10-2019 seem like the code is really complicate, is there any more easier way. RE: How to get the result of a ping to show in tkinter? - joe_momma - Jun-15-2019 thanks Yoriz and Deadeye for your examples. Yoriz I guess your using windows because to get it to work on linux I changed: result = os.popen("ping "+self.entry.get()+" -n 2") for line in result: self.insert_text(line)to: result = os.popen("ping "+self.entry.get()+" -c 2") for line in result: self.insert_text(line)no output other wise DeadEye I got an attribute error: and changed this line in your __init__:self.ip.trace_variable("w", self.validate)then I got a type error: so I deleted the keyword encoding and everything worked:stdout = check_output(['ping', '-c', '3', self.ip.get()],)fyi, Joe RE: How to get the result of a ping to show in tkinter? - Yoriz - Jun-15-2019 (Jun-15-2019, 07:53 PM)joe_momma Wrote: Yoriz I guess your using windows Yes i'm using windows. RE: How to get the result of a ping to show in tkinter? - NebularNerd - Feb-10-2023 (Jun-09-2019, 04:13 PM)Yoriz Wrote: This is quite a tricky task as calling ping can block the GUI mainloop. Thanks you for saving what little sanity I had left I've been trying to get this to work for about a week, I'm using this with customtkinter after a bit of adapting it works a treat, now I can live print to the GUI and not have the whole thing freeze up I can move forward |