Kivy: how to set subclass property relative to parent class? - kivy

I am moving my layout from a .py file to a .kv file. However, I am having difficulties in setting the text size of custom label subclass as relative to that of its parent class.
The two custom Label classes are defined in the .py script as follows:
class BaseLabel(Label):
pass
class SmallLabel(BaseLabel):
pass
while the .kv file reads:
<BaseLabel>:
color: 1, 0, 0, 1
font_size: '20sp'
<SmallLabel>:
font_size: 0.8*BaseLabel().font_size
However this last line causes an error saying that BaseLabel is not defined. How should I adjust this in the kv file?

An easy way to do that is to define a key in the kv, like this:
#:set my_font_size sp(20)
<BaseLabel>:
color: 1, 0, 0, 1
font_size: my_font_size
<SmallLabel>:
font_size: 0.8*my_font_size

Related

Kivy Access Touch Object

I'm new to kivy and I want to access the touch Object without overwriting motion event functions like on_touch_down(self,touch), on_touch_up(), etc..
I want to access touch.pos in order to dynamically draw lines on an Image in a Scatter Class.
Simplified my kv file looks like the following:
<Map#Scatter>:
source: None
do_rotation: False
Image:
id: main_image
source: root.parent.parent.parent.parent.map_path
allow_stretch: True
keep_ratio: True
size_hint_y: None
size_hint_x: None
width: self.parent.width
height: self.parent.width/self.image_ratio
<Zoom>:
id: zoom_class
Map:
id: map_class
<RoomMarkerScreen>:
id: room_marker_screen
AnchorLayout:
rows: 2
AnchorLayout:
anchor_x: 'center'
anchor_y: 'top'
Zoom:
id: zoom_class
AnchorLayout:
anchor_x:'center'
anchor_y: 'bottom'
Button:
text: "Fix/Unfix Map"
size_hint: 0.5, 0.05
on_press:
root.fix_unfix(root.fix)
Knowing that Class Zoom Inherits from FloatLayout, how can I access Touch Object in Zoom?
Thanks in advance!
If I take the touch.pos from the event motion functions, they will be overwritten and I won't be able use the drag and scale features that came with the Scatter Class.
Whenever you write a function that exists in a super class, you should call that that super class method, otherwise, you will be interfering in the functioning of that super class (for example, DragBehavior). So, I suggest trying something like:
class Zoom(FloatLayout):
fixed_map = BooleanProperty(False)
def on_touch_down(self, touch):
print(touch.pos)
return super(Zoom, self).on_touch_down(touch)
And returning True from a on_touch_down() method stops all further dispatching of that touch event, so other widgets do not see that event. See the documentation.
Also, from the same documentation:
on_touch_down(), on_touch_move(), on_touch_up() don’t do any sort of
collisions. If you want to know if the touch is inside your widget,
use collide_point().

Kivy Button macro w get screen instructions

looking to set up a reusable button in my kivy file that includes various root.manager.get_screen instructions under on_press ... Anyone know if this is possible to do in the kv? Thanks so much for any help in advance
<ProductButton#Button>
color: 'black'
outline_color: 'white'
outline_width: 15
on_press:
root.manager.transition.direction = "left"
root.manager.transition.duration = 1
root.manager.current = (root.ids.product1.text+root.ids.label.text+'Detail')
root.manager.get_screen(root.manager.MY_GLOBAL).ids.selection.background_normal = self.background_normal
etc.
The code works in the individual screens but it is long and ugly so I would like to set up a macro instead...
Here is the error I get -
AttributeError: 'ProductButton' object has no attribute 'manager'

Kivy:Can't put 'BorderImage' at the specified position

