Basic Kivy Q, Positioning Canvas Child {kivy language} - python

Good Evening All
Just wondering if someone can share the info, started playing around with kivy, all I am trying to so is have a basic canvas widget and position a rectangle on the top of the screen, using co-ord 0,0 draws it as the bottom.
it also raised the question that I can set near the top by using, say 0, 400, but how to you make it on the top all the time and resolution independent. I am trying to make a small app as part of learning it and re-enforcing what I've learnt in python so far.
Thanks for any insight
canvas:
Rectangle:
pos: self.pos
size: self.width , self.height / 10
Label:
font_size: 25
top: root.top
text:"Score"
Label:
font_size: 25
top: root.top
text:"4000 points"

In kivy canvas point (0, 0) is actually bottom left one. You can calculate top position yourself easily:
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.lang import Builder
from kivy.properties import ListProperty
kv_string = '''
<MyWidget>:
r_size: [root.size[0]/2, root.size[1]/2]
canvas:
Color:
rgb: 0.1, 0.6, 0.3
Rectangle:
size: root.r_size
pos: 0, root.size[1]-root.r_size[1]
'''
Builder.load_string(kv_string)
class MyWidget(Widget):
r_size = ListProperty([0, 0])
class TestApp(App):
def build(self):
return MyWidget()
if __name__ == '__main__':
TestApp().run()
You can also use FloatLayout, set resolution independent subwidget sizes and positions using pos_hint and size_hint attributes, then draw something within borders of each such widget:
from kivy.app import App
from kivy.uix.floatlayout import FloatLayout
from kivy.lang import Builder
kv_string = '''
<MyWidget>:
Widget:
pos_hint: {'center_y': 0.5, 'center_x': 0.5}
size_hint: 0.2, 0.2
canvas:
Color:
rgb: 0.1, 0.6, 0.3
Rectangle:
size: self.size
pos: self.pos
Widget:
pos_hint: {'center_y': 0.5, 'center_x': 0.2}
size_hint: 0.2, 0.2
canvas:
Color:
rgb: 0.1, 0.6, 0.3
Rectangle:
size: self.size
pos: self.pos
Widget:
pos_hint: {'center_y': 0.5, 'center_x': 0.8}
size_hint: 0.2, 0.2
canvas:
Color:
rgb: 0.1, 0.6, 0.3
Rectangle:
size: self.size
pos: self.pos
Widget:
pos_hint: {'center_y': 0.2, 'center_x': 0.5}
size_hint: 0.2, 0.2
canvas:
Color:
rgb: 0.1, 0.6, 0.3
Rectangle:
size: self.size
pos: self.pos
Widget:
pos_hint: {'center_y': 0.8, 'center_x': 0.5}
size_hint: 0.2, 0.2
canvas:
Color:
rgb: 0.1, 0.6, 0.3
Rectangle:
size: self.size
pos: self.pos
'''
Builder.load_string(kv_string)
class MyWidget(FloatLayout):
pass
class TestApp(App):
def build(self):
return MyWidget()
if __name__ == '__main__':
TestApp().run()

Related

Dynamically adding .kv childwidgets in python

I'm trying to add labels (in this case LightL and DarkL) dynamically within another (grid)layout widget within python.
I tried to use IDs, but I'm unsure how to implement it using add_widget.
The childlabels have a backgroundcolor (rectangle) and I would like all the newly created to be in the same format.
from kivy.lang import Builder
from kivy.properties import NumericProperty
from kivy.uix.screenmanager import Screen
from kivy.app import App
import kivy
kv = Builder.load_string("""
<BackgroundColor#Widget>
background_color: 1, 1, 1, 1
canvas.before:
Color:
rgba: root.background_color
Rectangle:
size: self.size
pos: self.pos
<LightL#Label+BackgroundColor>
background_color: 0.15, 0.15, 0.15, 1
size_hint_x: 0.0725
<DarkL#Label+BackgroundColor>
background_color: 0.1, 0.1, 0.1, 1
<IndexScreen>:
BoxLayout:
id: DynBox
GridLayout:
cols: 4
LightL:
id: LightLid
text: ""
DarkL:
id: DarkLid
text: ""
BoxLayout:
orientation: 'vertical'
Label:
text:'topright'
Label:
text:'bottomright'
""")
class IndexScreen(Screen):
pass
class MainApp(App):
xn = NumericProperty()
def build(self):
self.root = kv
self.AddLabel()
return self.root
def AddLabel(self, *arg):
for xn in range(0, 8):
App.DarkLid.add_widget(Builder.load_string('''
Label:
text:
'#D: {}'.format(self.xn)
'''))
App.LightLid.add_widget(Builder.load_string('''
Label:
text:
'#L: {}'.format(self.xn)
'''))
return
if __name__ == "__main__":
MainApp().run
I think the problem is with your kv definition of LightL and DarkL. It works if you simplify those definitions like this:
<LightL#Label>:
background_color: 0.15, 0.15, 0.15, 1
canvas.before:
Color:
rgba: root.background_color
Rectangle:
size: self.size
pos: self.pos
<DarkL#Label>:
background_color: 0.1, 0.1, 0.1, 1
canvas.before:
Color:
rgba: root.background_color
Rectangle:
size: self.size
pos: self.pos
Then, modifying your AddLabel() method:
def AddLabel(self, *arg):
for xn in range(0, 8):
self.root.ids.DynBox.add_widget(Builder.load_string('''
Label:
text:
''' + '\'{}\''.format(xn)
))
self.root.ids.DynBox.add_widget(Builder.load_string('''
Label:
text:
''' + '\'{}\''.format(xn)
))
The format(xn) cannot be inside the triple quotes, otherwise it is not executed. It appeared that you were trying to dynamically add the new Labels to the existing DarkL or LightL, but they are not widget containers, so I changed that to the BoxLayout just to demonstrate that it works.

