admin管理员组

文章数量:1125966

Currently battling with Kivy nested layotus and scorll view. I dynamically add or remove from a table with some buttons. As the page grows I expect self.minimum_height of the parent CreatePly layout to change but it does not.

Is there a neat way to dynamically change the height of my scorll view or will I have to do it Caveman style and increase the it manually after the creation of every widget?

Python Code:

#This file contains the graphical user interface logic of the DIS creator

from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from kivy.uix.boxlayout import BoxLayout
from kivy.metrics import dp
from kivy.uix.widget import Widget
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.uix.textinput import TextInput
from kivy.uix.togglebutton import ToggleButton

class DIS3(App):
    pass

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

#Dimensional control
        self.spacing = dp(2)
        self.padding = dp(10)
        self.cols = 1
        self.size_hint = (1, None)
        self.height = self.minimum_height #I expect this to dynamically change with the nested layouts. It does not.

#Varibales
        self.constituent_name = []
        self.constituent_areaweight = []
        self.structural_toggle = []

#Add and remove consituents
#Header
        self.add_remove_header = BoxLayout()
        self.add_remove_header.size_hint = (1, None)
        self.add_remove_header.height = dp(40)

        label = Label(text="Add constituents to create a ply")
        self.add_remove_header.add_widget(label)
        self.add_widget(self.add_remove_header)

#Add remove buttons
        self.add_remove_buttons = GridLayout()
        self.add_remove_buttons.cols = 4
        self.add_remove_buttons.size_hint = (1, None)
        self.add_remove_buttons.height = dp(40)
        self.add_remove_buttons.add_widget(Widget())
        button = Button(text="+", size_hint=(None, None), width=dp(40), height=dp(40))
        button.bind(on_press = lambda x: self.add_constituent_press())
        self.add_remove_buttons.add_widget(button)
        button = Button(text="-", size_hint=(None, None), width=dp(40), height=dp(40))
        button.bind(on_press = lambda x: self.remove_constituent_press())
        self.add_remove_buttons.add_widget(button)
        self.add_remove_buttons.add_widget(Widget())
        self.add_widget(self.add_remove_buttons)

#Constituent table
        self.constituent_table = GridLayout()
        self.constituent_table.cols = 3

        label = Label(text="Consituent name", size_hint=(0.55, None), height=dp(20))
        self.constituent_table.add_widget(label)
        label = Label(text="Areal weight (g/m2)", size_hint=(0.3, None), height=dp(20))
        self.constituent_table.add_widget(label)
        label = Label(text="Structural?", size_hint=(0.15, None), height=dp(20))
        self.constituent_table.add_widget(label)

        textinput = TextInput(size_hint=(0.55, None), height=dp(40))
        self.constituent_name.append(textinput)
        self.constituent_table.add_widget(textinput)
        textinput = TextInput(size_hint=(0.3, None), height=dp(40))
        self.constituent_areaweight.append(textinput)
        self.constituent_table.add_widget(textinput)
        toggle = ToggleButton(text="No", size_hint=(0.15, None), height=(dp(40)))
        toggle.bind(state=(lambda self, x: CreatePly.structural_constituent_toggle(self, toggle)))
        self.structural_toggle.append(toggle)
        self.constituent_table.add_widget(toggle)
        self.add_widget(self.constituent_table)

#Build ply button
        self.footer = GridLayout()
        self.footer.cols = 3

        self.footer.size_hint = (1, None)
        self.footer.height = dp(40)
        self.footer.add_widget(Widget())
        button = Button(text="Create ply", size_hint=(None, None), width=dp(120), height=dp(40))
        button.bind(on_press = lambda x: self.create_ply())
        self.footer.add_widget(button)
        self.footer.add_widget(Widget())
        self.add_widget(self.footer)

#Functions
    def structural_constituent_toggle(self, toggle):
        if toggle.state == "normal":
            toggle.text = "No"
        else:
            toggle.text = "Yes"

    def add_constituent_press(self):
        textinput = TextInput(size_hint=(0.55, None), height=(dp(40)))
        self.constituent_name.append(textinput)
        self.constituent_table.add_widget(textinput)

        textinput = TextInput(size_hint=(0.3, None), height=(dp(40)))
        self.constituent_areaweight.append(textinput)
        self.constituent_table.add_widget(textinput)

        toggle = ToggleButton(text="No", size_hint=(0.15, None), height=(dp(40)))
        toggle.bind(state=(lambda self, x: CreatePly.structural_constituent_toggle(self, toggle)))
        self.structural_toggle.append(toggle)
        self.constituent_table.add_widget(toggle)

    def remove_constituent_press(self):

        if len(self.constituent_name) == 1:
            pass
        
        else:
            self.constituent_table.remove_widget(self.constituent_name[-1])
            del self.constituent_name[-1]

            self.constituent_table.remove_widget(self.constituent_areaweight[-1])
            del self.constituent_areaweight[-1]

            self.constituent_table.remove_widget(self.structural_toggle[-1])
            del self.structural_toggle[-1]

    def create_ply(self):
        pass

