kivyMD 间歇性 AssertionError
Posted
技术标签:
【中文标题】kivyMD 间歇性 AssertionError【英文标题】:kivyMD intermittent AssertionError 【发布时间】:2021-07-15 04:06:24 【问题描述】:kivy 2.0.0、kivymd 0.104.2dev0、python3.7
当我按下按钮将 MDdatatable 添加到新屏幕的 MDBoxLayout 时,我间歇性出现错误。
有时会立即出错,有时会在尝试 30 次后出错一次。
AssertionError with .py and KeyError: <ParserRule name='<CommonElevationBehavior>'> with apk.
有人知道我应该去哪里看吗?
并且也有这个警告,间歇性地,按下按钮。
[WARNING] <kivymd.uix.gridlayout.MDGridLayout object at 0x00000290BDE1D278> have no cols or rows set, layout is not triggered.
即使我所有的网格布局都设置了 cols。
这是我的最小代码。
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()
【问题讨论】:
【参考方案1】:要使用线程,您必须限制您在该线程中所做的事情。有些操作必须在主线程上执行。这是您的 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 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'
【讨论】:
【参考方案2】:我认为问题在于您正在主线程以外的线程上对 GUI 进行更改。尝试改变:
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()
到:
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()
我认为您还需要从 MDDataTable
创建命令中删除 elevation=0,
。
【讨论】:
但是如果我仍然需要使用线程怎么办?我应该如何正确使用线程?在实际代码中,有大量数据,必须从我的 sql server 中获取。大概需要1~6秒。如果我不使用线程主线程冻结。所以我让主线程 ro 运行进度条并意味着另一个线程来获取数据。这就是为什么我需要使用线程 在新线程中执行除了将小部件添加到 GUI 之外的所有操作,然后使用Clock.schedule_once()
调用仅执行 add_widget()
的方法。以上是关于kivyMD 间歇性 AssertionError的主要内容,如果未能解决你的问题,请参考以下文章
使用 KivyMD 库运行应用程序时出现错误 No module named 'kivymd.app'
KivyMD 错误:ValueError:KivyMD:App 对象必须在加载根小部件之前进行初始化