Kivy ScrollView breaking layout of screen - python

So i'm making a program that will have a bunch of labels connected to one gridlayout. I want a few of these labels to be "under" the screen so that you can scroll down to it. However, I am having trouble with keeping the formatting of what I have currently and scrolling at the same time.
Below is what I want, with the "stuff7" label being under the screen. However I am unable to scroll.Image of non-scrollable screen
However, I noticed when I put size_hint_y: None I am able to scroll but it messes up my formatting completely.
Messed up format but able to scroll
Below is my MRE
KV code
#:import utils kivy.utils
<HomeScreen>:
FloatLayout:
canvas:
Color:
rgb: utils.get_color_from_hex("#FFFFFF")
Rectangle:
size: self.size
pos: self.pos
ScrollView:
size: self.size
GridLayout:
rows: 6
cols: 1
spacing: 10
size_hint_y: None
height: self.minimum_height
width: self.minimum_width
Label:
text:"stuff1"
color: "black"
size_hint: 1,.18
Label:
text:"stuff2"
color: "black"
size_hint: 1,.18
Label:
text:"stuff3"
color: "black"
size_hint: 1,.18
Label:
text:"stuff4"
color: "black"
size_hint: 1,.18
Label:
text:"stuff5"
color: "black"
size_hint: 1,.18
Label:
text:"stuff6"
color: "black"
size_hint: 1,.18
Label:
text:"stuff7"
color: "black"
size_hint: 1,.18

If you are using height: self.minimum_height for the GridLayout, then you cannot use size_hint: 1,.18 for the Labels. The GridLayout is trying to change its height based on the height of its children (the Labels). But the Labels are trying to set their height based on the height of the GridLaout. Try modifying the Labels as:
Label:
text:"stuff2"
color: "black"
size_hint: 1, None
height: self.texture_size[1]

Related

Is it possible to add padding and margin to each widgets in kivy?

I want to apply margin and padding to each widgets is that possible in kivy?
Here is the exact image I need; I want to apply padding and margin to each button:
![1][1]
I applied one method in kivy, put the widget in 2 layouts but the problem is without adding margin, padding there is space between the widgets. How can we set the 2 layout size according to widget size? Here is my code:
kv file
<Demoproject>:
Screen:
name:"screen_2917"
canvas.before:
Color:
rgba:(1.0,1.0,1.0,1.0)
Rectangle:
pos:self.pos
size:self.size
#source:""
BoxLayout:
orientation:"vertical"
BoxLayout:
orientation:"vertical"
padding:dp(0),dp(0),dp(0),dp(0)
color:(1,0,0,1)
canvas:
Color:
rgb: [.10, .10, .10]
Rectangle:
pos: self.pos
size: self.size
GridLayout:
cols:1
padding:dp(0),dp(0),dp(0),dp(0)
canvas:
Color:
rgb: [.6, .6, .6]
Rectangle:
pos: self.pos
size: self.size
Button:
text:"close"
size:(200,100)
size_hint:(None,None)
BoxLayout:
orientation:"vertical"
padding:dp(0),dp(0),dp(0),dp(0)
color:(1,0,0,1)
canvas:
Color:
rgb: [.10, .10, .10]
Rectangle:
pos: self.pos
size: self.size
GridLayout:
cols:1
padding:dp(0),dp(0),dp(0),dp(0)
canvas:
Color:
rgb: [.6, .6, .6]
Rectangle:
pos:self.pos
size:self.size
Button:
text:"close"
size:(200,100)
size_hint:(None,None)
I think you can simplify your kv file and just use padding and spacing. Like this:
<Demoproject>:
Screen:
name:"screen_2917"
canvas.before:
Color:
rgba:(1.0,1.0,1.0,1.0)
Rectangle:
pos:self.pos
size:self.size
#source:""
BoxLayout:
orientation:"vertical"
size_hint: None, None
size: self.minimum_size
pos_hint: {'top': 1}
padding: 5 # between Boxlayout edges and Buttons
spacing: 5 # between Buttons
Button:
text:"close"
size:(200,100)
size_hint:(None,None)
Button:
text:"close"
size:(200,100)
size_hint:(None,None)
Padding can only be applied by a few of the Layout classes. So if you want different padding for each Button, you must use separate Layouts. Here is another version of your kv that uses AnchorLayout to apply different padding for each Button:
<Demoproject>:
Screen:
name:"screen_2917"
canvas.before:
Color:
rgba:(1.0,1.0,1.0,1.0)
Rectangle:
pos:self.pos
size:self.size
#source:""
BoxLayout:
orientation:"vertical"
size_hint: None, None
size: self.minimum_size
pos_hint: {'top': 1}
canvas.before:
Color:
rgba:(0,1,0,1)
Rectangle:
pos:self.pos
size:self.size
AnchorLayout:
size_hint: None, None
size: butt1.width + self.padding[0] + self.padding[2], butt1.height + self.padding[1] + self.padding[3]
padding: 20
canvas.before:
Color:
rgba: 1,0,0,1
Rectangle:
pos: self.pos
size: self.size
Button:
id: butt1
text:"close"
size:(200,100)
size_hint:(None,None)
AnchorLayout:
size_hint: None, None
size: butt2.width + self.padding[0] + self.padding[2], butt2.height + self.padding[1] + self.padding[3]
padding: 5, 10, 15, 20
canvas.before:
Color:
rgba: 0,0,1,1
Rectangle:
pos: self.pos
size: self.size
Button:
id: butt2
text:"close"
size:(200,100)
size_hint:(None,None)
The canvas instructions are just to more easily visualize what is happening. The AnchorLayout sizes are calculated to just fit the Button with the specified padding.

