Kivy (kv language) StackLayout Issue and Boundary Issue - python

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

Related

Multiple recycleView are stacking

I've created an app with a main page that is going to have multiple sections with recycleView data. I have added the first but when I try to add a second (eventually adding 4 to replace the APPS, OTHER, etc sections) the second recycleView shows up on top of the first one (see top left of image) instead of next to it like I would expect. I tried putting both of the recycleView widgets inside a boxlayout but the second RV still overlays the top.
The information should be filling the second box on the right here instead of overlaying on the far top left
Screen:
MDNavigationLayout:
ScreenManager:
id: screenManager
Screen:
name: "monitor"
CoverImage:
source: 'images/monitor.png'
# Darken the photo
canvas:
Color:
rgba: 0, 0, 0, .6
Rectangle:
pos: self.pos
size: self.size
BoxLayout:
orientation: 'vertical'
MDToolbar:
title: 'Administration'
left_action_items: [["menu", lambda x: nav_drawer.set_state('toggle')]]
elevation:5
BoxLayout:
ServerListWidget:
MountListWidget:
Please let me know if you need to see any additional code. I've also tried using a GridLayout with 2 cols
<MountListWidget>:
id: mountListWidget
recycleView: recycleView_mounts
BoxLayout:
padding: dp(20)
spacing: dp(10)
BoxLayout:
spacing: dp(10)
BoxLayout:
canvas.before:
Color:
rgba: 1,1,1,.1
# Use a float layout to round the corners
RoundedRectangle:
pos: self.pos
size: self.size
RecycleView:
id: recycleView_mounts
viewclass: 'MountWidget'
RecycleGridLayout:
cols: 1
default_size: self.parent.width, dp(60)
default_size_hint: 1, None
size_hint_y: None
height: self.minimum_height
width: self.minimum_width
spacing: dp(155), dp(0)
<ServerListWidget>:
id: serverListWidget
recycleView: recycleView
BoxLayout:
padding: dp(20)
spacing: dp(10)
BoxLayout:
orientation: "horizontal"
BoxLayout:
canvas.before:
Color:
rgba: 1,1,1,.1
# Use a float layout to round the corners
RoundedRectangle:
pos: self.pos
size: self.size
RecycleView:
id: recycleView
viewclass: 'ServerWidget'
RecycleGridLayout:
cols: 1
default_size: self.parent.width / 5, dp(60)
default_size_hint: 1, None
size_hint_y: None
height: self.minimum_height
width: self.minimum_width
spacing: dp(155), dp(0)
<CoverImage#CoverBehavior+Image>:
reference_size: self.texture_size
<MountWidget>:
BoxLayout:
#size_hint_max_x: dp(360)
size_hint_min_x: dp(150)
orientation: "horizontal"
BoxLayout:
orientation: "horizontal"
Button:
# Use the on_press to print troubleshooting info, otherwise comment out
on_press: print(self.background_color)
padding: dp(10), dp(10)
text_size: self.size
font_size: dp(18)
background_color: .5,1,1,.6
halign: "left"
valign: "top"
size: 1,1
text: str(root.name)
bold: True
color: (1,1,1)
<ServerWidget>:
BoxLayout:
#size_hint_max_x: dp(360)
size_hint_min_x: dp(150)
orientation: "horizontal"
BoxLayout:
orientation: "horizontal"
Button:
# Use the on_press to print troubleshooting info, otherwise comment out
on_press: print(self.background_color)
padding: dp(10), dp(10)
text_size: self.size
font_size: dp(22) if root.has_issue else dp(18)
background_color: .5,1,1,.6 #utils.get_random_color(alpha=.6)
halign: "left"
valign: "top"
size: 1,1
# Show last 4 of server name
text: str(root.name).upper()[-4:]
bold: True
color: utils.get_color_from_hex(warn) if root.has_issue else (1,1,1)
Button:
background_color: .5,1,1,.6
text_size: self.size
font_size: dp(22) if root.work >= 85 and root.work < 90 else dp(26) if root.work >= 90 else dp(18)
valign: "center"
halign: "center"
text: str(root.work)
padding: dp(8), dp(8)
bold: True if root.work > 90 else False
# yellow red white
color: (1,1,0) if root.work >= 85 and root.work < 90 else utils.get_color_from_hex(warn) if root.work >= 90 else (1,1,1)

Scroll does not work in kivy Layout of buttons

<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.

Valign not working in kivy?

