Search code examples
pythonbuttonlayoutkivylabel

Kivy - Labels, Buttons and Layouts


HelloWorld! First of all, I'm new to the English version of this page. I think my English is good, but if make any mistakes let me know and I'll fix it. Second, the code I wrote (I'll show you in a minute) is probably not the most efficient, but I only want it to work. Here's the thing...

I'm practicing with kivy and I decided to make a program which will create an anagram out of a list of words, the user will have to guess the word and the program will tell if it is correct or not. I made a program that does that, but I was having problems with the 'new word' button (a new game, so to speak), so I've decided to make a new code (I'll show you the old version in a comment). And this new code fails from the beginning. When I add the labels and buttons, not only I can't click on them, but they are also shown on the bottom-left part of the screen, and very small. The image shows the result: Labels, Buttons and RelativeLayout.

from kivy.app import App
from kivy.uix.relativelayout import RelativeLayout
from kivy.uix.button import Button
from kivy.uix.label import Label
from random import choice, shuffle
from kivy.core.window import Window

Window.clearcolor = (.10, .54, 1, 1)
Window.size = (500,300)

# ------- THIS PART SHOULD GO ON A SEPARATE FILE ----------------------------
list_of_words = ['ELEPHANT', 'LION', 'COCODRILE', 'MONKEY', 'KANGAROO']

def create_anagram():
    # Takes a word from the list and shuffles the letters to create the anagram
    choices = choice(list_of_words)
    list_letters = []
    for item in choices:
        list_letters.append(item)
    shuffle(list_letters)
    choices = ''.join(list_letters)

    return choices
# ----------------------------------------------------------------------------
class Anagram(RelativeLayout):

    def __init__(self, **kwargs):
        super(Anagram, self).__init__(**kwargs)
        # These are all variables which will be used later on.

        self.choices = create_anagram()
        self.window = RelativeLayout()
        self.font_size = 20                     
        self.letters, self.underscores = [],[]  
        self.ind = 0                            # Index used on chose_letter()
        self.size_x, self.size_y = 100, 50      # Sizes for the labels and button
        self.pos_x = 0                          # Initial position for the labels and buttons
        self.word = ''                          # will concatonate the letters choosen

        self.new_game()

    def new_game(self):
        with self.canvas.after:
            for item in self.choices:
                self.letters.append(Button(text=item,
                                        size_hint=(1/len(self.choices), 0.2),
                                        pos_hint = {'x': self.pos_x, 'top': .8},
                                        font_size = self.font_size,
                                        color='#688FF8',
                                        background_color = '#1F48F2',
                                        disabled = False))

                self.underscores.append(Label(text='_',
                                        size_hint=(1/len(self.choices), 0.2),
                                        pos_hint = {'x': self.pos_x, 'top': 0.4},
                                        size=(self.size_x, self.size_y),
                                        font_size = self.font_size,
                                        color = '#FFFFFF'))

                self.pos_x += 1/len(self.choices)

            # Adding buttons for the letters and the underscores.
        for item in self.letters:
            self.window.add_widget(item)
        for item in self.underscores:
            self.window.add_widget(item)

class MainAnagramApp(App):
    def build(self):
        return Anagram()

if __name__ == '__main__':
    MainAnagramApp().run()'''

So that's it. That's the code and the problem. Any idea why this happens?

By the way, I've tried without the "with self.canvas" but it doesn't even show the widgets. I also tried changing the layout (Grid, Anchor, etc.), but the problem is exactly the same.

Thanks!


Solution

  • You don't need the self.window = RelativeLayout() or the with self.canvas.after:. Here is a modified version of your Anagram class:

    class Anagram(RelativeLayout):
    
        def __init__(self, **kwargs):
            super(Anagram, self).__init__(**kwargs)
            # These are all variables which will be used later on.
    
            self.choices = create_anagram()
            # self.window = RelativeLayout()
            self.font_size = 20
            self.letters, self.underscores = [],[]
            self.ind = 0                            # Index used on chose_letter()
            self.size_x, self.size_y = 100, 50      # Sizes for the labels and button
            self.pos_x = 0                          # Initial position for the labels and buttons
            self.word = ''                          # will concatonate the letters choosen
    
            self.new_game()
    
        def new_game(self):
            # with self.canvas.after:
            for item in self.choices:
                self.letters.append(Button(text=item,
                                        size_hint=(1/len(self.choices), 0.2),
                                        pos_hint = {'x': self.pos_x, 'top': .8},
                                        font_size = self.font_size,
                                        color='#688FF8',
                                        background_color = '#1F48F2',
                                        disabled = False))
    
                self.underscores.append(Label(text='_',
                                        size_hint=(1/len(self.choices), 0.2),
                                        pos_hint = {'x': self.pos_x, 'top': 0.4},
                                        size=(self.size_x, self.size_y),
                                        font_size = self.font_size,
                                        color = '#FFFFFF'))
    
                self.pos_x += 1/len(self.choices)
    
            # Adding buttons for the letters and the underscores.
            for item in self.letters:
                self.add_widget(item)
            for item in self.underscores:
                self.add_widget(item)
    

    And note that the Buttons and Labels are added using self.add_widget() not self.window.add_widget().

    In your code, when you create a Button inside a with self.canvas.after:, the canvas instructions for drawing a Button are added to the canvas.after of the Anagram instance. But the actual Button widget is not added. So you have an image of a Button, but it will not function as a Button.