Reputation: 63
kivy 2.0.0, kivymd 0.104.2dev0, python3.7
I am having error intermittently when I add MDdatatable to new screen's MDBoxLayout with button press.
sometime get error immediately, sometime get error once out of 30 times of try.
AssertionError with .py and KeyError: <ParserRule name='<CommonElevationBehavior>'> with apk.
any one have idea where should I look?
and also have this warning too, intermittently, with button press.
[WARNING] <kivymd.uix.gridlayout.MDGridLayout object at 0x00000290BDE1D278> have no cols or rows set, layout is not triggered.
even if my all gridlayout have cols set.
here is my minimal code.
from kivymd.app import MDApp
from kivymd.uix.datatables import MDDataTable
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.lang import Builder
from kivy.metrics import dp
import threading, time
KV = """
ScreenManager:
id : scr_mng
Ad_control_main_screen:
Ad_control_detail:
<Ad_control_main_screen>:
id: ad_control_main_screen
name: 'ad_control_main_screen'
MDFillRoundFlatButton
text: 'detail'
pos_hint: {"center_x": 0.5, "center_y": 0.5}
on_release:
root.Adctr_detail()
<Ad_control_detail>
id: ad_control_detail
name: "ad_control_detail"
MDBoxLayout:
orientation: "vertical"
MDBoxLayout:
height: self.minimum_height
size_hint_y: None
AnchorLayout:
anchor_x: "center"
anchor_y: "center"
size_hint_y: None
padding: [0, 5, 0, 0]
MDGridLayout:
cols: 1
spacing: [10, 12]
size_hint: None, None
height: self.minimum_height
width: self.minimum_width
MDFillRoundFlatButton:
text: "back"
on_release:
root.get_back()
MDBoxLayout:
id: table_layout
"""
class Ad_control_main_screen(Screen):
def on_enter(self, *args):
global scr_mng
scr_mng = self.manager
scr_mng.transition.direction = 'left'
def Adctr_detail(self):
scr_mng.current = 'ad_control_detail'
class Ad_control_detail(Screen):
def on_enter(self, *args):
if self.ids.table_layout.children != []:
self.ids.table_layout.clear_widgets()
self.get_camData_thread()
def get_camData_thread(self):
get_cam_data = threading.Thread(target=self.create_table)
get_cam_data.daemon = True
get_cam_data.start()
def create_table(self, *args):
time.sleep(1)
r_data = []
for i in range(10):
r_data.append((i, "data "+str(i), "data "+str(i), "data "+str(i), "data "+str(i), "data "+str(i)))
c_data = [("", dp(5)),
("colum 1", dp(30)),
("colum 2", dp(15)),
("colum 3", dp(15)),
("colum 4", dp(15)),
("colum 5", dp(15)),]
data_table = MDDataTable(
use_pagination=False,
check=False,
elevation=0,
column_data=c_data,
row_data=r_data,
rows_num=int(len(r_data))
)
self.ids.table_layout.add_widget(data_table)
def get_back(self):
scr_mng.transition.direction = 'right'
scr_mng.current = 'ad_control_main_screen'
sm = ScreenManager()
sm.add_widget(Ad_control_main_screen(name='ad_control_main_screen'))
sm.add_widget(Ad_control_detail(name='ad_control_detail'))
class Test(MDApp):
def build(self):
return Builder.load_string(KV)
Test().run()
Upvotes: 0
Views: 122
Reputation: 39117
To use the thread, you must limit what you do in that thread. Some operations must be performed on the main thread. Here is a modified version of your Ad_control_detail
class that does that:
class Ad_control_detail(Screen):
def on_enter(self, *args):
if self.ids.table_layout.children != []:
self.ids.table_layout.clear_widgets()
self.get_camData_thread()
def get_camData_thread(self):
get_cam_data = threading.Thread(target=self.create_table)
get_cam_data.daemon = True
get_cam_data.start()
def add_table(self, r_data, c_data, dt):
# This does the operations that must be on the main thread
data_table = MDDataTable(
use_pagination=False,
check=False,
column_data=c_data,
row_data=r_data,
rows_num=int(len(r_data))
)
self.ids.table_layout.add_widget(data_table)
def create_table(self, *args):
# this does the operations that may be done on another thread
time.sleep(1)
r_data = []
for i in range(10):
r_data.append((i, "data " + str(i), "data " + str(i), "data " + str(i), "data " + str(i), "data " + str(i)))
c_data = [("", dp(5)),
("colum 1", dp(30)),
("colum 2", dp(15)),
("colum 3", dp(15)),
("colum 4", dp(15)),
("colum 5", dp(15)), ]
# run the add_table() method on the main thread
Clock.schedule_once(partial(self.add_table, r_data, c_data))
def get_back(self):
scr_mng.transition.direction = 'right'
scr_mng.current = 'ad_control_main_screen'
Upvotes: 1
Reputation: 39117
I believe the problem is that you are making changes to the GUI on a thread other than the main thread. Try changing:
class Ad_control_detail(Screen):
def on_enter(self, *args):
if self.ids.table_layout.children != []:
self.ids.table_layout.clear_widgets()
self.get_camData_thread()
to:
class Ad_control_detail(Screen):
def on_enter(self, *args):
if self.ids.table_layout.children != []:
self.ids.table_layout.clear_widgets()
# self.get_camData_thread()
self.create_table()
I think you also need to remove elevation=0,
from the MDDataTable
creation command.
Upvotes: 1