(1) By using the following kv file version was able to place BorderImagewidget at the specified position..
<Screen>:
ProgressBar:
max: 100
pos_hint: {'top':0.86, 'x':0.01}
size_hint_x: 0.49
size_hint_y: 0.1
canvas:
BorderImage:
border: (10, 10, 10, 10)
pos: self.x, self.center_y
size: self.width, 8
source: '0.png'
(2) But, the following Pure Python code that should realize the same function as (1) doesn't work properly.BorderImagewidget is placed at the bottom of the screen.
pos_hint={'top':0.86,'x':0.01} doesn't work.
I think that how to specify pos=(bar.x, bar.center_y) is not good because bar.center_y value is different from the code of (1).
class BarWidget(FloatLayout):
def __init__(self, **kwargs):
super(BarWidget, self).__init__(**kwargs)
self.build()
def build(self):
bar = ProgressBar(pos_hint={'top':0.86,'x':0.01}, max=100, size_hint_x=0.49, size_hint_y=0.1)
with bar.canvas:
BorderImage(border=(10, 10, 10, 10), pos=(bar.x, bar.center_y), size=(self.width/2, 8), source='0.png')
self.add_widget(bar)
How should I modify bar.center_y?
(1):screen shot
(2):screen shot
In the kv language, when you set an attribute like size: self.size, this attribute is automatically updated whenever the 'self' widget changes size of shape. When things are loading up in a screen/layout, they start with funky positions and sizes then move to be correct. Since things automatically update upon changing sizes/positions if you work in kv, it works as you expect.
In python, you have to explicitly bind some function to update the canvas if the size or position of the widget it's inheriting its size and pos from changes. You can do that by using the bind function (available in most/all kivy widgets). Using bind, you can say bind(<attribute>=<function>) which means anytime the widget's <attribute>, aka size or pos, is changed, it calls the <function>
I didn't test this exactly with your code since not all of it is posted, but this is what I do for my projects. Let me know how it works. If it doesn't work, edit your answer to be a snippet of code that I can copy/paste to work with and I'll update my answer.
class BarWidget(FloatLayout):
def __init__(self, **kwargs):
super(BarWidget, self).__init__(**kwargs)
self.build()
def build(self):
# Make it so you can reference the bar and border image later
self.bar = ProgressBar(pos_hint={'top':0.86,'x':0.01}, max=100, size_hint_x=0.49, size_hint_y=0.1)
with self.bar.canvas:
# Make it so you can reference the border image
self.border_image = BorderImage(border=(10, 10, 10, 10), pos=(bar.x, bar.center_y), size=(self.width, 8), source='0.png')
self.add_widget(self.bar)
# Make it so whenever the widget's pos or size changes, we update the border image
self.bar.bind(pos=self.update_border_image, size=self.update_border_image)
# make a function to update border image
def update_border_image(self, *args):
self.border_image.size = (self.width, 8) # Should this 8 be 0.8 by the way?
self.border_image.pos = (self.bar.x, self.bar.center_y)

Difference between text_size and texture_size in kivy label properties

When setting up properties in kivy label, there are texture_size and text_size. What is the difference between them?
texture_size is a dynamically generated dimension for Label in kivy. It depends on the text length and font size. It is parameter value for the attribute size.
Label:
size: self.texture_size
text_size is an attribute for Label. Here you can hard-code the size of the Label.
Label:
text_size: cm(6), cm(4)

kivy.lang Builder doesn't evaluate simple expressions

While working with kivy.lang Builder I performed some simple arithmetic and it's not working, no error message even.
Builder.load_string ('''
<RootWidget>:
text: 'beautiful Flower Pics '
font_size: 50
Image:
pos: root.pos
size: root.width * 0.5, root.height
source: 'newflower.png'
allow_stretch: True
keep_ration: False
here at root.widht * 0.5 multiplication is not being done. suggestion, hint, advice?
Assuming that RootWidget is a Layout of some sort, you need to set your size_hint. size_hint defaults to 1, 1, and will override your specified sizes. If you set size_hint: None, None then this should size as expected - and depending on the specific type of Layout, you may be able to skip setting size altogether and just use size_hint: 0.5, 1 to get the same effect.

Resources