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()
Advertisement
Answer
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,
- First create a reference for that label,
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
- Pass exactly the ‘word’ in method
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) ...
- Now make the following changes in function
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.