Kivy AnchorPoint is not in the right place - kivy

I am trying to just put a piece of text centred in the top on the window but it ends up truncated in the bottom left.
I have the following python code:
# anchortest.py
from kivy.app import App
from kivy.uix.anchorlayout import AnchorLayout
from kivy.uix.widget import Widget
class Root(Widget):
pass
class TextTitle(AnchorLayout):
pass
class AnchorTestApp(App):
def build(self):
return Root()
AnchorTestApp().run()
and it's associated kv file.
# anchortest.kv
<Root>
TextTitle:
<TextTitle>
anchor_x: 'center'
anchor_y: 'top'
Label:
id: score
text: 'Hello World'
font_name: 'Courier New'
font_size: 40
pad_x: 10
pad_y: 10
When I run the app I get this:

Don't use AnchorLayout for this case, just use BoxLayout with
pos_hint: {'top': 1}
size_hint_y: None
from kivy.app import App
from kivy.lang.builder import Builder
KV = """
Screen:
BoxLayout:
orientation: 'vertical'
BoxLayout:
pos_hint: {'top': 1}
size_hint_y: None
canvas.before:
Color:
rgba: [0.5, 0, 1, 1]
Rectangle:
pos: self.pos
size: self.size
Label:
text: 'Hello World'
font_size: sp(60)
BoxLayout:
Label:
text: 'Screen text'
"""
class TestApp(App):
def build(self):
return Builder.load_string(KV)
TestApp().run()
You also can use Label parametrs valign and halign:
KV = """
Screen:
Label:
text: 'Hello World'
font_size: sp(60)
text_size: self.size
halign: 'center'
valign: 'top'
"""
In order to control sizing, you must specify text_size to constrain
the text and/or bind size to texture_size to grow with the text.
If you really want to use AnchorLayout for some reason, it's done this way. Following the kivy documentation, in order for the AnchorLayout rules to apply, the Label must be set with
size_hint_y: None
height: self.height
The size_hint is a tuple of values used by layouts to manage the sizes
of their children. It indicates the size relative to the layout’s size
instead of an absolute size (in pixels/points/cm/etc)
KV = """
AnchorLayout:
anchor_x: 'center'
anchor_y: 'top'
Label:
text: 'Hello World'
font_size: sp(60)
size_hint_y: None
height: self.height
"""

Related

Positioning a text field inside a toolbar in Kivy

I'm trying to put a textfield inside a toolbar with KivyMD, but the textfield is always directly against the right side of the window. I tried to adjust it with pos_hint, but none of the values I put for the x-coordinates moved it.
Screen:
canvas.before:
Rectangle:
pos: self.pos
size: self.size
source: 'assets/bg.png'
BoxLayout:
orientation: 'vertical'
MDToolbar:
id: toolbar
title: 'Placeholder'
elevation: 10
pos_hint: {"top": 1}
left_action_items: [['menu', lambda x: app.menu.open()]]
MDTextFieldRound:
id: textinput
icon_left: 'magnify'
pos_hint: {'x': 0.1 ,'center_y': 0.5, 'right': 0.3}
size_hint: {.6, .4}
text_color: 'white'
hint_text: 'Search'**strong text**
MDLabel:
text: 'Placeholder'
color: 'white'
halign: 'center'
Screenshot of toolbar
Any help is appreciated, thanks.
You can insert your widgets wherever you want, for this you can specify a position in the widget tree - add_widget(widget, index). I wrote a special get_widgets function for your solution, which goes through all the widgets in the class. In the example below, you can place the text field on the left, right, and center. Also examine the MDToolbar source code
from kivy.lang.builder import Builder
from kivy.metrics import dp
from kivy.clock import Clock
from kivy.weakproxy import WeakProxy
from kivymd.app import MDApp
from kivymd.uix.boxlayout import MDBoxLayout
from kivymd.uix.textfield import MDTextField
KV = """
MDScreen:
MDBoxLayout:
orientation: 'vertical'
MDToolbar:
id: toolbar
title: 'Placeholder'
pos_hint: {"top": 1}
MDLabel:
text: 'Placeholder'
color: 'white'
halign: 'center'
"""
class TestApp(MDApp):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.search_content = None
def build(self):
return Builder.load_string(KV)
def on_start(self):
Clock.schedule_once(lambda dt: self.add_search('left'))
#staticmethod
def get_widgets(root: WeakProxy, class_: str):
"""
:param root: root widget
:param class_: which subclass are we looking for
:return:
"""
widgets = []
for widget in root.walk():
if widget.__class__.__name__ == class_:
widgets.append(widget)
print(widget)
return widgets
def add_search(self, side: str):
"""
:param side: left/right/center
:return:
"""
box = self.get_widgets(self.root.ids.toolbar, 'MDBoxLayout')[0] # get root `MDBoxLayout`
if side == 'left':
index = 2
elif side == 'right':
index = 1
else:
index = 0
self.root.ids.toolbar.ids.label_title.size_hint = None, None
self.root.ids.toolbar.ids.label_title.opacity = 0
# NOTE: If you remove this `MDLabel`, you cant change `self.theme_cls.material_style`
# box.remove_widget(self.root.ids.toolbar.ids.label_title)
boxlayout = MDBoxLayout(padding=[dp(18), dp(0), dp(18), dp(18)])
self.search_content = MDTextField(icon_left='magnify',
mode='round',
color_mode="custom",
line_color_normal=(1, 0, 1, 1),
line_color_focus=(0, 0, 1, 1),
text_color_focus=self.theme_cls.text_color,
text_color_normal=self.theme_cls.text_color[0:3] + [0.7],
hint_text='Empty field',
)
boxlayout.add_widget(self.search_content)
box.add_widget(boxlayout, index)
TestApp().run()

