kivy: firing multiple functions on 1 button click - python

I have this code and it works, but I'm sure it's not the way to go properly. In my .kv a button fires two functions in my main.py.
Button:
text: "Press Me"
on_release: root.on_our_btn_release(text_input.text)
on_release: root.get_items(text_input.text)
Next step in my awesome project will be adding a lot more functions that will have to go off when the same button is clicked. This will result in a rather long list like:
Button:
text: "Press Me"
on_release: root.on_our_btn_release(text_input.text)
on_release: root.get_items(text_input.text)
on_release: root.another_function(text_input.text)
on_release: root.andanotherone(text_input.text)
on_release: root.herewegoagain(text_input.text)
on_release: root.this_is_getting_boring(text_input.text)
on_release: root.think_you_got_the_picture(text_input.text)
This looks to me as very ugly code, but I didn't find a pretty way to do this yet.
Anyone? Thanks in advance!
;-) Erik

You could structure this in a number of different ways, and the best option is mostly up to you.
One option if you don't want too many functions in kv is to call a single root.do_everything(), and put all the other calls in that on the python side.

I believe a slightly more elegant solution would be to indent and list the different callbacks.
on_release:
first()
second()
Another possible but ugly solution for this can be to separate the functions with a semicolon.
on_release: first(); second()

You could make use of "on_press" and "on_release". Assign one method/function to "on_press" and the other to "on_release"

Related

Kivy custom widget behaviour

I'm new to programming and playing with Kivy to learn. I came across something weird so have created this small example to demonstrate.
In my text.kv file I have this:
#:kivy 2.0.0
<smallLabel#Label>:
font_size: 40
<bigLabel#Label>:
font_size: 60
BoxLayout:
orientation:'vertical'
padding: 20
spacing: 5
smallLabel:
text: 'Stays the same'
bigLabel:
id: changes
text: 'changes'
And in my python file this:
from kivy.app import App
class TestApp(App):
pass
if __name__ == "__main__":
TestApp().run()
When I run it I get this:
File "/home/marty/Python/datatut/test.kv", line 15
text: 'Stays the same'
^
SyntaxError: invalid syntax
Now, if I change the case of my widget so the first letter is upper-case it works:
<SmallLabel#Label>:
font_size: 40
<bigLabel#Label>:
font_size: 60
BoxLayout:
orientation:'vertical'
padding: 20
spacing: 5
SmallLabel:
text: 'Stays the same'
bigLabel:
id: changes
text: 'changes'
Notice that I only changed the SmallLabel. I left the bigLable as lowercase.
If I do this the other way around, that is leave smallLabel but make BigLabel
It fails with same error.
Why do I need to capitlise the name of my widget and why only the first one?
I did notice in all of the examples that I've seen the first letter is always capitlised for the custom widget name but have not seen that this is a requirement, and if it is, then why does the second widget work if the first one is capitalised?
The KV lang loader needs to be able to distinguish between properties of your widget, and sub widgets, and as you can see both kind are simply a line of text ended by a :, but there is a trick, by assuming that your classes follow PEP8 convention of Capitalized classes and snake_case attributes, it’s able to make the guess correctly.
This is (i agree a bit lightly) indicated in https://kivy.org/doc/stable/guide/lang.html#instantiate-children which states
Note
Widget names should start with upper case letters while property names
should start with lower case ones. Following the PEP8 Naming
Conventions is encouraged.
I assume the second one doesn’t need this guess, as it’s unindented after the first block, so it can’t be an attribute of the parent class (attributes must be before children declaration), so it can only be a child widget, and this rule is not needed in this situation, but i couldn’t find how this happen from a quick glance at the code

why after calling the method my kivymd app won't close?

