Kivy: chow to obtain coordinates of FloatLayout center - python

I want to draw circle in center of FloatLayout. With my knowledges I obtained only default values for this. Why circle in showed code isn't red? Can You explain me process for obtaining necessary coordinates, please?
import kivy
from kivy.config import Config
kivy.config.Config.set('graphics','resizable', False)
from kivy.app import App
from kivy.graphics import Color, Ellipse
from kivy.uix.widget import Widget
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.label import Label
from kivy.uix.button import Button
class Scene(FloatLayout):
def __init__(self, **kwargs):
super(Scene, self).__init__(**kwargs)
def draw_circle(self):
with self.canvas:
Color=(1,0,0)
circ = Ellipse(pos = (self.center_x, self.center_y), size=(20,20))
def on_touch_down(self, touch):
pass
class Game(BoxLayout):
def __init__ (self,**kwargs):
super(Game, self).__init__(**kwargs)
self.orientation = 'vertical'
but1 = Button(text = 'button 1')
self.add_widget(but1)
self.scene = Scene()
self.add_widget(self.scene)
class TestApp(App):
def build(self):
game = Game()
game.scene.draw_circle()
return game
if __name__ == '__main__':
TestApp().run()

You should define the size of your float layout when you create it.
self.scene = Scene(size=(300, 300))
Then your circle should be at the center of the FloatLayout dimensions.
I also think FloatLayout is better used with size_hint and pos_hint instead of fixed coordinates.

You can call draw_circle with Clock to make sure the layout is completely initiated first.
Then make sure to create your color like this Color(1, 0, 0). Not Color = ()
from kivy.config import Config
Config.set('graphics','resizable', False)
from kivy.app import App
from kivy.graphics import Color, Ellipse
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button
from kivy.clock import Clock
class Scene(FloatLayout):
def draw_circle(self, dt):
with self.canvas:
Color(1,0,0)
circ = Ellipse(pos = (self.center_x, self.center_y), size=(20,20))
class Game(BoxLayout):
def __init__ (self,**kwargs):
super(Game, self).__init__(**kwargs)
self.orientation = 'vertical'
but1 = Button(text = 'button 1')
self.add_widget(but1)
self.scene = Scene()
self.add_widget(self.scene)
class TestApp(App):
def build(self):
game = Game()
Clock.schedule_once(game.scene.draw_circle) # call draw_circle on next frame
return game
if __name__ == '__main__':
TestApp().run()

Related

How to position a rectangle based on size of a window?

I'm trying to draw a rectangle and place it on the screen depending
on the size of the window / screen.
I've got this but it doesn't work:
with self.canvas:
Color: xyz
Rectangle(pos=(Window.size[0]-50,Window.size[1]-50),size=(50,50))
This didn't have any effect either:
with self.canvas:
Color: xyz
Rectangle(pos=(Window.height-50,Window.width-50),size=(50,50))
Runnable example:
from kivy.core.window import Window
from kivy.uix.widget import Widget
from kivy.app import App
from kivy.graphics import *
Window.size = (375, 812)
class Temporary(Widget):
def __init__(self, **kwargs):
super(Temporary, self).__init__(**kwargs)
with self.canvas:
Color(255/255.0, 99/255.0, 71/255.0)
Rectangle(pos=(0,0),size=(50,50))
class MainApp(App):
def build(self):
return Temporary()
if __name__ == '__main__':
MainApp().run()
I've managed to make it work as I intended:
class Temporary(Widget):
def __init__(self, **kwargs):
super(Temporary, self).__init__(**kwargs)
with self.canvas:
Color(255/255.0, 99/255.0, 71/255.0)
Rectangle(pos=(Window.size[0] / 2,Window.size[1] / 2),size=(50,50))
Nothing else worked. The above will do the trick.

How do I dynamically add items to scrollview in kivy