Changing position of a Label in Kivy

i'm new in kivy programming and while it seems that there is a lot of documentation about this problem online, i don't seem to understand any of it so i hope you could help.
I have 4 Buttons and a label, by pressing the buttons, i'm hoping to move the label in that direction.
I have two variables pX and pY which are the label's position and want it to update its position each time these two are updated.
Thanks in advance.
// main.py
from kivy.app import App
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.widget import Widget
from kivy.graphics import Rectangle, Color
from kivy.core.window import Window
from kivy.config import Config
from kivy.uix.floatlayout import FloatLayout
Window.size = (900, 600)
Config.set('graphics', 'resizable', True)
class FloatLayout(FloatLayout):
pX = 0.6
pY = 0.1
class FenetreApp(App):
def build(self):
return FloatLayout()
FenetreApp().run()
//fenetre.kv
<Button>:
size_hint: 0.1, 0.1
background_color: 0.1, 0.5, 0.6, 1
<Label>:
size_hint: 0.1, 0.1
background_color: 1, 0, 0, 1
canvas.before:
Color:
rgb: 0.1, 0.6, 0
Rectangle:
pos: self.pos
size: self.size
<FloatLayout>:
Button:
text: "Up"
pos_hint: {"x":0.8, "top":1}
on_press: root.pY= root.pY +0.1
Button:
text: "Down"
pos_hint: {"x":0.8, "top":0.8}
on_press: root.pY= root.pY -0.1
Button:
text: "Left"
pos_hint: {"x":0.7, "top":0.9}
on_press: root.pX= root.pX -0.1
Button:
text: "Right"
pos_hint: {"x":0.9, "top":0.9}
on_press: root.pX= root.pX +0.1
Label:
name: "L1"
text: "I wanna move"
pos_hint: {"x":root.pY, "top":root.pY} ```
You need to use NumericProperty for numeric values.Otherwise, kivy doesn't update its own childrens positions, texts and other stuffs.But if you don't want to use'em, check this code. I hope its clean to understand how it works:
main.py:
from kivy.app import App
from kivy.core.window import Window
from kivy.lang import Builder
Window.size = (900, 600)
kv = Builder.load_string('''
FloatLayout:
pY: .5
pX: .5
Button:
size_hint:.1,.1
background_color: 0.1, 0.5, 0.6, 1
text: "Up"
pos_hint: {"x":0.8, "y":.8}
on_press: self.parent.pY+=.1
Button:
size_hint:.1,.1
background_color: 0.1, 0.5, 0.6, 1
text: "Down"
pos_hint: {"x":0.8, "top":0.8}
on_press: self.parent.pY-=.1
Button:
size_hint:.1,.1
background_color: 0.1, 0.5, 0.6, 1
text: "Left"
pos_hint: {"x":0.7, "top":0.9}
on_press: self.parent.pX-= .1
Button:
size_hint:.1,.1
background_color: 0.1, 0.5, 0.6, 1
text: "Right"
pos_hint: {"x":0.9, "top":0.9}
on_press: self.parent.pX+=.1
Label:
size_hint: .1,.1
text: "I like to moving moving"
pos_hint: {"x":self.parent.pX, "top":self.parent.pY}
''')
class sahm(App):
def build(self):
return kv
if __name__ == '__main__':
sahm().run()

Kivy Treeview Position Issues

I am trying to create a layout with 2 sections that have a label over each and a view below (TreeView on the left and a window showing details on the right, e.g. "click on this node and see details"). I've got the labels sized and positioned, but when I add the TreeView, instead of fitting under the label, it pushes both labels over, no matter the position.
Here's the current result:
My main.py file--
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.label import Label
from kivy.uix.treeview import TreeView, TreeViewLabel
class MainScreen(BoxLayout):
def __init__(self, **kwargs):
super(MainScreen, self).__init__(**kwargs)
bridge_view = TreeView(root_options=dict(text='Clients'),
hide_root=False, indent_level=4,
pos_hint={"x": 0, "y": 0},
size_hint=(0.1, 0.5))
clients = {'client1': 'Connection A',
'client2': 'Connection B'}
for client in clients.keys():
node = bridge_view.add_node(TreeViewLabel(text=client))
bridge_name = clients[client]
bridge = bridge_view.add_node(TreeViewLabel(text=bridge_name), node)
self.add_widget(bridge_view)
class ConnectionApp(App):
def build(self):
self.title = 'My Support App'
return MainScreen()
if __name__ == '__main__':
ConnectionApp().run()
This is my kv file--
<Label>:
font_size: 30
<MainScreen>:
Label:
text: "Connections"
size_hint: 0.1, 0.5
pos_hint: {"left": 0.2, "top": 1.2}
color: 1,0,1,1
outline_color: 1,0,1,1
Label:
text: "Modules"
size_hint: 0.1, 0.5
pos_hint: {"right": 0.2, "top": 1.2}
Another thing that seems strange to me was how I had to use pos_hint to get my label spacing to work. As I understand it, these values should be on a scale between 0-1. A tutorial I read indicated as much--
Pos_hint gives a hint at the position, which is measured relatively
between 0 and 1, where 1 is "completely" something and 0 is "not"
something.
Does anyone know why it took using a value greater than 1 for "top" to get these labels at the top? I'm guessing this may be a hint as to why my layout isn't showing up correctly.
TreeView under Labels
The solution is to use GridLayout as child of BoxLayout (root widget, MainScreen), Labels and TreeViews as child of GridLayout. Added an ObjectProperty, container to hook it up to the GridLayout widget (place holder for the TreeView widget) created in the kv file. Please to the example for details.
Example - TreeView under Labels
main.py
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.treeview import TreeView, TreeViewLabel
from kivy.properties import ObjectProperty
from kivy.lang import Builder
Builder.load_string('''
#:kivy 1.10.0
<Label>:
font_size: 30
<MainScreen>:
container: tree_view
orientation: 'vertical'
GridLayout:
cols: 2
size_hint: 0.5, 0.1
Label:
canvas.before:
Color:
rgba: 1, 0, 0, 1 # red
Rectangle:
size: self.size
pos: self.pos
text: "Connections"
color: 1,0,1,1
outline_color: 1,0,1,1
Label:
canvas.before:
Color:
rgba: 0, 0, 1, 1 # blue
Rectangle:
size: self.size
pos: self.pos
text: "Modules"
GridLayout:
cols: 1
id: tree_view
''')
class MainScreen(BoxLayout):
container = ObjectProperty(None)
def __init__(self, **kwargs):
super(MainScreen, self).__init__(**kwargs)
bridge_view = TreeView(root_options=dict(text='Clients'),
hide_root=False, indent_level=4,
pos_hint={"x": 0, "y": 0},
size_hint=(0.1, 0.5))
clients = {'client1': 'Connection A',
'client2': 'Connection B'}
for client in clients.keys():
node = bridge_view.add_node(TreeViewLabel(text=client))
bridge_name = clients[client]
bridge = bridge_view.add_node(TreeViewLabel(text=bridge_name), node)
self.container.add_widget(bridge_view)
class DemoApp(App):
def build(self):
return MainScreen()
if __name__ == '__main__':
DemoApp().run()
Output - TreeView under Labels
pos_hint: {'top': 1}
The reason you have to use a value greater than 1 for top because the Label widget's height is 0.5 (size_hint: 0.1, 0.5). The solution to use pos_hint: {'top': 1} is to reduce size_hint_y as shown in the snippets.
In my example, Label's canvas color were added for visualization/demonstration.
Snippets
Label:
...
size_hint: 0.1, 0.1
pos_hint: {"top": 1}
Example - pos_hint
kv file
#:kivy 1.10.0
<Label>:
font_size: 30
<MainScreen>:
Label:
canvas.before:
Color:
rgba: 1, 0, 0, 1 # red
Rectangle:
size: self.size
pos: self.pos
text: "Connections"
size_hint: 0.1, 0.1
pos_hint: {"left": 0.2, "top": 1}
color: 1,0,1,1
outline_color: 1,0,1,1
Label:
canvas.before:
Color:
rgba: 0, 0, 1, 1 # blue
Rectangle:
size: self.size
pos: self.pos
text: "Modules"
size_hint: 0.1, 0.1
pos_hint: {"right": 0.2, "top": 1}
Output - pos_hint

Insert Image in the middle of the screen Kivy Python

I'm doing a Kivy App but I have an issue. I want to add an image to the screen but I don't know how to put it in the middle of the screen. The fact is that i want the image to work like a float layout (being adaptative to the screen, automatic resizing). I thought it was the same process that is done to center a label or a button, but I've realized it isn't. I insert here the Kivy language code I've been using.
<FloatLayout>
canvas.before:
Color:
rgba: 0.5, 0.5, 0.5, 0.1
BorderImage:
# BorderImage behaves like the CSS BorderImage
border: 10, 10, 10, 10
source: '../examples/widgets/sequenced_images/data/images/button_white.png'
pos: self.pos
size: self.size
Rectangle:
source: 'etseib.png'
size: 400, 400
pos: (400,400)
If someone knows how to fix the problem it would be very helpful.
To center a widget in the middle of a screen, use the anchor layout:
Screen:
AnchorLayout:
anchor_x: 'center'
anchor_y: 'center'
Image:
source: 'logo.png'
size_hint: None, None
size: 400, 400
# size: self.texture_size[0] / 2, self.texture_size[1] / 2
# opacity: 0.1
Version without anchor layout:
Screen:
Image:
source: 'image.png'
keep_ratio: False
allow_stretch: True
opacity: 0.8
size_hint: 0.3, 0.4
pos_hint: {'center_x': 0.5, 'center_y': 0.75}
Add rows:1
<FloatLayout>
canvas.before:
Color:
rgba: 0.5, 0.5, 0.5, 0.1
BorderImage:
rows: 1
border: 10, 10, 10, 10
source: '../examples/widgets/sequenced_images/data/images/button_white.png'
pos: self.pos
size: self.size
Rectangle:
source: 'etseib.png'
size: 400, 400
pos: (400,400)

Centering an object in Kivy

I am trying to center a circle inside a layout. I'm currently doing some padding calculations, but I'm also looking for a better way. I imagine one of the predefined layouts may be a better choice. Here's what my code is producing...
For square layouts:
For wide layouts:
This is the right behavior, which is great, but is there a better way? I can imagine this getting messy with non-circle shapes, for example.
Here's my code:
#!/usr/bin/kivy
import kivy
kivy.require('1.7.2')
from random import random
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.gridlayout import GridLayout
from kivy.uix.anchorlayout import AnchorLayout
from kivy.uix.relativelayout import RelativeLayout
from kivy.graphics import Color, Ellipse, Rectangle
class MinimalApp(App):
title = 'My App'
def build(self):
root = RootLayout()
return(root)
class RootLayout(AnchorLayout):
pass
class Circley(RelativeLayout):
pass
if __name__ == '__main__':
MinimalApp().run()
And the KV:
#:kivy 1.7.2
#:import kivy kivy
<RootLayout>:
anchor_x: 'center' # I think this /is/ centered
anchor_y: 'center'
canvas.before:
Color:
rgba: 0.4, 0.4, 0.4, 1
Rectangle:
pos: self.pos
size: self.size
Circley:
anchor_x: 'center' # this is /not/ centered.
anchor_y: 'center'
canvas.before:
Color:
rgba: 0.94, 0.94, 0.94, 1
Ellipse:
size: min(self.size), min(self.size)
pos: 0.5*self.size[0] - 0.5*min(self.size), 0.5*self.size[1] - 0.5*min(self.size)
Label:
text: unicode(self.size) # this is /not/ appearing
color: 1,0,0,1
Snippet using FloatLayout, size_hint and pos_hint:
from kivy.app import App
from kivy.lang import Builder
kv = '''
FloatLayout:
Widget:
size: min(root.size), min(root.size)
size_hint: None, None
pos_hint: {'center_x': .5, 'center_y': .5}
canvas:
Color:
rgb: 1, 0, 0
Ellipse:
size: self.size
pos: self.pos
'''
Builder.load_string(kv)
class MyApp(App):
def build(self):
return Builder.load_string(kv)
MyApp().run()
Flag of Japan:
from kivy.app import App
from kivy.lang import Builder
kv = '''
FloatLayout:
canvas:
Color:
rgb: 1, 1, 1
Rectangle:
size: self.size
pos: self.pos
Widget:
size: min(root.size)/2, min(root.size)/2
size_hint: None, None
pos_hint: {'center_x': .5, 'center_y': .5}
canvas:
Color:
rgb: 1, 0, 0
Ellipse:
size: self.size
pos: self.pos
'''
Builder.load_string(kv)
class MyApp(App):
def build(self):
return Builder.load_string(kv)
MyApp().run()

Categories