#Run loop
DIS3().run()

KV file code:

#This file contains the graphical user interface elements of the DIS creator app

#This is the layout of the entire screen
MainLayout:

<MainLayout@BoxLayout>:
    #Background colour
    canvas.before:
        Color:
            rgba:(.3,.3,.3,1)
        Rectangle:
            pos: self.pos
            size: self.size

    padding: '10dp'
    spacing: '10dp'
    MenuLayout:
    FocusFrame:

#This is the layout for the menu
<MenuLayout@StackLayout>:
    #Background colour
    canvas.before:
        Color:
            rgba:(0,0,0,1)
        Rectangle:
            pos: self.pos
            size: self.size

    #Dimension control
    size_hint: None, 1
    width: "160dp"
    spacing: "2dp"
    padding: "10dp"

    Button:
        text: "Database"
        size_hint: 1, None
        height: "40dp"

    Button:
        text: "Create ply"
        size_hint: 1, None
        height: "40dp"

    Button:
        text: "Create preform"
        size_hint: 1, None
        height: "40dp"

    Button:
        text: "Plan infusion"
        size_hint: 1, None
        height: "40dp"

    Button:
        text: "Write DIS"
        size_hint: 1, None
        height: "40dp"

    Button:
        text: "Review DIS"
        size_hint: 1, None
        height: "40dp"

#This is the layout for the scrollable focus frame
<FocusFrame@ScrollView>:
    canvas.before:
        Color:
            rgba:(0,0,0,1)
        Rectangle:
            pos: self.pos
            size: self.size

    CreatePly:

Thanks in advance!

Currently battling with Kivy nested layotus and scorll view. I dynamically add or remove from a table with some buttons. As the page grows I expect self.minimum_height of the parent CreatePly layout to change but it does not.

Is there a neat way to dynamically change the height of my scorll view or will I have to do it Caveman style and increase the it manually after the creation of every widget?

Python Code:

#This file contains the graphical user interface logic of the DIS creator

from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from kivy.uix.boxlayout import BoxLayout
from kivy.metrics import dp
from kivy.uix.widget import Widget
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.uix.textinput import TextInput
from kivy.uix.togglebutton import ToggleButton

class DIS3(App):
    pass

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

#Dimensional control
        self.spacing = dp(2)
        self.padding = dp(10)
        self.cols = 1
        self.size_hint = (1, None)
        self.height = self.minimum_height #I expect this to dynamically change with the nested layouts. It does not.

#Varibales
        self.constituent_name = []
        self.constituent_areaweight = []
        self.structural_toggle = []

#Add and remove consituents
#Header
        self.add_remove_header = BoxLayout()
        self.add_remove_header.size_hint = (1, None)
        self.add_remove_header.height = dp(40)

        label = Label(text="Add constituents to create a ply")
        self.add_remove_header.add_widget(label)
        self.add_widget(self.add_remove_header)

#Add remove buttons
        self.add_remove_buttons = GridLayout()
        self.add_remove_buttons.cols = 4
        self.add_remove_buttons.size_hint = (1, None)
        self.add_remove_buttons.height = dp(40)
        self.add_remove_buttons.add_widget(Widget())
        button = Button(text="+", size_hint=(None, None), width=dp(40), height=dp(40))
        button.bind(on_press = lambda x: self.add_constituent_press())
        self.add_remove_buttons.add_widget(button)
        button = Button(text="-", size_hint=(None, None), width=dp(40), height=dp(40))
        button.bind(on_press = lambda x: self.remove_constituent_press())
        self.add_remove_buttons.add_widget(button)
        self.add_remove_buttons.add_widget(Widget())
        self.add_widget(self.add_remove_buttons)

#Constituent table
        self.constituent_table = GridLayout()
        self.constituent_table.cols = 3

        label = Label(text="Consituent name", size_hint=(0.55, None), height=dp(20))
        self.constituent_table.add_widget(label)
        label = Label(text="Areal weight (g/m2)", size_hint=(0.3, None), height=dp(20))
        self.constituent_table.add_widget(label)
        label = Label(text="Structural?", size_hint=(0.15, None), height=dp(20))
        self.constituent_table.add_widget(label)

        textinput = TextInput(size_hint=(0.55, None), height=dp(40))
        self.constituent_name.append(textinput)
        self.constituent_table.add_widget(textinput)
        textinput = TextInput(size_hint=(0.3, None), height=dp(40))
        self.constituent_areaweight.append(textinput)
        self.constituent_table.add_widget(textinput)
        toggle = ToggleButton(text="No", size_hint=(0.15, None), height=(dp(40)))
        toggle.bind(state=(lambda self, x: CreatePly.structural_constituent_toggle(self, toggle)))
        self.structural_toggle.append(toggle)
        self.constituent_table.add_widget(toggle)
        self.add_widget(self.constituent_table)