Hello I'm relatively new to kivy. So far doing basic stuff has been relatively straightforward but this has stumped me. I'm making an app that needs to dynamically add rectangular canvas items to a grid in a scrollview. Since I'm doing this I need to create the scrollview in python and not in the .kv file. How can I do this so that the size of the rectangles will be the same as the window size upon resizing the windows?
.py file:
from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from kivy.uix.relativelayout import RelativeLayout
from kivy.graphics import Line,Rectangle
from kivy.uix.carousel import Carousel
from kivy.uix.scrollview import ScrollView
from kivy.core.window import Window
class Scroll(ScrollView):
def __init__(self, **kwargs):
super(Scroll, self).__init__(**kwargs)
layout = GridLayout(cols=1, spacing=10, size_hint_y=None)
layout.bind(minimum_height=layout.setter('height'))
# Make sure the height is such that there is something to scroll.
for i in range(100):
SkillStat = RelativeLayout(pos=(0,0), height=100, size_hint_y=None, size_hint_x=self.width)
with SkillStat.canvas:
Rectangle(pos=self.pos,size=(self.width, 90))
layout.add_widget(SkillStat)
self.add_widget(layout)
pass
pass
class Sheet(Carousel):
pass
class SheetApp(App):
def build(self):
return Sheet()
if __name__ == '__main__':
SheetApp().run()
.kv file:
# file name: Sheet.kv
<Sheet>:
RelativeLayout:
Scroll:
size_hint:(1,1)
The two main problem in your code are:
You are doing all your size and position setting of your SkillStat and its canvas in an __init__() method. In an __init__() method of a widget, the position of the widget is always (0,0), and the size is (100, 100). Those properties are not set to real values until the widget is actually drawn.
You are doing all this in python instead of in kv. In kv, bindings are created for many properties that you set, and get automatically updated. If you do your widget setup in python, you must provide those bindings yourself.
Here is a modified version of your Scroll class and a new MyRelativeLayout class that handle those bindings:
class MyRelativeLayout(RelativeLayout):
def adjust_size(self, *args):
self.rect.size = self.size # set the size of the Rectangle
class Scroll(ScrollView):
def __init__(self, **kwargs):
super(Scroll, self).__init__(**kwargs)
layout = GridLayout(cols=1, spacing=10, size_hint_y=None)
layout.bind(minimum_height=layout.setter('height'))
# Make sure the height is such that there is something to scroll.
for i in range(100):
SkillStat = MyRelativeLayout(pos=(0,0), height=100, size_hint=(1.0, None))
with SkillStat.canvas.before:
SkillStat.rect = Rectangle()
SkillStat.bind(size=SkillStat.adjust_size)
layout.add_widget(SkillStat)
self.add_widget(layout)
Note the SkillStat.bind() call to create the needed bindings, and the Rectangle is saved as SkillStat.rect in each MyRelativeLayout instance. Those bindings will get triggered as soon as the SkillStat gets displayed, so the initial pos and size of the Rectangle are not needed.
EDIT: Setting the pos of the Rectangle in a binding was probably causing problems. The default pos of the Rectangle is (0,0), which is what it should always be. So, we only need to adjust the size of the Rectangle. I have removed the binding for pos.
Solution
Create a class with inheritance from RelativeLayout.
Update or remove the instructions you have added to a canvas by using bind function.
Snippets
class CustomLayout(RelativeLayout):
def __init__(self, **kwargs):
super(CustomLayout, self).__init__(**kwargs)
with self.canvas:
self.rect = Rectangle(pos=self.pos, size=(self.width, 90))
self.bind(pos=self.update_rect, size=self.update_rect)
def update_rect(self, *args):
self.rect.pos = self.pos
self.rect.size = self.size
Example
main.py
from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from kivy.uix.relativelayout import RelativeLayout
from kivy.graphics import Line, Rectangle
from kivy.uix.carousel import Carousel
from kivy.uix.scrollview import ScrollView
from kivy.core.window import Window
from kivy.lang import Builder
class CustomLayout(RelativeLayout):
def __init__(self, **kwargs):
super(CustomLayout, self).__init__(**kwargs)
with self.canvas:
self.rect = Rectangle(pos=self.pos, size=(self.width, 90))
self.bind(pos=self.update_rect, size=self.update_rect)
def update_rect(self, *args):
self.rect.pos = self.pos
self.rect.size = self.size
class Scroll(ScrollView):
def __init__(self, **kwargs):
super(Scroll, self).__init__(**kwargs)
layout = GridLayout(cols=1, spacing=10, size_hint_y=None)
layout.bind(minimum_height=layout.setter('height'))
# Make sure the height is such that there is something to scroll.
for i in range(100):
SkillStat = CustomLayout(pos=(0, 0), height=100, size_hint_y=None, size_hint_x=self.width)
layout.add_widget(SkillStat)
self.add_widget(layout)
class Sheet(Carousel):
pass
Builder.load_file('main.kv')
class SheetApp(App):
def build(self):
return Sheet()
if __name__ == '__main__':
SheetApp().run()
main.kv
#:kivy 1.11.0
<Sheet>:
RelativeLayout:
Scroll:
size_hint:(1,1)
bar_width: 10
effect_cls: "ScrollEffect"
scroll_type: ['bars']
bar_color: [1, 0, 0, 1] # red color
bar_inactive_color: [0, 0, 1, 1] # blue color
Output