Adaptive_width property of MDLabel is not working correctly

I am making an app using kivy & kivymd and in one part of it, I would like the labels to take as much space as the actual text.
This seems pretty straightforward with kivy itself but for some reason, nothing works with the MDLabel class. I tried setting the adaptive_width property to True and I also tried to directly set the width to the texture_size[0] property but none of them worked (and yes I installed kivymd directly from github).
Here is my code:
from kivy.lang import Builder
from kivymd.app import MDApp
class MainApp(MDApp):
def __init__(self, **kwargs):
super(MainApp, self).__init__(**kwargs)
self.kv = Builder.load_string('''
#:kivy 2.0.0
BoxLayout:
MDLabel:
text: "Supposedly adaptive width (KivyMD)"
font_size: "21sp"
halign: "center"
adaptive_width: True
# I also tried directly setting the width to the texture_size but the results were worse
# size_hint_x: None
# width: self.texture_size[0]
canvas.before:
Color:
rgba: .8, .1, .2, .5
Rectangle:
pos: self.pos
size: self.size
Widget:
MDSeparator:
orientation: "vertical"
Widget:
Label:
text: "Actual adaptive width (Standard Kivy)"
font_size: "21sp"
color: 0, 0, 0, 1
size_hint_x: None
width: self.texture_size[0]
canvas.before:
Color:
rgba: 0, .6, .2, .5
Rectangle:
pos: self.pos
size: self.size
''')
def build(self):
return self.kv
if __name__ == '__main__':
MainApp().run()
Here is my results:
I don't believe that MDLabel supports the adaptive_width property. In using the width: self.texture_size[0], it seems that you must also add the text_size: None, None to the MDLabel, and it seems that its location in the kv is important. Here is a version of part of your kv that seems to work:
BoxLayout:
MDLabel:
text: "Supposedly adaptive width (KivyMD)"
font_size: "21sp"
halign: "center"
# adaptive_width: True
# I also tried directly setting the width to the texture_size but the results were worse
size_hint_x: None
width: self.texture_size[0]
text_size: None, None # added, and must be in this location
canvas.before:
Color:
rgba: .8, .1, .2, .5
Rectangle:
pos: self.pos
size: self.size

Border with Kivy/KivyMD

