Решён
Как в Kivy обновлять данные на экране без перезапуска приложения?

IoT_Ninja Python
910
5

Пишу приложение на Kivy (Python 3.11), там есть экран с таблицей данных из SQLite. Данные в базе обновляются фоновым скриптом каждые 30 секунд.

Проблема: чтобы увидеть свежие данные, приходится закрывать приложение и открывать заново. Пробовал вызывать метод, который перечитывает базу и пересоздает виджеты, но интерфейс зависает на секунду и потом вообще крашится с ошибкой:

ValueError: Widget already has a parent, remove it first

Как правильно обновлять данные в Kivy без полного перезапуска? Может есть какой то аналог setState из Flutter или React?

UPDATE: Решил через Clock.schedule_interval + clear_widgets(). Спасибо всем, рабочий вариант ниже в ответе от второго комментатора.
Решение
45
Эксперт • 2 ответа

Ошибка Widget already has a parent говорит о том, что ты пытаешься добавить виджет, который уже находится в дереве. Перед добавлением новых виджетов нужно сначала удалить старые.

Вот рабочий паттерн:

from kivy.clock import Clock

class DataScreen(Screen):
    def on_enter(self):
        # запускаем обновление каждые 30 сек
        self.update_event = Clock.schedule_interval(self.refresh_data, 30)

    def on_leave(self):
        # останавливаем когда уходим с экрана
        self.update_event.cancel()

    def refresh_data(self, dt):
        container = self.ids.data_container
        container.clear_widgets()  # <-- сначала чистим
        rows = self.load_from_db()
        for row in rows:
            container.add_widget(DataRow(data=row))

    def load_from_db(self):
        # твой код чтения из SQLite
        pass

Ключевые моменты:

  • clear_widgets() удаляет все дочерние виджеты из контейнера
  • Clock.schedule_interval - это и есть аналог таймера, не блокирует UI
  • Не забудь отменять расписание при уходе с экрана, иначе будут утечки

Если данных много (сотни строк), лучше использовать RecycleView вместо пересоздания виджетов. Он переиспользует существующие виджеты и просто меняет им данные через свойство data.

Аватар IoT_Ninja

Заработало с clear_widgets(). RecycleView попробую позже, пока строк немного. Спасибо огромное!

20
Участник • 1 ответ

Если таблица большая, clear_widgets каждые 30 секунд убьет перформанс. RecycleView обновляется так:

self.ids.rv.data = [{'text': str(row)} for row in new_rows]

Присвоил новый список в .data и все, виджеты сами пересоздадутся. Никаких clear/add.

11
Участник • 2 ответа

А может не надо каждые 30 сек дергать базу? Посмотри в сторону Kivy Properties. Создай ObjectProperty или ListProperty, привяжи к нему виджеты через kv-язык, и меняй только само свойство. Kivy сам перерисует все что привязано.

Это ближе к тому что ты назвал setState. Реактивная модель, а не ручное пересоздание виджетов.

3
Участник • 1 ответ

kivy в 2026 году? серьезно?

посмотри на flet, там все это из коробки работает, обновление стейта одной строчкой page.update(). или хотя бы на KivyMD переходи, голый kivy это боль

1
Участник • 2 ответа

у меня такая же проблема была, только я на buildozer собирал под андроид и clock вообще переставал работать после сворачивания. так и не починил, забил и сделал кнопку "обновить" руками))

Написать ответ

Премодерация гостей

Вы отвечаете как гость. Ваш ответ будет скрыт до проверки модератором. Чтобы ответ появился сразу и вы получали репутацию — войдите в аккаунт.

Будьте вежливы и соблюдайте правила платформы.