I have just started learning kivy. Please bear with me in case of my absurdity and stupidity.
Here just copy pasted the code from official site.
import kivy
from kivy.app import App
from kivy.uix.label import Label
class MyApp(App):
def build(self):
return Label(text='Hello world',)
if __name__ == '__main__':
MyApp().run()
And the output is in the link.
What I essentially wanted to know that how I can change the background (currently black) to some different color.
I have read some parts of documents ,Found documentation for changing color of widget but screen (probably not the accurate word).
I would really appreciate the advices and suggestions.
Thanks in advance.
You can use the canvas of the Label to paint a background color like this:
import kivy
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.label import Label
class MyLabel(Label):
pass
Builder.load_string('''
<MyLabel>:
canvas.before:
Color:
rgba: 1,0,0,1
Rectangle:
pos: self.pos
size: self.size
''')
class MyApp(App):
def build(self):
return MyLabel(text='Hello world',)
if __name__ == '__main__':
MyApp().run()
To do this without using the kv language is more complicated because you must set up the binding to pos and size that the kv language does for you automatically. Here is the equivalent without using kv:
from kivy.app import App
from kivy.graphics import Color, Rectangle
from kivy.uix.label import Label
class MyLabel(Label):
def __init__(self, **kwargs):
super(MyLabel, self).__init__(**kwargs)
with self.canvas.before:
Color(1, 0, 0, 1)
self.rect = Rectangle(pos=self.pos, size=self.size)
def on_pos(self, *args):
self.rect.pos = self.pos
def on_size(self, *args):
self.rect.size = self.size
class MyApp(App):
def build(self):
return MyLabel(text='Hello world',)
if __name__ == '__main__':
MyApp().run()
For more information about the canvas, see the documentation
Related
Im am trying to display my arduino data into my kivy window under label but it says an error " ValueError: Label.text accept only str". Anyone able to help?
Below is my python kivy file
test.py file
import serial
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import Screen, ScreenManager
from kivy.uix.button import Button
class MainWindow(Screen):
def tm(self):
while (1):
with serial.Serial('COM4', 9600) as ser:
x = ser.readline()
return str(x)
ser.close()
class WindowManager(ScreenManager):
pass
hi = Builder.load_file("test.kv")
class MyMainApp(App):
def build(self):
return hi
if __name__ == "__main__":
MyMainApp().run()
test.kv file
WindowManager:
MainWindow:
<MainWindow>:
Label:
size: 75, 50
size_hint: None, None
pos_hint: {'right': 1, 'bottom': 1}
background_color: (1.0, 0.0, 0.0, 1.0)
text: root.x
I see a few problems in your example.
Be careful naming your variables. x for example, is almost always a NumericProperty of the widget already.
When you reference an attribute in python, use self, or the widgets x in your case wil not change.
When you have a loop in kivy, you will block the application. So you either use Clock or threading. I will suggest threading instead of Clock when using serial, because readline() will also block the app if waiting for an input.
You never actually call tm()
So, heres what I would change in MainWindow class, and a few more imports.
import serial
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import Screen, ScreenManager
from kivy.uix.button import Button
from kivy.properties import StringProperty
from kivy.clock import mainthread
import threading
KV = """
WindowManager:
MainWindow:
<MainWindow>:
Label:
size: 75, 50
size_hint: None, None
pos_hint: {'right': 1, 'bottom': 1}
background_color: (1.0, 0.0, 0.0, 1.0)
text: root.label_text
"""
class MainWindow(Screen):
label_text = StringProperty("")
def __init__(self, **kwargs):
super(MainWindow, self).__init__(**kwargs)
threading.Thread(target=self.tm).start()
def tm(self):
while (1):
with serial.Serial('COM4', 9600) as ser:
value = ser.readline()
ser.close()
self.update_label(value.decode("ascii").strip())
#mainthread
def update_label(self, value):
self.label_text = value
class WindowManager(ScreenManager):
pass
class MyMainApp(App):
def build(self):
return Builder.load_string(KV)
if __name__ == "__main__":
MyMainApp().run()
Be sure to use mainthread when changing any ui element in another thread. In this case when you change a stringproperty that will change the display.
I am hoping to eventually create a button to pause/start/end a pong app I built as a learning exercise. However, to understand the basics of how to create a button in the first place, and assign a response to it I am just wanting to create a button that notifies me every time the button state changes. Here is the python code I have so far:
import kivy.uix.button as kb
from kivy.app import App
from kivy.uix.widget import Widget
class Button_Widget(Widget):
def callback(instance, value):
print('The button <%s> state is <%s>' % (instance, value))
btn1 = kb.Button(text='Hello World 1')
btn1.bind(on_press=callback)
class ButtonApp(App):
def build(self):
button = Button_Widget()
return button
with the associated kv file:
#:kivy 1.0.9
<Button_Widget>:
size: 100, 100
canvas:
Rectangle:
pos = self.pos
size = self.size
So far the only resources I have found are these (1 and 2) Kivy turorials, which aren't too helpful. Or at least, I don't understand their language enough yet for them to be useful
Let's see the simplest code to create a button in kivy
from kivy.app import App
from kivy.uix.button import Button
class your_app_name(App):
def build(self):
button = Button(text="Button")
return button
your_app_name().run()
You can also add command or event to a button by adding on_press= function_name
Solution
In the class Button_Widget(), you have to override the constructor, __init__() so that you can add the button widget to the root widget. Please refer to the example for details.
References
Programming Guide » Kivy Basics » Create an application
Programming Guide » Kv language
Kivy Language
Event dispatcher » bind() Bind an event type or a property to a callback.
Example
main.py
import kivy.uix.button as kb
from kivy.app import App
from kivy.uix.widget import Widget
class Button_Widget(Widget):
def __init__(self, **kwargs):
super(Button_Widget, self).__init__(**kwargs)
btn1 = kb.Button(text='Hello World 1')
btn1.bind(on_press=self.callback)
self.add_widget(btn1)
def callback(self, instance):
print('The button %s state is <%s>' % (instance, instance.state))
class ButtonApp(App):
def build(self):
return Button_Widget()
if __name__ == "__main__":
ButtonApp().run()
button.kv
#:kivy 1.10.1
<Button_Widget>:
size: 100, 100
canvas:
Rectangle:
pos: self.pos
size: self.size
Output
I was under the impression that svg worked like a canvas instruction.
However, I am unable to get the svg to change color. Part of the code below is using the code provided in the sample at Kivy's github.
with self.canvas:
Color(0.3833, 1.0, 0.0)
Entire Code
import sys
from glob import glob
from kivy.uix.scatter import Scatter
from kivy.app import App
from kivy.graphics.svg import Svg
from kivy.core.window import Window
from kivy.uix.floatlayout import FloatLayout
from kivy.lang import Builder
from random import randint
from kivy.graphics import *
Builder.load_string("""
<SvgWidget>:
do_rotation: False
<FloatLayout>:
id: svg_holder
canvas.before:
Color:
rgb: (1, 1, 1)
Rectangle:
pos: self.pos
size: self.size
""")
class SvgWidget(Scatter):
def __init__(self, filename, **kwargs):
super(SvgWidget, self).__init__(**kwargs)
with self.canvas:
Color(0.3833, 1.0, 0.0)
svg = Svg(filename)
self.size = svg.width, svg.height
def remove(self):
print('remove', self)
class SvgApp(App):
def build(self):
self.root = FloatLayout()
for i in range(6):
svg = SvgWidget('star.svg', size_hint=(None, None))
self.root.add_widget(svg)
svg.scale = randint(1,4)
svg.center = randint(0,Window.width), randint(0,Window.height)
if __name__ == '__main__':
SvgApp().run()
I don't think what you asking for is possible since the Svg contains Color instructions itself, so it overrides yours... Maybe your code can use an overlay with opacity to make the desired effect
In my exercise, the widget "TextInput" doesn't update its position and its size, when i resize the window; instead the widget "Label" updates correctly its size and its position. Why? Can someone help me, please?
from kivy.app import App
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.label import Label
from kivy.uix.textinput import TextInput
from kivy.graphics import Color, Rectangle
class MyWidget(FloatLayout):
def __init__(self, *args):
super(MyWidget, self).__init__(*args)
with self.canvas.before:
Color(255, 255, 255, 1)
self.rect = Rectangle(size=self.size, pos=self.pos)
def update_rect(instance, value):
instance.rect.pos = instance.pos
instance.rect.size = instance.size
self.bind(pos=update_rect, size=update_rect)
self.add_widget(TextInput(text='InsertText', multiline=False, size_hint=(1, 0.04),
pos_hint={'right': 1, 'y': 0.879}, font_size='12sp'))
self.add_widget(Label(text='label example', color=(0,0,255,0.5), pos_hint={'center_x': 0.5, 'center_y': 0.5}))
class MyApp(App):
def build(self):
return MyWidget()
if __name__ == '__main__':
MyApp().run()
I have BoxLayout with 3 elements, I need that first and last elements to occupy minimum available space. Middle element has fixed proportion (1:1), so when I resize the window, side elements become too small and content go out of it. I need e.g. label's (or button's, or even set's of different elements) text to be always inside the label. This size shouldn't be more, so I can say it should be fixed size depending on its content.
UPDATE:
I've made a mistake, size can be more, but not less. How it should be then?
UPDATE:
So it's my BoxLayout:
When I expand the window, only side parts should expand:
And when I constrict the window, side parts should have some minimum size:
So it's kind of fixed minimum I think.
Content size of Label is avaiable through texture_size property, so you can set size_hint to None and bind size to content size:
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button
from kivy.lang import Builder
kv = '''
<MyButton>:
size_hint: None, 1
size: self.texture_size
'''
Builder.load_string(kv)
class MyButton(Button):
pass
class MyWidget(BoxLayout):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.add_widget(MyButton(text="Fixed size button"))
self.add_widget(Button(text="Normal button"))
self.add_widget(MyButton(text="Fixed size button"))
class MyApp(App):
def build(self):
return MyWidget()
if __name__ == '__main__':
MyApp().run()
You should also check text_size property. From documentation: "By default, the label is not constrained to any bounding box. You can set the size constraint of the label with this property. The text will autoflow into the constrains. So although the font size will not be reduced, the text will be arranged to fit into the box as best as possible, with any text still outside the box clipped". For example:
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button
from kivy.lang import Builder
kv = '''
<MyButton>:
text_size: self.size
valign: "middle"
halign: "center"
'''
Builder.load_string(kv)
class MyButton(Button):
pass
class MyWidget(BoxLayout):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.add_widget(MyButton(text="Example text which is too long to fit in one line"))
self.add_widget(Button(text="Normal button"))
self.add_widget(MyButton(text="Example text which is too long to fit in one line"))
class MyApp(App):
def build(self):
return MyWidget()
if __name__ == '__main__':
MyApp().run()
UPDATE
If you want even more control about the way widgets scale, you can create method which calculate values for widgets and have it binded to changing size property (either bind or implementing on_size()). For example:
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.widget import Widget
from kivy.uix.label import Label
from kivy.lang import Builder
from functools import partial
kv = '''
<CentralWidget>:
pos_hint: {'center_y': .5}
size_hint: None, None
canvas:
Color:
rgb: 1, 0, 1
Rectangle:
pos: self.pos
size: self.size
<SideWidget>:
pos_hint: {'center_y': .5}
size_hint: None, 1
canvas.before:
Color:
rgb: 0, 0, 1
Rectangle:
pos: self.pos
size: self.size
'''
Builder.load_string(kv)
class CentralWidget(Widget):
pass
class SideWidget(Label):
pass
class MyWidget(BoxLayout):
def __init__(self, **kwargs):
super().__init__(**kwargs)
w1 = SideWidget(text="............................")
w2 = CentralWidget()
w3 = SideWidget(text="............................")
self.add_widget(w1)
self.add_widget(w2)
self.add_widget(w3)
def on_size(self, *args):
# self.size - size of parent widget
# self.children - children of widget
# self.children[0].texture_size - sife of content of selectend children widget
# self.children[0].size - size of selected children widget to set
if((self.size[0]-500)/2 > self.children[0].texture_size[0]):
self.children[0].size = ((self.size[0]-500)/2, 0)
self.children[1].size = (500, 500)
self.children[2].size = ((self.size[0]-500)/2, 0)
else:
self.children[1].size = (self.size[0]-2*self.children[0].texture_size[0], self.size[0]-2*self.children[0].texture_size[0])
class MyApp(App):
def build(self):
return MyWidget()
if __name__ == '__main__':
MyApp().run()