I am looking to add a border to the main screen of my application but I'm not sure how.
I tried to take some tips from this question:
Kivy-how can i make my canvas height smaller than the parent height
But I can't seem to figure it out.
The issue is that I am also using a KivyMD's Navigation Drawer, I would like the border be separate from the top bar, enclosing everything below the bar. Please let me know if I'm not being clear.
Here is some sample code that replicates my setup.
Perhaps I could add some random rectangles to act as a border?
EDIT:
Okay almost there, I got the 'border' but I now need the size_hint added in the AnchorLayout to ignore the top portion of the screen where the menu bar is. Here is the updated code.
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
from kivymd.app import MDApp
kv = '''
#:import hex kivy.utils.get_color_from_hex
NavigationLayout:
canvas.before:
Color:
rgb: hex('#C0C0C0')
Rectangle:
size: self.size
pos: self.pos
ScreenManager:
id: screen_manager
Screen:
name: "home_screen"
BoxLayout:
orientation: 'vertical'
MDToolbar:
title: 'Name of the App!'
elevation: 10
Widget:
FloatLayout:
orientation: 'vertical'
AnchorLayout:
anchor_x: 'center'
anchor_y: 'center'
Widget:
canvas.before:
Color:
rgb: hex('#F5F5F5')
Rectangle:
size: self.size
pos: self.pos
size_hint: .95, .95
MDLabel:
text: "Some More Text"
halign: "center"
color: 0,0,0,1
pos_hint: {"center_x": .5, "center_y": .75}
size_hint: .7, .1
MDNavigationDrawer:
id: nav_drawer
ContentNavigationDrawer:
orientation: "vertical"
padding: "8dp"
spacing: "8dp"
AnchorLayout:
anchor_x: "left"
size_hint_y: None
height: avatar.height
Image:
id: avatar
source: "image.jpg"
MDLabel:
text: "Text here"
font_style: "Button"
size_hint_y: None
height: self.texture_size[1]
'''
class ContentNavigationDrawer(BoxLayout):
pass
class MyApp(MDApp):
def build(self):
return Builder.load_string(kv)
MyApp().run()
I think you will get what you want if you indent the FloatLayout so that it is in the BoxLayout. Like this:
#:import hex kivy.utils.get_color_from_hex
NavigationLayout:
canvas.before:
Color:
rgb: hex('#C0C0C0')
Rectangle:
size: self.size
pos: self.pos
ScreenManager:
id: screen_manager
Screen:
name: "home_screen"
BoxLayout:
orientation: 'vertical'
MDToolbar:
title: 'Name of the App!'
elevation: 10
# Widget: # not needed
FloatLayout:
orientation: 'vertical'
AnchorLayout:
anchor_x: 'center'
anchor_y: 'center'
Widget:
canvas.before:
Color:
rgb: hex('#F5F5F5')
Rectangle:
size: self.size
pos: self.pos
size_hint: .95, .95
MDLabel:
text: "Some More Text"
halign: "center"
color: 0,0,0,1
pos_hint: {"center_x": .5, "center_y": .75}
size_hint: .7, .1
MDNavigationDrawer:
id: nav_drawer
ContentNavigationDrawer:
orientation: "vertical"
padding: "8dp"
spacing: "8dp"
AnchorLayout:
anchor_x: "left"
size_hint_y: None
height: avatar.height
Image:
id: avatar
# source: "image.jpg"
source: 'tester.png'
MDLabel:
text: "Text here"
font_style: "Button"
size_hint_y: None
height: self.texture_size[1]

How to change labels and buttons style for all file but one label?

