Python tkinter:使文本小部件自动滚动文本(与重定向的 stdout 一起使用)



我已将STDOUT重定向到文本小部件。 然后我使用线程运行一个子进程,通过 poll(( 捕获 stdout 并打印它(重定向到文本小部件(。

现在我希望小部件与文本小部件一起自动滚动,以便用户始终可以看到最新的输出。

(文本小部件的唯一用途是显示运行脚本的输出,因此请随时提出替代方案(

class myGui:
def __init__(self, master=none)
self.text_Output = tk.Text(frame_Output)
self.text_Output.config(borderwidth='1', height='10', insertborderwidth='2', relief='ridge')
self.text_Output.config(width='50')
# redirect stdout
redir = RedirectText(self.text_Output)
sys.stdout = redir
def runCode:
self.p = subprocess.Popen(["COMMAND HERE"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, bufsize=1, universal_newlines=True)
while self.p.poll() is None:
msg = self.p.stdout.readline().strip()
if msg:
print(msg)

class RedirectText(object):
def __init__(self, text_ctrl):
"""Constructor"""
self.output = text_ctrl
def write(self, string):
self.output.insert(tk.END, string)

Text有方法see(...(,您可以在插入新文本后使用它。

如果您使用see('end')那么它将滚动到最后。


最小的工作示例 - 它在每次insert()后滚动到最后

编辑:我添加了使用see()滚动到顶部(see('1.0')(或结尾(see('end')(的按钮。

import tkinter as tk
root = tk.Tk()
text = tk.Text(root)
text.pack()
button_top = tk.Button(root, text="Move to TOP", command=lambda:text.see('1.0'))
button_top.pack()
button_end = tk.Button(root, text="Move to END", command=lambda:text.see('end'))
button_end.pack()
# instert to Text and scroll it
for x in range(50):
text.insert('end', str(x) + 'n')
text.see('end')  # move to the end after adding new text
root.mainloop()    

编辑:使用类RedirectText的最小示例

import tkinter as tk
import sys
import datetime
# --- classes ---
class RedirectText(object):
def __init__(self, text_widget):
"""Constructor"""
self.output = text_widget
def write(self, string):
"""Add text to the end and scroll to the end"""
self.output.insert('end', string)
self.output.see('end')
# --- functions ---
def add_time():
"""Add current time every 2 seconds"""
print(datetime.datetime.now())
root.after(2000, add_time)
# --- main ---
root = tk.Tk()
text = tk.Text(root)
text.pack()
button_top = tk.Button(root, text="Move to TOP", command=lambda:text.see('1.0'))
button_top.pack()
button_end = tk.Button(root, text="Move to END", command=lambda:text.see('end'))
button_end.pack()
# keep original `stdout` and assing `RedirectText` as `stdout`
old_stdout = sys.stdout
sys.stdout = RedirectText(text)
# add some datetime at the beginning 
print('--- TOP ---')
for _ in range(50):
print(datetime.datetime.now())
# add new datetime every 2 seconds
add_time()
# write to console when `print()` and `sys.stdout` redirect to `Text`
old_stdout.write('Hello World!n')      # needs `n` 
print('Hello World!', file=old_stdout)  # doesn't need `n`
root.mainloop()    
# assign back original `stdout`    
sys.stdout = old_stdout

顺便说一句:如果您需要在print()重定向到Text时打印到控制台

old_stdout.write('Hello World!n')      # needs `n` 
print('Hello World!', file=old_stdout)  # doesn't need `n`

顺便说一句:您也可以使用file=进行打印,而无需将RedirectText分配给sys.stdout

redirect = RedirectText(text)
print('Hello World!', file=redirect)

最新更新