python - Kivy Dynamic Image Grid View - Stack Overflow

admin2025-04-17  2

I'm using python kivy. I want to display cards containing a title and underneath an image, in a grid with 5 columns.

The behavior of the following snippet is 90% of what I want. The images always fit the same space, leaving empty space up/down or left/right, so they maintain aspect ratio. The only problem is that all the rows are scaled to fit the window. I want the height of the space where the image should fit to be a custom percentage of the window height, and to scroll down and up to see the rows that don't fit the current window.

class MyApp(App):
    def build(self):
        scroll_view = ScrollView(do_scroll_x=False, do_scroll_y=True, smooth_scroll_end=15, scroll_wheel_distance=20, size=(Window.width, Window.height))
        grid = GridLayout(cols=5, size_hint_x=1)
        index = 0
        for uuid, record in records.items():
            image_texture = image_cache.get_image(uuid)
            card = BoxLayout(orientation='vertical')
            card.add_widget(Button(
                text=record.name,
                size_hint=(1, 0.2),  # Stretch to fit column width (1 means full width)
                on_press=lambda x: print(f"Button pressed: {x.text}")
            ))
            card.add_widget(Image(
                texture=image_texture,
                size_hint_x=1,
            ))
            grid.add_widget(card)
            index += 1
            if index >= 20:
                break

        scroll_view.add_widget(grid)
        return scroll_view


if __name__ == '__main__':
    MyApp().run()

I'm using python kivy. I want to display cards containing a title and underneath an image, in a grid with 5 columns.

The behavior of the following snippet is 90% of what I want. The images always fit the same space, leaving empty space up/down or left/right, so they maintain aspect ratio. The only problem is that all the rows are scaled to fit the window. I want the height of the space where the image should fit to be a custom percentage of the window height, and to scroll down and up to see the rows that don't fit the current window.

class MyApp(App):
    def build(self):
        scroll_view = ScrollView(do_scroll_x=False, do_scroll_y=True, smooth_scroll_end=15, scroll_wheel_distance=20, size=(Window.width, Window.height))
        grid = GridLayout(cols=5, size_hint_x=1)
        index = 0
        for uuid, record in records.items():
            image_texture = image_cache.get_image(uuid)
            card = BoxLayout(orientation='vertical')
            card.add_widget(Button(
                text=record.name,
                size_hint=(1, 0.2),  # Stretch to fit column width (1 means full width)
                on_press=lambda x: print(f"Button pressed: {x.text}")
            ))
            card.add_widget(Image(
                texture=image_texture,
                size_hint_x=1,
            ))
            grid.add_widget(card)
            index += 1
            if index >= 20:
                break

        scroll_view.add_widget(grid)
        return scroll_view


if __name__ == '__main__':
    MyApp().run()
Share Improve this question asked Jan 30 at 20:39 AndrewAndrew 1,1191 gold badge15 silver badges29 bronze badges
Add a comment  | 

1 Answer 1

Reset to default 0

You can set the height of the ScrollView by using size_hint_y.

Here is a similar App that does what I think you want:

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

kv = '''
ScrollView:
    size_hint_y: 0.75  # custom percentage of the window height
    do_scroll_x: False
    do_scroll_y: True
    smooth_scroll_end: 15
    scroll_wheel_distance: 20
    
    GridLayout:
        id: grid
        cols: 5
        spacing: 1, 5
        size_hint: 1, None
        height: self.minimum_height  # must be allowed to grow for ScrollView to work
        
<Card>:
    orientation: 'vertical'
    size_hint: 1, None
    height: 150  # must have a specified height for minimum_height to work in GridLayout
    Button:
        text: root.text
        on_press: print(f"Button pressed: {self.text}")
        size_hint_y: 0.25
    Image:
        texture: root.texture
        size_hint_y: 0.75
'''


class Card(BoxLayout):
    text = StringProperty('')
    texture = ObjectProperty(None)

class MyApp(App):
    def build(self):
        Clock.schedule_once(self.fill_grid)
        return Builder.load_string(kv)

    def fill_grid(self, _dt):
        grid = self.root.ids.grid

        texture = Image(source='tester.png').texture
        for index in range(50):
            grid.add_widget(Card(text='record #' + str(index), texture=texture))

if __name__ == '__main__':
    MyApp().run()
转载请注明原文地址:http://anycun.com/QandA/1744891284a89089.html