如何打印另一个Tkinter脚本中调用的gui脚本的输出?

时间:2017-12-30 22:48:30

标签: python tkinter python-2.x

我尝试过使用我在网上找到的几种不同的类似解决方案,但似乎没有一种方法可以完全实现我的目标。

我想将一个外部脚本(helloworld.py)调用到我的tkinter gui中。我希望这个名为脚本(helloworld.py)的函数在gui中按下按钮时执行其中包含的所有函数,并将结果输出打印到gui中,而不是控制台。我找到了一些解决方案,将输出打印到控制台,但我无法让它显示在gui中。当我试图让输出来自一个被调用的外部脚本时,我发现打印到gui的任何解决方案都不起作用。

我感谢任何帮助。我绝对是一个新手,所以我为可能是一个基本问题而道歉,并且无法在这里提出的类似问题上为自己连接点。下面是我目前正在使用的代码版本之一。提前感谢您的帮助!

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

修改

我也开始尝试将被调用的脚本作为模块导入。这个问题是我只能从被调用的脚本中打印出一个函数,即使我想尝试和调用多个函数(我只是希望整个被调用的脚本打印出其函数的所有结果)。

以下是我想调用helloworld.py的脚本示例:

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

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

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

以下是尝试导入helloworld.py的tkinter gui脚本示例:

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

这导致只有第一个函数打印('hello worldz!')。有关为什么它只会返回一行而不是整个helloworld.py脚本的任何想法?

2 个答案:

答案 0 :(得分:2)

您可以使用subprocess.check_output()获取输出并分配到Label

您还可以import脚本并从脚本执行函数。

import test
test.function()

但首先,您必须使用sys.stdout类重定向write(),然后它将捕获所有打印文本。

您可以将sys.stdout重定向到变量(请参阅StdoutRedirector),然后您可以对其进行编辑(即最后为条带\n),也可以直接重定向到Label (见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 :(得分:1)

在运行return ...行的方法中,在该行之后将看不到任何其他内容,因为return ...的第二行实际上没用,因为return cooz()是无条件地运行 。您只需将main替换为:

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

并据此printSomething

x, y = helloworld.main()

从脚本返回所有方法/函数,而不显式传递方法名称:

嗯,我stand corrected,基于this answer你可以相当简单地做到。对于调用所有方法或函数this answer有很多帮助。

假设有一个名为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))

位于以下GUI脚本的相同的目录中:

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

hello_world.py作为字符串返回所有方法和函数的控制台输出。根据{{​​3}},然后将该字符串放在this suggestion字段中。