I am working with a FileChooser module in Kivy which is black by default.
But for the rest of my app I used this to define Labels and Buttons style :
<Label>
canvas.before:
Color:
rgba: 1, 1, 1, 1
Rectangle:
pos: self.pos
size: self.size
and
<Button>
font_size:20
color: 1,1,1,1
background_color: (0.55,0.55,0.47,1.0)
size_hint:0.9,0.2
This is efficient and time saver BUT it breaks the FileChooserIconView I use :
The filechooser contains Labels and buttons. They are all in the same class, so do you know how to NOT affect this button and label stuyle to one class ?
I already tried to change the filechooser style instead but it's not working
The filechooser class
<LoadDialog>:
BoxLayout:
size: root.size
pos: root.pos
orientation: "vertical"
FileChooserIconView:
id: filechooser
BoxLayout:
size_hint_y: None
height: 30
Button:
text: "Cancel"
on_release: root.cancel()
Button:
text: "Load"
on_release: root.load(filechooser.path, filechooser.selection)

How to center buttons in Kivy?

I am new to Python UI programming, and I am trying out Kivy. I want to center some buttons on my screen, but the buttons do not move from the bottom right of the window. I was wondering if anyone could point out what I am doing wrong or am missing?
vgx.kv:
#:kivy 1.9.1
<VgxMainScreen>:
BoxLayout:
size_hint: 0.2,0.2
size: 200, 100
orientation: 'vertical'
Button:
text: 'Game Select'
Button:
text: 'Options'
Button:
text: 'Controllers'
<VgxUI>:
AnchorLayout:
anchor_x: 'center'
VgxMainScreen:
size_hint: 0.2,0.2
<VgxApp>:
FloatLayout:
VgxUI:
center: 0.5, 0.5
VgxApp.py:
import kivy
from kivy.app import App
from kivy.uix.widget import Widget
kivy.require('1.9.1')
class VgxMainScreen(Widget):
pass
class VgxUI(Widget):
pass
class VgxApp(App):
def build(self):
return VgxUI()
if __name__ == '__main__':
VgxApp().run()
Edit: Best way to debug what's going on with you widgets is to change their background colors :).
canvas.before:
Color:
rgba: X, X, X, 1
Rectangle:
pos: self.pos
size: self.size
The problem was that your BoxLayout wasn't positioned relatively to its parent even though it was inside it.
What I did here is that I positioned the BoxLayout to its parent's size and position using:
size: self.parent.size
pos: self.parent.pos
I also moved the size property from VgxMainScreen to VgxUI because I assume this is more common use-case (you can have multiple VgxMainScreens each with different size). Full code with background colors:
#:kivy 1.9.1
<VgxMainScreen>:
size_hint: None, None
canvas.before:
Color:
rgba: 1, 0, 0, 1 # red
Rectangle:
pos: self.pos
size: self.size
BoxLayout:
canvas.before:
Color:
rgba: 0, 0, 1, 1 # blue
Rectangle:
pos: self.pos
size: self.size
size: self.parent.size # important!
pos: self.parent.pos # important!
orientation: 'vertical'
Button:
text: 'Game Select'
Button:
text: 'Options'
Button:
text: 'Controllers'
<VgxUI>:
AnchorLayout:
canvas.before:
Color:
rgba: 1, 1, 1, 1 # white
Rectangle:
pos: self.pos
size: self.size
size: self.parent.size
anchor_x: 'center'
anchor_y: 'center'
VgxMainScreen:
size: 200, 100
<VgxApp>:
FloatLayout:
VgxUI:
center: 0.5, 0.5
There's yet another solution to this.
You can use RelativeLayout and all widgets inside it will position relatively to this layout.
<VgxMainScreen>:
size_hint: None, None
RelativeLayout:
pos: self.parent.pos
size: self.parent.size
BoxLayout:
orientation: 'vertical'
Button:
text: 'Game Select'
Button:
text: 'Options'
Button:
text: 'Controllers'
I've personally scratched my head many times when using Kivy and wondered why my widgets aren't positioned as I think they should :).
VgxMainScreen is a Widget, so it doesn't apply any positioning or sizing to its children (only Layouts do that), so the BoxLayout has the default position of (0, 0) and size of (100, 100).
Make VgxMainScreen inherit from something else, like a FloatLayout.

Categories

Resources