pythonkivywidget

How to add Widget to specific spot in Kivy layout


Basically after the Spinner, I'll have a Python built widget for each option to collect input data based on the chosen "Type". Now the problem is that when I run it like this the label gets put in the middle of the screen ignoring every widget already placed. I need to control where it's put in the existing layout.

Here's the Python part

class NewTaskScreen(Screen):

    testlabel = Label(text="test label")

    #need to create elements in a certain position on the grid/box
    def selecttype(self, instance):
        self.add_widget(self.testlabel)


class TaskReminder(App):
     def build(self):
        # Create the screen manager
        sm = ScreenManager()
        #sm.add_widget(MenuScreen(name='menu'))
        sm.add_widget(NewTaskScreen(name='newtask'))

        return sm

And the Kyvi part

<NewTaskScreen>:
      BoxLayout:
            orientation: 'vertical'
            Button:
                  text: "Back to menu"
                  font_size: 64
                  size: 100, 50
                  on_release: root.manager.current = 'menu'
            GridLayout:
                  cols:2
                  Label:
                        text: "Name:"
                  TextInput:
                        multiline:False
                  Label:
                        text: "Description:"
                  TextInput:
                        multiline:False
                  Label:
                        text: "Type:"
                  Spinner:
                        text: 'Constant'
                        values: 'Constant', 'Daily', 'Monthly', 'Yearly', 'OneOff'
                  Button:
                        text: 'test'
                        font_size: 64
                        size: 100, 50
                        on_release: root.selecttype(self)

I've tried changing the index variable on the add_widget method but the only thing that changes is whether the widget is in Front of everything or Behind everything. I know that if the class that I'm calling in main was a GridLayout then the add_widget method would work by inserting it right after it's called. Example:

class ExampleGrid(GridLayout):
    def __init__(self, **kwargs):
        super(ExampleGrid, self).__init__(**kwargs)

        self.cols = 2

        self.submit = Button(text="Submit", font_size=32)
        self.submit.bind(on_press=self.press)
        self.add_widget(self.submit)
    
    def press(self, instance):
        self.add_widget(Label(text="test label"))

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

Problem is I kinda need the multiple screens for future functions.

--edit-- Clarification, I need it in the space that's occupied by the Label "times", between two grids, in the middle of the BoxLayout

<NewTaskScreen>:
  BoxLayout:
        orientation: 'vertical'
        Button:
              text: "Back to menu"
              font_size: 64
              size: 100, 50
              on_release: root.manager.current = 'menu'
              #on_release: root.selecttype(self)
        GridLayout:
              id: grid
              cols:2
              Label:
                    text: "Name:"
              TextInput:
                    multiline:False
              Label:
                    text: "Description:"
              TextInput:
                    multiline:False
              Label:
                    text: "Type:"
              Spinner:
                    text: 'Constant'
                    values: 'Constant', 'Daily', 'Monthly', 'Yearly', 'OneOff'
        Label:
              id: times
              text: "Times"
        GridLayout:
              cols:2
              Button:
                    text: 'test'
                    font_size: 64
                    size: 100, 50
                    on_release: root.selecttype(self)
              Button:
                    
                    text: "Destroy"
                    font_size: 64
                    size: 100, 50
                    on_release: root.test(self)

Solution

  • If I understand your question correctly, you want to add the testlabel to the GridLayout. To do that, just add an id to the GridLayout:

    <NewTaskScreen>:
          BoxLayout:
                orientation: 'vertical'
                Button:
                      text: "Back to menu"
                      font_size: 64
                      size: 100, 50
                      on_release: root.manager.current = 'menu'
                GridLayout:
                      id: grid
    

    Then, in the selecttype() method, use the new id like this:

    def selecttype(self, instance):
        self.ids.grid.add_widget(self.testlabel)
    

    If you want the testlabel to appear between the GridLayouts, you can add a container in the location:

        GridLayout:
            id: grid
            cols:2
            Label:
                text: "Name:"
            TextInput:
                multiline:False
            Label:
                text: "Description:"
            TextInput:
                multiline:False
            Label:
                text: "Type:"
            Spinner:
                text: 'Constant'
                values: 'Constant', 'Daily', 'Monthly', 'Yearly', 'OneOff'
        BoxLayout:
            id: times
        # Label:
        #     id: times
        #     text: "Times"
        GridLayout:
            cols:2
            Button:
                text: 'test'
                font_size: 64
                size: 100, 50
                on_release: root.selecttype(self)
            Button:
                
                text: "Destroy"
                font_size: 64
                size: 100, 50
                on_release: root.test(self)
    

    Then change the selecttype() method to use that new container:

    def selecttype(self, instance):
        self.ids.times.add_widget(self.testlabel)