Search code examples
pythondatatableskivykivymd

How to do single row selection in kivyMD DataTables


I am using kivyMD DataTables widget to display my data and allow single row can be selected to do some further edit. The following is my test case. I have encountered several problems.

  1. I use on_row_press event to treat the selection, but I found only clicking on the first column will give check box's state change.
  2. I use instance_table.table_data.select_all('normal') to cancel all existed selections. But the cursor always moves to the bottom row but not the selected row.
  3. I found the instance_row.state keeps down whatever I select or deselect one row. How can I get the row selection state?

Could you help me out? Thanks.

from kivy.metrics import dp
from kivy.uix.anchorlayout import AnchorLayout
from kivy.lang import Builder
from kivy.logger import Logger

from kivymd.app import MDApp
from kivymd.uix.datatables import MDDataTable
from kivymd.uix.datatables.datatables import CellRow

kv = '''
BoxLayout:
    orientation: "vertical"
    BoxLayout:
        id:button_tab
        size_hint_y:None
        height: dp(48)

        MDFlatButton:
            text: "Hello <3"
            on_release:
                app.update_row_data()

    BoxLayout:
        id:body

'''


class Example(MDApp):
    def build(self):
        self.data_tables = MDDataTable(
            # MDDataTable allows the use of size_hint
            size_hint=(0.8, 0.7),
            use_pagination=True,
            check=True,
            column_data=[
                ("No.", dp(30)),
                ("Status", dp(30)),
                ("Signal Name", dp(60)),
                ("Severity", dp(30)),
                ("Stage", dp(30)),
                ("Schedule", dp(30)),
                ("Team Lead", dp(30))
            ],
            row_data=[
                ("1", ("alert", [255 / 256, 165 / 256, 0, 1], "No Signal"),
                 "Astrid: NE shared managed", "Medium", "Triaged", "0:33",
                 "Chase Nguyen"),
                ("2", ("alert-circle", [1, 0, 0, 1], "Offline"),
                 "Cosmo: prod shared ares", "Huge", "Triaged", "0:39",
                 "Brie Furman"),
                ("3", (
                    "checkbox-marked-circle",
                    [39 / 256, 174 / 256, 96 / 256, 1],
                    "Online"), "Phoenix: prod shared lyra-lists", "Minor",
                 "Not Triaged", "3:12", "Jeremy lake"),
                ("4", (
                    "checkbox-marked-circle",
                    [39 / 256, 174 / 256, 96 / 256, 1],
                    "Online"), "Sirius: NW prod shared locations",
                 "Negligible",
                 "Triaged", "13:18", "Angelica Howards"),
                ("5", (
                    "checkbox-marked-circle",
                    [39 / 256, 174 / 256, 96 / 256, 1],
                    "Online"), "Sirius: prod independent account",
                 "Negligible",
                 "Triaged", "22:06", "Diane Okuma"),
            ]
        )
        self.data_tables.bind(on_row_press=self.on_row_press)
        root = Builder.load_string(kv)
        root.ids.body.add_widget(self.data_tables)
        return root

    def on_row_press(self, instance_table, instance_row):
        '''Called when a table row is clicked.'''
        print(instance_table, instance_row)
        if instance_row.ids.check.state == 'normal':
            instance_table.table_data.select_all('normal')
            instance_row.ids.check.state = 'down'
        else:
            instance_table.table_data.select_all('normal')
            # instance_row.ids.check.state = 'normal'
        print("instance_row.state:",instance_row.state)


Example().run()


Solution

  • after digging into the kivyMD, I got the solution

    """
    @author:
    @file:test_table_check2.py
    @time:2022/09/079:39
    @file_desc
    """
    from kivy.metrics import dp
    from kivy.uix.anchorlayout import AnchorLayout
    from kivy.lang import Builder
    from kivy.logger import Logger
    
    from kivymd.app import MDApp
    from kivymd.uix.datatables import MDDataTable
    
    kv = '''
    BoxLayout:
        orientation: "vertical"
        BoxLayout:
            id:button_tab
            size_hint_y:None
            height: dp(48)
    
            MDFlatButton:
                text: "Hello <3"
                on_release:
                    app.update_row_data()
    
        BoxLayout:
            id:body
    
    '''
    
    
    class Example(MDApp):
        def build(self):
            self.data_tables = MDDataTable(
                # MDDataTable allows the use of size_hint
                size_hint=(0.8, 0.7),
                use_pagination=True,
                check=True,
                column_data=[
                    ("No.", dp(30)),
                    ("Status", dp(30)),
                    ("Signal Name", dp(60)),
                    ("Severity", dp(30)),
                    ("Stage", dp(30)),
                    ("Schedule", dp(30)),
                    ("Team Lead", dp(30))
                ],
                row_data=[
                    ("1", ("alert", [255 / 256, 165 / 256, 0, 1], "No Signal"),
                     "Astrid: NE shared managed", "Medium", "Triaged", "0:33",
                     "Chase Nguyen"),
                    ("2", ("alert-circle", [1, 0, 0, 1], "Offline"),
                     "Cosmo: prod shared ares", "Huge", "Triaged", "0:39",
                     "Brie Furman"),
                    ("3", (
                        "checkbox-marked-circle",
                        [39 / 256, 174 / 256, 96 / 256, 1],
                        "Online"), "Phoenix: prod shared lyra-lists", "Minor",
                     "Not Triaged", "3:12", "Jeremy lake"),
                    ("4", (
                        "checkbox-marked-circle",
                        [39 / 256, 174 / 256, 96 / 256, 1],
                        "Online"), "Sirius: NW prod shared locations",
                     "Negligible",
                     "Triaged", "13:18", "Angelica Howards"),
                    ("5", (
                        "checkbox-marked-circle",
                        [39 / 256, 174 / 256, 96 / 256, 1],
                        "Online"), "Sirius: prod independent account",
                     "Negligible",
                     "Triaged", "22:06", "Diane Okuma"),
    
                ],
                sorted_on="Schedule",
                sorted_order="ASC",
                elevation=2
            )
            self.data_tables.bind(on_row_press=self.on_row_press)
            root = Builder.load_string(kv)
            root.ids.body.add_widget(self.data_tables)
            return root
    
        def on_row_press(self, instance_table, instance_row):
            '''Called when a table row is clicked.'''
            print(instance_table, instance_row)
            index = instance_row.index
            cols_num = len(instance_table. column_data)
            row_num = int(index/cols_num)
            col_num = index%cols_num
            cell_row =instance_table.table_data.view_adapter.get_visible_view(row_num*cols_num)
            if cell_row.ids.check.state == 'normal':
                instance_table.table_data.select_all('normal')
                cell_row.ids.check.state = 'down'
            else:
                cell_row.ids.check.state = 'normal'
            instance_table.table_data.on_mouse_select(instance_row)
    
    
    
    Example().run()