#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
aStringVar
и использовать его какtextvariable
ofself.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.