Invalid indentation, must be a multiple of 8 spaces, rounded button kivy .kv file

so yeah I was learning kivy - "rounded buttons" and when I ran the tutorial's program ---------------
ERROR:
https://i.stack.imgur.com/rGhSa.png
python:
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.lang import Builder
from kivy.uix.textinput import TextInput
from kivy.uix.label import Label
from kivy.core.window import Window
Builder.load_file("my.kv")
class MyLayout(Widget,App):
def __init__(self,*args,**kwargs):
super(MyLayout, self).__init__(**kwargs)
class AwesomeApp(App):
def build(self):
Window.clearcolor = (1,1,1,1)
return MyLayout()
if __name__ == '__main__':
AwesomeApp().run()
.kv
<MyLayout>
BoxLayout:
orientation: "vertical"
size: root.width, root.height
padding: 50
spacing: 20
Button:
text: "Hello World!"
RoundedButton:
text: "Goodbye World!"
pos_hint: {'center_x': 0.5}
size_hint: (1, .3)
#background_color: (0/255,255/255,203/255,1)
#background_normal: ''
<RoundedButton#Button>
background_color: (0,0,0,0)
background_normal: ''
canvas.before:
Color:
rgba: (0/255,255/255,203/255,1)
RoundedRectangle:
size: self.size
pos: self.pos
radius: [58]
thanks,can anyone help, don't like these errors,
indentation error it seems like
You are not doing proper indentation you must use only one type of indentation in a file but you are using 8 spaces and 4 spaces both as indentation that is why error is coming.
Here,I have used 4 spaces as indentation in whole code that is why its working fine.
<MyLayout>
BoxLayout:
orientation: "vertical"
size: root.width, root.height
padding: 50
spacing: 20
Button:
text: "Hello World!"
RoundedButton:
text: "Goodbye World!"
pos_hint: {'center_x': 0.5}
size_hint: (1, .3)
#background_color: (0/255,255/255,203/255,1)
#background_normal: ''
<RoundedButton#Button>
background_color: (0,0,0,0)
background_normal: ''
canvas.before:
Color:
rgba: (0/255,255/255,203/255,1)
RoundedRectangle:
size: self.size
pos: self.pos
radius: [58]

Multiple text fields inside of a Kivy language Button/Label

