Home > Net >  How do I keep a tkinter GUI responsive when running a subprocess for its stdout?
How do I keep a tkinter GUI responsive when running a subprocess for its stdout?

Time:09-06

So I'm trying to make a GUI for my python script with Tkinter. I want I fairly simple just window where you can type the IP you want to ping and a button to execute the command. Here is my script:

import os
address = input("Enter Ip Here:")
os.system(f"ping {address} -t -l 65500")

So basically what I want is to be able to type the {address} in a small window and then press a button below to execute this but I can't figure out how to do this. (I have already tried the script and it works in the cmd prompt. I just want a GUI for it. Help would be appreciated!

I also made a separate script which opens a window with Tkinter and it has an exit button to close the window:

import Tkinter as tk
from Tkinter import ttk

# root window
root = tk.Tk()
root.geometry('600x600')
root.resizable(False, False)
root.title('Ping Of Death')

# exit button
exit_button = ttk.Button(
    root,
    text='Execute',
    command=lambda: root.quit()
)

exit_button.pack(
    ipadx=5,
    ipady=5,
    expand=True
)

root.mainloop()

CodePudding user response:

Try this. Used ip address or hostname.

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(f'Starting ping request')
 
        result = os.popen(f"ping {self.entry.get()} -n 2")
        for line in result:
            self.insert_text(line)
 
        self.insert_text(f'ping request finished')
        self.button_state(True)
 
 
if __name__ == '__main__':
    app = tk.Tk()
    main_frame = MainFrame()
    app.mainloop()

CodePudding user response:

In order to do this you need to add an Entry to your window and execute your ping with address being set to the value of the entry once your button is pressed. Here is a simple example on how this could work:

import tkinter as tk


def ping(address):
    import os
    os.system(f"ping {address} -t -l 65500")


root = tk.Tk()
root.geometry('600x600')
root.resizable(False, False)
root.title('Ping Of Death')

ip_input_label = tk.Label(root, text="IP: ")
ip_input_label.grid(row=0, column=0)

ip_input = tk.Entry(root)
ip_input.grid(row=0, column=1)

button = tk.Button(root, text="Ping", command=lambda: ping(ip_input.get()))
button.grid(row=1, column=0)

root.mainloop()
  • Related