Kivy TreeView with checkbox and editable text

How to add to Kivy TreeView a checkbox and editable text to each child.
The documentation for the TreeView touches on how to do that, but doesn't provide much detail. Here is a way to do that:
from kivy.app import App
from kivy.metrics import dp
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.checkbox import CheckBox
from kivy.uix.label import Label
from kivy.uix.textinput import TextInput
from kivy.uix.treeview import TreeView, TreeViewNode
class MyNode(BoxLayout):
def __init__(self, **kwargs):
text = kwargs.pop('text', 'None')
super(MyNode, self).__init__(**kwargs)
self.orientation = 'horizontal'
# make height reasonable
self.size_hint_y = None
self.height = dp(25)
# make the parts of the node
self.lbl = Label(text=text, size_hint_x=0.2)
self.chkbx = CheckBox(size_hint_x=0.1, color=(1, 1, 1, 3.5)) # alpha=3.5 to make it more visible
self.txtinpt = TextInput(multiline=False, font_size=15, padding=[6, 3, 6, 0])
# add the parts to the BoxLayout
self.add_widget(self.lbl)
self.add_widget(self.chkbx)
self.add_widget(self.txtinpt)
class MyTreeNode(MyNode, TreeViewNode):
pass
class MyTreeView(TreeView):
def __init__(self):
super(MyTreeView, self).__init__()
self.add_node(MyTreeNode(text='node 1'))
node2 = self.add_node(MyTreeNode(text='node 2'))
self.add_node(MyTreeNode(text='node 3'), node2)
self.add_node(MyTreeNode(text='node 4'), node2)
class TreeViewApp(App):
def build(self):
return MyTreeView()
if __name__ == '__main__':
TreeViewApp().run()

Why does the rotated button widget's position doesn't rotate?

