#python #pandas #tkinter
Вопрос:
У меня есть фрейм данных, отображаемый в графическом интерфейсе в виде таблицы с использованием pandastable. Я хотел бы, чтобы эта таблица часто обновлялась по мере поступления новых данных (которые обновляют столбцы фрейма данных).
Поэтому я написал этот простой пример, чтобы проиллюстрировать это:
Я создаю фрейм данных df, затем дважды обновляю его в программе, ожидая 5 секунд между каждым обновлением. Я ожидаю, что появится графический интерфейс, а затем содержимое будет обновляться с той же частотой. Вместо этого программа выполняется только с окончательным значением dt, отображаемым в таблице.
Я попытался использовать .update() и .redraw() вместо .show() для обновления значений, но это тоже не сработало.
Мы высоко ценим ваш вклад!
import pandas as pd
import tkinter as tk
from pandastable import Table
import time
df = pd.DataFrame({
'A': [1,1,1,1,1,1,],
'B': [1,1,1,1,1,1,],
'C': [1,1,1,1,1,1,],
'D': [1,1,1,1,1,1,],
})
root = tk.Tk()
root.title('PandasTable Example')
frame = tk.Frame(root)
frame.pack(fill='both', expand=True)
pt = Table(frame, dataframe=df)
pt.show()
time.sleep(5)
df = pd.DataFrame({
'A': [2,2,2,2,2,2,],
'B': [2,2,2,2,2,2,],
'C': [2,2,2,2,2,2,],
'D': [2,2,2,2,2,2,],
})
pt.model.df = df
pt.show()
time.sleep(5)
df = pd.DataFrame({
'A': [3,3,3,3,3,3,],
'B': [3,3,3,3,3,3,],
'C': [3,3,3,3,3,3,],
'D': [3,3,3,3,3,3,],
})
pt.model.df = df
pt.show()
root.mainloop()
Комментарии:
1. виджеты tkinter обновляются только при
mainloop()
запуске tkinter.root.mainloop()
выполняется после того, как вы дважды обновили табличную модель, поэтому вы можете видеть только последнюю табличную модель.2. Итак, должен ли я изменить порядок кода или вы хотите сказать, что я просто не могу сделать то, что я надеялся сделать?
3. В вашем случае вы можете добавить
root.update()
перед каждымtime.sleep(5)
.4. Блестяще! Это, кажется, решает мою проблему. Большое вам спасибо!
5. Итак, каков правильный порядок между root.show() и root.update()?
Ответ №1:
mainloop
запускает графический интерфейс — он показывает/отображает окно. Все, что было раньше mainloop
, — это только информация о mainloop
том, что она должна отображать.
Вы можете использовать root.update()
для принудительной mainloop()
перерисовки окна.
Или вы можете использовать root.after(milliseconds, function_name)
вместо sleep
, и он будет запускать код после запуска mainloop
Вы также можете использовать pt.readraw
вместо pt.show
после обновления pd.model.df
— он не будет мигать.
import pandas as pd
import tkinter as tk
from pandastable import Table
# --- function ---
def update1():
df = pd.DataFrame({
'A': [2,2,2,2,2,2,],
'B': [2,2,2,2,2,2,],
'C': [2,2,2,2,2,2,],
'D': [2,2,2,2,2,2,],
})
pt.model.df = df
#pt.show()
pt.redraw()
root.after(5000, update2)
def update2():
df = pd.DataFrame({
'A': [3,3,3,3,3,3,],
'B': [3,3,3,3,3,3,],
'C': [3,3,3,3,3,3,],
'D': [3,3,3,3,3,3,],
})
pt.model.df = df
#pt.show()
pt.redraw()
# --- main ---
df = pd.DataFrame({
'A': [1,1,1,1,1,1,],
'B': [1,1,1,1,1,1,],
'C': [1,1,1,1,1,1,],
'D': [1,1,1,1,1,1,],
})
# - gui -
root = tk.Tk()
root.title('PandasTable Example')
frame = tk.Frame(root)
frame.pack(fill='both', expand=True)
pt = Table(frame, dataframe=df)
pt.show()
root.after(5000, update1)
root.mainloop()
Если вы будете запускать один и тот же код, вы можете использовать after
его для запуска одной и той же функции.
import pandas as pd
import tkinter as tk
from pandastable import Table
# --- function ---
def update():
pt.model.df = 1
pt.redraw()
# run again after 5000ms (5s)
root.after(5000, update)
# --- main ---
df = pd.DataFrame({
'A': [1,1,1,1,1,1,],
'B': [1,1,1,1,1,1,],
'C': [1,1,1,1,1,1,],
'D': [1,1,1,1,1,1,],
})
# - gui -
root = tk.Tk()
root.title('PandasTable Example')
frame = tk.Frame(root)
frame.pack(fill='both', expand=True)
pt = Table(frame, dataframe=df)
pt.show()
root.after(5000, update)
root.mainloop()
Вы можете увидеть больше в моем блоге в статье Tkinter PandasTable Примеры [ГБ]
Комментарии:
1. Большое вам спасибо за ваш ответ, Фурас, однако в моем реальном коде я хочу сделать обновление на основе условия, а не на основе статической задержки по времени. Я знаю, что мой пример основан на временной задержке, но это была всего лишь иллюстрация изменения таблицы в реальном времени. Как я могу изменить ваш последний пример кода, чтобы он обновлялся по условию?
2. в каком состоянии? Я понятия не имею, чего ты хочешь. Вы должны показать все детали, чтобы получить ответ. Обычно в графическом интерфейсе мы используем
Button
для выполнения функцию, которая получает значения из других виджетов и используется в обновлении. Вы также можете назначить функцию некоторым виджетам (т. е.Checkbutton
,Optionmenu
,Slider
) и он выполнит эту функцию, когда вы измените значение в виджете, и это может изменить таблицу. И вы всегда можете использовать некоторыеif/else
изupdate()
них для периодического обновления таблицы с использованием условий.