【问题标题】:Print the output of imported functions in Tkinter widget with Python使用 Python 在 Tkinter 小部件中打印导入函数的输出
【发布时间】:2021-07-06 17:59:06
【问题描述】:

我的 GUI 应用程序有两个文件:gui.py 包含所有 Tkinter 对象,controller.py 包含逻辑。逻辑是一个主函数def automation():,它嵌套了几个其他函数。该应用程序非常简单,只有一个按钮调用automation()

我想在 GUI 小部件中添加出现在终端中的打印语句和错误,以便用户可以看到发生了什么。我找不到为导入的模块执行此操作的方法。

gui.py

import tkinter as tk
from tkinter import *
from controller import automation    

root = tk.Tk()
frame_button = tk.Frame(root)
button = Button(frame_button, text="Ship", command=lambda:automation())
lower_frame = tk.Frame(root)
terminal = tk.Label(lower_frame)

frame_button.place()
button.place()
lower_frame.place()
terminal.place()

controller.py

def automation():
  def folder_cleaner():
    print('Folders cleaned')

  def dispatch():
    print('Dispatch done')

  def ship():
    print('Shipment successful')

  def process():
    folder_cleaner()
    dispatch()
    ship()

  process()

这非常简化,但每个函数都有许多不同类型的输出。如何将它们全部重定向到 gui.pyterminal widget 内?

【问题讨论】:

  • this: command=lambda:automation() 可以缩短为:command=automation

标签: python function user-interface tkinter


【解决方案1】:

为了在 UI 中显示输出,我在 gui.py 中添加了一个 output 函数。所以这个函数可以在controller.py中使用,我在调用automation的时候加了一个参数outputFunc。然后可以使用它代替打印来在 UI 中显示字符串。

gui.py

import tkinter as tk
from tkinter import *
from controller import automation    

def output(text):
    terminal.insert("end", text + "\n")

root = tk.Tk()
frame_button = tk.Frame(root)

button = Button(frame_button, text="Ship", command=lambda:automation(output))
lower_frame = tk.Frame(root)
#Changed to text widget as it is more ideal for this purpose
terminal = tk.Text(lower_frame)

#Changed place to pack so widgets actually display
frame_button.pack()
button.pack()
lower_frame.pack()
terminal.pack()

controller.py

def automation(outputFunc):
  def folder_cleaner():
    outputFunc('Folders cleaned')

  def dispatch():
    outputFunc('Dispatch done')

  def ship():
    outputFunc('Shipment successful')

  def process():
    folder_cleaner()
    dispatch()
    ship()

  process()

【讨论】:

    【解决方案2】:

    这是解决您的问题的一种方法(如果您的自动化在循环中运行或基本上没有那么快,它会确保在发生任何变化时进行更新):

    from tkinter import Tk, Button, Label, Frame
    from _thread import start_new_thread
    from time import sleep
    
    
    values = {'random_values': []}
    
    
    def automation():
        for i in range(10):
            values['random_values'].append(i)
            sleep(3)
    
    
    def watch_values():
        compare = None
        while True:
            value = str(values['random_values'])
            if compare != value:
                label.config(text=values['random_values'])
                compare = value
    
    
    root = Tk()
    
    Button(root, text='start', command=lambda: start_new_thread(automation, ())).pack()
    
    label = Label(root)
    label.pack()
    start_new_thread(watch_values, ())
    
    root.mainloop()
    

    所以基本上首先它会启动一个线程来监视values 字典(重要的是它仅在发生更改时才与 tkinter 交互,否则它会导致 tkinter GUI 出现问题,这就是为什么有 @987654323 @)。

    只要该特定变量发生变化,它就会将标签文本设置为该变量(变量为values['random_values'])。

    然后是自动化功能。我建议您将它返回的所有内容都放在一个字典中,该字典将由另一个线程监视。您还需要线程化您的自动化功能,以便它可以并行工作。 (而且您显然可以从另一个文件中导入该函数,只需将其添加到线程中,这看起来也很奇怪,但是那些空元组是必要的,因为这是一个参数(在这些元组中,如果你有这些,但在这种情况下没有))

    而且您只需要一个观察函数,只需向该循环添加更多比较和检查等等(如果您想为字典中的每个键创建这样的函数,这是完全没有必要的)

    【讨论】:

      猜你喜欢
      • 2019-02-22
      • 1970-01-01
      • 2022-11-13
      • 2015-12-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多