#Build ply button
        self.footer = GridLayout()
        self.footer.cols = 3

        self.footer.size_hint = (1, None)
        self.footer.height = dp(40)
        self.footer.add_widget(Widget())
        button = Button(text="Create ply", size_hint=(None, None), width=dp(120), height=dp(40))
        button.bind(on_press = lambda x: self.create_ply())
        self.footer.add_widget(button)
        self.footer.add_widget(Widget())
        self.add_widget(self.footer)

#Functions
    def structural_constituent_toggle(self, toggle):
        if toggle.state == "normal":
            toggle.text = "No"
        else:
            toggle.text = "Yes"

    def add_constituent_press(self):
        textinput = TextInput(size_hint=(0.55, None), height=(dp(40)))
        self.constituent_name.append(textinput)
        self.constituent_table.add_widget(textinput)

        textinput = TextInput(size_hint=(0.3, None), height=(dp(40)))
        self.constituent_areaweight.append(textinput)
        self.constituent_table.add_widget(textinput)

        toggle = ToggleButton(text="No", size_hint=(0.15, None), height=(dp(40)))
        toggle.bind(state=(lambda self, x: CreatePly.structural_constituent_toggle(self, toggle)))
        self.structural_toggle.append(toggle)
        self.constituent_table.add_widget(toggle)

    def remove_constituent_press(self):

        if len(self.constituent_name) == 1:
            pass
        
        else:
            self.constituent_table.remove_widget(self.constituent_name[-1])
            del self.constituent_name[-1]

            self.constituent_table.remove_widget(self.constituent_areaweight[-1])
            del self.constituent_areaweight[-1]

            self.constituent_table.remove_widget(self.structural_toggle[-1])
            del self.structural_toggle[-1]

    def create_ply(self):
        pass

#Run loop
DIS3().run()

KV file code:

#This file contains the graphical user interface elements of the DIS creator app

#This is the layout of the entire screen
MainLayout:

<MainLayout@BoxLayout>:
    #Background colour
    canvas.before:
        Color:
            rgba:(.3,.3,.3,1)
        Rectangle:
            pos: self.pos
            size: self.size

    padding: '10dp'
    spacing: '10dp'
    MenuLayout:
    FocusFrame:

#This is the layout for the menu
<MenuLayout@StackLayout>:
    #Background colour
    canvas.before:
        Color:
            rgba:(0,0,0,1)
        Rectangle:
            pos: self.pos
            size: self.size

    #Dimension control
    size_hint: None, 1
    width: "160dp"
    spacing: "2dp"
    padding: "10dp"

    Button:
        text: "Database"
        size_hint: 1, None
        height: "40dp"

    Button:
        text: "Create ply"
        size_hint: 1, None
        height: "40dp"

    Button:
        text: "Create preform"
        size_hint: 1, None
        height: "40dp"

    Button:
        text: "Plan infusion"
        size_hint: 1, None
        height: "40dp"

    Button:
        text: "Write DIS"
        size_hint: 1, None
        height: "40dp"

    Button:
        text: "Review DIS"
        size_hint: 1, None
        height: "40dp"

#This is the layout for the scrollable focus frame
<FocusFrame@ScrollView>:
    canvas.before:
        Color:
            rgba:(0,0,0,1)
        Rectangle:
            pos: self.pos
            size: self.size

    CreatePly:

Thanks in advance!

Share Improve this question asked 2 days ago Joseph Joe SoltanJoseph Joe Soltan 898 bronze badges
Add a comment  | 

2 Answers 2

Reset to default 1

Using:

self.height = self.minimum_height

in your __init__() method sets the height to the value of minimum_height at the time when the __init__() method executes. It will have no effect on the height after that.

You want to bind the minimum_height to the height, so that the height will change when minimum_height changes. Two ways to do that are to use:

height: self.minimum_height

inside a kv file (The Builder will create the needed binding for you). or in your python code:

self.constituent_table.bind(minimum_height=self.constituent_table.setter('height'))

which explicitly creates the needed binding. See the documentation.

So, try making the following changes to your code: In your kv file:

CreatePly:
    height: self.minimum_height

and in your python code:

comment out the line in the __init__() method:

# self.height = self.minimum_height

and add the lines:

    self.constituent_table.size_hint_y = None
    self.constituent_table.bind(minimum_height=self.constituent_table.setter('height'))

This is my 'caveman' solution until I get an actual working automated scailing of the height:

I manually enter the desired starting height:

#self.height = self.minimum_height
self.height = dp(220)

I then add a cumulative height change within the add and remove functions:

self.height += dp(40)

本文标签: Kivy ScrollView minimumheight no longer dynamic with nested layouts in pythonStack Overflow