gridview.py (6337B)
1 from kivy.uix.boxlayout import BoxLayout 2 from kivy.adapters.dictadapter import DictAdapter 3 from kivy.adapters.listadapter import ListAdapter 4 from kivy.properties import ObjectProperty, ListProperty, AliasProperty 5 from kivy.uix.listview import (ListItemButton, ListItemLabel, CompositeListItem, 6 ListView) 7 from kivy.lang import Builder 8 from kivy.metrics import dp, sp 9 10 Builder.load_string(''' 11 <GridView> 12 header_view: header_view 13 content_view: content_view 14 BoxLayout: 15 orientation: 'vertical' 16 padding: '0dp', '2dp' 17 BoxLayout: 18 id: header_box 19 orientation: 'vertical' 20 size_hint: 1, None 21 height: '30dp' 22 ListView: 23 id: header_view 24 BoxLayout: 25 id: content_box 26 orientation: 'vertical' 27 ListView: 28 id: content_view 29 30 <-HorizVertGrid> 31 header_view: header_view 32 content_view: content_view 33 ScrollView: 34 id: scrl 35 do_scroll_y: False 36 RelativeLayout: 37 size_hint_x: None 38 width: max(scrl.width, dp(sum(root.widths))) 39 BoxLayout: 40 orientation: 'vertical' 41 padding: '0dp', '2dp' 42 BoxLayout: 43 id: header_box 44 orientation: 'vertical' 45 size_hint: 1, None 46 height: '30dp' 47 ListView: 48 id: header_view 49 BoxLayout: 50 id: content_box 51 orientation: 'vertical' 52 ListView: 53 id: content_view 54 55 ''') 56 57 class GridView(BoxLayout): 58 """Workaround solution for grid view by using 2 list view. 59 Sometimes the height of lines is shown properly.""" 60 61 def _get_hd_adpt(self): 62 return self.ids.header_view.adapter 63 64 header_adapter = AliasProperty(_get_hd_adpt, None) 65 ''' 66 ''' 67 68 def _get_cnt_adpt(self): 69 return self.ids.content_view.adapter 70 71 content_adapter = AliasProperty(_get_cnt_adpt, None) 72 ''' 73 ''' 74 75 headers = ListProperty([]) 76 ''' 77 ''' 78 79 widths = ListProperty([]) 80 ''' 81 ''' 82 83 data = ListProperty([]) 84 ''' 85 ''' 86 87 getter = ObjectProperty(lambda item, i: item[i]) 88 ''' 89 ''' 90 on_context_menu = ObjectProperty(None) 91 92 def __init__(self, **kwargs): 93 self._from_widths = False 94 super(GridView, self).__init__(**kwargs) 95 #self.on_headers(self, self.headers) 96 97 def on_widths(self, instance, value): 98 if not self.get_root_window(): 99 return 100 self._from_widths = True 101 self.on_headers(instance, self.headers) 102 self._from_widths = False 103 104 def on_headers(self, instance, value): 105 if not self._from_widths: 106 return 107 if not (value and self.canvas and self.headers): 108 return 109 widths = self.widths 110 if len(self.widths) != len(value): 111 return 112 #if widths is not None: 113 # widths = ['%sdp' % i for i in widths] 114 115 def generic_args_converter(row_index, 116 item, 117 is_header=True, 118 getter=self.getter): 119 cls_dicts = [] 120 _widths = self.widths 121 getter = self.getter 122 on_context_menu = self.on_context_menu 123 124 for i, header in enumerate(self.headers): 125 kwargs = { 126 'padding': ('2dp','2dp'), 127 'halign': 'center', 128 'valign': 'middle', 129 'size_hint_y': None, 130 'shorten': True, 131 'height': '30dp', 132 'text_size': (_widths[i], dp(30)), 133 'text': getter(item, i), 134 } 135 136 kwargs['font_size'] = '9sp' 137 if is_header: 138 kwargs['deselected_color'] = kwargs['selected_color'] =\ 139 [0, 1, 1, 1] 140 else: # this is content 141 kwargs['deselected_color'] = 1, 1, 1, 1 142 if on_context_menu is not None: 143 kwargs['on_press'] = on_context_menu 144 145 if widths is not None: # set width manually 146 kwargs['size_hint_x'] = None 147 kwargs['width'] = widths[i] 148 149 cls_dicts.append({ 150 'cls': ListItemButton, 151 'kwargs': kwargs, 152 }) 153 154 return { 155 'id': item[-1], 156 'size_hint_y': None, 157 'height': '30dp', 158 'cls_dicts': cls_dicts, 159 } 160 161 def header_args_converter(row_index, item): 162 return generic_args_converter(row_index, item) 163 164 def content_args_converter(row_index, item): 165 return generic_args_converter(row_index, item, is_header=False) 166 167 168 self.ids.header_view.adapter = ListAdapter(data=[self.headers], 169 args_converter=header_args_converter, 170 selection_mode='single', 171 allow_empty_selection=False, 172 cls=CompositeListItem) 173 174 self.ids.content_view.adapter = ListAdapter(data=self.data, 175 args_converter=content_args_converter, 176 selection_mode='single', 177 allow_empty_selection=False, 178 cls=CompositeListItem) 179 self.content_adapter.bind_triggers_to_view(self.ids.content_view._trigger_reset_populate) 180 181 class HorizVertGrid(GridView): 182 pass 183 184 185 if __name__ == "__main__": 186 from kivy.app import App 187 class MainApp(App): 188 189 def build(self): 190 data = [] 191 for i in range(90): 192 data.append((str(i), str(i))) 193 self.data = data 194 return Builder.load_string(''' 195 BoxLayout: 196 orientation: 'vertical' 197 HorizVertGrid: 198 on_parent: if args[1]: self.content_adapter.data = app.data 199 headers:['Address', 'Previous output'] 200 widths: [400, 500] 201 202 <Label> 203 font_size: '16sp' 204 ''') 205 MainApp().run()