How can I print output from a script to a gui called in another Tkinter script?

I have tried a few different similar solutions I found on the internet, but none seem to do what I was aiming for.

I want to call an external script (helloworld.py) in my tkinter gui. I want this to call a script (helloworld.py) to execute all the functions it contains on a button click in the gui and print the resulting outputs to the gui, not the console. I found some solutions that will print the output to the console, but I can't seem to get it to show up in the gui. Any solutions I've found that printing to the gui doesn't work when I try to get the output coming from the external script being called.

I appreciate any help. I am definitely a newbie so I apologize for what is probably the main question and not being able to connect the dots for myself on similar questions asked here. Below is one of the versions of the code I'm currently working with. Thank you in advance for your help!

import Tkinter
import sys
import subprocess
sys.path.append('/users/cmbp')

def callback():
    import os
    print subprocess.call('python /users/cmbp/p4e/helloworld.py', 
shell=True)
    lbl = Tkinter.Label(master)
    lbl.pack()

master = Tkinter.Tk()
master.geometry('200x90')
master.title('Input Test')

Btn1 = Tkinter.Button(master, text="Input", command=callback)
Btn1.pack()

master.mainloop()

      

EDIT

I also started to have some success trying to import the called script as a module. The problem is that I can only get one function to print from the called script, although there are several functions that I want to try and call (I just want the entire called script to print all the results of its function).

Here is an example script I want to call helloworld.py:

def cooz():
    return ('hello worldz!')

def tooz():
    return ("here is another line")

def main():
    return cooz()
    return tooz()

      

And here is an example tkinter gui script that tries to import helloworld.py:

import Tkinter as tk
import helloworld

def printSomething():
    y = helloworld.main()
    label = tk.Label(root, text= str(y))
    label.pack()


root = tk.Tk()
root.geometry('500x200')
root.title('Input Test')

button = tk.Button(root, text="Print Me", command=printSomething)
button.pack()

root.mainloop()

      

This results in only the first print function ("hello worldz!"). Any thoughts on why it is only returning one line and not the whole helloworld.py script?

+2


source to share


2 answers


You can use subprocess.check_output()

to get output and assignLabel

You can also import

script and execute a function from within a script.

import test
test.function()

      

But first you have to redirect sys.stdout

with class c write()

and then catch all the text.



You can redirect sys.stdout

to a variable (see StdoutRedirector

) and then you can edit it (i.e. strip \n

at the end) or you can redirect directly to Label

(see StdoutRedirectorLabel

)

import Tkinter as tk

# -----

import subprocess

def callback1():
    cmd = 'python test.py'

    # it will execute script which runs only `function1`
    output = subprocess.check_output(cmd, shell=True)

    lbl['text'] = output.strip()

# -----

class StdoutRedirector(object):

    def __init__(self):
        # clear before get all values
        self.result = ''

    def write(self, text):
        # have to use += because one `print()` executes `sys.stdout` many times
        self.result += text

def callback2():

    import test

    # keep original `sys.stdout
    old_stdout = sys.stdout

    # redirect to class which has `self.result`
    sys.stdout = StdoutRedirector()

    # it will execute only `function2`
    test.function2()

    # assign result to label (after removing ending "\n")
    lbl['text'] = sys.stdout.result.strip()

    # set back original `sys.stdout
    sys.stdout = old_stdout

# -----

import sys

class StdoutRedirectorLabel(object):

    def __init__(self, widget):
        self.widget = widget
        # clear at start because it will use +=
        self.widget['text'] = ''

    def write(self, text):
        # have to use += because one `print()` executes `sys.stdout` many times
        self.widget['text'] += text

def callback3():

    import test

    # keep original `sys.stdout
    old_stdout = sys.stdout

    # redirect to class which will add text to `lbl`
    sys.stdout = StdoutRedirectorLabel(lbl)

    # it will execute only `function3` and assign result to Label (with ending "\n")
    test.function3()

    # set back original `sys.stdout
    sys.stdout = old_stdout

# --- main ---

master = tk.Tk()
master.geometry('200x200')

lbl = tk.Label(master, text='')
lbl.pack()

btn1 = tk.Button(master, text="subprocess", command=callback1)
btn1.pack()

btn2 = tk.Button(master, text="StdoutRedirector", command=callback2)
btn2.pack()

btn3 = tk.Button(master, text="StdoutRedirectorLabel", command=callback3)
btn3.pack()

master.mainloop()

      

test.py

def function1():
    print('function 1')

def function2():
    print('function 2')

def function3():
    print('function 3')

if __name__ == '__main__':
    function1() 

      

+1


source


In the method, when the line with is executed return ...

, nothing will be visible what appears after that line, as in your second line it is return ...

useless as it return cooz()

runs unconditionally. You can simply replace yours main

with:

def main():
    return cooz(), tooz()

      

and accordingly yours printSomething

:

x, y = helloworld.main()

      


Returning all methods / functions from a script without explicitly missing method names:



Well I fixed the stand , based on this answer you can do it quite simply. For calling all methods or functions, this answer helped a lot.

Let's say there's a script named hello_world.py

:

def hello_world():
    print("Hello World!")
    print("this is the 2nd line of this method")

def multiplication(*args):
    mult = 1
    for arg in args:
        mult *= arg

    return mult

def some_other_method():
    print("some other method")
    print(multiplication(2, 3, 5, 7))

      

is in the same directory as the GUI script below:

import tkinter as tk    # required for the GUI
import subprocess       # required for redirecting stdout to GUI
import sys, inspect     # required for all methods and functions redirection
import hello_world      # the script file that is redirected

def redirect(module, method):
    '''Redirects stdout from the method or function in module as a string.'''
    proc = subprocess.Popen(["python", "-c",
        "import " + module.__name__ + ";" + module.__name__ + "." + method + "()"],
                                                                stdout=subprocess.PIPE)
    out = proc.communicate()[0]
    return out.decode('unicode_escape')

def redirect_module(module):
    '''Retruns all stdout from all methods or functions in module as a string.'''
    # to filter out non-method, and non-function attributes
    all_mtds_or_funcs = inspect.getmembers(sys.modules[module.__name__], 
                                                inspect.isfunction or inspect.ismethod)
    red_str_buffer = ""
    for method in all_mtds_or_funcs:
        red_str_buffer += redirect(module, method[0]) + "\n---\n"

    return red_str_buffer

def put_in_txt(module):
    '''Puts the redirected string in a text.'''
    txt.insert('1.0', redirect_module(module))

root = tk.Tk()
txt = tk.Text(root)
btn = tk.Button(root, text="Redirect")
btn['command'] = lambda module=hello_world : put_in_txt(module)

txt.pack()
btn.pack()

root.mainloop()

      

which returns the console output of all methods and functions in hello_world.py

as a string. Based on that suggestion, he puts that string in the Text field .

+1


source







All Articles