I am using Kivy MDDataTables in a Python3 App. During runtime i want to dynamically add and remove rows in the table. When I add data using add_row(self, data: Union[list, tuple]), afterwards remove the rows using remove_row(self, data: Union[list, tuple]) and then start to fill the table again, it crashes after 20 to 50 rows with the following error message:
[INFO ] [Base ] Leaving application in progress...
Traceback (most recent call last):
File "<PATH TO PROGRAM>\test.py", line 93, in <module>
sm.run()
File "<PATH TO VIRTUAL ENV>\lib\site-packages\kivy\app.py", line 950, in run
runTouchApp()
File "<PATH TO VIRTUAL ENV>\lib\site-packages\kivy\base.py", line 582, in runTouchApp
EventLoop.mainloop()
File "<PATH TO VIRTUAL ENV>\lib\site-packages\kivy\base.py", line 347, in mainloop
self.idle()
File "<PATH TO VIRTUAL ENV>\lib\site-packages\kivy\base.py", line 387, in idle
Clock.tick()
File "<PATH TO VIRTUAL ENV>\lib\site-packages\kivy\clock.py", line 733, in tick
self.post_idle(ts, self.idle())
File "<PATH TO VIRTUAL ENV>\lib\site-packages\kivy\clock.py", line 776, in post_idle
self._process_events()
File "kivy\_clock.pyx", line 616, in kivy._clock.CyClockBase._process_events
File "kivy\_clock.pyx", line 649, in kivy._clock.CyClockBase._process_events
File "kivy\_clock.pyx", line 645, in kivy._clock.CyClockBase._process_events
File "kivy\_clock.pyx", line 218, in kivy._clock.ClockEvent.tick
File "<PATH TO VIRTUAL ENV>\lib\site-packages\kivy\uix\recycleview\__init__.py", line 257, in refresh_views
lm.set_visible_views(indices, data, viewport)
File "<PATH TO VIRTUAL ENV>\lib\site-packages\kivy\uix\recyclelayout.py", line 253, in set_visible_views
refresh_view_layout(index, opt, widget, viewport)
File "<PATH TO VIRTUAL ENV>\lib\site-packages\kivy\uix\recycleview\layout.py", line 148, in refresh_view_layout
self.apply_selection(index, view, index in self.selected_nodes)
File "<PATH TO VIRTUAL ENV>\lib\site-packages\kivy\uix\recycleview\layout.py", line 143, in apply_selection
view.apply_selection(self.recycleview, index, is_selected)
File "<PATH TO VIRTUAL ENV>\lib\site-packages\kivymd\uix\datatables\datatables.py", line 1804, in apply_selection
ic = instance_table_data.recycle_data[index].get("icon", None)
IndexError: list index out of range
I tried this on Windows 10 and Raspbian 11 using:
- Python 3.9
- Kivy v2.0.0
- KivyMD 1.0.0.dev0, git-Unknown, 2022-03-21, directly installed from Github
- Virtual Environment via Anaconda resp. venv
- Packages installed via Anaconda resp. pip
In an older version of the Program, I used kivymd 0.104.2 and directly added and removed the data to self._table.row_data. In this version of the program the same crash happens.
I see that there is an Index out of range Error, but i have no impact to change that. What can i do to fix the program and avoid the crash?
Example Code:
from kivymd.app import MDApp
from kivy.uix.screenmanager import ScreenManager
from kivy.uix.screenmanager import Screen
from kivymd.uix.datatables import MDDataTable
from kivy.metrics import dp
import threading
import time
class TestScreen(Screen):
def __init__(self, **kw):
super().__init__(**kw)
self._table = None
self.createTable()
def createTable(self):
self._table = MDDataTable(
rows_num=99,
column_data=[("col1", dp(10)),
("col2", dp(50)),
("col3", dp(20)),
("col4", dp(30)),
("col5", dp(15)),
("col6", dp(15)),
("col7", dp(15)),
])
self.add_widget(self._table)
def clearTable(self):
while len(self._table.row_data) > 0:
self._table.remove_row(self._table.row_data[-1])
def updateTable(self, data):
for item in data:
row = (str(len(self._table.row_data)),
item[0],
item[1],
item[2],
item[3],
item[4],
item[5])
self._table.add_row(row)
def addData(self):
self.updateTable([("1", "1", "1", "1", "1", "1", "1")] * 5)
def getTableSize(self):
return len(self._table.row_data)
class TestApp(MDApp):
def build(self):
sm = ScreenManager()
sm.add_widget(TestScreen())
return sm
class DataProvider(threading.Thread):
def __init__(self, sm):
threading.Thread.__init__(self)
self.sm = sm
def run(self):
time.sleep(1)
sm.root.current_screen.addData()
time.sleep(1)
sm.root.current_screen.clearTable()
while True:
sm.root.current_screen.addData()
time.sleep(1)
print(sm.root.current_screen.getTableSize())
sm = TestApp()
data_p = DataProvider(sm)
data_p.start()
sm.run()