I created CustomCard for displaying data in sqlite. The problem i encounter is when there are atleast 20 CustomCards created, it shows the error based on the title.
[CRITICAL] [Clock ] Warning, too much iteration done before the next frame. Check your code, or increase the Clock.max_iteration attribute. Remaining events:
<ClockEvent (-1.0) callback=<bound method Label.texture_update of <main.AdaptiveLabel object at 0x000001994A383680>>>
<ClockEvent (-1.0) callback=<bound method BoxLayout.do_layout of <kivymd.uix.boxlayout.MDBoxLayout object at 0x000001994A317610>>>
**
This only happens when i used RecycleView. Before I was just using a loop of MDCards but the performance is degrading and i need atleast 100 cards to create so switching to RecycleView is important
Here is the minimal code:
class AdaptiveLabel(Label):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.size_hint_y = None
self.bind(texture_size=self.update_height)
self.bind(width=self.update_text_size)
def update_height(self, *args):
self.height = self.texture_size[1]
def update_text_size(self, *args):
self.text_size = (self.width, None)
class CustomCard(BoxLayout, RecycleDataViewBehavior):
bg_color = ListProperty([1, 1, 1, 1])
event_id = NumericProperty()
widget_count = NumericProperty()
event_type = StringProperty()
reference_number = StringProperty()
remarks = StringProperty()
image_count = NumericProperty()
latitude = NumericProperty()
longitude = NumericProperty()
image_path = StringProperty(defaultvalue='')
index = None
def refresh_view_attrs(self, rv, index, data):
self.index = index
self.event_id = int(data.get('event_id', 0))
self.widget_count = data.get('widget_count', 0)
self.event_type = data.get('event_type', '')
self.reference_number = data.get('reference_number', '')
self.remarks = data.get('remarks', '')
self.image_count = data.get('image_count', 0)
self.latitude = data.get('latitude', 0)
self.longitude = data.get('longitude', 0)
self.image_path = data.get('image_path', '')
return super(CustomCard, self).refresh_view_attrs(
rv, index, data)
def on_touch_down(self, touch):
if self.collide_point(*touch.pos):
self.on_release()
return True
return super(CustomCard, self).on_touch_down(touch)
def on_release(self):
app = MDApp.get_running_app()
print(f"Event ID on release: {self.event_id}")
app.display_event_details(self.event_id)
class MainFunction(MDApp):
def fetch_data_from_db(self):
conn = sqlite3.connect('event.db')
cursor = conn.cursor()
cursor.execute(
'SELECT event_id, event_type, reference_number, remarks, image_path, image_count, latitude,longitude FROM events')
data = cursor.fetchall()
print(data)
conn.close()
return data
# Main Add widgets
def add_main_widgets(self):
def fetch_data_thread():
events_data = self.fetch_data_from_db()
# Once data is fetched, update the UI on the main thread
Clock.schedule_once(lambda dt: self.update_ui_with_data(events_data), 0)
Thread(target=fetch_data_thread).start()
def update_ui_with_data(self, events_data):
event_buttons = self.sm.get_screen('main').ids.bottom_nav
card_list = self.sm.get_screen('main').ids.card_list
current_data = {card['event_id']: card for card in card_list.data}
for event in events_data:
event_id, event_type, reference_number, remarks, image_path, image_count, latitude, longitude = event
if event_id in self.cards_dict:
# Update existing card
card_data = self.cards_dict[event_id]
card_data['event_type'] = event_type
card_data['reference_number'] = reference_number
card_data['remarks'] = remarks
card_data['image_count'] = image_count
card_data['latitude'] = latitude
card_data['longitude'] = longitude
else:
card_data = {
'event_id': event_id,
'widget_count': len(self.cards_dict) + 1,
'event_type': event_type,
'reference_number': reference_number,
'remarks': remarks,
'image_count': image_count,
'latitude': latitude,
'longitude': longitude
}
self.cards_dict[event_id] = card_data
card_list.data.append(card_data)
event_buttons.action_items = [
MDActionBottomAppBarButton(icon="send-circle"),
MDActionBottomAppBarButton(icon="image"),
]
# Force a refresh
card_list.refresh_from_data()
And here is my kv file:
<CustomCard>:
orientation: "horizontal"
size_hint_y: None
height: self.minimum_height
padding: "5dp"
spacing: "10sp"
radius: 16
MDFloatLayout:
size_hint: .01, .95
pos_hint: {"center_x": .02, "center_y": .5}
md_bg_color: "yellow" if root.latitude and root.longitude else "#EC1F26"
MDBoxLayout:
orientation: "vertical"
size_hint_y: None
height: self.minimum_height
AdaptiveLabel:
text: f"[{root.widget_count} of {root.widget_count}]: {root.reference_number}"
font_size:"15sp"
color:"black"
bold: True
AdaptiveLabel:
text: "Remarks:"
bold: True
font_size:"13sp"
color:"#666666"
height: self.texture_size[1] if root.remarks else 0
opacity: 1 if root.remarks else 0
AdaptiveLabel:
text: root.remarks
font_size:"12sp"
color: (0, 0, 0, 1)
height: self.texture_size[1] if root.remarks else 0
opacity: 1 if root.remarks else 0
MDButton:
style: 'text'
height: "20dp" if root.image_count > 0 else 0
size_hint_x: .3
opacity: 1 if root.image_count > 0 else 0
MDButtonIcon:
icon: 'image'
x: 1
theme_icon_color: "Custom"
icon_color: "black"
MDButtonText:
text: f"{root.image_count} Pictures"
theme_text_color: "Custom"
text_color: "black"
AdaptiveLabel:
text: "Status: Ready to transmit" if root.latitude and root.longitude else "Status: No location found"
bold: True
font_size: "12sp"
color: "#666666"
AnchorLayout:
anchor_x: 'right'
anchor_y: 'top'
size_hint: None, None
size: 120, 50
pos_hint: {'right': 1, 'top': 1}
AdaptiveLabel:
text: root.event_type
font_name: "f2icons/status.ttf"
halign: "right"
color: "#ffff00"
font_size: "16sp"
<AdaptiveLabel>
MDScreen:
name: 'main'
md_bg_color: "#ffffff"
ScrollView:
do_scroll_x: False
do_scroll_y: True
size_hint_y: .83
RecycleView:
id: card_list
viewclass: "CustomCard"
RecycleGridLayout:
default_size: None, dp(120)
default_size_hint: 1, None
size_hint_y: None
height: self.minimum_height
spacing: dp(10)
padding: dp(10)
cols: 1 # Ensure single column layout
I knew it was on the CustomCard widgets but i can not find the exact solution here.
Also the UI has also bug. The height does not adjusting automatically even though it is. Photo for reference