KIVY:动态按钮内部的图像+标签

3 投票
1 回答
3791 浏览
提问于 2025-04-18 16:30

我想在一个循环中创建的动态按钮里显示图片和标签。问题是,现在只在最后一个按钮里显示了图片和标签的布局。我该怎么做才能让所有按钮都显示这些内容呢?

main.py

class HomeScreen(Screen):
    grid_l = ObjectProperty(None)
    top_lbl = ObjectProperty(None)

    def search_btn_pressed(self):
        grid = self.grid_l
        grid.bind(minimum_height=grid.setter('height'),
                     minimum_width=grid.setter('width'))

        for i in range(3):
                layout = GridLayout(cols=1)
                print layout
                img = Image(source='kivy.png')
                print img
                lbl = Label(text='label')
                layout.add_widget(img)
                layout.add_widget(lbl)

                btn1 = Button(size_hint=(1, None))
                btn1.text = '%r' % i
                btn1.add_widget(layout)

                grid.add_widget(btn1)

.kv

#:kivy 1.7.2

<HomeScreen>:
    scroll_view: scrollviewID
    top_lbl: lblID
    grid_l: gridlayoutID
    AnchorLayout:
        size_hint: 1, .1   
        pos_hint: {'x': 0, 'y': .9}
        anchor_x: 'center'
        anchor_y: 'center'
        Label:
            id: lblID
            text: 'Button Tester'
    Button:
        size_hint: 1, .1   
        pos_hint: {'x': 0, 'y': .8}
        text: 'Press me!'
        on_release: root.search_btn_pressed()
    ScrollView:
        id: scrollviewID
        orientation: 'vertical'
        pos_hint: {'x': 0, 'y': 0}
        size_hint: 1, .8
        bar_width: '8dp'
        GridLayout:
            id: gridlayoutID
            cols: 1
            size_hint: 1, None
            row_default_height: 40
            row_force_default: False

screenshot

1 个回答

4

其实不是只有最后一个按钮没有显示,而是每个按钮都在显示,但它们都在同一个位置。问题在于,Button 不是一个布局,所以它不会自动安排里面的子元素的位置。每个按钮的 GridLayout 都是在 0, 0 的位置渲染,大小是 100, 100,这个位置是相对于最近的相对父元素(在这里是 GridLayout grid_l,因为它被包含在 ScrollView 中)。

当你把小部件添加到一个非布局的小部件时,你需要自己设置这些小部件的位置和大小。要注意的是,你必须设置实际的 pos(或者 xy)以及 size(或者 widthheight)- 你不能使用 pos_hintsize_hint,因为这些只能由布局来处理。

这可以通过在 kv 语言 中使用 动态类 来轻松实现:

<CustomButton@Button>:
    image_source: ''
    subtext: ''
    GridLayout:
        height: self.parent.height  # match the button's height
        width: 100                  # set to whatever you would like
        pos: self.parent.pos        # match the button's position
        cols: 1
        Image:
            source: root.image_source
        Label:
            text: root.subtext

要使用你的动态类,你需要导入 Factory

from kivy.factory import Factory

然后,在你的循环中:

for i in range(3):
    btn = Factory.CustomButton(text=str(i), size_hint=(1, None),
                               image_source='kivy.png', subtext='label')
    grid.add_widget(btn)

最后,补充一点:每次调用 search_btn_pressed() 时,你都在 grid_l 上创建新的绑定。这些绑定应该只创建一次。你可以通过把这些绑定移动到 HomeScreen.__init__() 来在 Python 中只绑定一次,但在 kv 中这样做会更简单:

    GridLayout:
        id: gridlayoutID
        cols: 1
        size_hint: 1, None
        row_default_height: 40
        row_force_default: False
        height: self.minimum_height   # bind height to minimum_height
        width: self.minimum_width     # bind width to minimum_width

撰写回答