Search code examples
pythonbuttonwidgetkivyspinner

How to ensure proper functionality when adding widgets to Kivy


I am attempting to create a Kivy/Python application which gets the user to push a button on one screen, and in turn adds several widgets to the next screen. However, when I run the script, the button appears and can be clicked on the first page, and the widgets are visible on the second page, but they can not be interacted with.

Here is an example of my code, any help is appreciated:

py:

import kivy
kivy.require('1.11.1')

from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.gridlayout import GridLayout
from kivy.properties import ListProperty, StringProperty, ObjectProperty
from kivy.core.window import Window
from kivy.uix.label import Label
from kivy.uix.scrollview import ScrollView
from kivy.uix.button import Button
from kivy.uix.spinner import Spinner

sm = None

class RcGUITestApp(App):
    def build(self):
        global sm
        Window.clearcolor = (0, 0, 0.35, 1)
        sm = ScreenManager()
        sm.add_widget(NewJobPage(name="new_job_page"))
        sm.add_widget(IPMConfirmPage(name = "ipm_confirm_page"))
        return sm

class NewJobPage(Screen):
    def retrieve(self):
        global rc
        global sm
        sm.get_screen("ipm_confirm_page").displayIPM()

class IPMConfirmPage(Screen):
    grid = ObjectProperty(None)

    def displayIPM(self):
        for ipm in range(50):
            self.grid.add_widget(Label(text="A"))
            self.grid.add_widget(Spinner(text="B"))
            self.grid.add_widget(Spinner(text="C"))

def main():
    rc_gui = RcGUITestApp()
    rc_gui.run()

if __name__ == "__main__":
        main()

kv:

<NewJobPage>:
        BoxLayout:
                orientation: "horizontal"
                size_hint: (1, .35)

                Button:
                        text: "RETRIEVE"
                        pos_hint: {"center_x": .5, "center_y": .5}
                        size_hint: (.33, .33)
                        color: (1,1,1,1)
                        on_press:
                                root.retrieve()
                                root.manager.transition.direction = "left"
                                root.manager.transition.duration = .8
                                root.manager.current = "ipm_confirm_page"

<IPMConfirmPage>:
        grid: Grid
        GridLayout:
                cols: 1
                size_hint_x: 1
                padding: 10
                spacing: 10

                BoxLayout:
                        size_hint: (1, 0.1)

                        Label:
                                text: "IPM"
                        Label:
                                text: "CD#"
                        Label:
                                text: "CONDUCTOR"

                ScrollView:

                        GridLayout:
                                id: Grid
                                cols: 3
                                height: self.minimum_height
                                size_hint: 1, None
                                spacing: 50
                                padding: 30

First Page output

First Page output

Second Page output

Second Page output


Solution

  • You need to provide the height of each widget added to grid. There are two solutions to the problem.

    Method 1 - kv file

    This method involves changing only the kv file by adding row_force_default: True and row_default_height: 40.

    Snippets - kv file

        ScrollView:
    
            GridLayout:
                row_force_default: True
                row_default_height: 40
                ...
    

    Method 2 - py file

    This method involves changing only the py file by adding size_hint_y=None and height=40.

    Snippets

    def displayIPM(self):
        for ipm in range(50):
            self.grid.add_widget(Label(text="A", size_hint_y=None, height=40))
            self.grid.add_widget(Spinner(text="B", size_hint_y=None, height=40))
            self.grid.add_widget(Spinner(text="C", size_hint_y=None, height=40))