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()
Related
I created a stack layout with 100 buttons in it. This alone works but when I add the stack layout under scroll view layout nothing is displayed on the screen.without using scroll view
when scroll view is used
Python code
from kivy.app import App
from kivy.metrics import dp
from kivy.uix.stacklayout import StackLayout
from kivy.uix.widget import Widget
from kivy.uix.button import Button
from kivy.uix.scrollview import ScrollView
class stacklayoutex(StackLayout):
def __init__(self,**kwargs):
super().__init__(**kwargs)
for i in range(100):
b=Button(text=str(i+1),size_hint=(None,None),size=(dp(100),dp(100)))
self.add_widget(b)
class MainWidget(Widget):
pass
class TheLabApp(App):
pass
TheLabApp().run()
KV file
scrollviewex:
<scrollviewex#ScrollView>:
stacklayoutex:
size_hint: 1,None
height:4000
<stacklayoutex>:
A couple problems:
Your class names must begin with upper case. Not following this rule can cause syntax errors in your kv.
Also, indentation error in your kv, it should be:
Scrollviewex:
<Scrollviewex#ScrollView>:
Stacklayoutex:
size_hint: 1,None
height:4000
<Stacklayoutex>:
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()
So I am very new to Kivy, and it is pretty frustrating so far.....anyway, I am trying to now make a popup that I can drag and move around, and I don't understand what is going on.... when I call popup.open() in the onButtonPress function, the popup is closeable through the dismiss action, though I lose dragable functionality....when I add the popup directly to the main window through self.layout.add_widget(popup), I am able to move the popup but then am not able to close it....I'm guessing the open() call is redefining the dragable window? Is this true? If not what is happening and how do I fix it?
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.image import Image
from kivy.core.window import Window
from kivy.uix.behaviors import DragBehavior
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.popup import Popup
class PopupExample(App):
# override the build method and return the root widget of this App
def build(self):
# Define a grid layout for this App
self.layout = FloatLayout()
# Add a button
self.button = Button(text ="Click for pop-up")
self.layout.add_widget(self.button)
# Attach a callback for the button press event
self.button.bind(on_press = self.onButtonPress)
return self.layout
def onButtonPress(self, button):
# print('opening')
layout = GridLayout(cols = 1, padding = 10)
img = Image(source="temp_plot.png")
closeButton = Button(text = "Close the pop-up")
layout.add_widget(img)
layout.add_widget(closeButton)
popup = MoveableImage( title ='Demo Popup', content = layout, size_hint =(None, None), size = (400,400))
popup.open()
#self.layout.add_widget(popup)
#closeButton.bind(on_press = self.remove_widget(popup))
class MoveableImage(DragBehavior,Popup):
def __init__(self, **kwargs):
super(MoveableImage, self).__init__(**kwargs)
self.drag_timeout = 10000000
self.drag_distance = 0
self.drag_rectangle = [self.x, self.y, self.width, self.height]
def on_pos(self, *args):
self.drag_rectangle = [self.x, self.y, self.width, self.height]
def on_size(self, *args):
self.drag_rectangle = [self.x, self.y, self.width, self.height]
# Run the app
if __name__ == '__main__':
PopupExample().run()
If you want to drag the Popup, adding it to the App layout is probably the best way to go. Of course, then you don't really need to use the Popup, just use some Layout. If you go that route, deleting the Popup can be accomplished by defining the Button binding like this:
closeButton.bind(on_press = lambda x: self.layout.remove_widget(popup))
The lambda is just there to suck up the button instance arg that on_press adds, so you won't get errors about too many arguments to the remove_widget() method.
The modalView class (base of the Popup) has a method that keeps the Popup centered. Looks like the DragBehavior will work, if you over-ride that method. So, if your add:
def _align_center(self, *l):
pass
to your MoveableImage class, I think you will then be able to drag it. The open() method of the ModalView does some bindings to insure that the _align_center() method is called on any position or size change. Since adding the Popup to a Layout does not call the open() method, those bindings are never set up.
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()
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.