call a class from another on python kivy button press - python-3.x

i am working with kivy and i wrote this code.
from kivy.app import App
from kivy.uix.button import Button
from kivy.graphics import Rectangle
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.widget import Widget
class Main(Widget):
def __init__(self,**kwargs):
super().__init__(**kwargs)
pass
def on_press(self):
sub()
class sub(Widget):
def __init__(self,**kwargs):
super().__init__(**kwargs)
pass
class Rect(App):
def build(self):
return Main()
if __name__=='__main__':
Rect().run()
.kv file
<Main>:
FloatLayout:
canvas:
Rectangle:
pos:100,0
size:200,200
Button:
text:'Click'
on_press:root.on_press()
<Sub>:
FloatLayout:
canvas:
Rectangle:
pos:100,0
size:400,400
when i run the code,the window showing rectangle and button opens up. when i click on button, i expect to show a bigger rectangle but nothing actually happens.what should i do to dislay the bigger rectangle which is defined in another class by clicking 'click'.Thanks in advance.

First of all, the code you put here contains some errors, you are instantiating an object called main() instead of the object created Main() with capitalized M, in Rect class.
About what you are wanting, when the action on_press() is called, you are instantiating an object of type sub(), but you are not placing it inside the desired widget, that is, the object is actually being created, but not appears on the screen.
To solve this you need to add this newly created object to your main widget, in that case just call self.add_widget()
The code with the fixes are:
RectApp.py
from kivy.app import App
from kivy.uix.button import Button
from kivy.graphics import Rectangle
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.widget import Widget
class Main(Widget):
def __init__(self,**kwargs):
super().__init__(**kwargs)
pass
def on_press(self):
self.add_widget(Sub())
class Sub(Widget):
def __init__(self,**kwargs):
super().__init__(**kwargs)
pass
class RectApp(App):
def build(self):
return Main()
if __name__=='__main__':
RectApp().run()
rect.kv
<Main>:
FloatLayout:
canvas:
Rectangle:
pos: 100, 0
size: 200, 200
Button:
text: 'click'
on_press: root.on_press()
<Sub>:
FloatLayout:
canvas:
Rectangle:
size: 400, 400
pos: 300, 0

Related

How to change background color in kivy?

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

How to pass data to a custom widget from kv language

I want to pass a variable to the class of a custom widget to construct it.
Python:
class Customwidget(BoxLayout)
mystring = StringProperty()
def __init__(self, **kwargs):
super(Customwidget, self).__init__(**kwargs)
print(mystring)
Kivy
Root:
BoxLayout:
orientation: 'vertical'
Customwidget:
mystring: 'stringcontents'
When this is executed, mystring remains empty. How do I pass it to the class such that it can be used within init for logic in defining the widget's contents?
Problem - empty string
When this is executed, mystring remains empty. How do I pass it to the
class such that it can be used within init for logic in defining the
widget's contents?
Root Cause
The load_kv() function is called from run(), therefore,
any widget whose styling is defined in this kv file and is created
before run() is called (e.g. in __init__), won’t have its styling
applied. Note that build() is called after load_kv has been
called.
Solution
Use Kivy Clock schedule_once() method to invoke the print() function after Kivy completed styling.
Snippets
def __init__(self, **kwargs):
super(Customwidget, self).__init__(**kwargs)
Clock.schedule_once(lambda dt: print(f"mystring={self.mystring}"), 0.02)
Example
main.py
from kivy.base import runTouchApp
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import StringProperty
from kivy.clock import Clock
class Customwidget(BoxLayout):
mystring = StringProperty()
def __init__(self, **kwargs):
super(Customwidget, self).__init__(**kwargs)
Clock.schedule_once(lambda dt: print(f"mystring={self.mystring}"), 0.02)
runTouchApp(Builder.load_string("""
Screen:
BoxLayout:
orientation: 'vertical'
Customwidget:
mystring: 'stringcontents'
"""))

How do I create a button with Kivy?

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

How to load string from text file to kivy label, Python 3.5

I've been searching around for answers on stackoverflow for a couple of days now to be honest but I could not find the thing for me, lets say I have a text file named bind.txt with a couple lines of text, how can i load that text file to a kivy label? be it directly or indirectly. I've been trying to teach myself python and this is kind of in the way of me building my first app. Thank you in advance, and heres the code.
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.scrollview import ScrollView
from kivy.uix.widget import Widget
from kivy.uix.boxlayout import BoxLayout
from kivy.lang import Builder
from kivy.properties import StringProperty
from kivy.uix.screenmanager import ScreenManager, Screen, FadeTransition
class MainScreen(Screen):
pass
class MainLabel(ScrollView):
text = StringProperty("")
class ScreenManagement(ScreenManager):
pass
presentation = Builder.load_file("bind.kv")
class MainApp(App):
def build(self):
return presentation
if __name__ == "__main__":
MainApp().run()
And the kv file.
#: import FadeTransition kivy.uix.screenmanager.FadeTransition
ScreenManagement:
transition: FadeTransition()
MainScreen:
<MainLabel>:
text: #bind.txt here, somehow..
Label:
text: root.text
font_size: 15
text_size: self.width, None
size_hint_y: None
height: self.texture_size[1]
<MainScreen>:
name: "main"
canvas.before:
Rectangle:
pos: self.pos
size: self.size
source: 'img/Fundal.png'
MainLabel
You can open file in reading mode, store contents in a variable and assign it to the text property.
For an example
with open("bind.txt") as f:
contents = f.read()
main_label.text = contents # main_label is an instance of kivy's Label class.

How do I set minimum allowable width/height for widget/layout in Kivy?

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()

Resources