Search code examples
pythonuser-interfacekivykivy-languagekivymd

I can't add a row to a MDDatatable (Kivy, Python) using a button inside a kv file. I have problems making the Datatable a global variable


The only relevant Parts of the codes right now are the "Start" Button and the MDDatatable. In the future I want to use the Start Button to add new rows to the table. I have problems making the Datatable accesible for the button.

Can someone give me feedback if that is possible with the architecture right now or do I have to change it. Im also new to kivy. So if you have a solution it would be greate if you can explain whats going on.

Python file:

from kivy.config import Config
Config.set('graphics','width','1280')
Config.set('graphics','height','800')
Config.set('graphics', 'resizable', False)
Config.write()
from kivymd.app import MDApp
from kivy.core.window import Window
from kivymd.uix.datatables import MDDataTable
#from kivymd.uix.floatlayout import MDFloatLayout
from kivy.metrics import dp
from kivymd.uix.screen import MDScreen

class MainScreen(MDScreen):
    
    def load_table(self):
        data_tables = MDDataTable(
            pos_hint={'center_x': 0.81,'center_y': 0.3},
            size_hint=(None, None),
            size = (460, 460),
            use_pagination=True,
            column_data=[("No.", dp(10)),
                ("UID", dp(30)),
                ("Reichweite in cm", dp(30))],
            row_data=[
                ("1", "x100", "30")])
        self.add_widget(data_tables)
        return data_tables

    def on_enter(self):
        self.data_tabels = self.load_table()
    pass

    def add_data(self):
        MainScreen.data_tabels.add_row(("1","2","3"))
        pass

class SettingsScreen(MDScreen):
    pass

class MDApp(MDApp):

    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.load_kv("mdapp.kv")

    def clkfunc(self):
        Window.close()
        MDApp.get_running_app().stop()
        pass
        
    def Start(self):
        print("Achse bewegt sich")
        print("Reader Liest")
        MainScreen.add_data(MainScreen)
        pass
    
    def Stop(self):
        print("Messung wird abgebrochen")
        pass
    
if __name__ == '__main__':
    MDApp().run()

kv file

#:kivy 1.0.9
#: import NoTransition kivy.uix.screenmanager.NoTransition

<MainScreen>:
    MDScreen:
        canvas:
            Color: 
                rgba: 0,0,1,1
            Rectangle:
                pos: 0,0
                size: 800, 800
            
    FloatLayout:
        
        Button:
            text: 'Quit'
            on_press: app.clkfunc()
            pos: 1210, 780
            size_hint: None, None
            size: 70, 20
            
        Button:
            text: 'Start'
            on_press: app.Start()
            pos: 1050, 650
            size_hint: None, None
            size: 200, 80
            
        Button:
            text: 'Stopp'
            on_press: app.Stop()
            pos: 1050, 550
            size_hint: None, None
            size: 200, 80  
            
             
            
<SettingsScreen>:
    BoxLayout:
        Button:
            text: 'My settings button'
        Button:
            text: 'Back to Main'
            on_press: root.manager.current = 'main'
            
ScreenManager:
    id: screen_manager
    transition: NoTransition()
    
    MainScreen:
        id: main_screen
        name: "main_screen"

