Pacu
Pacu

Reputation: 163

Separate layout and controller in kivy gui

I'm writing a kivy app and I want to keep the layout and the controller separate. Here is the sample code of what I'm trying to accomplish:

from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button
from kivy.uix.textinput import TextInput
from kivy.uix.label import Label


class AppLayout(BoxLayout):
    def __init__(self, **kwargs):
    super(AppLayout, self).__init__(**kwargs)
    self.orientation = 'vertical'
    self.padding = [10, 10, 10, 10]
    self.text_bar = TextInput(hint_text='Write Something',
                              multiline=False,
                              padding=[5, 5, 5, 5],
                              font_size=20,
                              size_hint=(0.8, 1))
    self.button = Button(text="Do Something",
                                size_hint=(0.2, 1))

    self._text_bar_box = BoxLayout(pos_hint={'top': 1},
                                   size_hint=(1, 0.04),
                                   orientation='horizontal')
    self._text_bar_box.add_widget(self.text_bar)
    self._text_bar_box.add_widget(self.button)
    self.add_widget(self._text_bar_box)

    self.label = Label(text="Your text will be displayed here", font_size=20)
    self._big_box = BoxLayout(padding=[10, 10, 10, 10],
                              size_hint=(1, 0.65))
    self._big_box.add_widget(self.label)
    self.add_widget(self._big_box)


class AppController:
    def __init__(self, app_layout: AppLayout):
        super(AppController, self).__init__()
        self.app_layout = app_layout
        self.app_layout.search_button.bind(on_press=self.get_string)

    def get_string(self):
        self.app_layout.label.text = self.app_layout.text_bar.text


class MainApp(App):
    def build(self):
        app_layout = AppLayout()
        AppController(app_layout)
        return app_layout


if __name__ == "__main__":
    MainApp().run()

This is how the gui appears: Here is what the the GUI looks like When I press the button the text in the text_bar is not displayed in the label. How can I accomplish this?

Upvotes: 1

Views: 626

Answers (1)

zeeMonkeez
zeeMonkeez

Reputation: 5177

There are a few other issues with the example you posted, however what really breaks it is that here

class MainApp(App):
    def build(self):
        app_layout = AppLayout()
        AppController(app_layout)
        return app_layout

the instance of AppController gets garbage collected immediately. Save it as a property of MainApp:

self.controller = AppController(app_layout)

Edit: Full example

The callback expects one extra argument,instance: the object that fired the event.

from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button
from kivy.uix.textinput import TextInput
from kivy.uix.label import Label

class AppLayout(BoxLayout):
    def __init__(self, **kwargs):
        super(AppLayout, self).__init__(**kwargs)
        self.orientation = 'vertical'
        self.padding = [10, 10, 10, 10]
        self.text_bar = TextInput(hint_text='Write Something',
                                  multiline=False,
                                  padding=[5, 5, 5, 5],
                                  font_size=20,
                                  size_hint=(0.8, 1))
        self.button = Button(text="Do Something",
                                    size_hint=(0.2, 1))

        self._text_bar_box = BoxLayout(pos_hint={'top': 1},
                                       size_hint=(1, 0.04),
                                       orientation='horizontal')
        self._text_bar_box.add_widget(self.text_bar)
        self._text_bar_box.add_widget(self.button)
        self.add_widget(self._text_bar_box)

        self.label = Label(text="Your text will be displayed here", font_size=20)
        self._big_box = BoxLayout(padding=[10, 10, 10, 10],
                                  size_hint=(1, 0.65))
        self._big_box.add_widget(self.label)
        self.add_widget(self._big_box)


class AppController:
    def __init__(self, app_layout= AppLayout):
        self.app_layout = app_layout
        self.app_layout.button.bind(on_press=self.get_string)

    def get_string(self, *args):
        self.app_layout.label.text = self.app_layout.text_bar.text


class MainApp(App):

    def build(self):
        app_layout = AppLayout()
        self._controller = AppController(app_layout)
        return app_layout


if __name__ == "__main__":
    MainApp().run()

Upvotes: 2

Related Questions