I'm trying to make a very simple GUI for my program(here i have replaced it with the test function). I'm able to run my code via the gui, but the output for the program is being displayed in the terminal. I want the output to be visible in my original window instead.
Here is my code:
import tkinter as tk
from test import *
from tkinter import *
import os
root = tk.Tk()
canvas = tk.Canvas(root, height=400, width =550, bg ="#202020")
canvas.pack()
#frame = tk.Frame(root, bg="white");
#frame.place(relwidth=0.8, relheight = 0.8, relx=0.1, rely=0.1)
topFrame = tk.Frame(root, bg="#202020")
topFrame.place(relwidth=1, relheight = 0.75)
bottomFrame = tk.Frame(root, bg="#202020")
bottomFrame.place(rely=0.75, relwidth=1, relheight = 0.25)
launch = tk.Button(bottomFrame, text="Launch", bg="white", fg="#202020", font="noah 10 bold", padx=20, command=test)
launch.place(in_=bottomFrame, rely=0.5, relx=0.5, anchor=CENTER)
root.mainloop()
and here is the other file I'm calling the function from:
import os
def test():
print("Hello World")
os.system("ping 192.168.0.1 -c 4")
Is there any way to capture the output of this function and display it in the topframe of my gui in realtime?
You can create class with function write()
which insert text to tkinter.Text
and assign its instance to sys.stdout
- and then print()
will send to tkinter.Text
class Redirect():
def __init__(self, widget):
self.widget = widget
def write(self, text):
self.widget.insert('end', text)
# some widget may need it
#def flush(self):
# pass
and
text = tk.Text(root)
text.pack()
# keep original stdout
old_stdout = sys.stdout
# assing Redirect with widget Text
sys.stdout = Redirect(text)
root.mainloop()
# assign back original stdout (if you need it)
sys.stdout = old_stdout
But os.system
you will have to replace with ie. subprocess.run()
to catch output and print()
it.
def test():
print("Hello World")
p = subprocess.run("ping -c 4 stackoverflow.com", shell=True, stdout=subprocess.PIPE)
print(p.stdout.decode())
Minimal working code
import tkinter as tk
import os
import sys
import subprocess
# --- functions ---
def test():
print("Hello World")
p = subprocess.run("ping -c 4 stackoverflow.com", shell=True, stdout=subprocess.PIPE)
print(p.stdout.decode())
# --- classes ---
class Redirect():
def __init__(self, widget):
self.widget = widget
def write(self, text):
self.widget.insert('end', text)
#def flush(self):
# pass
# --- main ---
root = tk.Tk()
text = tk.Text(root)
text.pack()
button = tk.Button(root, text='TEST', command=test)
button.pack()
old_stdout = sys.stdout
sys.stdout = Redirect(text)
root.mainloop()
sys.stdout = old_stdout
Two problems:
It sends text from subprocess
to widget Text
after getting all text from ping
. It may need more work to display line by line.
test()
needs some time to finish work and it blocks tkinter
so it can't update widgets and it freezes. It may need to run test()
in separated thread
but I don't know if this will not gives other problems because in many GUI frameworks you can't use widgets in separated threat.
EDIT: Version with threading
. It resolvs previous problems.
But it may have new problems:)
you can click button two times and it will run two pings
at the same time and mix strings from both pings
code doesn't have method to stop thread (ie. when you run ping
without -c 4
)
Code:
import tkinter as tk
import sys
import subprocess
import threading
# --- functions ---
def run():
threading.Thread(target=test).start()
def test():
print("Hello World")
p = subprocess.Popen("ping -c 4 stackoverflow.com".split(), stdout=subprocess.PIPE, bufsize=1, text=True)
while p.poll() is None:
msg = p.stdout.readline().strip() # read a line from the process output
if msg:
print(msg)
print("Finished")
# --- classes ---
class Redirect():
def __init__(self, widget):
self.widget = widget
def write(self, text):
self.widget.insert('end', text)
#def flush(self):
# pass
# --- main ---
root = tk.Tk()
text = tk.Text(root)
text.pack()
button = tk.Button(root, text='TEST', command=run)
button.pack()
old_stdout = sys.stdout
sys.stdout = Redirect(text)
root.mainloop()
sys.stdout = old_stdout
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.