Clicking on the button throws the following error message.

      File ~\AppData\Local\anaconda3\envs\kivy\lib\site-packages\spyder_kernels\py3compat.py:356 in compat_exec
    exec(code, globals, locals)

  File i:\sebastian\bachelorarbeit\code\gui\gui_kivymd.py:62
    MDApp().run()

  File ~\AppData\Local\anaconda3\envs\kivy\lib\site-packages\kivy\app.py:955 in run
    runTouchApp()

  File ~\AppData\Local\anaconda3\envs\kivy\lib\site-packages\kivy\base.py:574 in runTouchApp
    EventLoop.mainloop()

  File ~\AppData\Local\anaconda3\envs\kivy\lib\site-packages\kivy\base.py:339 in mainloop
    self.idle()

  File ~\AppData\Local\anaconda3\envs\kivy\lib\site-packages\kivy\base.py:383 in idle
    self.dispatch_input()

  File ~\AppData\Local\anaconda3\envs\kivy\lib\site-packages\kivy\base.py:334 in dispatch_input
    post_dispatch_input(*pop(0))

  File ~\AppData\Local\anaconda3\envs\kivy\lib\site-packages\kivy\base.py:263 in post_dispatch_input
    listener.dispatch('on_motion', etype, me)

  File kivy\_event.pyx:731 in kivy._event.EventDispatcher.dispatch

  File ~\AppData\Local\anaconda3\envs\kivy\lib\site-packages\kivy\core\window\__init__.py:1660 in on_motion
    self.dispatch('on_touch_down', me)

  File kivy\_event.pyx:731 in kivy._event.EventDispatcher.dispatch

  File ~\AppData\Local\anaconda3\envs\kivy\lib\site-packages\kivy\core\window\__init__.py:1677 in on_touch_down
    if w.dispatch('on_touch_down', touch):

  File kivy\_event.pyx:731 in kivy._event.EventDispatcher.dispatch

  File ~\AppData\Local\anaconda3\envs\kivy\lib\site-packages\kivy\uix\screenmanager.py:1210 in on_touch_down
    return super(ScreenManager, self).on_touch_down(touch)

  File ~\AppData\Local\anaconda3\envs\kivy\lib\site-packages\kivy\uix\widget.py:589 in on_touch_down
    if child.dispatch('on_touch_down', touch):

  File kivy\_event.pyx:731 in kivy._event.EventDispatcher.dispatch

  File ~\AppData\Local\anaconda3\envs\kivy\lib\site-packages\kivy\uix\relativelayout.py:306 in on_touch_down
    ret = super(RelativeLayout, self).on_touch_down(touch)

  File ~\AppData\Local\anaconda3\envs\kivy\lib\site-packages\kivy\uix\widget.py:589 in on_touch_down
    if child.dispatch('on_touch_down', touch):

  File kivy\_event.pyx:731 in kivy._event.EventDispatcher.dispatch

  File ~\AppData\Local\anaconda3\envs\kivy\lib\site-packages\kivy\uix\widget.py:589 in on_touch_down
    if child.dispatch('on_touch_down', touch):

  File kivy\_event.pyx:731 in kivy._event.EventDispatcher.dispatch

  File ~\AppData\Local\anaconda3\envs\kivy\lib\site-packages\kivy\uix\behaviors\button.py:151 in on_touch_down
    self.dispatch('on_press')

  File kivy\_event.pyx:727 in kivy._event.EventDispatcher.dispatch

  File kivy\_event.pyx:1307 in kivy._event.EventObservers.dispatch

  File kivy\_event.pyx:1191 in kivy._event.EventObservers._dispatch

  File ~\AppData\Local\anaconda3\envs\kivy\lib\site-packages\kivy\lang\builder.py:55 in custom_callback
    exec(__kvlang__.co_value, idmap)

  File i:\sebastian\bachelorarbeit\code\gui\mdapp.kv:24
    on_press: app.Start()

  File i:\sebastian\bachelorarbeit\code\gui\gui_kivymd.py:54 in Start
    MainScreen.add_data(MainScreen)

  File i:\sebastian\bachelorarbeit\code\gui\gui_kivymd.py:34 in add_data
    MainScreen.data_tabels.add_row(("1","2","3"))

AttributeError: type object 'MainScreen' has no attribute 'data_tabels'

Screenshot from the GUI:

enter image description here


Solution

  • The error message:

    AttributeError: type object 'MainScreen' has no attribute 'data_tabels'

    is giving you a big hint. Your code is using MainScreen (which is a class) as though it were an instance.

    The fix is to replace your uses of the MainScreen class with your instance of MainScreen. Modify your add_data() method as:

    def add_data(self):
        # MainScreen.data_tabels.add_row(("1", "2", "3"))
        self.data_tabels.add_row(("1", "2", "3"))
    

    And modify your Start() method as:

    def Start(self):
        print("Achse bewegt sich")
        print("Reader Liest")
        # MainScreen.add_data(MainScreen)
        self.root.get_screen('main_screen').add_data()