Обновите содержимое таблицы с помощью pandastable (Python, tkinter)

#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() них для периодического обновления таблицы с использованием условий.