how to center canvas? kivy - python

How to place the white square to the center? I tried a lot of variants, but nothing worked. It work for Label and Buttons, but not for canvas. Or maybe I'm doing everything in wrong way. maybe you suggest the best solution for this task. I need window with background, label in left corner, label in right corner and a square in center
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.floatlayout import FloatLayout
from kivy.config import Config
from kivy.animation import Animation
from kivy.vector import Vector
from kivy.clock import Clock
from kivy.properties import NumericProperty, ReferenceListProperty,\
ObjectProperty
Config.set('graphics', 'resizable', 'true')
Config.set('graphics', 'width', '900')
Config.set('graphics', 'height', '450')
Config.write()
class Helicopter(Widget):
pass
class Background(Widget):
pass
class Root(FloatLayout):
#def on_touch_down(self, touch):
# Animation(center=touch.pos).start(self)
pass
class FriendsApp(App):
def build(self):
return Root()
if __name__ == '__main__':
FriendsApp().run()
.kv file
#: kivy 1.10.0
<Root>
AnchorLayout:
canvas.before:
Color:
rgba: 1, 1, 1, 1 # white
Rectangle:
source: 'background.jpg'
pos: self.pos
size: self.size
size: self.parent.size
anchor_x: 'center'
anchor_y: 'center'
AnchorLayout:
anchor_y:'top'
anchor_x:'left'
padding: 20
Label:
text: 'Lives: x2'
size: self.texture_size
size_hint: None, None
AnchorLayout:
anchor_x: 'right'
anchor_y: 'top'
padding: 20
Label:
text: 'Score: 0000000'
size: self.texture_size
size_hint: None,None
AnchorLayout:
anchor_x: 'center'
anchor_y: 'center'
canvas:
Rectangle:
size: 100, 100
pos: self.pos

The AnchorLayout has its own canvas and you cannot aligns itself. There are two solutions to this problem. In the example, colors were added for visualization.
The AnchorLayout aligns its children to a border (top, bottom,
left, right) or center.
Solution 1
Add a Widget as a children.
AnchorLayout:
anchor_x: 'center'
anchor_y: 'center'
Widget:
canvas.before:
Color:
rgba: 1, 1, 1, 1 # white
Rectangle:
size: 100, 100
pos: self.pos
size_hint: None,None
Solution 2
Replace the last AnchorLaoyout with Widget.
Widget:
canvas:
Rectangle:
pos: self.center_x - 50, self.center_y - 50
size: 100, 100
Example - Solution 1
kv file
#: kivy 1.10.0
<Root>
AnchorLayout:
anchor_y:'top'
anchor_x:'left'
padding: 20
Label:
canvas.before:
Color:
rgba: 1, 0, 0, 1 # red
Rectangle:
pos: self.pos
size: self.size
text: 'Lives: x2'
size: self.texture_size
size_hint: None, None
AnchorLayout:
anchor_x: 'right'
anchor_y: 'top'
padding: 20
Label:
canvas.before:
Color:
rgba: 0, 0, 1, 1 # blue
Rectangle:
pos: self.pos
size: self.size
text: 'Score: 0000000'
size: self.texture_size
size_hint: None,None
AnchorLayout:
anchor_x: 'center'
anchor_y: 'center'
Widget:
canvas.before:
Color:
rgba: 1, 1, 1, 1 # white
Rectangle:
size: 100, 100
pos: self.pos
size_hint: None,None
Output

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

Scale with Kivy ScatterLayout Doesn't Behave as Expected

