I'm trying to draw a rectangle in the center of my widget:
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.graphics import Rectangle
class MyWidget(Widget):
def __init__(self):
super(MyWidget, self).__init__()
with self.canvas:
Rectangle(pos=(self.center_x, self.center_y)
class MyApp(App):
def build(self):
return MyWidget()
if __name__ == '__main__':
MyApp().run()
This is what I'm getting:
Doing the exact same thing using a .kv file works:
<MyWidget>:
canvas:
Rectangle:
pos: self.center_x, self.center_y
Please explain how to achieve what I'm trying to do, and why it does work using a .kv file, as opposed to Python code. Thank you
If you add the Widget from a kv file the the widget will be automatically be attached to the App’s root attribute and used as the base of the application widget tree. So in your situation from the kv file the size of the widget is automatically bind to the application windows size and becomes root widget. Taking that into consideration the self.center_x and self.center_y works. You can read this at https://kivy.org/docs/guide/lang.html under the line `MyApp -> my.kv.
When not using a kv file this will not happen and the default size of the widget will be (100,100). To properly place your rectangle use a layout so you can refer use the size_hint to properly place or re size any child widget. As stated in the documentation
FloatLayout honors the pos_hint and the size_hint properties of its children.
https://kivy.org/docs/api-kivy.uix.floatlayout.html#kivy.uix.floatlayout.FloatLayout
So create a Float layout in example, add a widget with pos_hint equals to center_x and center_y that will refer to the layout being a parent and then draw a rectangle to the widget.
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.floatlayout import FloatLayout
from kivy.graphics import Rectangle
from kivy.core.window import Window
class myLayout(FloatLayout):
def __init__(self):
super(myLayout, self).__init__()
self.size = Window.size
self.myWidget = Widget(size=(100,100))
self.add_widget(self.myWidget)
with self.myWidget.canvas:
Rectangle(pos=(self.center_x, self.center_y))
class MyApp(App):
def build(self):
return myLayout()
if __name__ == '__main__':
MyApp().run()
Related
im really new in Kivy and i would like to make an app where i could create a MDIconButton that is draggable, and if possible, droppable in any BoxLayout? Is that possible in KivyMD or Kivy? Also is there a Kivy function where whenever I hold down a button, it'll display some kind of small dialogue box that contains details that can be entered by the user. thanks!
Rather than use Drag-N-Drop from kivy-garden just use the DragBehavior class! It comes directly installed with Kivy and it'll save you having to install kivy-garden.
https://kivy.org/doc/stable/api-kivy.uix.behaviors.drag.html
Here is some example code of how it's used:
from kivy.uix.label import Label
from kivy.app import App
from kivy.uix.behaviors import DragBehavior
from kivy.lang import Builder
# You could also put the following in your kv file...
kv = '''
<DragLabel>:
# Define the properties for the DragLabel
drag_rectangle: self.x, self.y, self.width, self.height
drag_timeout: 10000000
drag_distance: 0
FloatLayout:
# Define the root widget
DragLabel:
size_hint: 0.25, 0.2
text: 'Drag me'
'''
class DragLabel(DragBehavior, Label):
pass
class TestApp(App):
def build(self):
return Builder.load_string(kv)
TestApp().run()
I was just learning Kivy from Youtube, and The size_hint attribute in all layouts, buttons, widgets is not working. How do I fix this issue?
from kivy.uix.widget import Widget
from kivy.uix.button import Button
from kivy.core.window import Window
from kivy.graphics import Ellipse,Color,Line
from random import randint
class PaintApp(App):
def build(self):
rootWindow=Widget()
self.painter=PaintWindow()
# clearBtn=Button(text="Clear",color=(1,0,0,1),font_size="30sp",background_color=(0,1,0,1),pos =(300, 250))
print(f"SIZE OF PAINTER: {self.painter.width},{self.painter.height}")
#####################################################################################################
'''
This Button's size_hint is not working on running on my device or due to some kivy issue.
'''
clearBtn = Button(text="Clear Screen",size_hint=(0.2,0.2),pos_hint=(0.8,0.8))
#####################################################################################################
clearBtn.bind(on_release=self.clearCanvas)
rootWindow.add_widget(self.painter)
rootWindow.add_widget(clearBtn)
return rootWindow
def clearCanvas(self,obj):
print(obj)
self.painter.canvas.clear()
class PaintWindow(Widget):
def on_touch_down(self, touch):
self.canvas.add(Color(rgb=(randint(0,255)/255,randint(0,255)/255,randint(0,255)/255)))
# d=20
# self.canvas.add(Ellipse(pos=(touch.x-d/2,touch.y-d/2),size=(d,d)))
touch.ud['line']= Line(points=(touch.x,touch.y),width=5)
self.canvas.add(touch.ud['line'])
def on_touch_move(self, touch):
touch.ud["line"].points+=[touch.x,touch.y]
if __name__ == "__main__":
PaintApp().run()
I'm a complete beginner at kivy. Here is an image of Kivy window I get as an output:
I wanted it to get on kind of to the top right corner of screen.
I tried it in kvlang but still showing the same result.
The size_hint does work for Layouts, but Widget is not a Layout. The Layout that interprets the size_hint is the Layout that contains the Widget with the size_hint. So, when you provide a size_hint to a Button:
clearBtn = Button(text="Clear Screen",size_hint=(0.2,0.2),pos_hint=(0.8,0.8))
The size_hint is not used by the Button itself, it is used by the Layout when you do something like:
l.add_widget(clearBtn)
where l is a Layout. If you do:
rootWindow.add_widget(clearBtn)
The size_hint will not be honored, because rootWindow is a Widget, but not a Layout. Try defining rootWindow as:
rootWindow = RelativeLayout()
I want to have opportunity to change or delete rectangle in builder, but I get AttributeError.
How can I fix it? I hope you help me
from kivy.app import App
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.image import Image
from kivy.lang import Builder
from kivy.core.window import Window
from kivy.graphics import Color, Rectangle
Builder.load_string('''
<RootWidget>
FloatLayout:
id: layout
canvas.before:
Rectangle:
id: image
size: (100, 180)
pos: (223, 191)
source:'image.gif'
''')
class RootWidget(FloatLayout):
def __init__(self, **kwargs):
super(RootWidget, self).__init__(**kwargs)
self.ids.layout.remove_widget(self.ids.image)
class WindowApp(App):
def build(self):
return RootWidget()
if __name__ == '__main__':
WindowApp().run()
Unfortunately, you can't set the id of a canvas object. Here is a workaround: Consider you want to change the source attribute of your Rectangle. Set rectangle_image: "image.gif" in your FloatLayout, then set source: self.rectangle_image in your Rectangle. Now you can reference the FloatLayout by its id and change its rectangle_image variable, and it will automatically update the Rectangle's source attribute!
I would like to create a scrollable Floatlayout with dynamically created buttons (kind of paint where I can scroll the drawing board). Unfortunately, the code that I come out doesn't work and the buttons don't move while scrolling the FloatLayout. How can I attach the button to the FloatLayout?
import kivy
kivy.require('1.0.7')
from kivy.app import App
from kivy.uix.scrollview import ScrollView
from kivy.lang import Builder
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.button import Button
Builder.load_string('''
<Scroller>
view: glayout
FloatLayout:
id: glayout
width: 2000
height: 2000
size_hint: (None, None)
''')
class Main(App):
def build(self):
self.root=Scroller()
return self.root
class Scroller(ScrollView):
def __init__(self, **kwargs):
super(Scroller, self).__init__(**kwargs)
a = Button(size_hint=(None,None), width=200, height=200)
self.ids.glayout.add_widget(a)
a.bind(pos=self.ids.glayout.pos)
if __name__ in ('__main__'):
app = Main()
app.run()
The FloatLayout handle the size, not the position. The most simple solution is to replace your FloatLayout with a RelativeLayout, which handle size, and position is relative to the RelativeLayout origin.
I was learning how to create an App with Kivy and I see that the App looks different when I use Python vs kv language.
What I am trying to do is to get the background colored red.
When I do it with Python, I get a little red box at the bottom left corner (probably, the default 100px kivy widget size).
When I do it with the kv file, I get the entire background colored red
Here is my python code -
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.graphics import *
class MyWidget(Widget):
def __init__(self, **kwargs):
super(MyWidget, self).__init__(**kwargs)
with self.canvas:
Color(1,0,0,1)
Rectangle(size = self.size, pos = self.pos)
class MyWidgetApp(App):
def build(self):
x = MyWidget()
return x
pass
if __name__ == "__main__":
MyWidgetApp().run()
Here is my kv file
<MyWidget#Widget>:
canvas:
Color:
rgba: 1, 0, 0, 1.0
Rectangle:
size: self.size
pos: self.pos
Why does this happen? And how can I set the background color from Python?
I am using Python 2.7 on a Linux machine
The problem is that kv automatically makes a binding to update the red rectangle position and size, while python doesn't (and can't). You have to use the bind method to create your own binding. I have a blog post about this here - coincidentally, it addresses precisely your example.