So I am a beginner in kivy. I have written a programm that reads sentences from a list and displays them in a Boxlayout as buttons. The Boxlayout is in a Floatlayout, so I can control where the sentences are located. If I click one of the sentences, it splits into buttons for each word. So far so good. Now I want to create a Label, that shows up somewhere below the Boxlayout. It should show up whenever a word button is clicked, and display the same text as the button. So lets say I have this sentence as a Button:
| Hello World, this is an example sentence. |
If I click the sentence:
| Hello || World || this || is || an || example || sentence |
The words should split into indivudal buttons. When I click for example the 'sentence' Button, a Label should show up somewhere below having the text 'sentence'
.py:
import kivy
from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.label import Widget, Label
from kivy.config import Config
sentences = ['This is example sentence 1.', 'This is example sentence 2.', 'This is example sentence 3.', 'This is example sentence 4.', 'This is example sentence 5.', 'This is example sentence 6.']
words = [ ['This', 'is' , 'example' , 'sentence' , '1' ], ['This', 'is' , 'example' , 'sentence' , '2' ], ['This', 'is' , 'example' , 'sentence' , '3' ], ['This', 'is' , 'example' , 'sentence' , '4' ], ['This', 'is' , 'example' , 'sentence' , '5' ], ['This', 'is' , 'example' , 'sentence' , '6' ] ]
class AdaptiveButton(Button):
"""This button takes as much space as it needs to contain its text."""
def __init__(self, **kwargs):
super(AdaptiveButton, self).__init__(**kwargs)
self.size_hint = (None, None)
self.bind(texture_size = self.setter("size"))
class Boxlayout(BoxLayout):
"""This will arrange all the necessary widgets."""
def __init__(self, **kwargs):
super(Boxlayout, self).__init__(**kwargs)
self.orientation = "vertical"
self.spacing = "10dp"
for i, line in enumerate(sentences):
abtn = AdaptiveButton(text = line, font_size=30)
abtn.bind(on_press = lambda btn, j = i : self.destroy_then_create(btn, j))
self.add_widget(abtn)
def destroy_then_create(self, btn, index):
self.remove_widget(btn)
box = BoxLayout(size_hint = (None, None), spacing = "10dp")
box.bind(minimum_size = box.setter("size"))
sentence = words[index]
i = len(sentences)-index-1
for word in sentence:
abtn = AdaptiveButton(text = word)
abtn.bind(on_press=lambda btn, j=i: show(word)) # Here is the function for #the label being binded
box.add_widget(abtn)
self.add_widget(box, i)
class Meaningclass(Label): # Label class
pass
def show(k): #function for the Label
MeC = Meaningclass()
Meaning = Label(text=k, font_size=30)
MeC.add_widget(Meaning)
class MyApp(App):
def build(self):
self.icon = 'budspencer.png'
# creating Floatlayout
Fl = FloatLayout()
Box = Boxlayout(pos_hint={'x': .23, 'y': .58})
meaning = Meaningclass(pos_hint={'x': .9, 'y': .1})
Fl.add_widget(Box)
Fl.add_widget(meaning) #Here we add the Label to the FloatLayout
# return the layout
return Fl
# run the App
if __name__ == "__main__":
MyApp().run()
The problem is that you are actually adding a label into another label in your function show
but you never accessed the label you've already added to the app's subclass.
The fixes are as follows,
def build(self):
...
Box = Boxlayout(pos_hint={'x': .23, 'y': .58})
# Create a reference of the label with 'self'.
self.meaning = Meaningclass(pos_hint={'x': .2, 'y': .1}, font_size=30) # Reduce it so that it doesn't go out of the screen.
Fl.add_widget(Box)
Fl.add_widget(self.meaning) #Here we add the Label to the FloatLayout
destroy_then_create
as before using kwarg., ...
for word in sentence:
abtn = AdaptiveButton(text = word)
abtn.bind(on_press=lambda btn, w=word: show(w)) # Pass the word only as before using kwarg.
box.add_widget(abtn)
...
show
,def show(k): #function for the Label
# Grab the running app instance.
app = App.get_running_app()
# Access the label you already added to the app's subclass and set the text.
app.meaning.text = k
You could've added this function show
anywhere in your code but remember to access the app instance in whatever way is suitable.