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.
Related
I am building a simple game using Kivy. I have two classes, Result() and Game(), where both are inheriting from 'Screen'. The Game Class has a function that calculates the the result of the game and produces a message which I want to display on the Result Screen which contains a label and the screen gets displayed after the result is calculated.
My KV file:
<Result>:
BoxLayout:
orientation: "vertical"
Label:
text: "Result Screen"
Label:
id: result_label
Using the id of the Label, 'result_label', I thought using would work `
Result().ids.result_label.text = "message"
`
I tried confirming this using:
print(Result().ids)
And yes it tells me that indeed the id does exist and so i expected that the previous block of code would change the text of the label to "message", but it just shows a Label with no text, and there is no error. So how would you change the text of a label from outside the class?
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.
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.
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"
I would like to create an app in kivy with widgets in a grid and I want to be able to set some widgets to be larger - to occupy more than one cell in a grid.
GridLayout seems the most appropriate, but it seems to not support placing widgets in more than one cell.
To be more specific I want behavour similar to the grid geometry manager from Tkinter, when setting columnspan or rowspan to more than 1.
Like this:
(widget)(widget)(widget)
( bigger widget )(widget)
...
I would prefer to be able to do this using existing kivy layouts instead of having to write my own layout class to handle this, but if no other option is possible, this is also ok.
Another option here is to have a GridLayout with 1 column and populate each row with a BoxLayout with orientation="horizontal". You can then format each BoxLayout (row) as you want.
For more info on the BoxLayout: http://kivy.org/docs/api-kivy.uix.boxlayout.html
I don't think a GridLayout is really suitable, it just isn't designed for quite that usage.
If I personally had to do this, I'd probably make my own Layout class, it wouldn't need a very complicated do_layout method.
One possible start point would be the SparseGridLayout I made a while ago. You could very easily add column and row span properties to it...actually, I'll probably add them myself now that you've given me the idea!
That might not be ideal if you have a big grid full of widgets, in which case something similar to a gridlayout might be better, or possibly a combination of multiple layouts if the spanning widgets are in a particular pattern.
Lets assume you have a GridLayout with two columns and you want to span the first row.You can add Two FloatLayout whereby the first FloatLayout will contain the widget you would like to span while the second Layout will have row and height values to zero.This would archive a span effect
here is an example of .kv span effect
GridLayout:
cols:2
FloatLayout: # The first FloatLayout in the first column in the gridLayout
size_hint:None,None
size: 0,50
BoxLayout:
size_hint: None,None
size: root.width-40,50
pos_hint: {'x':.5,'center_y':.5}
BoxLayout:
padding:0,0,5,0
Label:
id:lbl_unknown
text:'Accession number :'
TextInput:
text:''
FloatLayout: # The second FloatLayout in the second column of the gridLayout
size_hint:None,None
size:0,0
Label:
text:'Label 1:'
TextInput:
Label:
text:'Label 2:'
TextInput:
An easy work around is to pack BoxLayout objects into any type of parent layout you want using your better judgement to decide the orientation of each subsequent BoxLayout
(decided to use box layouts for almost all of my own project over any gridlayout)
This is my class:
class AuthPage(BoxLayout):
def __init__(self, **kwargs):
super(AuthPage, self).__init__(**kwargs)
self.orientation = 'vertical'
self.add_widget(Label(text='Authenticate'))
unameRow = BoxLayout(orientation='horizontal')
unameRow.add_widget(Label(text='User Name'))
unameRow.username = TextInput(multiline=False)
unameRow.add_widget(unameRow.username)
self.add_widget(unameRow)
pwordRow = BoxLayout(orientation='horizontal')
pwordRow.add_widget(Label(text='password'))
pwordRow.password = TextInput(password=True, multiline=False)
pwordRow.add_widget(pwordRow.password)
self.add_widget(pwordRow)
self.add_widget(Button(text='authenticate'))