Search code examples
pythonpython-3.xkivy

How to make two classes interact between them on the TabbedPanel of the Kivy Framework?


There are three classes:


from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from kivy.uix.checkbox import CheckBox
from kivy.uix.label import Label
from kivy.uix.scrollview import ScrollView
from kivy.uix.tabbedpanel import TabbedPanel, TabbedPanelItem, TabbedPanelHeader
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button
from kivy.uix.textinput import TextInput
from kivy.uix.filechooser import FileChooserIconView


class SimplePanel(BoxLayout):
    def __init__(self, **kwargs):
        super(SimplePanel, self).__init__(**kwargs)
        self.text_area = TextInput()
        self.add_widget(self.text_area)
        self.text_area.text += f'Hello, SimplePanel\n'


class FileChooserBoxLayout(BoxLayout):
    def __init__(self, **kwargs):
        super(FileChooserBoxLayout, self).__init__(**kwargs)
        self.orientation = 'vertical'
        self.file_chooser = FileChooserIconView(path='.', filters=['*'])
        self.add_widget(self.file_chooser)
        self.save_button = Button(text='Save', on_release=self.save_file, size_hint=(1, None), height=70) #
        self.add_widget(self.save_button)
        self.save_path = None
    
    def save_file(self, instance):
        selected_file = self.file_chooser.selection and self.file_chooser.selection[0]
        if selected_file:
            self.save_path = selected_file
            print(f'Saving file: {self.save_path}')
        else:
            print('No file selected.')
    
    def get_save_path(self):
        return self.save_path


class MyTabbedPanel(TabbedPanel):
    def __init__(self, **kwargs):
        super(MyTabbedPanel, self).__init__(**kwargs)
        
        self.tab_width = 200
        self.default_tab_text = 'Panel 1'
        self.default_tab_content = Label(text='Hello, World!')

        simple_panel = SimplePanel()
        filechooserboxlayout = FileChooserBoxLayout()
        
        tab2 = TabbedPanelHeader(text='Panel 2')
        tab2.content = simple_panel
        
        tab3 = TabbedPanelHeader(text='Panel 3')
        tab3.content = filechooserboxlayout

        tab4 = TabbedPanelHeader(text='Panel 4')
        content4 = Label(text='Content of Panel 4')
        tab4.content = content4

        # Add the panels to the TabbedPanel
        self.add_widget(tab2)
        self.add_widget(tab3)
        self.add_widget(tab4)


class MyApp(App):
    def build(self):
        return MyTabbedPanel()


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

The class SimplePanel has the text_area. The class FileChooserBoxLayout chooses a path of a file with using FileChooserIconView. The class MyTabbedPanel aggregates the SimplePanel and FileChooserBoxLayout with the help of TabbedPanel.

A problem is to append the file path to the text_area. How to do it?

As a variant I try to use a class Mediator to integrate this possibility between the two classes. Here is the code:


class Mediator:
    def __init__(self, simple_panel, file_chooser_box_layout):
        self.simple_panel = simple_panel
        self.file_chooser_box_layout = file_chooser_box_layout
        self.file_chooser_box_layout.save_button.bind(on_release=self.update_text_area)
    
    def update_text_area(self, instance):
        print('Hello, World!!!')
        save_path = self.file_chooser_box_layout.get_save_path()
        if save_path:
            self.simple_panel.text_area.text += f'{save_path}\n'
        else:
            print('No file selected.')

And then the MyTabbedPanel must be corrected with such a way:


class MyTabbedPanel(TabbedPanel):
    def __init__(self, **kwargs):
        super(MyTabbedPanel, self).__init__(**kwargs)
        
        self.tab_width = 200
        self.default_tab_text = 'Panel 1'
        self.default_tab_content = Label(text='Hello, World!')

        simple_panel = SimplePanel()
        filechooserboxlayout = FileChooserBoxLayout()
        mediator = Mediator(simple_panel, filechooserboxlayout)
        
        tab2 = TabbedPanelHeader(text='Panel 2')
        tab2.content = mediator.simple_panel
        
        tab3 = TabbedPanelHeader(text='Panel 3')
        tab3.content = mediator.file_chooser_box_layout

        tab4 = TabbedPanelHeader(text='Panel 4')
        content4 = Label(text='Content of Panel 4')
        tab4.content = content4

        # Add the panels to the TabbedPanel
        self.add_widget(tab2)
        self.add_widget(tab3)
        self.add_widget(tab4)

It's all done to get possibility to append the file path to the text_area but it doesn't work. Are there any ideas how to do it?


Solution

  • In your MyTabbedPanel.__init__() method, you can save a reference to the SimplePanel:

        self.simple_panel = SimplePanel()
        filechooserboxlayout = FileChooserBoxLayout()
    
        tab2 = TabbedPanelHeader(text='Panel 2')
        tab2.content = self.simple_panel
    

    Then, in your FileChooserBoxLayout.save_file():

    def save_file(self, instance):
        selected_file = self.file_chooser.selection and self.file_chooser.selection[0]
        if selected_file:
            self.save_path = selected_file
            print(f'Saving file: {self.save_path}')
            simple_panel = App.get_running_app().root.simple_panel
            simple_panel.text_area.text += self.save_path
    
        else:
            print('No file selected.')