I want to have a button that has the Date, then below a weather icon, then below that the temperature. But kivy seems to ignore/overwrite the first text field with the second when i do it this way:
Button:
text: "Day"
text_size: self.size
halign: 'center'
valign: 'top'
padding_y: 10
text: "temp"
text_size: self.size
halign: 'center'
valign: 'bottom'
padding_y: 30
Image:
source: "data/%s.png" % root.dIcon
pos: self.parent.center_x-(self.width/2), self.parent.center_y-(self.height/4)
height: self.parent.height-self.parent.height/3
width: self.parent.width/2
Then if i try to build 2 Labels inside of the Button(as below) it wont compile with a getitem attribute error.
Button:
Label:
text: "Day"
text_size: self.size
halign: 'center'
valign: 'top'
padding_y: 10
Label:
text: "temp"
text_size: self.size
halign: 'center'
valign: 'bottom'
padding_y: 30
Image:
source: "data/%s.png" % root.dIcon
pos: self.parent.center_x-(self.width/2), self.parent.center_y-(self.height/4)
height: self.parent.height-self.parent.height/3
width: self.parent.width/2
Is there a way to do this or do I need to have separate fields with say a BoxLayout where only the image is clickable?
EDIT:
I realized that I can achieve this is i put some \n characters between the day and the temp then have the icon lay on top of those. I would still like to see if there is a better way to do this since it will be on different size mobile devices.
You have to use a BoxLayout with a multiline Label
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.button import Button
from kivy.uix.boxlayout import BoxLayout
Builder.load_string('''
<MyButton>:
orientation: 'vertical'
Label:
text: "Day\\nTemp"
halign: 'center'
Image:
source: "data/%s.png" % root.dIcon
''')
class MyButton(BoxLayout, Button):
pass
class TestApp(App):
def build(self):
return MyButton()
if __name__ == '__main__':
TestApp().run()
Or a BoxLayout with 2 Labels:
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.button import Button
from kivy.uix.boxlayout import BoxLayout
Builder.load_string('''
<MyButton>:
orientation: 'vertical'
Label:
text: "Day"
Label:
text: "Temp"
Image:
source: "data/%s.png" % root.dIcon
''')
class MyButton(BoxLayout, Button):
pass
class TestApp(App):
def build(self):
return MyButton()
if __name__ == '__main__':
TestApp().run()

Kivy: How can I combine the two screens into one?

I am new to kivy. I have two screens and I want to combine them into one.
The code for the first screen:
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.scrollview import ScrollView
from kivy.lang import Builder
Builder.load_string('''
<Button>:
font_size: 40
color: 0,1,0,1
<Widgets>:
Button:
size: root.width/2, 75
pos: root.x , root.top - self.height
text: 'OK'
Button:
size: root.width/2, 75
pos: root.x + root.width/2, root.top - self.height
text: 'Cancel'
Label:
text: "bbbbbaäa üß AäÄ"
size: root.width, 75
valign: 'middle'
halign: 'center'
anchor: 'left'
pos: root.x, root.top - 150
font_size: 50
height: 75
Label:
text: "Tssssssssssa #aaäa Äaaäa Üaa Maaäa a"
size: root.width, 75
valign: 'middle'
halign: 'left'
anchor: 'left'
pos: root.x, root.top - 150 - 50
font_size: 30
height: 50
''')
class ScrollableLabel(ScrollView):
pass
class Widgets(Widget):
def build(self):
return Widgets()
class MyApp(App):
def build(self):
return Widgets()
if __name__ == "__main__":
MyApp().run()
The code for the second screen is from Alexander Taylor: https://github.com/kivy/kivy/wiki/Scrollable-Label
I paste the code here again:
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.scrollview import ScrollView
from kivy.properties import StringProperty
from kivy.lang import Builder
long_text = 'yay moo cow foo bar moo baa ' * 100
Builder.load_string('''
<ScrollableLabel>:
Label:
size_hint_y: None
height: self.texture_size[1]
text_size: self.width, None
text: root.text
''')
class ScrollableLabel(ScrollView):
text = StringProperty('')
class ScrollApp(App):
def build(self):
return ScrollableLabel(text=long_text)
if __name__ == "__main__":
ScrollApp().run()
Question one:
I want to combine those two screens into one, to have the Scrollbale Label from the second screen below the Label from the first screen. How can I do it?
Question two:
I want to have the Label text from first code started from left. Now the text is in the middle of the Label. It seems that anchor: 'left' is not working. How can I do it?
And help will be appreciated. Thanks.
You can do that like this:
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.scrollview import ScrollView
from kivy.lang import Builder
from kivy.properties import StringProperty
Builder.load_string('''
<Button>:
font_size: 40
color: 0,1,0,1
<Widgets>:
GridLayout:
size_hint: 1,0.4
cols: 2
rows: 2
Button:
text: 'OK'
Button:
text: 'Cancel'
Label:
text: "bbbbb"
font_size: 50
halign: "left"
size: self.texture_size
text_size: root.width/2, None
Label:
text: "Tssssssssssa #aaäa Äaaäa Üaa Maaäa a"
font_size: 30
halign: "left"
size: self.texture_size
text_size: root.width/2, None
ScrollView:
Label:
size_hint_y: None
height: self.texture_size[1]
text_size: self.width, None
text: root.text
''')
class Widgets(BoxLayout):
text = StringProperty("")
def __init__(self,**kwargs):
super(Widgets,self).__init__(**kwargs)
self.orientation = "vertical"
self.text = 'yay moo cow foo bar moo baa ' * 100
class MyApp(App):
def build(self):
return Widgets()
if __name__ == "__main__":
MyApp().run()