I would like to zoom in and zoom out of a collection of widgets. I would also like to scroll. I tried to accomplish this with a ScrollView as the root widget and a ScatterLayout as the child.The widgets I'd like to zoom in and out of are children to the ScatterLayout. This isn't behaving as expected. Here's a minimal version.
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.scatter import Scatter
from kivy.uix.scatterlayout import ScatterLayout
from kivy.uix.scrollview import ScrollView
kv = '''
#:kivy 1.11.1
<MyScatter>:
do_translation_y: False
do_rotation: False
do_scale: False
canvas:
Color:
hsv: .1, 1, .5
Rectangle:
size: 100, 100
<ScrollView>:
size_hint: None, None
size: 640, 480
pos_hint: {'center_x': .5, 'center_y': .5}
scroll_type: ['bars']
bar_width: 10
bar_inactive_color: self.bar_color
canvas:
Color:
rgb: 1, 0, 0
Rectangle:
pos: self.pos
size: self.size
<MyScatterLayout>:
size_hint: None, None
size: 1280, 720
do_translation: False
do_rotation: False
pos_hint: {'center_x': 0.5, 'center_y': 0.5}
canvas:
Color:
rgb: 0, 0, 1
Rectangle:
pos: self.pos
size: self.size
'''
Builder.load_string(kv)
class MyScatter(Scatter):
pass
class MyScatterLayout(ScatterLayout):
pass
class MyApp(App):
def build(self):
layout = MyScatterLayout()
layout.add_widget(MyScatter())
root = ScrollView()
root.add_widget(layout)
return root
if __name__ == '__main__':
MyApp().run()
When zooming out, the child of ScatterLayout ends up outside of the layout's bounds. I would expect all the children to stay within the layout's bounds no matter what the transformation is. What am I doing wrong?
Tangential to the question: when I zoom out enough that the ScatterLayout is smaller than the ScrollView, scrolling snaps the ScatterLayout to the origin (bottom left corner). Per the ScrollView docs it looks like a ScrollView's child is expected to be larger than the ScrollView itself. I assume to prevent this from happening I need to increase the size of the ScatterLayout as I scroll.
Not sure this is related to the issue, but ScatterLayout is a subclass of Scatter so its canvas instructions must be in local coordinates.
<MyScatterLayout>:
...
canvas:
Color:
rgb: 0, 0, 1
Rectangle:
pos: 0, 0 # <- shold be this
size: self.size
And you shouldn't write any rule for ScrollView because it affects all instances that might exist outside of your code. So instead, define a subclass and write a rule for it.
class MyScrollView(ScrollView):
pass
<MyScrollView>:
...
You have to scale the size of the ScatterLayout for the children's position to be consistent. I've also incorporated Nattosai Mito's answer.
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.scatter import Scatter
from kivy.uix.scatterlayout import ScatterLayout
from kivy.uix.scrollview import ScrollView
kv = '''
#:kivy 1.11.1
<MyScatter>:
do_translation_y: False
do_rotation: False
do_scale: False
canvas:
Color:
hsv: .1, 1, .5
Rectangle:
size: 100, 100
<MyScrollView>:
size_hint: None, None
size: 640, 480
pos_hint: {'center_x': .5, 'center_y': .5}
scroll_type: ['bars']
bar_width: 10
bar_inactive_color: self.bar_color
canvas:
Color:
rgb: 1, 0, 0
Rectangle:
pos: self.pos
size: self.size
<MyScatterLayout>:
size_hint: None, None
size: 1280 * self.scale, 720 * self.scale # this is the correction
do_translation: False
do_rotation: False
pos_hint: {'center_x': 0.5, 'center_y': 0.5}
canvas:
Color:
rgb: 0, 0, 1
Rectangle:
pos: 0, 0
size: self.size
'''
Builder.load_string(kv)
class MyScatter(Scatter):
pass
class MyScatterLayout(ScatterLayout):
pass
class MyScrollView(ScrollView):
pass
class MyApp(App):
def build(self):
layout = MyScatterLayout()
layout.add_widget(MyScatter())
root = MyScrollView()
root.add_widget(layout)
return root
if __name__ == '__main__':
MyApp().run()

Python Kivy RecycleView. How to change the background color of the Recycleview table based on the data value of the cells

