Обновите текстовый виджет Tkinter, как он написан, а не после того, как класс закончен - PullRequest
5 голосов
/ 05 июля 2011

Я в затруднении, так как это пишется на секретной машине, я не могу скопировать + вставить здесьБудучи новичком, мой подход, вероятно, неортодоксален.

У меня есть графический интерфейс, написанный на Tkinter, с несколькими кнопками.Каждая кнопка связана с классом, который, по сути, запускает короткий скрипт.Когда кнопка нажата, я запускаю класс log_window, который является просто текстовым виджетом Tkinter.Затем я создаю глобальную переменную, связывающую log с только что созданным log_window, и когда скрипт запускается, я передаю sys.stdout/stderr в log (специально для этого я создал метод записи).Все является кошерным, за исключением того, что текстовый виджет log_window не обновляется с моим piped stdout до тех пор, пока не вызовет вызов класса.Однако, если я просто print внутри класса, он напечатает в том порядке, в котором он называется.

Пример

import Tkinter
from Tkinter import *
import time

class log_window:
    def __init__(self,master):
        self.textframe = Tkinter.Frame(master)
        self.text = Text(self.textframe)
        self.text.pack()
        self.textframe.pack()
    def write(self,text):
        self.text.insert(END,text)

class some_func1: # This effectively waits 5 seconds then prints both lines at once
    def __init__(self,master):
        log.write("some text")
        time.sleep(5)
        log.write("some text")

class some_func2: # This prints the first object, waits 5 seconds, then prints the second
    def __init__(self,master):
        print "some text"
        time.sleep(5)
        print "some text"

if __name__ == '__main__':
    global log    
    root = Tk()
    log = log_window(root)
    root.after(100,some_func1, root)
    root.after(100,some_func2, root)
    root.mainloop()

Извините, если мой пример немного приглушен, но ядумаю, что это имеет значение.Я использую Popen и некоторые системные вызовы, но они не являются частью проблемы, поэтому я только выделил то, что, как я полагаю, является ЖК-дисплеем проблемы.

Ответы [ 3 ]

8 голосов
/ 06 июля 2011

Я не знаю подробностей параллелизма Tkinter, но возни с этим показывают, что если вы поставите

master.update_idletasks()

после каждого вызова log.write обновляется по сигналу. Вы можете дать журналу .flush() метод для этого (как у файловых дескрипторов), или вы можете просто заставить log.write вызвать его после записи.

2 голосов
/ 07 июля 2011

Когда вы звоните sleep, это приводит к зависанию всего вашего графического интерфейса.Вы должны помнить, что ваш графический интерфейс запускает цикл обработки событий, который представляет собой бесконечный цикл, который оборачивает весь ваш код.Цикл событий отвечает за перерисовку виджетов при их изменении.Когда привязка запускается, она вызывает ваш код из этого цикла, поэтому, пока ваш код работает, цикл обработки событий не может зацикливаться.

У вас есть несколько вариантов.Одним из них является вызов update_idletasks после добавления текста в виджет.Это позволяет службе цикла событий «на холостых» событиях - вещи, которые запланированы для запуска, когда программа больше ничего не делает.Перерисовка экрана - одно из таких событий, и есть и другие.

Другой вариант - запускать ваши функции в потоке или отдельном процессе.Поскольку Tkinter не является поточно-ориентированным, эти другие потоки или процессы не могут напрямую взаимодействовать с GUI.Что они должны сделать, это отправить сообщение в очередь, а затем ваш основной поток (GUI) должен опросить очередь и удалить сообщения.Было бы легко встроить этот код в ваш класс журнала, и опрос очереди можно выполнить с помощью цикла обработки событий - просто напишите метод, который извлекает сообщения из очереди и вставляет их в виджет, а сам вызов вызывает с помощью afterнесколько сотен миллисекунд спустя.

0 голосов
/ 31 мая 2019

Вы должны обновить содержимое виджета, добавив self.text.update() после self.text.insert(END,text)

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