Как управлять sys.stdout на ScrolledText - PullRequest
0 голосов
/ 08 апреля 2019

Я написал простое приложение, см. Ниже, для перенаправления данных справочной функции библиотеки tkinter на ScrolledText, что-то вроде

print (help (tkinter.Label)) на cli.

Я использую класс, написанный @Bryan Oakley.

После запуска скрипта нажмите кнопку «Загрузить» и после нажатия на голос в левом дереве.

Это приводит к записи данных функции справки выбранного элемента в ScrolledText с использованием sys.stdout из класса @Bryan Oakley

sys.stdout.write (help (s))

Все работает, но я не могу обновить данные на ScrolledText даже с

self.widget.delete ('1.0', tk.END)

, чем при использовании

sys.stdout.flush ()

По сути, я не могу, когда вы щелкаете по другому элементу, удалить все данные из ScrolledText и написать новый sys.stdout

Что неправильно в моем подходе?

import sys
import tkinter as tk
from tkinter import ttk
from tkinter.scrolledtext import ScrolledText


class TextRedirector(object):
    """Written Bryan Oakley
       https://stackoverflow.com/users/7432/bryan-oakley 
    """
    def __init__(self, widget, tag="stdout"):

        self.widget = widget
        self.tag = tag

    def write(self, str):
        #this generate an error
        #self.widget.delete('1.0', tk.END)
        self.widget.configure(state="normal")
        #it works but generete an error
        self.widget.insert("end", str, self.tag)
        self.widget.configure(state="disabled")

class App(tk.Frame):

    def __init__(self,):

        super().__init__()

        self.master.title("Hello Tkinter ")

        self.selected = tk.StringVar()

        self.init_ui()

    def init_ui(self):

        f = tk.Frame()

        f1 = tk.Frame(f)

        tk.Label(f, textvariable = self.selected).pack()
        cols = (["#0",'','w',False,200,200],
                 ["#1",'','w',True,0,0],)

        self.Voices = self.get_tree(f1, cols, show="tree")
        self.Voices.show="tree"
        self.Voices.pack(fill=tk.Y, padx=2, pady=2)
        self.Voices.bind("<<TreeviewSelect>>", self.on_selected)
        f1.pack(side=tk.LEFT, fill=tk.BOTH, expand=0)

        f2 = tk.Frame(f)

        self.text = ScrolledText(f2)
        self.text.pack(side="top", fill="both", expand=True)
        self.text.tag_configure("stderr", foreground="#b22222")

        sys.stdout = TextRedirector(self.text, "stdout")
        sys.stderr = TextRedirector(self.text, "stderr")

        f2.pack(side=tk.LEFT, fill=tk.BOTH, expand=1)

        w = tk.Frame()

        tk.Button(w, text="Load", command=self.set_values).pack()
        tk.Button(w, text="Close", command=self.on_close).pack()

        w.pack(side=tk.RIGHT, fill=tk.Y, expand=0)
        f.pack(side=tk.LEFT, fill=tk.BOTH, expand=0)

    def set_values(self,):

        rs = []

        for i in dir(tk):
            rs.append(i)

        for i in rs:

            tree = self.Voices.insert("", tk.END, text=i, values=(i,'tree'))

    def on_selected(self, evt=None):

        selected_item = self.Voices.focus()

        d = self.Voices.item(selected_item)

        if d['values']:

            item = (d['values'][0])

            self.selected.set(item)

            s = "tkinter.{}".format(item)
            #this generate an error
            #sys.stdout.flush()
            sys.stdout.write(help(s))


    def get_tree(self,container, cols, size=None, show=None):

        headers = []

        for col in cols:
            headers.append(col[1])
        del headers[0]

        if show is not None:
            w = ttk.Treeview(container,show=show)
        else:
            w = ttk.Treeview(container,)

        w['columns']=headers

        for col in cols:
            w.heading(col[0], text=col[1], anchor=col[2],)
            w.column(col[0], anchor=col[2], stretch=col[3],minwidth=col[4], width=col[5])

        sb = ttk.Scrollbar(container)
        sb.configure(command=w.yview)
        w.configure(yscrollcommand=sb.set)

        w.pack(side=tk.LEFT, fill=tk.BOTH, expand =1)
        sb.pack(fill=tk.Y, expand=1)

        return w

    def on_close(self):
        self.master.destroy()

if __name__ == '__main__':
    app = App()
    app.mainloop()

enter image description here

1 Ответ

1 голос
/ 08 апреля 2019

Добавление удаления внутри оператора write является неправильным решением, поскольку вы не всегда можете контролировать то, что отправляется в оператор записи.Например, help может фактически вызывать write более одного раза каждый раз, когда вы звоните.Если это произойдет, вы увидите только результаты самого последнего звонка на write.

Правильным решением является удаление содержимого перед вызовом help.Для этого вам нужно включить виджет перед удалением содержимого, так как класс перенаправителя, как написано, оставляет виджет отключенным.

Например, вы можете добавить метод clear в класс перенаправителя следующим образом:

class TextRedirector(object):
    ...
    def clear(self):
        self.widget.configure(state="normal")
        self.widget.delete("1.0", "end")
        self.widget.configure(state="disabled")

Затем вы можете вызвать его непосредственно перед вызовом справки:

def on_selected(self, evt=None):
    ...
    if d['values']:
        ...
        sys.stdout.clear()
        help(s)

Примечание: вам не нужно делать sys.stdout.write(help(s)), потому что help(s) просто возвращает пустую строку.help(s) уже отправляет информацию на стандартный вывод.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...