I'm trying to change the background color of the Recycleview table based on the data value of the cells. So, I'would like to change the color only the in the cells containing a specific string of text.
The Goal is to change the color when text is = '1'
Somebody could help?
Here is my code, a simple working app.
.py file:
from kivy.core.window import Window
from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.recycleview.views import RecycleDataViewBehavior
from kivy.uix.label import Label
from kivy.properties import BooleanProperty
from kivy.uix.recyclegridlayout import RecycleGridLayout
from kivy.uix.behaviors import FocusBehavior
from kivy.uix.recycleview.layout import LayoutSelectionBehavior
class ScreenManagement(ScreenManager):
pass
class Sfondo_tabella(RecycleDataViewBehavior, Label):
index = None
selected = BooleanProperty(False)
selectable = BooleanProperty(False)
class RecycleGridLayout(FocusBehavior, LayoutSelectionBehavior, RecycleGridLayout):
pass
class Schermo_1(Screen):
data_list = ['1', '2', '3', '2', '1', '3', '3', '2', '1']
class Temp_kvApp(App):
Window.size = (1182, 739)
if __name__ == "__main__":
Temp_kvApp().run()
.kv file:
ScreenManager:
id: screen_manager
name: "screen_manager"
Schermo_1:
id: schermo_1
name: "Schermo_1"
manager: screen_manager
<Sfondo_tabella>:
color: 0,0,0,1
font_size: self.height * 0.5
text_size: self.width, None
valign: 'top'
halign: 'center'
canvas.before:
Color:
rgba: (1, 1, 1, 1)
Rectangle:
pos: self.pos
size: self.size
canvas:
Color:
rgba:0,0,0,1
Line:
width:0.5
rectangle:(self.x,self.y,self.width,self.height)
<Schermo_1>
BoxLayout:
orientation: "vertical"
GridLayout:
size_hint: 1, 0.1
height: 50
cols: 1
Label:
font_size: self.height / 1.75
text_size: self.width, None
valign: 'top'
halign: 'left'
color: 1, 1, 1 ,1
text: ""
canvas.before:
Color:
rgb: 0.803, 0.486, 0.176
Rectangle:
pos: self.pos
size: self.size
GridLayout:
id: tasti
size_hint: 1, 0.075
cols: 3
#COL_1
Button:
id: col_1
text: "COL_1"
size_hint_x: 0.33
font_size: self.height / 2.5
text_size: self.width, None
valign: 'top'
halign: 'center'
background_color: 1.22, 1.22, 1.22, 1
#COL_2
Button:
id: col_2
text: "COL_2"
size_hint_x: 0.33
font_size: self.height / 2.5
text_size: self.width, None
valign: 'top'
halign: 'center'
background_color: 1.22, 1.22, 1.22, 1
#COL_3
Button:
id: col_3
text: "COL_3"
size_hint_x: 0.33
font_size: self.height / 2.5
text_size: self.width, None
valign: 'top'
halign: 'center'
background_color: 1.22, 1.22, 1.22, 1
BoxLayout:
RecycleView:
id: tabella_lista_costi_aggiuntivi
viewclass: 'Sfondo_tabella'
data: [{'text': str(x)} for x in root.data_list]
scroll_y: 1
effect_cls: "ScrollEffect" # prevents overscrolling
RecycleGridLayout:
cols: 3
cols_minimum: {0: col_1.width, 1: col_2.width, 2: col_3.width}
size_hint: 1, None
default_size: None, dp(col_1.height/1.75)
default_size_hint: 1, None
height: self.minimum_height
width: self.minimum_width
This can be done in the canvas.before instruction under <Sfondo_tabella> section like below:
<Sfondo_tabella>:
color: 0,0,0,1
font_size: self.height * 0.5
text_size: self.width, None
valign: 'top'
halign: 'center'
canvas.before:
Color:
rgba: (0, 1, 0, 1) if root.text == '1' else (1, 1, 1, 1)
Rectangle:
pos: self.pos
size: self.size
canvas:
Color:
rgba:0,0,0,1
Line:
width:0.5
rectangle:(self.x,self.y,self.width,self.height)
Here the background of the cell would be green if the cell text is '1' otherwise it would be white.

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