https://kivymd.readthedocs.io/en/latest/components/image-list/#smarttilewithstar
How do you generalize the kiymd doc image-list example so the image display logic is outside of the kv file?
This is my attempt but it displays all the images in the top row only (and also leaves the first image on the left blank). Thanks.
from kivymd.app import MDApp
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
from kivymd.uix.imagelist import SmartTile
from kivymd.uix.gridlayout import MDGridLayout
img = ["00.jpg", "03.jpg", "13.jpg", "15.jpg", "24.jpg", "28.jpg", "29.jpg", "33.jpg", "34.jpg"]
Builder.load_string('''
<MyTile#SmartTile>
size_hint_y: None
height: "240dp"
<CatScreen>:
ScrollView:
id: scroll
MDGridLayout:
id: grid
cols: 3
adaptive_height: True
padding: dp(4), dp(4)
spacing: dp(4)
MyTile:
''')
class CatScreen(Screen):
def __init__(self, **kwargs):
super().__init__(**kwargs)
def display_image(self):
for im in img:
self.ids.grid.add_widget(SmartTile(source = im))
return self
class CatApp(MDApp):
def __init__(self, **kwargs):
super().__init__(**kwargs)
def build(self):
self.cs = CatScreen()
return self.cs.display_image()
CatApp().run()
import os
from kivy.factory import Factory as F
from kivy.lang import Builder
from kivymd.app import MDApp
from kivy.uix.screenmanager import Screen
from kivymd.uix.imagelist import SmartTile
######################################
# this part of the code is to take images from my folder
img = []
PATH = "/root/Pictures" # source folder
for i in os.listdir(PATH):
if ".png" in i:
img.append(PATH + "/" + i)
######################################
Builder.load_string('''
<MyTile#SmartTile>:
size_hint_y: None
height: "240dp"
<CatScreen>:
ScrollView:
id: scroll
MDGridLayout:
id: grid
cols: 3
adaptive_height: True
padding: dp(4), dp(4)
spacing: dp(4)
MyTile:
''')
class CatScreen(Screen):
def __init__(self, **kwargs):
super().__init__(**kwargs)
def display_image(self):
for im in img:
self.ids.grid.add_widget(F.MyTile(source=im))
return self
class CatApp(MDApp):
def __init__(self, **kwargs):
super().__init__(**kwargs)
def build(self):
self.cs = CatScreen()
return self.cs.display_image()
CatApp().run()
You can make this add a feature..
row_default_height: 500
# Telegram : #DIBIBl , #TDTDI ,#ruks3
# by ruks ,muntazir
# YouTube : https://youtube.com/channel/UCUNbzQRjfAXGCKI1LY72DTA
# Instagram : https://instagram.com/_v_go?utm_medium=copy_link
# github : https://github.com/muntazir-halim
# ---------------------
from kivymd.app import MDApp
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
from kivymd.uix.imagelist import SmartTile
from kivymd.uix.gridlayout import MDGridLayout
img = ["00.jpg", "03.jpg", "13.jpg", "15.jpg", "24.jpg", "28.jpg", "29.jpg", "33.jpg", "34.jpg"]
Builder.load_string('''
<MyTile#SmartTile>
size_hint_y: None
height: "240dp"
<CatScreen>:
ScrollView:
id: scroll
MDGridLayout:
id: grid
padding: 30, 30
size_hint_y: None
height: self.minimum_height
adaptive_height: True
row_default_height: 500
cols: 3
adaptive_height: True
padding: dp(4), dp(4)
spacing: dp(4)
''')
class CatScreen(Screen):
def __init__(self, **kwargs):
super().__init__(**kwargs)
def display_image(self):
for im in img:
self.ids.grid.add_widget(SmartTile(source = im))
return self
class CatApp(MDApp):
def __init__(self, **kwargs):
super().__init__(**kwargs)
def build(self):
self.cs = CatScreen()
return self.cs.display_image()
CatApp().run()
Related
anyone can help me about how to add KivyMD Expansion Panel in RecycleView kivy? Because I have issue with slow perfomance while add MDExpansionPanel with "add_widget" on kivy (run in old android).
Then i have idea to put Expansion into RecycleView, but the expansionpanel can't open with true index.
fyi, i have make custom expansion.py file
expansion.py
from kivy.animation import Animation
from kivy.lang import Builder
from kivy.metrics import dp
from kivy.properties import StringProperty, ObjectProperty, NumericProperty
from kivy.uix.boxlayout import BoxLayout
from kivymd.uix.button import MDIconButton
from kivymd.uix.list import (IRightBody, ILeftBody, TwoLineAvatarIconListItem)
from kivymd.uix.selectioncontrol import MDCheckbox
Builder.load_string(
"""
#:import images_path kivymd.images_path
#:import md_icons kivymd.icon_definitions.md_icons
<CustomExpansionPanel>
text: root.title
secondary_text: root.desc
_no_ripple_effect: True
IconRightSampleWidget:
id: check
disabled_color: [.2, .3, .6, .9]
disabled: True
ChevronRight:
id: chevron
icon: 'chevron-right'
disabled: True
canvas.before:
PushMatrix
Rotate:
angle: self.angle
axis: (0, 0, 1)
origin: self.center
canvas.after:
PopMatrix
<CustomMDExpansionPanel>
size_hint_y: None
height: dp(68)
padding:dp(0)
BoxLayout:
id: box_item
size_hint_y: None
height: root.height
orientation: 'vertical'
CustomExpansionPanel:
id: item_anim
title: root.title
desc: root.desc
on_press: root.check_open_box(self)
"""
)
class IconRightSampleWidget(ILeftBody, MDCheckbox):
pass
class ChevronRight(IRightBody, MDIconButton):
angle = NumericProperty(0)
class CustomExpansionPanel(TwoLineAvatarIconListItem):
title = StringProperty()
desc = StringProperty()
class CustomMDExpansionPanel(BoxLayout):
content = ObjectProperty()
title = StringProperty()
desc = StringProperty()
def __init__(self, **kwargs):
super(CustomMDExpansionPanel, self).__init__(**kwargs)
self.register_event_type("on_open")
self.register_event_type("on_close")
def on_open(self, *args):
pass
def on_close(self, *args):
pass
def check_open_box(self, instance,CloseAll=False):
press_current_item = False
for box in self.parent.children:
if isinstance(box, CustomMDExpansionPanel):
if len(box.ids.box_item.children) == 2:
if instance is box.ids.item_anim:
press_current_item = True
box.ids.box_item.remove_widget(box.ids.box_item.children[0])
chevron = box.ids.box_item.children[0].ids.chevron
self.anim_chevron_up(chevron)
self.anim_resize_close(box)
self.dispatch("on_close")
break
if not press_current_item and not CloseAll:
self.anim_chevron_down()
def anim_chevron_down(self):
chevron = self.ids.item_anim.ids.chevron
angle = -90
Animation(angle=angle, d=0.2).start(chevron)
self.anim_resize_open_item()
self.dispatch("on_open")
def anim_chevron_up(self, instance):
angle = 0
Animation(angle=angle, d=0.2).start(instance)
def anim_resize_close(self, box):
Animation(height=dp(68), d=0.1, t="in_cubic").start(box)
def anim_resize_open_item(self, *args):
self.content.name_item = self.title
anim = Animation(
height=self.content.height + dp(70), d=0.2, t="in_cubic"
)
anim.bind(on_complete=self.add_content)
anim.start(self)
def add_content(self, *args):
if self.content and len(self.ids.box_item.children) == 1:
self.ids.box_item.add_widget(self.content)
main.py
from kivymd.app import MDApp as App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.properties import ObjectProperty
from kivy.clock import Clock
from expansion import CustomMDExpansionPanel
from time import time
from kivy.uix.boxlayout import BoxLayout
Builder.load_string(
"""
<ListScreen>:
recycle_view: recycle_view
RecycleView:
id: recycle_view
size_hint: 1, 0.9
viewclass: "CustomMDExpansionPanel"
RecycleGridLayout:
id: items_box
cols:1
default_size_hint: 1, None
size_hint: 1, None
height:self.minimum_height
"""
)
class Container(BoxLayout):
def __init__(self,**kwargs):
super(Container,self).__init__()
class ListScreen(Screen):
recycle_view = ObjectProperty(None)
items_box = ObjectProperty(None)
def on_enter(self):
start = time()
container = []
for i in range(0,50):
container.append(Container(item='strrr'+str(i), index=i))
self.recycle_view.data.append(
{
'content':container[i],
'title':'title'+str(i),
'desc':'desc'+str(i)
}
)
def on_leave(self):
self.recycle_view.data = []
class ListApp(App):
sm = ScreenManager()
screens = {}
def build(self):
self.__create_screens()
ListApp.sm.add_widget(ListApp.screens['list1'])
return ListApp.sm
def __create_screens(self):
ListApp.screens['list1'] = ListScreen(name='list1')
if __name__ == '__main__':
ListApp().run()
Thank You
From my understanding , if you are trying to add your expansion panel inside the RecycleView.
Here is an example code of how to do that
from kivy.lang import Builder
from kivymd.app import MDApp
from kivymd.uix.boxlayout import MDBoxLayout
from kivymd.uix.expansionpanel import MDExpansionPanel, MDExpansionPanelThreeLine
from kivymd import images_path
KV = """
<Content>
adaptive_height: True
TwoLineIconListItem:
text: "(050)-123-45-67"
secondary_text: "Mobile"
RecycleView:
MDGridLayout:
id: box
cols: 1
adaptive_height: True
"""
class Content(MDBoxLayout):
"""Custom content."""
class Test(MDApp):
def build(self):
return Builder.load_string(KV)
def on_start(self):
for i in range(10):
self.root.ids.box.add_widget(
MDExpansionPanel(
icon=f"{images_path}kivymd.png",
content=Content(),
panel_cls=MDExpansionPanelThreeLine(
text="Text",
secondary_text="Secondary text",
tertiary_text="Tertiary text",
),
)
)
Test().run()
Please Refer Documentations Before Asking Questions :) As It Solves 90 % Of Your Problems <3
Also Edit Your Question And Specify Your Problem Clearly :)
please check why the below program is giving an
AttributeError: 'super' object has no attribute '__getattr__'
.py:
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import ListProperty, NumericProperty, ObjectProperty
from kivy.uix.recycleview.views import RecycleDataViewBehavior
from kivy.uix.textinput import TextInput
# from kivy.effects.scroll.ScrollEffect import ScrollEffect
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.gridlayout import GridLayout
from kivy.uix.recycleboxlayout import RecycleBoxLayout
Builder.load_file('so_extractTIC.kv')
class RecycleItem(ScreenManager,RecycleDataViewBehavior, TextInput):
index = NumericProperty(0)
def refresh_view_attrs(self, rv, index, data):
self.index = index
return super(RecycleItem, self).refresh_view_attrs(rv, index, data)
class DataView(Screen):
DataList = ListProperty()
TextInputNum = NumericProperty(10)
def __init__(self,*args,**kwargs):
super(DataView, self).__init__(*args,**kwargs)
# for key, val in self.ids.items():
# print("key={0}, val={1}".format(key, val))
data12= []
for x in range(self.TextInputNum):
data12.append({'text': '', 'height': 50})
self.ids.rv.data = data12
def extract_data(self,rv):
print(self.parent.parent.parent)
self.DataList.clear()
for x in range(self.TextInputNum):
self.DataList.append(self.ids.rv.data[x]['text'])
print(self.DataList)
class RootWidget(ScreenManager):
pass
class MainApp(App):
def build(self):
# self.root = Builder.load_string(APP_KV)
return RootWidget()
if __name__ == '__main__':
MainApp().run()
.kv:
<DataView>:
BoxLayout:
orientation: 'vertical'
RecycleView:
size_hint_y: 0.9
viewclass: 'RecycleItem'
id: rv
key_size: 'size'
# effect_cls: ScrollEffect
cols: 1
RecycleBoxLayout:
id: rvbox
cols: rv.cols
orientation: 'vertical'
size_hint_y: None
height: self.minimum_height
default_size_hint: 1, None
Button:
text: 'Submit'
size_hint_y: 0.1
on_release: root.extract_data()
<RecycleItem>:
on_text: self.parent.parent.data[self.index]['text'] = self.text
<RootWidget>:
DataView:
name:"DataView_screen"
I have been searching for extract data from recycleview using textInput boxes. Please find the link for the query:
Retrieve Data from Kivy Recycleview
I am trying to inherit from ScreenManager, but it is giving the 'super' attribute error. Tried passing id as argument in the .kv and tried to find real parent but nothing works.
Also, please suggest how to use the above code for recycle GridLaout, with 2d rows and columns, i tried using for loops, but getting key related errors.
like:
for z in range(12):
for y in range(8):
self.table_data12.append(self.ids.idname.data[y][z]['text'])
thanks!
In your DataView class, the __init__() method references self.ids, but the ids are not yet available at that point. You can delay that referencing by using Clock.schedule_once() like this:
def __init__(self, *args, **kwargs):
super(DataView, self).__init__(*args, **kwargs)
# for key, val in self.ids.items():
# print("key={0}, val={1}".format(key, val))
Clock.schedule_once(self.setup_data)
def setup_data(self, dt):
data12 = []
for x in range(self.TextInputNum):
data12.append({'text': '', 'height': 50})
self.ids.rv.data = data12
I see no reason for making the RecycleItem a subclass of ScreenManager.
In your 'kv, the on_textline forRecycleItem` can be:
<RecycleItem>:
on_text: app.root.get_screen('DataView_screen').ids.rv.data[self.index]['text'] = self.text
And the submit Button can be:
Button:
text: 'Submit'
size_hint_y: 0.1
on_release: root.extract_data(rv)
I am able to make a recycle view layout of TextInput boxes. Now, further, I would like to give text input in these boxes and gather these inputs in the form of list or dict.
I have tried, self.ids.idname.data to append in an empty list but it didn't work.
Following an example showing how to extract TextInput entries under a RecycleView and put that into a list:
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import ListProperty, NumericProperty, ObjectProperty
from kivy.uix.recycleview.views import RecycleDataViewBehavior
from kivy.uix.textinput import TextInput
APP_KV = """
#:import ScrollEffect kivy.effects.scroll.ScrollEffect
<DataView>:
orientation: 'vertical'
RecycleView:
id: rv
size_hint_y: 0.9
viewclass: 'RecycleItem'
key_size: 'size'
effect_cls: ScrollEffect
cols: 1
RecycleBoxLayout:
id: rvbox
cols: rv.cols
orientation: 'vertical'
size_hint_y: None
height: self.minimum_height
default_size_hint: 1, None
Button:
text: 'Submit'
size_hint_y: 0.1
on_release: root.extract_data()
<RecycleItem>:
on_text: self.parent.parent.data[self.index]['text'] = self.text
"""
class RecycleItem(RecycleDataViewBehavior, TextInput):
index = NumericProperty(0)
def refresh_view_attrs(self, rv, index, data):
self.index = index
return super(RecycleItem, self).refresh_view_attrs(rv, index, data)
class DataView(BoxLayout):
DataList = ListProperty()
TextInputNum = NumericProperty(10)
def __init__(self, **kwargs):
super().__init__(**kwargs)
data = []
for x in range(self.TextInputNum):
data.append({'text': '', 'height': 50})
self.ids.rv.data = data
def extract_data(self):
self.DataList.clear()
for x in range(self.TextInputNum):
self.DataList.append(self.ids.rv.data[x]['text'])
print(self.DataList)
class MainApp(App):
def build(self):
self.root = Builder.load_string(APP_KV)
return DataView()
if __name__ == '__main__':
MainApp().run()
I'm trying to append data of RV from Newline. I see that refresh_view_attrs works but there is nothing shown on the screen. How can I do it?
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.recycleview import RecycleView
from kivy.uix.recycleview.views import RecycleDataViewBehavior
from kivy.uix.gridlayout import GridLayout
from kivy.uix.recycleboxlayout import RecycleBoxLayout
from kivy.uix.recycleview.layout import LayoutSelectionBehavior
from kivy.clock import Clock
Builder.load_string('''
<SelectableLabel>:
# Draw a background to indicate selection
canvas.before:
Color:
rgba: (0, 0, 0, 1)
Rectangle:
pos: self.pos
size: self.size
pos: self.pos
size: self.size
Label:
id: id_label
<RV>:
viewclass: 'SelectableLabel'
SelectableRecycleBoxLayout:
default_size: None, dp(56)
default_size_hint: 1, None
size_hint_y: None
height: self.minimum_height
orientation: 'vertical'
multiselect: True
touch_multiselect: True
''')
class SelectableRecycleBoxLayout(LayoutSelectionBehavior,
RecycleBoxLayout):
''' Adds selection and focus behaviour to the view. '''
class SelectableLabel(RecycleDataViewBehavior, GridLayout):
''' Add selection support to the Label '''
def refresh_view_attrs(self, rv, index, data):
print('SelectableLabel', data)
self.ids['id_label'].text = data['label']
return super(SelectableLabel, self).refresh_view_attrs(
rv, index, data)
class RV(RecycleView):
def __init__(self, **kwargs):
super(RV, self).__init__(**kwargs)
self.data = []
rv = RV()
class Newline(GridLayout):
def __init__(self, **kwargs):
Clock.schedule_once(self.add_line, 3)
def add_line(self, dt):
d = {'label': 'NEW LINE'}
rv.data.append(d)
Newline()
class TestApp(App):
def build(self):
return RV()
if __name__ == '__main__':
TestApp().run()
rv = RV()
class Newline(GridLayout):
def __init__(self, **kwargs):
Clock.schedule_once(self.add_line, 3)
def add_line(self, dt):
d = {'label': 'NEW LINE'}
rv.data.append(d)
Newline()
class TestApp(App):
def build(self):
return RV()
Your root widget is a RV(), and you append data to a different RV().
You want to append data to the RV that you're actually displaying: App.get_running_app().root.data.append(d) would work.
i want to add kivy filechooser into gridlayout https://kivy.org/docs/api-kivy.uix.filechooser.html
i apply documentation and use root widget for have list file, but it's not work, my all folders not appear to my window
i have my main class :
from kivy.app import App
from kivy.uix.floatlayout import FloatLayout
from kivy.factory import Factory
from kivy.properties import ObjectProperty
from kivy.uix.popup import Popup
import os
class LoadDialog(FloatLayout):
load = ObjectProperty(None)
cancel = ObjectProperty(None)
class SaveDialog(FloatLayout):
save = ObjectProperty(None)
text_input = ObjectProperty(None)
cancel = ObjectProperty(None)
class Root(FloatLayout):
loadfile = ObjectProperty(None)
savefile = ObjectProperty(None)
text_input = ObjectProperty(None)
def dismiss_popup(self):
self._popup.dismiss()
def show_load(self):
content = LoadDialog(load=self.load, cancel=self.dismiss_popup)
self._popup = Popup(title="Load file", content=content,
size_hint=(0.9, 0.9))
self._popup.open()
def show_save(self):
content = SaveDialog(save=self.save, cancel=self.dismiss_popup)
self._popup = Popup(title="Save file", content=content,
size_hint=(0.9, 0.9))
self._popup.open()
def load(self, path, filename):
with open(os.path.join(path, filename[0])) as stream:
self.text_input.text = stream.read()
self.dismiss_popup()
def save(self, path, filename):
with open(os.path.join(path, filename), 'w') as stream:
stream.write(self.text_input.text)
self.dismiss_popup()
class Editor(App):
pass
import kivy
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button
class MyApp(App):
def build(self):
layout = BoxLayout(orientation='vertical')
root=Root()
root.show_load()
layout.add_widget(root)
return layout
if __name__ == '__main__':
MyApp().run()
i have only filechooser title, i have not folder or file in window why ?
the result :
You need to create a kv file, my.kv and some minor changes to the Python code. Please refer to the example for details.
Example
Python Script - main.py
from kivy.app import App
from kivy.uix.floatlayout import FloatLayout
from kivy.properties import ObjectProperty
from kivy.uix.popup import Popup
import os
class LoadDialog(FloatLayout):
load = ObjectProperty(None)
cancel = ObjectProperty(None)
class SaveDialog(FloatLayout):
save = ObjectProperty(None)
text_input = ObjectProperty(None)
cancel = ObjectProperty(None)
class Root(FloatLayout):
loadfile = ObjectProperty(None)
savefile = ObjectProperty(None)
text_input = ObjectProperty(None)
def dismiss_popup(self):
self._popup.dismiss()
def show_load(self):
content = LoadDialog(load=self.load, cancel=self.dismiss_popup)
self._popup = Popup(title="Load file", content=content,
size_hint=(0.9, 0.9))
self._popup.open()
def show_save(self):
content = SaveDialog(save=self.save, cancel=self.dismiss_popup)
self._popup = Popup(title="Save file", content=content,
size_hint=(0.9, 0.9))
self._popup.open()
def load(self, path, filename):
with open(os.path.join(path, filename[0])) as stream:
self.text_input.text = stream.read()
self.dismiss_popup()
def save(self, path, filename):
with open(os.path.join(path, filename), 'w') as stream:
stream.write(self.text_input.text)
self.dismiss_popup()
class MyApp(App):
def build(self):
return Root()
if __name__ == '__main__':
MyApp().run()
kv file - my.kv
#:kivy 1.11.0
<Root>:
text_input: text_input
BoxLayout:
orientation: 'vertical'
BoxLayout:
size_hint_y: None
height: 30
Button:
text: 'Load'
on_release: root.show_load()
Button:
text: 'Save'
on_release: root.show_save()
BoxLayout:
TextInput:
id: text_input
text: ''
RstDocument:
text: text_input.text
show_errors: True
<LoadDialog>:
BoxLayout:
size: root.size
pos: root.pos
orientation: "vertical"
FileChooserListView:
id: filechooser
BoxLayout:
size_hint_y: None
height: 30
Button:
text: "Cancel"
on_release: root.cancel()
Button:
text: "Load"
on_release: root.load(filechooser.path, filechooser.selection)
<SaveDialog>:
text_input: text_input
BoxLayout:
size: root.size
pos: root.pos
orientation: "vertical"
FileChooserListView:
id: filechooser
on_selection: text_input.text = self.selection and self.selection[0] or ''
TextInput:
id: text_input
size_hint_y: None
height: 30
multiline: False
BoxLayout:
size_hint_y: None
height: 30
Button:
text: "Cancel"
on_release: root.cancel()
Button:
text: "Save"
on_release: root.save(filechooser.path, text_input.text)
Output