Автоматическое обновление метки tkinter, которая недоступна напрямую

#python #user-interface #tkinter

#python #пользовательский интерфейс #tkinter

Вопрос:

Я хочу создать простой графический интерфейс для постоянных данных, которые поступают через Serial. Я решил использовать tkinter. Значение reading обновлено и должно быть отображено в метке. Я создал отдельные классы для контейнера и других страниц. Я определил контейнер как таковой:

 class Gui(Tk):
def __init__(self, *args, **kwargs):
    Tk.__init__(self, *args, **kwargs)
    container = Frame(self)
    container.pack(side="top", fill = "both", expand = TRUE)
    container.grid_rowconfigure(0, weight = 1)

    self.frames={}

    for F in (StartPage, PageOne):
        frame = F(container, self)
        self.frames[F] = frame
        frame.grid(row = 0, column = 0, sticky = "nsew")
        frame.UpdateMe()

    self.show_frame(StartPage)


def show_frame(self, cont):
    frame = self.frames[cont]
    frame.tkraise()
  

И страница, показывающая метку:

 class PageOne(Frame):
def __init__(self, parent, controller):
    Frame.__init__(self,parent)
    global reading
    self.label1text = StringVar()
    self.label1 = Label(self, textvariable = label1text)
    self.label1.pack()
    button1 = Button (self, text = "Show Start Page", command = lambda: controller.show_frame(StartPage))
    button1.pack()
    self.label1text.set(reading)


def UpdateMe(self):
    global reading
    self.lable1text.set(reading)
  

Теперь, чтобы инициализировать графический интерфейс:

 root = Gui()
root.mainloop()
  

Однако, поскольку mainloop() это блокировка, любой аргумент, следующий за этим, не будет выполнен; я мог бы обойти это с помощью update и update_idletasks . Однако я все еще не знаю, как я мог вызвать функцию UpdateMe() внутри PageOne() , когда я только создал экземпляр Gui() . Есть ли способ для меня решить это или исправить мое понимание классов и объектного программирования?

Комментарии:

1. Можете ли вы создать reading a StringVar и использовать его как textvariable of self.label1 ? Тогда при каждом reading обновлении метка также будет обновляться, и вызывать ее не нужно frame.UpdateMe() .

2. Я попытался сделать то, что вы рекомендовали. Окно будет отображаться, но метка будет пустой. Я проверил, что значение reading меняется при использовании другого потока.

3. Можете ли вы обновить свой вопрос с вашими изменениями на данный момент?

Ответ №1:

Поскольку вы не можете создавать StringVar без инициализации Tk() (в вашем случае это так Gui() ), поэтому вам нужно создать reading переменную внутри Gui() и PageOne.label1 использовать ее как свою textvariable . Ниже приведен пример, основанный на вашем коде:

 from tkinter import *
from random import randint

class Gui(Tk):
    def __init__(self, *args, **kwargs):
        Tk.__init__(self, *args, **kwargs)
        container = Frame(self)
        container.pack(side="top", fill="both", expand=True)
        container.grid_rowconfigure(0, weight=1)
        container.grid_columnconfigure(0, weight=1)

        self.reading = StringVar() # create the StringVar for PageOne

        self.frames = {}
        for F in (StartPage, PageOne):
            frame = F(container, self)
            frame.grid(row=0, column=0, sticky="nsew")
            self.frames[F] = frame
        self.show_frame(StartPage)

    def show_frame(self, cont):
        self.frames[cont].tkraise()

class StartPage(Frame):
    def __init__(self, parent, controller):
        Frame.__init__(self, parent)
        button1 = Button (self, text="Show Page 1", command=lambda: controller.show_frame(PageOne))
        button1.pack(fill="both", expand=True)

class PageOne(Frame):
    def __init__(self, parent, controller):
        Frame.__init__(self, parent)
        self.label1 = Label(self, textvariable=controller.reading) # refer to Gui.reading StringVar
        self.label1.pack(fill='x')
        button1 = Button (self, text="Show Start Page", command=lambda: controller.show_frame(StartPage))
        button1.pack(fill='x')


# use .after() to simulate the update of reading variable periodically
def update_reading():
    app.reading.set(randint(0, 10000))
    print('reading:', app.reading.get())
    app.after(1000, update_reading)

app = Gui()
update_reading() # start the simulation task of updating reading variable
app.mainloop()
  

Обратите внимание, что я создал функцию update_reading() для имитации периодического обновления reading переменной с помощью after() function.