Is there any way to make a kivy checkbox from a circle checkbox to a square checkbox?
This is my code for my current checkbox:
CheckBox:
group: 'check'
id : chk
pos: 240,300
When you use group with a CheckBox, it changes to a circle. You can subclass CheckBox to avoid that behavior:
<MyCheckBox#CheckBox>:
canvas:
Clear:
Color:
rgba: self.color
Rectangle:
source: self._checkbox_image
size: sp(32), sp(32)
pos: int(self.center_x - sp(16)), int(self.center_y - sp(16))
This creates a MyCheckBox widget that does not display the circle behavior even when group is used. The above kv just defines the canvas by using Clear to remove the CheckBox canvas instructions, and replacing them with basically the same instructions, but eliminating the group reference.
Related
So I am working on a file explorer user interface and I ran into a problem with the user interface. The user interface is basically divided into two parts. One of the parts contains a MDBackdrop. I wanted to position this Backdrop at the right side of the screen. So I added it into a BoxLayout and positioned it to the side of the screen as shown...
<MainScreen>:
FloatLayout:
canvas:
Color:
rgba: 0.05,0.05,0.05, 1
Rectangle:
pos: root.pos
size: root.size
Color:
rgba: 0.1, 0.1, 0.1, 1
RoundedRectangle:
size:(root.width-10, root.height-10)
pos:(5,5)
radius: (30,30,30,30)
Color:
rgba: 0.15, 0.15, 0.15, 1
RoundedRectangle:
pos:(10,10)
size:(400,root.height-20)
radius: (30,30,30,30)
BoxLayout:
size:500,500
size_hint_y : None
size_hint_x : None
pos_hint:{"right":1, "top": .95}
MDBackdrop:
I also had to modify the source code of the Backdrop so that the actual back element and the toolbar at the top of the widget will be positioned correctly. The source code is at https://raw.githubusercontent.com/HeaTTheatR/KivyMD/master/kivymd/uix/backdrop.py
The line I changed is I added
pos:root.pos
after line 176 i.e. told the _frontLayer to follow the positioning of the root class(Backdrop)
I also want the toolbar to appear at the right of the screen rather than the left side of the screen so
I changed(line 162 i.e.MDBackdropToolbar)
pos_hint: {'top': 1,}
to
pos_hint: {'top': 1, 'right':1}
the toolbar shift correctly but I get this extra blue rectangle which I just cannot figure out why and how to remove it...
That weird rectangle that I see
I have no idea why that rectangle keeps on showing up and how do I remove it? THANKS :)
So I found out the answer myself ;). Turns out nothing was wrong with MDBackdrop Widget it was actually the toolbar widget that was causing that weird rectangle. I edited the source code of the toolbar widget which can be found here https://raw.githubusercontent.com/HeaTTheatR/KivyMD/master/demos/kitchen_sink/studies/shrine/baseclass/toolbar.py
and I changed line 281 from
(root.action_button.width - dp(6), self.height)) if root.type == "bottom" else self.pos
to
(root.action_button.width - dp(6), self.height)) if root.type == "bottom" else self.size
i.e. I changed self.pos to self.size
and now that weird rectangle is gone
The way I intended it to look like without that weird rectangle
I am trying to align labels and button in my test UI this is my kv file
<test>:
Label:
text: "foo"
color: 0,1,0,1
#pos:120,20
pos_hint:{"right":0.1,"top":1}
Label:
text:"boo"
color: 0,0,1,1
#pos:80,20
pos_hint:{"right":0.1,"top":0.5}
Label:
text:"bar"
color: 1,0,0,1
#pos:20,120
pos_hint:{"right":0.1,"top":0.1}
Button:
text:"goo"
size_hint:0.1,0.1
I am able to succesfully create labels foo,boo and bar using pos but when I used pos_hint it returns blank output?
You are getting "blank" output because the text of the labels is off screen (and the labels themselves are transparent).
Since your layout <test> has no size_hint so it takes on the
default of (1,1) which makes it the size of the Window (which is
800 x 600).
Your labels also don't have a size_hint so they default to the size of their parent - the layout, so they end up having size [800, 600]. The text in the labels is centered by default, and their background is transparent. (maybe you should try this with buttons first so you have a visual representation of the sizes)
Thus, the text a label with pos = (0,0) will appear in the center of the screen
Then we have the pos_hint taking different arguments (the below description might not be accurate for things outside of a FloatLayout):
pos_hint:{"right":v1,"top":v2} sets the pos to (self.parent.right*v1 - self.width, self.parent.top*v2 - self.height) - you are setting the top and right of the widget you are placing. Thus your labels get such negative coordinates that their texts never appear on screen (because bottom left is 0,0)
then we have pos_hint:{"x":v1,"y":v2} (which you may find more useful for your case), and pos_hint:{"center_x":v1,"center_y":v2}. You should be able to figure out how they work bearing in mind that the size affects how things looks, since pos only sets the bottom left coordinate.. you can play around with this .kv file:
#:kivy 1.0.9
<test>:
#size: (500, 500)
#size_hint:(None, None)
canvas:
Color:
rgb: 1,0,0
Rectangle:
size: (5,5)
pos: (0,0)
Widget:
id:wig
pos: (250,250)
canvas:
Color:
rgb: 1,1,1
Rectangle:
size: (5,5)
pos: self.pos
Label:
id: boo
text:"boo"
color: 0,0,1,1
#size_hint:(1,1)
pos_hint:{"center_x":1,"center_y":1}
Label:
id: foo
text: "foo"
color: 0,1,0,1
#size_hint: (.6,.6)
pos_hint:{"x":1,"y":1}
Label:
id: bar
text:"bar"
color: 1,0,0,1
#size:(500,500)
#size_hint:(None, None)
pos_hint:{"right":1,"top":1}
#pos:100, 10
Button:
text:"goo"
size_hint:0.1,0.1
pos:(1,1)
#some debug info, i know the code is ugly
on_press: print self.parent.size,'\n', self.parent.right, self.parent.top, self.parent.x, self.parent.y, self.parent.center_x, self.parent.center_y, "\n","bar_right_top:", bar.pos,"foo_x_y:", foo.pos,"boo_center:", boo.pos, "\nwhite square:", wig.pos, "\n", bar.size, foo.size, boo.size
I want to create a TextInput and modify its canvas to have a white RoundedRectangle in the background. I made the background_color transparent, but I don't see that rectangle behind the TextInput.
I've tried to instead draw on canvas.before and canvas.after. The both seemed to result in one thing: the expected Rectangle covered the cursor and the text. And while this would be expected for canvas.after, I thought canvas.before wouldn't cover anything? How to make a background through canvas instructions for a TextInput?
Here is the code:
from kivy.base import runTouchApp
from kivy.lang import Builder
from kivy.uix.textinput import TextInput
Builder.load_string('''
<Test>:
canvas: # no rectangle this way
Color:
rgba: 1, 1, 1, 1
RoundedRectangle:
pos: self.pos
size: self.size
background_color: 1, 1, 1, 0
''')
class Test(TextInput):
pass
runTouchApp(Test())
Simple! You set Color in canvas which is set to (some?) other components too (probably via OpenGL directly). Therefore you have to "unset" it - or better said set it to the default Color, which you have already access to:
from kivy.lang import Builder
from kivy.base import runTouchApp
from kivy.uix.textinput import TextInput
Builder.load_string('''
<Test>:
canvas.before:
Color:
rgba: 1, 0, 0, .5
Rectangle:
pos: self.pos
size: self.size
Color:
rgba: root.foreground_color
background_color: 1,1,1,0
''')
class Test(TextInput): pass
runTouchApp(Test())
You already have colors set in the default TextInput, so you can access them with root.
Also for more features play with background_* properties. Making an image with rounded corners will be probably better for a performance if you need it(mobiles) and you can switch between them just with setting those properties, because TextInput handles switchess automatically.
I'm trying to understand how kv files work.
So far, i've been able to tackle a couple errors, but I'm stuck with something that doesn't produces errors but doesn't produce the intended result.
Expected :
My goal is to create a parent widget containing two isntances of a sub-widget. The sub-widget contains a rectangle and a touch-move instruction. I want each instance to cover only part of the main widget (the rectangle is here for me to see where the sub-widget is). I assume the on-touch-move instructions should trigger only on the part of the screen where the sub-widget instance is.
Actual:
The sub-widget rectangles don't show, and the on-touch-move behaviour is triggered anywhere twice (which makes be think both sub-widgets span on the whole screen but the rectangle isn't shown).
Removing the parent widget canvas doesn't solve my problem, neither does adding only one sub-widget.
What am I doing wrong ?
python file :
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.graphics import Rectangle
class MainWidget(Widget):
pass
class SubWidget(Widget):
def on_touch_move(self, touch):
self.center_x, self.center_y = (touch.x, touch.y)
print touch.x, touch.y
class testApp(App):
def build(self):
x = MainWidget()
return x
if __name__ == '__main__':
testApp().run()
kv file:
#:kivy 1.8.0
<MainWidget>:
canvas:
Color:
rgb: 0,1,0
Rectangle:
pos: self.center
size: 10,10
SubWidget:
pos: self.width - self.width/5 ,0
size: self.width/5 , self.height
SubWidget:
pos: 0, 0
size: self.width/5 , self.height
<SubWidget>:
canvas:
Color:
rgb: 1,0,0
Rectangle:
pos: self.pos
size: self.size
Thanks in advance for answers.
edit :
1) child widgets should be added within a layout. Still need to find a way to
position my widgets properly within the layout.
2) widgets' touch events are triggered even if the widget isn't directly clicked. Using widget.collide_point(*touch.pos) makes it work.
edit2 :
Fixed the .kv. Self.parent.pos/size didn't behave consistently so I moved to root.pos/size :
#:kivy 1.8.0
<MainWidget>:
canvas:
Color:
rgb: 0,1,0
Rectangle:
pos: self.center
size: 10,10
FloatLayout:
SubWidget:
pos: root.width - root.width/5 ,0
size: root.width/5 , root.height
SubWidget:
pos: 0, 0
size: root.width/5 , root.height
<SubWidget>:
canvas:
Color:
rgb: 1,0,0
Rectangle:
pos: self.pos
size: self.size
I believe you need to put the child elements into a box layout.
So it would be something like this.
<MainWidget>:
canvas:
...
BoxLayout:
SubWidget:
...
SubWidget:
...
The SubWidget elements' attributes (like pos) might need some changing.
Some more info here too.
I assume the on-touch-move instructions should trigger only on the part of the screen where the sub-widget instance is.
This assumption is incorrect. To check for the collision yourself, you can do if self.collide_point(*touch.pos): ... in your on_touch_move method.
Also, your positioning problems are caused by using only Widgets - these do not impose anything on their children, so everything except the root widget has the default pos of (0, 0) and size of (100, 100). You should use Layout classes to have widgets automatically resize and position their children.
I'm fairly new to Kivy and have a few questions about widgets.
I started out messing with Kivy a few months back. I've read some documentation but I might have missed out lots of stuff.
Is it possible to create multiple instances of the same widget class with their own properties?
My goal is to have a few rectangles that I can resize and drag around independently.
I'm taking a java class so I'll compare to what I learnt in that class:
For example, lets say I have a basic rect.java class set up to take in two variables for width and height.
So in my main .java code file I would write something like this to create a few instances of the rectangle class:
rect s1 = new rect(2,3); // width & height
rect s2 = new rect(5,4);
Then, s1.height and s2.height will have different values.
Is it possible to achieve something similar in Kivy? For now I have many classes with the same properties set up in my .kv file:
<rect1>:
canvas:
Color:
rgba: 1, 0, 1, 0.5
Rectangle:
pos: root.center_x - root.width/2,root.center_y - root.height/2
size: self.size
<rect2>:
canvas:
Color:
rgba: 1, 1, 0, 0.5
Rectangle:
pos: root.center_x - root.width/2,root.center_y - root.height/2
size: self.size
<rect3>:
canvas:
Color:
rgba: 0, 1, 0, 0.5
Rectangle:
pos: root.center_x - root.width/2,root.center_y - root.height/2
size: self.size
I've written code in my .py file for it to be resized and dragged around. For now, I copied/modified the code to work with each additional class.
For now, if I use:
Window.add_widget(rect1)
It will create a new instance directly on top of the older one but they still share the same coordinates and other properties etc. If I drag with my mouse, all the instances of that class follow the same coordinates. Once again, my goal is to have multiple rectangles that I can resize and drag around independently.
The Window should only have one widget (the application root widget). It's best to let this widget be added automatically by returning the root widget instance from App.build() or by including a root widget in your app's kv file.
In this case, a FloatLayout would make the most sense.
Also, you can use the Scatter widget to handle transformations - move (translate), resize and rotate - which might be easier than doing it yourself. Just wrap each widget in a Scatter, or make your widgets extend Scatter.
Each entry you define with the angle brackets (<, >) are class declarations not instances. If you want to instantiate a class in the kv file with different properties then use the name without the angle brackets.
Here's some working code based on the code fragments you supplied:
<MovableRect>:
size: 50, 50
canvas:
Color:
rgba: root.color
Rectangle:
size: self.size
pos: self.pos
<MyRoot#Widget>:
MovableRect:
id: rect1
color: 1, 0, 1, 0.5
pos: 5, 5
MovableRect:
id: rect2
color: 1, 1, 0, 0.5
pos: 130, 130
MovableRect:
id: rect3
color: 0, 1, 0, 0.5
pos: 250, 250
# instantiation of root widget
MyRoot:
Here's the python file (without your movement functionality because you didn't list it):
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.screenmanager import ScreenManager
from kivy.properties import ListProperty
class MovableRect(Widget):
color = ListProperty([1, 0, 1, 0.5])
class Test1App(App):
def build(self):
pass
if __name__ == '__main__':
Test1App().run()
For a more complete example you can refer to the excellent kivy crash course series on youtube. There's one example that's very similar to what you're trying to do:
https://www.youtube.com/watch?v=ChmfVOu9aIc