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 对象必须在加载根小部件之前进行初始化

KivyMD - 如何使用 KivyMD BottomNavigationItems 和屏幕本身内的按钮在屏幕上导航?

禁用全屏 kivymd

如何在 kivymd 中制作网格布局?

.spec 文件中的“ModuleNotFoundError:没有名为 'kivymd' 的模块”