I have a very basic kivy code. I have the .py file and the .kv file. The questions are: where should the methods be placed? In this example the 2 methods that interact are 'def GetTicker(ticker):' and 'def GetTickers(self):'. I have placed both outside of any class, because I could not get the code to work otherwise; however I think the proper way to code would be to place them inside the 'app' class.
As an aside I am very confused about where/when the 'self' should be passed. I'm working by trial and error here.
Then there is the 'NumericProperty'. I read here that when it is updated, it automatically updates the widgets that are associated with it. It doesn't for me, therefore I had to create Id's for some labels; but the id's won't work at the beginning of the run, only on update.
I'm using python 3.9 and kivy 2.0.0, PyCharm 2021.3.1 (Community Edition) on win10 box.
Any and all assistance will be greatly appreciated.
Ray
the .py file
from kivy.app import App
from kivy.properties import NumericProperty
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.gridlayout import GridLayout
from kivy.uix.textinput import TextInput
from kivy.core.window import Window
Window.size = (300, 300)
import time
from yahoo_fin.stock_info import get_live_price # This API only gets the live price
from yahoo_fin import stock_info as si # This is SLOWER than the above API, buts gets more info
class MyBoxLayout(BoxLayout):
def __init__(self, **kwargs):
super().__init__(**kwargs)
def press(self):
name = self.ids.ticker_name.text.upper()
self.ids.ticker_value.text = self.GetTicker(name)
def update(self):
#GetTickers(self) # This won't work here :(
self.ids.mydow_price.text, self.ids.mydow_chg = self.GetTicker("^DJI")
self.ids.mysp_price.text, self.ids.mysp_chg = self.GetTicker("^GSPC")
self.ids.mynasdaq_price.text, self.ids.mynasdaq_chg.text = self.GetTicker("^IXIC")
self.ids.myeuro_price, self.ids.myeuro_chg.text = self.GetTicker("EURUSD=X")
#print(self.ids.amazon_id.text)
class MyOtherBoxlayout(BoxLayout):
pass
class MyTicker(TextInput):
pass
class gridlayout(GridLayout):
pass
def GetTicker(ticker):
# data = get_live_price(ticker)
data = si.get_quote_table(ticker)
price = data['Quote Price']
change = price - data['Previous Close']
# print("Price: %.3f" % price)
# print("Change: %.3f" % change)
return [str("%s" % format(price, ',.3f')), str("%s" % format(change, ',.3f'))]
def GetTickers(self):
self.dow_price, self.dow_chg = self.GetTicker("^DJI")
self.sp_price, self.sp_chg = self.GetTicker("^GSPC")
self.nasdaq_price, self.nasdaq_chg = self.GetTicker("^IXIC")
self.euro_price, self.euro_chg = self.GetTicker("EURUSD=X")
# This is the app class
class StockTickerApp(App):
def __init__(self, **kwargs):
super().__init__(**kwargs)
App.title = "Ray's Stock Ticker"
dow_price = NumericProperty(0.00)
dow_chg = NumericProperty(0.00)
sp_price = NumericProperty(0.00)
sp_chg = NumericProperty(0.00)
nasdaq_price = NumericProperty(0.00)
nasdaq_chg = NumericProperty(0.00)
euro_price = NumericProperty(0.00)
euro_chg = NumericProperty(0.00)
start_time = time.time()
self.GetTickers()
end_time = time.time()
print (end_time - start_time)
# and its run here
StockTickerApp().run()
the .kv file
MyBoxLayout:
<MYLabel#ButtonBehavior+Label>: # this is something I found that helps make a label behave
# like a button.
<MyBoxLayout>:
canvas.before:
Color:
rgba: (153/255, 255/255, 255/255, 1)
Rectangle:
pos: self.pos
size: self.size
padding: ("15dp", "15dp", "15dp", "15dp") #left, top, right, bottom
spacing: "10dp"
orientation: "vertical"
#
# 1st widget
#
Label:
text: "Stocks Ticker"
size_hint: 1, .1
#pos_hint: {"top": 1}
color:0,0,0,1
#
# 2nd widget
#
BoxLayout:
canvas.before:
Color:
rgba: (19/255,202/255,55/255,1) # lime more intense
Rectangle:
pos: self.pos
size: self.size
padding: ("10dp", "0dp", "15dp", "0dp")
spacing: "20dp"
orientation: "horizontal"
size_hint: 1, .4
#pos_hint: {"center": .5}
Label:
text: " Enter Stock"
size_hint: .6, .5
pos_hint: {"center_X":.5, "top": .7}
color: 72/255,89/255,89/255,1
MyTicker: # this is a textinput widget
id: ticker_name
text: ""
size_hint: .6, .6
pos_hint: {"top": .8}
Label:
id: ticker_value
#text: " Enter Stock"
size_hint: .5, .1
color: 0,0,0,1
pos_hint: {"top":.5, "center": 1}
#
# 3rd widget
#
BoxLayout:
size_hint: 1, .3
Button:
#id: "Find_Value"
text: "Find Value"
on_press: root.press()
#
# 4th widget
#
gridlayout:
canvas.before:
Color:
rgba: (19/255,202/255,55/255,1) # lime more intense
Rectangle:
pos: self.pos
size: self.size
rows: 4
cols: 3
padding: "10dp"
MYLabel:
color: 72/255,89/255,89/255,1
text: "Dow"
text_size: self.size
halign: 'left'
on_press: root.update()
MYLabel:
id: mydow_price
color: 0,0,0,1
text: app.dow_price
text_size: self.size
halign: 'right'
on_press: root.update()
MYLabel:
id: mydow_chg
color: 0,0,0,1
text: app.dow_chg
text_size: self.size
halign: 'right'
on_press: root.update()
MYLabel:
text: "S&P 500"
color: 72/255,89/255,89/255,1
text_size: self.size
halign: 'left'
on_press: root.update()
MYLabel:
id: mysp_price
text: app.sp_price
color: 0,0,0,1
text_size: self.size
halign: 'right'
MYLabel:
id: mysp_chg
text: app.sp_chg
color: 0,0,0,1
text_size: self.size
halign: 'right'
MYLabel:
text: "Nasdaq"
color: 72/255,89/255,89/255,1
text_size: self.size
halign: 'left'
on_press: root.update()
MYLabel:
id: mynasdaq_price
text: app.nasdaq_price
color: 0,0,0,1
text_size: self.size
halign: 'right'
MYLabel:
id: mynasdaq_chg
text: app.nasdaq_chg
color: 0,0,0,1
text_size: self.size
halign: 'right'
MYLabel:
text: "Euro/USD"
color: 72/255,89/255,89/255,1
text_size: self.size
halign: 'left'
on_press: root.GetTickers()
MYLabel:
id: myeuro_price
text: app.euro_price
color: 0,0,0,1
text_size: self.size
halign: 'right'
MYLabel:
id: myeuro_chg
text: app.euro_chg
color: 0,0,0,1
text_size: self.size
halign: 'right'
Related
I'm trying to combine this recycleview example with this screenmanager example so that the recycleview example can be one of the screens in my app. The app runs but all the control buttons display at the bottom of the UI (They're supposed to be at the top) and are either disabled or obscured, disallowing input. Consequently, the recycleview cannot be populated and/or viewed.
Here's my attempt:
import asyncio
from random import sample, randint
from string import ascii_lowercase
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen, FadeTransition
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.recycleview.views import RecycleDataViewBehavior
kv = '''
#:import FadeTransition kivy.uix.screenmanager.FadeTransition
#:import BoxLayout kivy.uix.boxlayout.BoxLayout
#:import RecycleDataViewBehavior kivy.uix.recycleview.views.RecycleDataViewBehavior
ScreenManagement:
transition: FadeTransition()
ContactsScreen:
name: 'contacts'
MessengerScreen:
name: 'messenger'
<Row#RecycleKVIDsDataViewBehavior+BoxLayout>:
canvas.before:
Color:
rgba: 0.5, 0.5, 0.5, 1
Rectangle:
size: self.size
pos: self.pos
value: ''
Label:
id: name
Label:
text: root.value
<ContactsScreen>:
canvas:
Color:
rgba: 0.3, 0.3, 0.3, 1
Rectangle:
size: self.size
pos: self.pos
rv: rv
orientation: 'vertical'
GridLayout:
cols: 3
rows: 2
size_hint_y: None
height: dp(108)
padding: dp(8)
spacing: dp(16)
Button:
text: 'Populate list'
on_press: root.populate()
Button:
text: 'Sort list'
on_press: root.sort()
Button:
text: 'Clear list'
on_press: root.clear()
BoxLayout:
spacing: dp(8)
Button:
text: 'Insert new item'
on_press: root.insert(new_item_input.text)
TextInput:
id: new_item_input
size_hint_x: 0.6
hint_text: 'value'
padding: dp(10), dp(10), 0, 0
BoxLayout:
spacing: dp(8)
Button:
text: 'Update first item'
on_press: root.update(update_item_input.text)
TextInput:
id: update_item_input
size_hint_x: 0.6
hint_text: 'new value'
padding: dp(10), dp(10), 0, 0
Button:
text: 'Remove first item'
on_press: root.remove()
RecycleView:
id: rv
scroll_type: ['bars', 'content']
scroll_wheel_distance: dp(114)
bar_width: dp(10)
viewclass: 'Row'
RecycleBoxLayout:
default_size: None, dp(56)
default_size_hint: 1, None
size_hint_y: None
height: self.minimum_height
orientation: 'vertical'
spacing: dp(2)
<MessengerScreen>:
Button:
on_release: app.root.current = 'contacts'
text: 'back to the home screen'
font_size: 50
'''
class ContactsScreen(Screen):
def populate(self):
self.rv.data = [
{'name.text': ''.join(sample(ascii_lowercase, 6)),
'value': str(randint(0, 2000))}
for x in range(50)]
def sort(self):
self.rv.data = sorted(self.rv.data, key=lambda x: x['name.text'])
def clear(self):
self.rv.data = []
def insert(self, value):
self.rv.data.insert(0, {
'name.text': value or 'default value', 'value': 'unknown'})
def update(self, value):
if self.rv.data:
self.rv.data[0]['name.text'] = value or 'default new value'
self.rv.refresh_from_data()
def remove(self):
if self.rv.data:
self.rv.data.pop(0)
class MessengerScreen(Screen):
pass
class ScreenManagement(ScreenManager):
pass
presentation = Builder.load_string(kv)
class MainApp(App):
def build(self):
return presentation
def main_runner(self):
async def run_wrapper():
# we don't actually need to set asyncio as the lib because it is
# the default, but it doesn't hurt to be explicit
await self.async_run(async_lib='asyncio')
print('App done')
#self.other_task.cancel()
return asyncio.gather(run_wrapper())
if __name__ == '__main__':
loop = asyncio.get_event_loop()
loop.run_until_complete(MainApp().main_runner())
loop.close()
The trouble seems to come from the <Row#RecycleKVIDsDataViewBehavior+BoxLayout> directive but I can't seem to fix it no matter where I place it.
You can position the Buttons using pos_hint, like this:
GridLayout:
id: grid
pos_hint: {'center_x': 0.5, 'top': 1}
Then, you need to size the RecycleView so that it is not over the Buttons, like this:
RecycleView:
id: rv
size_hint_y: None
height: root.height - grid.height
I'm trying to create this simple background.
This is what I have so far:
import kivy
kivy.require('1.11.1')
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.floatlayout import FloatLayout
class BaseLayout(BoxLayout):
pass
class MyWindow(FloatLayout):
def __init__(self, **kwargs):
super(MyWindow, self).__init__(**kwargs)
self.add_widget(BaseLayout())
class MyApp(App):
# 'Global' Variables
size_x = 220*1.3
size_y = 250*1.3
def build(self):
return BaseLayout()
MyApp().run()
And my .kv-file:
#:kivy 1.11.1
#:import hex kivy.utils.get_color_from_hex
<BaseLayout>:
orientation: "vertical"
size: (app.size_x, app.size_y)
size_hint: (None, None)
#:set bg_color hex('#262626')
#:set topBar_color hex('#1c1c1c')
#:set bt_color hex('#4d4d4d')
AnchorLayout:
size_hint_y: .1
Label:
canvas.before:
Color:
rgba: topBar_color
Rectangle:
size: self.size
pos: self.pos
AnchorLayout:
anchor_x: 'right'
anchor_y: 'center'
padding: 10, 10
Label:
size_hint: (1, 1)
# size: (25, 0)
canvas.before:
Color:
rgba: bt_color
Ellipse:
pos: self.pos
size: self.size
Label:
size_hint_y: .9
canvas.before:
Color:
rgba: bg_color
Rectangle:
size: self.size
pos: self.pos
I'm looking for a way to have the circle always adapt to the height of the bar at the top (and of course it should be an actual circle and not the stretched ellipse it is now).
The window is not meant to be resized, but I want to be able to control the widget with the size_x and size_y variables, so I cannot just enter some absolute values.
The size_hint for the height is correct, but I could not find a way to just set the width of the circle to its height.
Thanks in advance
Here is a modified version of your kv:
#:kivy 1.11.1
#:import hex kivy.utils.get_color_from_hex
<BaseLayout>:
orientation: "vertical"
size: (app.size_x, app.size_y)
size_hint: (None, None)
#:set bg_color hex('#262626')
#:set topBar_color hex('#1c1c1c')
#:set bt_color hex('#4d4d4d')
AnchorLayout:
anchor_x: 'right'
size_hint_y: .1
canvas.before:
Color:
rgba: topBar_color
Rectangle:
size: self.size
pos: self.pos
Widget:
size_hint: None, 1
width: self.height
canvas.before:
Color:
rgba: bt_color
Ellipse:
pos: self.pos
size: self.size
Label:
size_hint_y: .9
canvas.before:
Color:
rgba: bg_color
Rectangle:
size: self.size
pos: self.pos
This uses a Widget with size_hint: None, 1 to make it the height of the parent, and allow the width to be set as width: self.height to make a square Widget. The drawn Ellipse using that size will be a circle. Note that, in general, the AnchorLayout only works well with one child (additional children will be drawn on top of each other).
When the application is windowed the button and labels are in the right places, exactly where I want them, but when I view the window in full screen everything moves out of place
I've tried messing around with the padding and height of the box layouts and label properties, but I just getting the broken outcome.
*.py
import kivy
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.image import Image
class LoginReg(BoxLayout):
pass
class LoginApp(App):
def build(self):
return LoginReg()
if __name__== '__main__':
LoginApp().run()
*.kv
#:kivy 1.0
#:import hex kivy.utils.get_color_from_hex
<TextInput>:
size_hint_y: None
height:30
<Label>:
size_hint_y: None
height:30
color: 0,0,0,1
<FlatButton#ButtonBehavior+Label>:
font_size: 18
<LoginReg>:
id: main_win
orientation: "vertical"
spacing: 10
space_x: self.size[0]/3
space_y: 40
#Code for background start
BoxLayout:
id: background
orientation: 'vertical'
canvas.before:
Color:
rgba: hex('#f2f2f2f2')
Rectangle:
size: self.size
pos: self.pos
BoxLayout:
id: header
size_hint_y:None
height: 50
canvas.before:
Color:
rgba: hex('#1A5276')
Rectangle:
size: self.size
pos: self.pos
FlatButton:
text:"Virtual Assistant"
color: (1,1,1,1)
BoxLayout:
orientation: 'vertical'
padding: main_win.space_x, main_win.space_y
BoxLayout:
spacing: 10
orientation: 'vertical'
padding: 50
canvas.before:
Color:
rgba: hex('#111')
Rectangle:
size: self.size
pos: self.pos
Label:
text: "Login: "
TextInput:
hint_text: "Username"
multiline: False
Label:
text: "Password: "
TextInput:
hint_text: "password"
multiline: False
Button:
text:"Login"
size_hint_y: None
height: 60
background_color: (2.08, 2.40, 1.92,1)
Label:
id:sp
size_hint_y:None
height: 200
I am not getting any error messages, I just want to work out how to keep everything relative it its size when resizing the window.
The best way to get everything to keep relative size/position is to use hints. Use size_hint for sizes and pos_hint for positions. Also, don't add unnecessary complexity to your layout. In your posted code, your LoginReg is a BoxLayout, and the only item you have in it is another BoxLayout. Similarly, later in your kv you have another vertical BoxLayout with its only child being another vertical BoxLayout. That is unnecessary complexity. Here is a simpler version of your code that I believe accomplished what you want:
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.floatlayout import FloatLayout
class LoginReg(FloatLayout):
pass
Builder.load_string('''
#:kivy 1.0
#:import hex kivy.utils.get_color_from_hex
<TextInput>:
size_hint_y: None
height:30
<Label>:
size_hint_y: None
height:30
color: 0,0,0,1
<FlatButton#ButtonBehavior+Label>:
font_size: 18
<LoginReg>:
spacing: 10
#Code for background start
canvas.before:
Color:
rgba: hex('#f2f2f2f2')
Rectangle:
size: self.size
pos: self.pos
FlatButton:
id: fb
canvas.before:
Color:
rgba: hex('#1A5276')
Rectangle:
size: self.size
pos: self.pos
pos_hint: {'center_x': 0.5, 'top':1.0}
size_hint_y:None
height: 50
text:"Virtual Assistant"
color: (1,1,1,1)
BoxLayout:
spacing: 10
orientation: 'vertical'
padding: 50
canvas.before:
Color:
rgba: hex('#111')
Rectangle:
size: self.size
pos: self.pos
pos_hint: {'center_x': 0.5, 'top': (root.height - fb.height)/root.height}
size_hint: 0.33, None
size_hint_min_x: 200
height: self.minimum_height
Label:
text: "Login: "
TextInput:
id: ti
hint_text: "Username"
multiline: False
Label:
text: "Password: "
TextInput:
hint_text: "password"
multiline: False
Button:
text:"Login"
size_hint_y: None
height: 60
background_color: (2.08, 2.40, 1.92,1)
''')
class LoginApp(App):
def build(self):
return LoginReg()
if __name__== '__main__':
LoginApp().run()
I have used Builder.load_string instead of a file just for my own convenience.
The important changes are to make LoginReg extend FloatLayout just because it allows more flexibility than a BoxLayout. I have removed any BoxLayouts that only had a single BoxLayout child.
The FlatButton now uses pos_hint to position it at the top of LoginReg.
The BoxLayout inside Loginreg uses pos_hint to center it horizontally, and to position it vertically just below the FlatButton. It also uses size_hint to make its width one third of the width of LoginReg, but with a minimum width of 200. Its height is set to use the minimum height that will contain its children.
I was trying to look at different examples online to solve this issue but Still cannot figure out. I have an app that calls a popup class. The popup has an input field that does some manipulation to the text in the input field. The manipulated data is stored in a variable inside of the popup class. Now how can the parent widget access the data obtained from this widget. Here is a short example of the code.
KV
<ScreenManagement>:
ScreenManager:
id: manager
size_hint_y: 93
Screen:
name: "Case_info_screen"
id: sc1
FloatLayout:
BoxLayout:
orientation: 'vertical'
BoxLayout:
size_hint_y: 10
canvas.before:
Color:
rgb: 0.17, 0.17, 0.17 # your color here
Rectangle:
pos: self.pos
size: self.size
Label:
text_size: self.size
font_size: 20
valign: 'middle'
height: "75dp"
size_hint_y: None
color: 1,1,1,1
size_hint_x: 75
text: " Case Info"
RelativeLayout:
size_hint_x: 25
Button:
text_size: self.size
halign: 'center'
valign: 'middle'
size_hint: 0.70, 0.6
pos_hint: {'center_x': 0.5, 'center_y': 0.5}
text: 'Automatic Filler'
on_press: root.formfiller()
BoxLayout:
size_hint_y: 5
spacing: 35
LabelCases:
text: ' Name: '
width: '125dp'
size_hint_x: None
TextInput:
id: first_name_input
width: '300dp'
height: '40dp'
size_hint_x: None
font_size: 18
hint_text: 'First Name'
TextInput:
id: last_name_input
width: '300dp'
height: '40dp'
size_hint_x: None
font_size: 18
hint_text: 'Last Name'
<Formfillerpop>:
title: 'Automatic Filler'
size_hint: None, None
size: 600, 600
BoxLayout:
orientation: 'vertical'
Label:
size_hint_y: 20
text: 'Please Paste your text'
markup: True
TextInput:
id: sentence
size_hint_y: 65
BoxLayout:
size_hint_y: 10
orientation: 'horizontal'
Button:
text: 'Analyze'
on_press: root.on_analyze(sentence.text)
Button:
text: 'Close'
on_press: root.closepop()
Python:
class Formfillerpop(Popup):
selection = StringProperty
id = ObjectProperty
def on_analyze(self, selection):
analyze = TextExtractor(selection)
names = analyze.name()
def closepop(self):
self.dismiss()
class ScreenManagement(FloatLayout):
def formfiller(self, *args):
Formfillerpop().open()
class IOApp(App):
def build(self):
return ScreenManagement()
if __name__ == '__main__':
IOApp().run()
Ultimately I want to take the txt from names in the popup and then autopopulate the first name and last name in the main app with the analyzed data
Sorry if this is basic. I am fairly new to Kivy.
You can access popup content using its content property. You can use it to read text property of read underlying TextInput. For example this code binds this property to local popup_text StringProperty, which means that any change in the popup text input will be reflected there:
from kivy.uix.popup import Popup
from kivy.uix.button import Button
from kivy.uix.boxlayout import BoxLayout
from kivy.app import App
from kivy.lang import Builder
from kivy.properties import StringProperty
Builder.load_string('''
<CustomPopup>:
size_hint: .5, .5
auto_dismiss: False
title: 'Hello world'
BoxLayout:
text_input: text_input
orientation: 'vertical'
TextInput:
id: text_input
Button:
text: 'dismiss'
on_press: root.dismiss()
''')
class CustomPopup(Popup):
pass
class TestApp(App):
popup_text = StringProperty()
def build(self):
l = BoxLayout()
l.add_widget(Button(
text='show_popup', on_press=self.show_popup
))
l.add_widget(Button(
text='print popup text', on_press=self.print_popup_text
))
return l
def show_popup(self, *args):
p = CustomPopup()
p.content.text_input.bind(text=self.setter('popup_text'))
p.open()
def print_popup_text(self, *args):
print(self.popup_text)
if __name__ == '__main__':
TestApp().run()
I have a spinner used to select items as dropdown. The text in the textfield itself is normal. But the text in the spinner items looks blurry/vague, see the attached image. How could I resolve this?
The source file qmonos.py:
from kivy.app import App
from kivy.core.window import Window
from kivy.uix.boxlayout import BoxLayout
class qmonosHome(BoxLayout):
def init_qmonos(self):
self.objtype.text = ''
self.objtype.values = ('Home', 'Work', 'Other', 'Custom')
class qmonosApp(App):
def build(self):
Window.clearcolor = (.95,.95,.95,1)
Window.size = (800, 200)
homeWin = qmonosHome()
homeWin.init_qmonos()
return homeWin
qmonosApp().run()
The kivy file qmonos.kv
# File: qmonos.kv
#:import Factory kivy.factory.Factory
#:set color_button (.5,1,1,1)
#:set color_button_pressed (0.7,0.9,1,1)
#:set color_font (1,1,1,1)
<MySpinnerOption#SpinnerOption>:
background_color: color_button if self.state == 'down' else color_button_pressed
color: color_font
font_size: 12
text_size: self.width - 10, self.height
height: 25
<qmonosHome>:
objtype:objtype
BoxLayout:
orientation: "horizontal"
padding: 10,10,10,10
BoxLayout
orientation: "vertical"
size_hint: 0.5,1
BoxLayout:
orientation: "horizontal"
height: "20dp"
size_hint_y: None
Label:
text: "Hello World"
size_hint: 1,1
size: self.texture_size
halign: 'left'
valign: 'middle'
font_size: 12
color: .3,.3,.3,1
BoxLayout
orientation: "vertical"
size_hint: 0.5,1
padding: 10,0,10,0
BoxLayout:
orientation: "horizontal"
height: "20dp"
size_hint_y: None
Label:
text: "Type Object:"
size_hint: 0.25,1
size: self.texture_size
halign: 'left'
valign: 'middle'
font_size: 12
color: .3,.3,.3,1
Spinner:
id: objtype
text: ''
background_color: color_button if self.state == 'normal' else color_button_pressed
color: color_font
option_cls: Factory.get("MySpinnerOption")
font_size: 12
text_size: self.width - 10, self.height
size_hint: 0.25,1
multiline: False
foreground_color: .3,.3,.3,1
disabled_foreground_color: .3,.3,.3,1
Label:
text: "Hello too"
size_hint: 0.5,1
size: self.texture_size
halign: 'left'
valign: 'middle'
font_size: 12
color: .3,.3,.3,1
This is a known issue in Kivy, that apparently hasn't been fixed yet. Refer to those links for more info on this case: GitHub, Google Groups, Bountysource. They tell that the issue is that the text is not drawn on the whole pixel, but rather on a part of it.
An unexpected solution in your case: mess around with the padding. Is it important for the padding to be exactly 10? Because I've found out that (12, 12, 12, 12) works perfectly and the text is sharp. That's kinda strange, but I hope it works for you. That's as far as I can help you with this problem.
You could address this issue to Kivy devs, but considering it was discovered in 2014, I'm surprised it wasn't fixed.