I have two button widgets. The Button1 was rotated and the Button2 wasn't. I'm trying to test if the two button widgets will collide.
Here is my code:
from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.widget import Widget
from kivy.core.window import Window
from kivy.graphics import *
from kivy.logger import Logger
class RotateMe(Button):
def __init__(self, **kwargs):
Button.__init__(self, **kwargs)
with self.canvas.before:
PushMatrix()
self.rot = Rotate(angle= 45, origin= self.center)
with self.canvas.after:
PopMatrix()
class Main(Widget):
def __init__(self):
super(Main, self).__init__()
self.size = Window.size
self.rotatethis = RotateMe(text= "Button1", center= self.center)
self.add_widget(self.rotatethis)
self.somebutton = Button()
self.somebutton.text = "Button2"
self.somebutton.right = self.center_x - 60
self.somebutton.y = self.center_y
self.add_widget(self.somebutton)
if self.somebutton.collide_widget(self.rotatethis):
Logger.info("The buttons collided! Much happiness")
else:
Logger.info("The buttons didn't collide. Such sadness.")
class TestApp(App):
def build(self):
return Main()
TestApp().run()
This is how it looked when I ran my code.
I can clearly see from the output (the image) that the two buttons collided but when I checked the log , it says that the Button Widgets didn't collide. It seems that the widget position of Button1 didn't change/rotate.
I tried to change the position of the Button2 to see at which point it collides with Button1. And I found out that the Widget position of Button1 didn't change.
Like this:
The white square at the back of Button1 is the actual position of the Button1 widget.
Is there a way to rotate the position of Button1 widget?
UPDATE: I tried to use the ScatterLayout as suggested in here.
Here is my updated code:
from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.widget import Widget
from kivy.core.window import Window
from kivy.graphics import *
from kivy.logger import Logger
from kivy.uix.scatterlayout import ScatterLayout
from kivy.uix.floatlayout import FloatLayout
class RotateMe(ScatterLayout):
def __init__(self):
ScatterLayout.__init__(self)
self.size_hint = (None, None)
self.size = (100, 100)
self.rotation = 45
self.do_rotation = False
self.add_widget(Button(text= "Button1"))
class Main(FloatLayout):
def __init__(self):
super(Main, self).__init__()
self.size = Window.size
self.rotatethis = RotateMe()
self.rotatethis.center = self.center
self.add_widget(self.rotatethis)
self.button2 = Button(text= "Button2")
self.button2.size_hint = (None, None)
self.button2.size = (100, 100)
self.button2.right = self.center_x - 60
self.button2.y = self.center_y
self.add_widget(self.button2)
if self.button2.collide_widget(self.rotatethis):
Logger.info("The buttons collided! Much happiness")
else:
Logger.info("The buttons didn't collide. Such sadness.")
class TestApp(App):
def build(self):
return Main()
TestApp().run()
Now the buttons were collided but when I try to change the position of the Button2, like this:
self.button2.y = self.center_y + 45
The output is like this:
Looking at the output (image), the two buttons' widgets doesn't seem to collide with each other but when I look at the log, it says that they collided with each other.
It turns out that the widget size of Button1 is this (the colored teal background):

How to display slider value as it changes in python kivy

how do i change the text of a label to the value of the slider immediately.
this is my current code
import kivy
kivy.require('1.10.0')
from kivy.app import App
from kivy.uix.slider import Slider
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.label import Label``
class app(App):
def build(self):
layout = BoxLayout(orientation='vertical')
slide = Slider(min=-100, max=100,value=0)
label = Label(text=str(slide.value))
layout.add_widget(slide)
layout.add_widget(label)
return layout
app().run()
i want the answer in python
You need to create a Kivy Property and bind the slider value to an on_ event where you can then update the label's text. Here's one way to do that:
from kivy.app import App
from kivy.uix.slider import Slider
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.label import Label
from kivy.properties import NumericProperty
import kivy
kivy.require('1.10.0')
class Container(BoxLayout):
slider_val = NumericProperty(0)
def __init__(self, *args, **kwargs):
super(Container, self).__init__(*args, **kwargs)
self.orientation = 'vertical'
slide = Slider(min=-100, max=100, value=0)
slide.fbind('value', self.on_slider_val)
self.label = Label(text=str(self.slider_val))
self.add_widget(slide)
self.add_widget(self.label)
def on_slider_val(self, instance, val):
self.label.text = str(val)
class app(App):
def build(self):
return Container()
app().run()

Categories

Resources