<Builder_Screen>
ScrollView:
do_scroll_y:True
FloatLayout:
Button:
text:"Heading"
size_hint_x: .25
size_hint_y: .25
text_size: self.size
halign:"center"
valign:"center"
pos: 0,10
Button:
text:"Paragraph"
halign:"center"
valign:"center"
size_hint_x: .25
size_hint_y: .25
pos: (0,self.height)
I have some buttons like these with positions like pos: 0, self.height2 , self.height3 etc.
But, the scroll layout does not work as intended.
Can you help me regarding that!...
According to the documentation, regarding the child of a ScrollView:
By default, the size_hint is (1, 1), so the content size will fit your
ScrollView exactly (you will have nothing to scroll). You must
deactivate at least one of the size_hint instructions (x or y) of the
child to enable scrolling.
So, you probably need to set size_hint_y: None for your FloatLayout. That will cause further problems, because you have size_hint_y values for your Buttons. You can set the heights of your Buttons and eliminate the size_hint_y values. Another approach would be to use a GridLayout:
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import Screen
kv = '''
<Builder_Screen>
ScrollView:
do_scroll_y:True
effect_cls: 'ScrollEffect'
GridLayout:
cols: 2
size_hint_y: None
height: self.minimum_height
padding: 5
spacing: 5
Button:
text:"Heading1"
halign:"center"
valign:"center"
size_hint_y: None
height: 48
Button:
text:"Paragraph1"
halign:"center"
valign:"center"
size_hint_y: None
height: 48
Button:
text:"Heading2"
halign:"center"
valign:"center"
size_hint_y: None
height: 48
Button:
text:"Paragraph2"
halign:"center"
valign:"center"
size_hint_y: None
height: 48
Button:
text:"Heading3"
halign:"center"
valign:"center"
size_hint_y: None
height: 48
Button:
text:"Paragraph3"
halign:"center"
valign:"center"
size_hint_y: None
height: 48
'''
class Builder_Screen(Screen):
pass
class TestApp(App):
def build(self):
Builder.load_string(kv)
return Builder_Screen()
TestApp().run()
Note that every Button has an explicit height. That is required if you use height: self.minimum_height for their container.
Related
I'm trying to create a screen which has a horizontal scrollview at the top of the page, taking up ~25% of the vertical space and a vertical scrollview taking up the rest of the space (and then being able to scroll further down the screen).
I've managed to create a horizontal scrollview but can't get the vertical scrollview to work on the same screen.
py file:
import kivy
from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.lang import Builder
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.uix.image import Image
from
Window.clearcolor = (1,1,1,1)
class Window(Screen):
pass
class MyApp(App):
theme_cls = ThemeManager()
def build(self):
kv = Builder.load_file("kivy.kv")
self.sm = WindowManager()
screens = [Window(name="window")]
for screen in screens:
self.sm.add_widget(screen)
self.sm.current = "window"
return self.sm
if __name__ == '__main__':
MyApp().run()
kv file:
<Window>:
name: "window"
NavigationLayout:
id: nav_layout
MyNavDrawer:
BoxLayout:
orientation: "vertical"
MDToolbar:
pos_hint: {'top': 1}
md_bg_color: 1, 1, 1, 1
ScrollView: #horizontal scrollview - works fine
size_hint_y: 0.5
GridLayout:
rows: 1
id: scroll_horizontal
size_hint_x: None
col_default_width: root.width*0.2
width: self.minimum_width*1.3
spacing: 20
ScrollView: #vertical scrollview, not working
size_hint_y: 0.85
do_scroll_x: False
GridLayout:
id: scroll_vertical
cols: 1
size_hint_y: None
spacing: 40
height: self.minimum_height
canvas:
Color:
rgba: (1, 1, 1, 1)
Rectangle:
size: self.size
pos: self.pos
BoxLayout:
cols: 2
spacing: 10
Button:
size_hint_y: 0.5
text: "Btn1"
Button:
size_hint_y: 0.5
text: "Btn2"
BoxLayout:
cols: 2
spacing: 10
Button:
size_hint_y: 0.5
text: "Btn1"
Button:
size_hint_y: 0.5
text: "Btn2"
BoxLayout:
cols: 2
spacing: 10
Button:
size_hint_y: 0.5
text: "Btn1"
Button:
size_hint_y: 0.5
text: "Btn2"
I'd like them to be independent of each other, so you can either scroll horizontal on the top scrollview or scroll veritcally through the buttons on the boxlayouts on the vertical scrollview
It took some work to get your MCVE working, but here is the part of your kv that I modified to get scrolling working in both directions with two ScrollViews:
ScrollView: #horizontal
size_hint_y: 0.25
do_scroll_y: False
GridLayout:
rows: 1
id: scroll_horizontal
size_hint: None, 1
col_default_width: root.width*0.2
width: self.minimum_width*1.3
spacing: 20
BoxLayout:
cols: 2
spacing: 10
size_hint_x: None
width: self.minimum_width
Button:
size_hint: None, 1
width: 500
text: "Btn1"
Button:
size_hint: None, 1
width: 500
text: "Btn2"
BoxLayout:
cols: 2
spacing: 10
size_hint_x: None
width: self.minimum_width
Button:
size_hint: None, 1
width: 500
text: "Btn1"
Button:
size_hint: None, 1
width: 500
text: "Btn2"
BoxLayout:
cols: 2
spacing: 10
size_hint_x: None
width: self.minimum_width
Button:
size_hint: None, 1
width: 500
text: "Btn1"
Button:
size_hint: None, 1
width: 500
text: "Btn2"
ScrollView: # vertical
size_hint_y: 0.75
do_scroll_x: False
GridLayout:
id: scroll_vertical
cols: 1
size_hint: 1.0, None
spacing: 40
# must set height
height: self.minimum_height
BoxLayout:
cols: 2
spacing: 10
size_hint_y: None
Button:
size_hint: 0.5, None
height: 100
text: "Btn1"
Button:
size_hint: 0.5, None
height: 100
text: "Btn2"
BoxLayout:
cols: 2
spacing: 10
size_hint_y: None
height: self.minimum_height
Button:
size_hint: 0.5, None
height: 100
text: "Btn1"
Button:
size_hint: 0.5, None
height: 100
text: "Btn2"
BoxLayout:
cols: 2
spacing: 10
size_hint_y: None
height: self.minimum_height
Button:
size_hint: 0.5, None
height: 100
text: "Btn1"
Button:
size_hint: 0.5, None
height: 100
text: "Btn2"
I have this code where i want to change the position of the buttons, but if i change the position, the scroll is no longer working. How to manage to make it work? Below is the working version. If i change size_hint: 1, .1 to size_hint: 1, .7, the scroll no longer works...
from kivy.app import App
from kivy.lang.builder import Builder
from kivy.uix.floatlayout import FloatLayout
Builder.load_string('''
<Root>:
ScrollView:
size_hint: 1, .1
GridLayout:
size_hint_y: None
cols: 1
# minimum_height: self.height
Button
text: 'one'
Button:
text: 'two'
Button:
text: 'three'
Button:
text: 'four'
''')
class Root(FloatLayout):
pass
class DemoApp(App):
def build(self):
return Root()
if __name__ == '__main__':
DemoApp().run()
You are doing it right. The ScrollView allows you to scroll to see parts of your GridLayout that don't fit in the ScrollView. When you set the size_hint to (1, .7), everything fits within the ScrollView, so it does not scroll.
You can force scrolling by adding Widgets to take up more space (like Labels with no text):
<Root>:
ScrollView:
size_hint: 1, .7
GridLayout:
size_hint_y: None
cols: 1
height: self.minimum_height
Label:
text: ''
size_hint_y: None
height: 300
Button
text: 'one'
size_hint: 1, None
height: self.texture_size[1]
Button:
text: 'two'
size_hint: 1, None
height: self.texture_size[1]
Button:
text: 'three'
size_hint: 1, None
height: self.texture_size[1]
Button:
text: 'four'
size_hint: 1, None
height: self.texture_size[1]
Label:
text: ''
size_hint_y: None
height: 300
Once theres a size_hint_y = None in the parent widget, then you have to manually declare the height of the child widget since size_hint_y deals with the height or Y axis.. so i modified your code to make things a lil clearer
from kivy.app import App
from kivy.lang.builder import Builder
from kivy.uix.floatlayout import FloatLayout
Builder.load_string('''
<Root>:
ScrollView:
size_hint_y:None
height:root.width / 2
GridLayout:
size_hint_y: None
cols: 1
height:self.minimum_height
spacing:dp(20)
Button
text: 'one'
size_hint_y:None
height:dp(50)
Button:
text: 'two'
size_hint_y:None
height:dp(50)
Button:
text: 'three'
size_hint_y:None
height:dp(50)
Button:
text: 'four'
size_hint_y:None
height:dp(50)
''')
class Root(FloatLayout):
pass
class DemoApp(App):
def build(self):
return Root()
if __name__ == '__main__':
DemoApp().run()
I'm new to Kivy and still working out the best way to use it. Currently, I'm taking an example from their repo (textsize demo) and attempting to use layout concepts in a personal project.
At the end of the day, all I want is a "navbar" at the top of my screen and a content section below it. At the moment, I'm trying to accomplish this with a BoxLayout which includes a StackLayout (nav items) and a GridLayout (other content).
My Code Snippet:
<WindowWidget>:
BoxLayout:
orientation: 'vertical'
StackLayout:
Label:
text: 'Test1'
Label:
text: 'Test1.1'
Label:
text: 'Test2'
This code produces this: Kivy Screenshot.
I don't understand why label 1.1 is pushed down on top of label 2 rather than appearing beside label 1.
I added the following code taken from the kivy examples hoping the height setting would add some clarity, but I get the error below:
Code:
<StackLayout>:
size_hint_y: None
spacing: dp(6)
padding: dp(6), dp(4)
height: self.minimum_height
Error:
Warning, too much iteration done before the next frame. Check your
code, or increase the Clock.max_iteration attribute
This is caused by my inclusion of the "height: self.minimum_height" line. However, this works in the demo, so I'm not sure how I managed to screw it up. I'll include the example's kv code below for reference.
The original:
BoxLayout:
orientation: 'vertical'
HeadingLabel:
text: 'These modify all demonstration Labels'
StackLayout:
# Button is a subclass of Label and can be sized to text in the same way
Button:
text: 'Reset'
on_press: app.reset_words()
ToggleButton:
text: 'Shorten'
on_state:
app.shorten=self.state=='down'
ToggleButton:
text: 'max_lines=3'
on_state:
app.max_lines=3 if self.state=='down' else 0
Spinner:
text: 'bottom'
values: 'bottom', 'middle', 'top'
on_text: app.valign=self.text
Spinner:
text: 'left'
values: 'left', 'center', 'right', 'justify'
on_text: app.halign=self.text
GridLayout:
id: grid_layout
cols: 2
height: cm(6)
size_hint_y: None
HeadingLabel:
text: "Default, no text_size set"
HeadingLabel:
text: 'text_size bound to size'
DemoLabel:
id: left_content
disabled_color: 0, 0, 0, 0
DemoLabel:
id: right_content
text_size: self.size
padding: dp(6), dp(6)
ToggleButton:
text: 'Disable left'
on_state:
left_content.disabled=self.state=='down'
# Need one Widget without size_hint_y: None, so that BoxLayout fills
# available space.
HeadingLabel:
text: 'text_size width set, size bound to texture_size'
text_size: self.size
size_hint_y: 1
DemoLabel:
id: bottom_content
# This Label wraps and expands its height to fit the text because
# only text_size width is set and the Label size binds to texture_size.
text_size: self.width, None
size: self.texture_size
padding: mm(4), mm(4)
size_hint_y: None
# The column heading labels have their width set by the parent,
# but determine their height from the text.
<HeadingLabel#Label>:
bold: True
padding: dp(6), dp(4)
valign: 'bottom'
height: self.texture_size[1]
text_size: self.width, None
size_hint_y: None
<ToggleButton,Button>:
padding: dp(10), dp(8)
size_hint: None, None
size: self.texture_size
# This inherits Button and the modifications above, so reset size
<Spinner>:
size: sp(68), self.texture_size[1]
<DemoLabel#Label>:
halign: app.halign
valign: app.valign
shorten: app.shorten
max_lines: app.max_lines
canvas:
Color:
rgb: 68/255.0, 164/255.0, 201/255.0
Line:
rectangle: self.x, self.y, self.width, self.height
<StackLayout>:
size_hint_y: None
spacing: dp(6)
padding: dp(6), dp(4)
height: self.minimum_height
TYIA
I want to create a Widget changing only the text of a label inside it, but all the ways I find how to change this are by changing it in the python code instead of reusing only Kivy objects.
So I have a widget like the following:
<AmiLabel#Label>
color: .1, .5, .8, 1
font_size: 16
<AmiTextInput#TextInput>
font_size: 16
<PropertyInputForm>:
BoxLayout:
size: root.size
pos: root.pos
orientation: 'horizontal'
AmiLabel:
text: 'Folder Location'
size_hint_x: .5
AmiTextInput:
text: 'None'
size_hint_x: .5
<MainFormWidget>:
BoxLayout:
size: root.size
pos: root.pos
id: foo_bar
padding: 5
spacing: 5
canvas:
Color:
rgb: (1, 1, 1)
Rectangle:
pos: self.pos
size: self.size
orientation: 'vertical'
AmiLabel:
height: 36
size_hint_x: 1
size_hint_y: None
text: 'Project Name'
PropertyInputForm:
height: 36
size_hint_x: 1
size_hint_y: None
# I WANT TO CHANGE THE TEXT OF THE LABEL IN HERE
PropertyInputForm:
height: 36
size_hint_x: 1
size_hint_y: None
# I WANT TO CHANGE THE TEXT OF THE LABEL IN HERE
All I want to is change the text of the label from another widget in another level without touching the python code.
¿Is that possible?
One simple way would be to add a new property to your PropertyInputForm and reference or set that.
<PropertyInputForm>:
new_text_property: ''
BoxLayout:
size: root.size
pos: root.pos
orientation: 'horizontal'
AmiLabel:
text: root.new_text_property
size_hint_x: .5
AmiTextInput:
text: 'None'
size_hint_x: .5
and later
PropertyInputForm:
height: 36
size_hint_x: 1
size_hint_y: None
new_text_property: 'whatever'
You may also need to declare new_text_property in the python class to have it be a StringProperty rather than an ObjectProperty, though even that is I think not necessary in kivy 1.8.
I'm having trouble with going back and forth between the concepts in the Kivy language, vs. Python language. I'm not very good at explaining things, and i've thought about how to explain my specific problem, but the best way i can think to do that is:
How would one implement the ScrollViewApp using the Builder function?
hm, something like
ScrollView:
size_hint: None, None
size: 500, 320
pos_hint: {'center_x': .5, 'center_y': .5}
do_scroll_x: False
GridLayout:
cols: 1
padding: 10
spacing: 10
size_hint_y: None
height: self.minimum_height
ScrollButton:
text: '1'
ScrollButton:
text: '2'
ScrollButton:
text: '3'
ScrollButton:
text: '4'
ScrollButton:
text: '5'
ScrollButton:
text: '6'
<ScrollButton#Button>
size_hint: None, None
size: 480, 40
here, however we don't really have a way to dynamically create the children (well, there would be ways, but they are ugly), so i put a few manualy, idealy you would create the ScrollView and GridLayout in kv, and then put the children inside from python (using ids, as explained in the doc).
edit: more complete version using an app and ObjectProperty
kv file (scroll.kv):
ScreenManager:
Screen:
ScrollView:
size_hint: None, None
size: 500, 320
pos_hint: {'center_x': .5, 'center_y': .5}
GridLayout:
cols: 1
padding: 10
spacing: 10
height: self.minimum_height
size_hint: None, None
do_scroll_x: False
id: container
<ScrollButton>
size_hint: None, None
size: 480, 40
python file (main.py):
from kivy.app import App
from kivy.uix.button import Button
class ScrollButton(Button):
pass
class ScrollApp(App):
def build(self):
super(ScrollApp, self).build()
container = self.root.ids.container
for i in range(30):
container.add_widget(ScrollButton(text=str(i)))
return self.root # return root does not work
if __name__ == '__main__':
ScrollApp().run()