Kivy - 如何在 ModalView 内向 ScrollView 添加多个按钮?

Posted

技术标签:

【中文标题】Kivy - 如何在 ModalView 内向 ScrollView 添加多个按钮?【英文标题】:Kivy - How to add multiple Buttons to ScrollView inside ModalView? 【发布时间】:2021-07-09 01:37:29 【问题描述】:

我想编写一个带有 KivyMD 的移动应用程序,例如底部表菜单。我对 KivyMD 按钮表的问题是,当我单击按钮打开它时,需要很长时间(取决于菜单长度),因为每次按下按钮时都会调用函数生成列表。所以我想为此编写自己的解决方案。 在我的 kv 文件中,我手动添加了 20 个按钮来查看,一切正常。但是我没有找到在带有循环的python文件中执行此操作的方法。 谁能帮我将 30 多个按钮添加到 modalview 以使其可滚动?

这是我的 python 文件:

from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.lang import Builder
from kivy.core.window import Window


Builder.load_file('mylayout.kv')
Window.size = (350, 700)

class MyLayout(BoxLayout):
    pass

class MainApp(App):

    def build(self):
        return MyLayout()


MainApp().run()

我的 kv 文件:

#:import Factory kivy.factory.Factory

<MyPopup@ModalView>
    auto_dismiss: True
    size_hint: 1, 0.5
    pos_hint: 'x': 0, 'top': 0.5
    background_color: 0,0,0,0
    background_normal: ''
    canvas.before:
        Color:
            rgba: 48/150,84/150,150/150,1
        Rectangle:
            size: self.size
            pos: self.pos
    ScrollView:
        #do_scroll_x: False
        GridLayout:
            id: container1
            cols: 1
            size_hint: None, None
            size: root.width, 1200
            pos_hint: 'center_x': .5, 'center_y': .5

            MyButton:
                text: '1'
                on_press:
                    root.dismiss()
                    print(1)
            MyButton:
                text: '2'
                on_press:
                    root.dismiss()
                    print(2)
            MyButton:
                text: '3'
                on_press:
                    root.dismiss()
                    print(3)
            MyButton:
                text: '4'
                on_press:
                    root.dismiss()
                    print(4)
            MyButton:
                text: '5'
                on_press:
                    root.dismiss()
                    print(5)
            MyButton:
                text: '6'
                on_press:
                    root.dismiss()
                    print(6)
            MyButton:
                text: '7'
                on_press:
                    root.dismiss()
                    print(7)
            MyButton:
                text: '8'
                on_press:
                    root.dismiss()
                    print(8)
            MyButton:
                text: '9'
                on_press:
                    root.dismiss()
                    print(9)
            MyButton:
                text: '10'
                on_press:
                    root.dismiss()
                    print(10)
            MyButton:
                text: '11'
                on_press:
                    root.dismiss()
                    print(11)
            MyButton:
                text: '12'
                on_press:
                    root.dismiss()
                    print(12)
            MyButton:
                text: '13'
                on_press:
                    root.dismiss()
                    print(13)
            MyButton:
                text: '14'
                on_press:
                    root.dismiss()
                    print(14)
            MyButton:
                text: '15'
                on_press:
                    root.dismiss()
                    print(15)
            MyButton:
                text: '16'
                on_press:
                    root.dismiss()
                    print(16)
            MyButton:
                text: '17'
                on_press:
                    root.dismiss()
                    print(17)
            MyButton:
                text: '18'
                on_press:
                    root.dismiss()
                    print(18)
            MyButton:
                text: '19'
                on_press:
                    root.dismiss()
                    print(19)
            MyButton:
                text: '20'
                on_press:
                    root.dismiss()
                    print(20)

<MyLayout>
    orientation: 'vertical'
    size: root.width, root.height

    Label:
        size_hint: 1, 0.9
        text: 'main'
        font_size: 24

    Button:
        size_hint: 1, 0.1
        text: 'menu'
        font_size: 24
        on_release: Factory.MyPopup().open()

<MyButton@Button>
    background_color: 0,0,0,0
    background_normal: ''
    canvas.before:
        Color:
            rgba: (48/255,84/255,150/255,1) if self.state == 'normal' else (43/255,108/255,229/255,1)
        Rectangle:
            size: self.size
            pos: self.pos

【问题讨论】:

【参考方案1】:

为了构建用MyButtons 填充的MyPopup,您必须在python 代码中定义这些类或使用Factory 来创建实例。这是您的 kv 的修改版本:

<MyPopup@ModalView>
    auto_dismiss: True
    size_hint: 1, 0.5
    pos_hint: 'x': 0, 'top': 0.5
    background_color: 0,0,0,0
    background_normal: ''
    canvas.before:
        Color:
            rgba: 48/150,84/150,150/150,1
        Rectangle:
            size: self.size
            pos: self.pos
    ScrollView:
        #do_scroll_x: False
        GridLayout:
            id: container1
            cols: 1
            size_hint: None, None
            width: root.width
            height: self.minimum_height  # let the GridLayout set its own height as needeed
            pos_hint: 'center_x': .5, 'center_y': .5
            
<MyLayout>
    orientation: 'vertical'
    size: root.width, root.height

    Label:
        size_hint: 1, 0.9
        text: 'main'
        font_size: 24

    Button:
        size_hint: 1, 0.1
        text: 'menu'
        font_size: 24
        # on_release: Factory.MyPopup().open()
        on_release: app.open_popup()  # call app method to build MyPopup and fill it

<MyButton@Button>
    background_color: 0,0,0,0
    background_normal: ''
    size_hint_y: None
    height: 20
    canvas.before:
        Color:
            rgba: (48/255,84/255,150/255,1) if self.state == 'normal' else (43/255,108/255,229/255,1)
        Rectangle:
            size: self.size
            pos: self.pos

注意GridLayout 高度设置为self.minimum_height 以允许任意数量的MyButton 子级,MyButton 高度设置为固定值(以便GridLayout 可以计算最小高度)。此外,kv 中不再需要导入Factory

修改后的python代码:

from kivy.app import App
from kivy.factory import Factory
from kivy.uix.boxlayout import BoxLayout
from kivy.lang import Builder
from kivy.core.window import Window

Builder.load_file('mylayout.kv')
Window.size = (350, 700)

class MyLayout(BoxLayout):
    pass

class MainApp(App):

    def build(self):
        return MyLayout()

    def open_popup(self, *args):
        # create the popup (must use Factory since MyPopup is defined in kv)
        self.popup = Factory.MyPopup()

        # fill the GridLayout
        grid = self.popup.ids.container1
        for i in range(60):
            grid.add_widget(Factory.MyButton(text=str(i), on_press=self.myButtPress))

        # open popup
        self.popup.open()

    def myButtPress(self, butt):
        print(butt.text)
        self.popup.dismiss()

MainApp().run()

【讨论】:

以上是关于Kivy - 如何在 ModalView 内向 ScrollView 添加多个按钮?的主要内容,如果未能解决你的问题,请参考以下文章

如何将 modalView 设置为 false?

关闭一次后如何呈现相同的modalView

iPhone:如何使用modalView实现类似于popToRootViewController的功能?

如何设置 Modalview 控制器的中心。我能找到任何解决方案吗?

从 ModalView 打开 ModalView

在 ModalView 中丢失 firstResponder