I have this kivy file here:
<Help>:
Label:
text: "[b]Help Page[/b]\n"
font_size: 30
markup: True
valign: "top"
color: 0,0,0,1
Label:
text: "[b] How To Use:[/b]\n"
font_size: 30
markup: True
valign: 'top'
color: 0,0,0,1
However, the text does not go to the top of the page. This is the output:
What is wrong with this? and may I also ask about how to format those overlapping text. Thanks :)
edit:
This is what I want to happen with the text:
desired output
So to get that result I tried using the valign and halign to format the text but it does not seem to work. Hope this clarified my question :)
Display Text at Top
To display the text at top using valign: 'top', replace text_size: root.width, None with text_size: root.width, root.height
Snippet
<Help>:
Label:
id: help
text_size: root.width, root.height
markup: True
valign: 'top'
halign: 'center'
color: 0,0,0,1
Output
Display Both Strings as One
To display both strings, "How to Operate: Some text here" and "Some title Some more text" as one, we will do the following:
kv file
<Help>:
Label:
id: help
text_size: root.width, None
markup: True
halign: 'center'
color: 0,0,0,1
Python Code
class Help(Screen):
def on_pre_enter(self, *args):
self.ids.help.text = "[size=30][b]How to Operate[/b][/size]\nSome text here" + \
"\n\n[size=30][b]Some title[/b][/size]\nSome more text"
Output - Combined Text
Text Overlapping
The Label's text are overlapping because you are adding two Label widgets on-top each other in a Screen Layout.
Add a BoxLayout as parent of the two Label widgets to prevent text overlapping.
Text Wrapping
Wraps the text at a certain width, provide the width. For example, a Label to be created in a box with width=200 and unlimited height.
Label(text='Very big big line', text_size=(200, None))
Snippet
<Help>:
BoxLayout:
orientation: 'vertical'
Label:
text_size: dp(230), None
height: self.texture_size[1]
text: "[size=30][b]How to Operate[/b][/size]Some text here"
markup: True
valign: "top"
halign: 'center'
color: 0,0,0,1
Label:
text_size: dp(150), None
text: "[size=30][b]Some title[/b][/size]Some more text"
markup: True
valign: 'top'
halign: 'center'
color: 0,0,0,1
Output
Text Alignment
Add text_size: self.size
Snippet
<Help>:
Label:
text_size: self.size
text: "[b]Help Page[/b]\n"
font_size: 30
markup: True
valign: "top"
color: 0,0,0,1
Label:
text_size: self.size
text: "[b] How To Use:[/b]\n"
font_size: 30
markup: True
valign: 'top'
color: 0,0,0,1
Text alignment and wrapping
In order for the halign and valign alignment properties to
take effect, set the text_size, which specifies the size of the
bounding box within which text is aligned.
Output

Change custom buttons attributes

I created a custom button as follows
#: import icon kivy.garden.iconfonts.icon
<custom_Button#Button>:
background_normal: 'icons/backg.png'
RelativeLayout:
size: self.parent.width, self.parent.height
top: self.parent.top
right: self.parent.right
Label:
canvas.before:
Color:
rgba: 1,1,1,1
Rectangle:
pos: self.pos
size: self.size
source: 'icons/restaurant.png'
color: 0,0,0,1
id: icon_name
markup: True
font_size: '20dp'
text: '{}'.format(icon('ion-settings', 38))
pos_hint: {'center_y': .5, 'right': .25}
size_hint: .18, .9
Label:
text:'Change Settings'
id: label
color: 0,0,0,1
text_size: self.size
halign: 'left'
valign: 'middle'
font_size: '20dp'
pos_hint: {'center_y': .5, 'right': 1}
size_hint: .7, .9
i want to be able to pass this (Custom_Button) as a child to different layouts, and change some of the attributes to what i want. Heres what i mean.
for example,
GridLayout:
custom_Button
custom_Button
custom_Button
But i would like to be able to explicitly change the label icon for the first label in the custom_Button, also the text in the second Label, so that for the three instances of the cutom_Button a different icon and text would be displayed. I really dont know how to achieve this. So please i need some help.
An example code will be very helpful. Thanks in advance...
First of all, do change the class name to something standard, like CustomButton. Then, define a new property containing the icon_source:
<CustomButton#Button>:
icon_source: 'icons/restaurant.png'
...
and refer to it later:
Rectangle:
pos: self.pos
size: self.size
source: root.icon_source
Then it's simple to change this for every instance, either in kv or in python:
GridLayout:
CustomButton:
icon_source: 'something/else.png'

How to bind using kivy only?

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.

Categories