pythonkivykivy-language

Kivy: Accessing the data from a filechooser popup in the parent widget


I'm trying to build a widget with 3 buttons, each of which will open a filechooser popup. The popup has two buttons Select and Cancel. When user selects a file and clicks on Select button, the popup closes.

But, now, I don't know how to access the file path from the popup in the main widget. I want to display the file path in a TextInput field, and also pass the file path to a python script. Something like this:

enter image description here

Below is my code:

python:

import kivy

kivy.require('2.3.0')

from kivy.app import App
from kivy.uix.widget import Widget
from kivy.properties import ObjectProperty
from kivy.uix.popup import Popup

class FileSelect(Popup):
    filechooser = ObjectProperty(None)

    def selected(self):
        print(self.filechooser.selection[0])
        return self.filechooser.selection[0]

class Prototype(Widget):
    categories_file_path = ObjectProperty(None)
    categories_file_path_btn = ObjectProperty(None)
    

    def select_press(self):
        self.categories_file_path.text = FileSelect().selected()
        print(FileSelect().selected())


class PrototypeApp(App):
    def build(self):
        return Prototype()

    pass


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

kv file:

#:kivy 2.3.0
#:import Factory kivy.factory.Factory


<FileSelect@Popup>
    filechooser:filechooser
    auto_dismiss: False
    size_hint: 0.5, 0.5
    pos_hint: {"x":0.2, "top":0.9}
    title: "Select File"
    on_dismiss: Factory.Prototype().select_press()

    BoxLayout:
        orientation: "vertical"
        size: root.width, root.height

        FileChooserListView:
            id:filechooser

        GridLayout:
            size_hint: 1, 0.2
            cols:2

            Button:
                text: "Select"
                size_hint: 0.25, 0.1
                pos_hint: {'x':0, 'y':0, 'bottom':1, 'left':1}
                font_size: 12
                on_press: root.selected()
                on_release: root.dismiss()


            Button:
                text: "Close"
                size_hint: 0.25, 0.1
                pos_hint: {'bottom':1, 'right':1}
                font_size: 12
                on_release: root.dismiss()


<Prototype>:
    categories_file_path:categories_file_path
    categories_file_path_btn:categories_file_path_btn
    

    GridLayout:
        cols:2
        size: root.width, root.height

        GridLayout:
            cols:2
            #size: (root.width)/10, root.height

            Label:
                text: "Categories File Path"
            TextInput:
                id:categories_file_path
                multiline:True


            Button:
                id:categories_file_path_btn
                text: "Select"
                #on_press: root.select_press()
                on_release: Factory.FileSelect().open()
            Label:
                text: ""

            Label:
                text: "Another label"
            TextInput:
                id:anotherfilepath
                multiline:False

            Label:
                text: "Third label"
            TextInput:
                id:thirdfilepath
                multiline:False

            Button:
                text: "Submit"
                font_size:60
                size: 100,80
                on_press: root.press()

        Label:
            id:output
            text: ""
            multiline:True

As the code shows, I'm trying to access the filechooser.selection[0] from the popup FileSelect in the main widget Prototype right after the popup closes. But, I can't find the right event to bind a method or function to.


Solution

  • One problem is that whenever you use an expression like:

    FileSelect()
    

    with the (), you are creating a new instance of FileSelect. That new instance is not the one where you have selected a file, so it cannot provide the path to the selected file.

    One fix is to just pass the selection to the select_press() method. If you modify the kv like this:

    <FileSelect@Popup>
        filechooser:filechooser
        auto_dismiss: False
        size_hint: 0.5, 0.5
        pos_hint: {"x":0.2, "top":0.9}
        title: "Select File"
        # on_dismiss: Factory.Prototype().select_press()
        on_dismiss: app.root.select_press(filechooser.selection)
    

    Then the select_press() method of the Prototype instance (which is the root of the app) will get called with the selection argument. The select_press() method then must be modified to accept the new argument:

    def select_press(self, selection):
        print(selection)
        self.categories_file_path.text = str(selection)
        # print(FileSelect().selected())