Kivy app with .kv file doesn't display

I am trying to modify this example: https://github.com/inclement/kivycrashcourse/blob/master/video14-using_a_screenmanager/after.py to make it work with a .kv file. This is my myscreenmanager.py file:
from kivy.app import App
from kivy.base import runTouchApp
from kivy.lang import Builder
from kivy.properties import ListProperty
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.screenmanager import ScreenManager, Screen, FadeTransition
import time
import random
class FirstScreen(Screen):
pass
class SecondScreen(Screen):
pass
class ColourScreen(Screen):
colour = ListProperty([1., 0., 0., 1.])
class MyScreenManager(ScreenManager):
def new_colour_screen(self):
name = str(time.time())
s = ColourScreen(name=name,
colour=[random.random() for _ in range(3)] + [1])
self.add_widget(s)
self.current = name
class MyScreenManagerApp(App):
def build(self):
return MyScreenManager()
if __name__ == "__main__":
MyScreenManagerApp().run()
And this is my myscreenmanager.kv file:
#:import FadeTransition kivy.uix.screenmanager.FadeTransition
MyScreenManager:
transition: FadeTransition()
FirstScreen:
SecondScreen:
<FirstScreen>:
name: 'first'
BoxLayout:
orientation: 'vertical'
Label:
text: 'first screen!'
font_size: 30
BoxLayout:
Button:
text: 'goto second screen'
font_size: 30
on_release: app.root.current = 'second'
Button:
text: 'get random colour screen'
font_size: 30
on_release: app.root.new_colour_screen()
<SecondScreen>:
name: 'second'
BoxLayout:
orientation: 'vertical'
Label:
text: 'second screen!'
font_size: 30
BoxLayout:
Button:
text: 'goto first screen'
font_size: 30
on_release: app.root.current = 'first'
Button:
text: 'get random colour screen'
font_size: 30
on_release: app.root.new_colour_screen()
<ColourScreen>:
BoxLayout:
orientation: 'vertical'
Label:
text: 'colour {:.2},{:.2},{:.2} screen'.format(*root.colour[:3])
font_size: 30
Widget:
canvas:
Color:
rgba: root.colour
Ellipse:
pos: self.pos
size: self.size
BoxLayout:
Button:
text: 'goto first screen'
font_size: 30
on_release: app.root.current = 'first'
Button:
text: 'get random colour screen'
font_size: 30
on_release: app.root.new_colour_screen()
After running the app nothing is displayed on the screen. No errors in console. Switching back to Builder.load_string displays the app as expected.
Found my mistake: when using a .kv file the root widget needs to be surrounded in <>, like this:
#:import FadeTransition kivy.uix.screenmanager.FadeTransition
<MyScreenManager>:
transition: FadeTransition()
FirstScreen:
SecondScreen:
Not sure why the discrepancy between load_string and .kv files, but it works now.

Resources