i've tried using '''App.get_running_app().close()''' but with no results at all, I have read the documentation but have not found anything useful, can you help me please?
Add on_press=lambda x: MDApp.stop(self) to your button if you are using python.
If you are using kv to do this then make a function,
def close_app(self):
MDApp.stop(self)
and add on_press: root.close_app() or on_press: app.close_app()to your kv button

2 FloatLayouts in BoxLayout not formatting correctly

I'm brand new to Kivy, and am working on the UI to get a fairly complex set of widgets to display properly. My root widget is a boxlayout(horiz), and I'm trying to get 2 floatlayouts to appear side by side. But the second floatlayout displays on the left side of the boxlayout over the first floatlayout. I've tried with and without pos_hints and size_hints at the floatlayout level, to no avail. Some base code:
<BoxLayout>:
id: rootwid
orientation: 'horizontal'
FloatLayout:
id: leftside
pos_hint: {'x':0, 'y':0} (Also tried 'right' and 'top' and commenting out the line)
#size_hint: (.5, 1)
(Buttons & Labels here, which lay out properly within the floatlayout)
FloatLayout:
id: rightside
pos_hint: {'x': .5, 'y':0} (Also tried 'right' and 'top' and commenting out the line)
#size_hint: (.5, 1)
(Buttons & Labels here, which lay out properly within the floatlayout)
What am I missing? Thanks!
unless you have a future use for the FloatLayouts, I advise that you replace them with other types of layouts bcoz since they are float, they tend to be independent of the parent.
Try using GridLayout to house the buttons and labels and other widgets
like this;
BoxLayout:
orientation: 'horizontal'
GridLayout:
cols: any
rows: any
# Left widgets added here
GridLayout:
cols: any
rows: any
# Right widgets added here
You can also nest them accordingly, for extensize insight on these run KivyCatalog , an inbuilt python file in kivy-examples,
usually at ~/.local/share/kivy-examples/demo/kivycatalog/main.py for Ubuntu
for windows i think check AppData then local then share, AppData is by default hidden , dont forget that.
KivyCatalog is interative as it shows you changes in your kv code as you write it,try it.

Using a RST Document in a ScrollView using Kivy

I am in a bit of a predicament. While working with Kivy's ScrollView Layout and (Current Experimental) reStructuredText renderer module, I ran into a slight problem. Whenever I run my code, my terminal spams me with:
[CRITICAL] [Clock] Warning, too much iteration done before the next frame. Check your code, or increase the Clock.max_iteration attribute
Now, the application seems to run perfectly fine, until you get to the page with the rST Document inside a ScrollView Layout. That page does all kinds of odd things. The Main scroll view will slowly scroll down, forever, trailing off the page into whiteness, and the rST document is placed oddly, shifted slightly to the left.
When I remove the document though, the screen and application behave perfectly normal, running smoothly. Does anyone have any idea as to how I could fix this, to make the page work correctly? (Did I mention the rST Document was originally in a Carousel, but I took out the carousel to see if that was the problem.)
Here is the Kivy Language Code:
<Page>:
orientation: 'vertical'
ScrollView:
size_hint: (.99, .99)
StackLayout:
size_hint_y: None
id: content_layout
height: self.minimum_height
WrappedLabel:
text: "Test"
font_size: min(root.height, root.width)
RstDocument:
underline_color: 'blue'
text:("Some Text")
Could the problem be that rST Documents are based off of the ScrollView Layout by any chance?
Sometimes height: self.minimum_height and similar stuff are like shooting yourself in a foot. Definitely try to comment out these things first, because if you don't do something fancy, the sizing is the issue.
Now, why is it an issue? StackLayout has its minimum_height set from minimum_size, which is set I think somewhere here and has some initial value that is not zero.
Don't be confused though, minimum_height really defaults to zero at the beginning, but then it's recalculated probably on each added widget or so. If you add on_height: print(self.height) after your height: self.minimum_height, you'll see what I mean.
Why does it do it like that? Simple! You didn't set absolute size for those children (each child has size_hint == [1, 1]).
Also, ScrollView expects size bigger that the ScrollView if I remember correctly (so that it would scroll).
from kivy.lang import Builder
from kivy.base import runTouchApp
from kivy.uix.boxlayout import BoxLayout
Builder.load_string('''
<Test>:
orientation: 'vertical'
ScrollView:
size_hint: (.99, .99)
StackLayout:
size_hint_y: None
id: content_layout
height: self.minimum_height
on_height: print(self.height)
Label:
size_hint: None, None
size: 100, 30
text: "Test"
font_size: min(root.height, root.width)
RstDocument:
size_hint: None, None
size: 100, 1000
underline_color: 'blue'
text:("Some Text")
''')
class Test(BoxLayout): pass
runTouchApp(Test())
Remove size_hint and size from children and you have your too much iteration there.

Using user input from TextInput - Kivy

I am trying to do some simple math in a kivy app using TextInput to allow users to input values. I defined the TextInput in the kv section of the code. I am unsure how to create a simple submit button to assign what's in the TextInput (which is defined in kv) to a variable so that I can do basic math with it in the python section.
You'll want to do something like the following:
BoxLayout:
orientation: 'vertical'
TextInput:
id: ti
Button:
text: 'do something!'
on_press: run_some_function_with_text(ti.text)
run_some_function_with_text would probably most usefully be a method of some other widget, but could be anything else you like, or you could just write the function inline if it's simple.

Categories