-1

I made a recycleview list of custom cards. For each card i want to pass a custom object called "show", its type is "Content". The class of custom card is "StreamingShowCard". I can't create the card by KVlang because its class contains some pytho methods.

This is the code:

from kivymd.app import MDApp
from kivy.lang import Builder
from kivymd.uix.behaviors import RoundedRectangularElevationBehavior
from kivymd.uix.card import MDCard
from kivy.properties import StringProperty
from kivy.uix.behaviors import ButtonBehavior
from kivymd.uix.list import OneLineIconListItem
from kivymd.uix.tab import MDTabsBase
from kivymd.uix.floatlayout import MDFloatLayout
from kivymd.uix.boxlayout import MDBoxLayout
from kivymd.uix.label import MDLabel
from kivymd.uix.gridlayout import MDGridLayout
from kivymd.uix.fitimage import FitImage
from kivy.uix.image import AsyncImage
from kivymd.uix.button import MDFlatButton
#import datetime
from datetime import datetime
from kivy.uix.image import Image
from kivymd.uix.dialog import MDDialog
from kivymd.uix.screen import MDScreen
from kivymd.uix.responsivelayout import MDResponsiveLayout
from kivymd.uix.progressbar import MDProgressBar
from kivy.clock import Clock
from kivymd.uix.button import MDIconButton
from kivymd.uix.list import IconLeftWidget
from kivymd.uix.recycleview import MDRecycleView
from kivy import properties


KV = '''

<Cover>:


<StreamingShowCard>:
    show: root.show



MDScreen:
    MDRecycleView:
        size_hint_y: 1
        size_hint_x: 1
        viewclass: 'StreamingShowCard'
        id: rv
        
        MDRecycleGridLayout:
            cols: 2
            height: self.minimum_height
            size_hint_y: None
            row_default_height: '250dp'

            row_force_default: True

            padding: dp(10)
            spacing: dp(10)

            

    MDFloatingActionButton:
        id: fab
        icon: "plus"
        pos_hint: {"center_x": .5, "center_y": .1}
        on_release: app.add_item()


'''
class MD3Card(MDCard, RoundedRectangularElevationBehavior):
    '''Implements a material design v3 card.'''

    text = StringProperty()

class Content: #eg: film found
    name = ""
    url = ""
    platform = ""
    imageUrl = ""
    Image = False
    #free = False
    def __init__(self, name, url, platform, imageUrl):
        self.name = name
        self.url = url
        self.platform = platform
        self.imageUrl = imageUrl

class StreamingShowCard(MD3Card):
    #show = None #the object of Content class attached to the 
    show = properties.ObjectProperty()
    def __init__(self, **kwargs):
        super(StreamingShowCard, self).__init__(**kwargs)
        self.__set_cardGraphic()
        
        self.image = Cover(size_hint_min_y=0.7,  source="https://kivy.org/doc/stable/_static/logo-kivy.png", opacity= 100 if True else 0, radius= ["10dp", "10dp", "0dp", "0dp"])
        grid1 = MDGridLayout(cols=1, size_hint_x=1, size_hint_y=1, rows=3)
        grid1.add_widget(self.image)
        grid1.add_widget(MDLabel(text=self.show, size_hint_y = 0.3, font_style='Subtitle2', halign='left', valign='middle'))
        
        box1 = MDBoxLayout(orientation = "horizontal", size_hint_x=1, size_hint_y=0.2)
        box1.add_widget(MDLabel(text="self.show.platform", size_hint_y = 1, size_hint_x=0.8, theme_text_color="Secondary", font_style='Caption', halign='left', valign='middle'))
        

        grid1.add_widget(box1)
        self.add_widget(grid1)
        
    def __set_cardGraphic(self):
        self.md_bg_color = "#18222c"
        #self.size_hint_y = None
        self.elevation = 10
        self.padding = "1dp"
        self.size_hint_x = 1
        self.radius = "10dp"
        self.ripple_behavior = True
        self.on_press = self.cardPress
    
    def cardPress(self, *args):
        dialog = MDDialog(
            title = "Aprire la pagina in un browser?",
            text = "Text",#self.show.name,
            size_hint = (0.8, 0.8),
            auto_dismiss = False,
            buttons=[
                MDFlatButton(text="No", text_color=self.theme_cls.primary_color, on_release=lambda x: dialog.dismiss()),
                MDFlatButton(text="Si", text_color=self.theme_cls.primary_color, on_release=lambda x: yesClick())
            ]
        )
        dialog.open()

        def yesClick():
            #openUrl(self.show.url)
            dialog.dismiss(force=True)

    def loadImage(self, *args):
        if not self.show.Image:
            self.show.loadImage(True)
            self.image.source = self.show.imageUrl
            self.image.opacity = 100
            self.image.reload()
    

class Cover(AsyncImage, FitImage):
    pass


class MainApp(MDApp):
    def build(self):
        return Builder.load_string(KV)

    def add_item(self):
        for i in range(100):
            self.root.ids.rv.data.append({
                "show": Content("name", "www.google.com", "platform", "https://kivy.org/doc/stable/_static/logo-kivy.png")
            })

MainApp().run()

If the recycleview's viewclass is a Label i can pass the text directly from main by appending dict to RV data, but whit this custom class of recycle view i cannot pass Content to show property. Is it possible to populate the RecycleView by the main?

VLN
  • 13
  • 5

1 Answers1

0

Couldn't get your code to run, but if you want to use an ObjectProperty in the data of a RecycleView, you need to handle it a bit differently. Here is an example of using an ObjectProperty in the data:

from kivy.app import App
from kivy.lang import Builder
from kivy.properties import ObjectProperty, StringProperty
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.image import Image
from kivy.uix.recycleview import RecycleView

Builder.load_string('''
<MyObject>:
    size_hint_y: None
    height: 100
    Label:
        id: label
        text: root.text  # uses the text StringProperty
        size_hint: None, None
        size: 200, 100
<RV>:
    viewclass: 'MyObject'
    RecycleBoxLayout:
        default_size: None, 100
        default_size_hint: 1, None
        size_hint_y: None
        height: self.minimum_height
        orientation: 'vertical'
''')


class MyObject(BoxLayout):
    show = ObjectProperty(None)
    text = StringProperty('Abba')

    def on_show(self, instance, new_obj):
        # handle the ObjectProperty named show
        if new_obj.parent:
            # remove this obj from any other MyObject instance
            new_obj.parent.remove_widget(new_obj)
        for ch in self.children:
            if isinstance(ch, Image):
                # remove any previous obj instances
                self.remove_widget(ch)
                break
        # add the new obj to this MyObject instance
        self.add_widget(new_obj)


class RV(RecycleView):
    def __init__(self, **kwargs):
        super(RV, self).__init__(**kwargs)
        self.data = [{'text': str(x),
                      'show': Image(source='tester.png', size_hint=(None, None), size=(100, 100),
                                    allow_stretch=True, keep_ratio=True)}
                     for x in range(100)]


class TestApp(App):
    def build(self):
        return RV()

if __name__ == '__main__':
    TestApp().run()
John Anderson
  • 35,991
  • 4
  • 13
  • 36
  • Perfect, at now, i get what was the problem: i added on_show and a i moved all code from __init__ to this new method. Thanks – VLN Sep 06 '22 at 18:52