Search code examples
pythonpython-3.xkivykivy-language

Drag and Drop image and display image on gridlayout - Kivy


I'm new to kivy and I'm trying to create a drag and drop app where if the image is dropped onto the gridlayout the image is shown on the app as shown below. I'm trying to get the file_path of the image and then using the file_path to display it on the gridlayout but unfortunately, that is not working. Any help would be greatly appreciated!

This is the current image enter image description here

This is what I want after dragging the image enter image description here

Kv file

# Custom button
<CustButton@Button>:
    font_size: 32
    background_normal: 'Colour_yellow.png'
    background_down: 'Colour_blue.png'

<Cust2@Button>:
    font_size: 32
    background_normal: 'Colour_red.png'
    background_down: 'Colour_blue.png'

<Cust3@Button>:
    font_size: 32
    background_normal: 'Colour_white.png'
    background_down: 'Colour_blue.png'

<Cust4@Button>:
    font_size: 32
    background_normal: 'Colour_blue.png'
    background_down: 'Colour_white.png'

<CalcGridLayout>:
    id: calculator
    display: entry
    rows: 5
    padding: 10
    spacing: 10

    BoxLayout:
        spacing: 100
        size_hint: .5, None
        Cust2:
            text: "Whats the intensity you want?"

    BoxLayout:

        size_hint: .5, None
        TextInput:
            id: entry
            font_size: 70
            multiline: False
            hint_text: "Type here"

    BoxLayout:
        spacing: 100
        size_hint: .5, None
        Cust4:
            text: "Drag and Drop picture below:"
            on_release: root.build1()

    #THIS IS WHERE I'M STUCK ON
    BoxLayout:
        Image:
            source: root._on_file_drop(file_path)

    BoxLayout:
        size_hint: 1, .3
        spacing: 10

        CustButton:
            text: "Click here for \n reduced size"

        CustButton:
            text: "Click here for pos \n  and intensity of \n      each pixel"
            on_release: root.reduced_image()

        CustButton:
            text: "Click here \n for graph"

        CustButton:
            text: "Click here \n     for all"

        CustButton:
            text: "Extra"

Python file

import kivy

kivy.require("1.9.0")

from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from kivy.core.window import Window
Window.clearcolor = (0.5, 0.5, 0.5, 1)


class CalcGridLayout(GridLayout):

    def reduced_image(self):
    #ignore

    def build1(self):
        Window.bind(on_dropfile=self._on_file_drop)
        return

    def _on_file_drop(self, window, file_path):
        print(file_path)
        return file_path



class dropdownApp(App):

    def build(self):
        return CalcGridLayout()


dropApp = dropdownApp()
dropApp.run()

Solution

  • Solution

    Please refer to the snippets, and complete example for details.

    kv file

    1. Remove on_release: root.build1()
    2. Replace source: root._on_file_drop(file_path) with id: img

    Snippet

    BoxLayout:
        spacing: 100
        size_hint: .5, None
        Cust4:
            text: "Drag and Drop picture below:"
    
    BoxLayout:
        Image:
            id: img
    

    Python Code

    1. Add import statement, from kivy.properties import StringProperty
    2. Declare property, filePath = StringProperty('') in class CalcGridLayout().
    3. Add constructor to class CalcGridLayout() and move Window.bind(on_dropfile=self._on_file_drop) from build1() method
    4. Remove build1() method
    5. In _on_file_drop() method, replace return file_path with self.filePath = file_path.decode("utf-8") self.ids.img.source = self.filePath and self.ids.img.reload()

    Snippet

    from kivy.properties import StringProperty
    ...
    
    class CalcGridLayout(GridLayout):
        filePath = StringProperty('')
    
        def __init__(self, **kwargs):
            super(CalcGridLayout, self).__init__(**kwargs)
            Window.bind(on_dropfile=self._on_file_drop)
    
        def reduced_image(self):
            print(self.filePath)
    
        def _on_file_drop(self, window, file_path):
            print(file_path)
            self.filePath = file_path.decode("utf-8")     # convert byte to string
            self.ids.img.source = self.filePath
            self.ids.img.reload()   # reload image
    

    Window » on_dropfile Event

    on_dropfile(filename)
    

    Event called when a file is dropped on the application.

    Warning

    This event currently works with sdl2 window provider, on pygame window provider and OS X with a patched version of pygame. This event is left in place for further evolution (ios, android etc.)

    Example

    main.py

    import kivy
    kivy.require("1.11.0")
    
    from kivy.app import App
    from kivy.uix.gridlayout import GridLayout
    from kivy.core.window import Window
    from kivy.properties import StringProperty
    
    Window.clearcolor = (0.5, 0.5, 0.5, 1)
    
    
    class CalcGridLayout(GridLayout):
        filePath = StringProperty('')
    
        def __init__(self, **kwargs):
            super(CalcGridLayout, self).__init__(**kwargs)
            Window.bind(on_dropfile=self._on_file_drop)
    
        def reduced_image(self):
            print(self.filePath)
    
        def _on_file_drop(self, window, file_path):
            print(file_path)
            self.filePath = file_path.decode("utf-8")     # convert byte to string
            self.ids.img.source = self.filePath
            self.ids.img.reload()   # reload image
    
    
    class DragDropApp(App):
    
        def build(self):
            return CalcGridLayout()
    
    
    if __name__ == "__main__":
        DragDropApp().run()
    

    dragdrop.kv

    #:kivy 1.11.0
    
    # Custom button
    <CustButton@Button>:
        background_normal: "/home/iam/Pictures/AppImages/Colors/yellow.png"   # 'Colour_yellow.png'
        background_down: "/home/iam/Pictures/AppImages/Colors/blue.png"       # 'Colour_blue.png'
        text_size: self.size
        halign: 'center'
        valign: 'middle'
    
    <Cust2@Button>:
        font_size: 32
        background_normal: "/home/iam/Pictures/AppImages/Colors/red.png"   # 'Colour_red.png'
        background_down: "/home/iam/Pictures/AppImages/Colors/blue.png"     # 'Colour_blue.png'
    
    <Cust3@Button>:
        font_size: 32
        background_normal: "/home/iam/Pictures/AppImages/Colors/white.png"     # 'Colour_white.png'
        background_down: "/home/iam/Pictures/AppImages/Colors/blue.png"       # 'Colour_blue.png'
    
    <Cust4@Button>:
        font_size: 32
        background_normal: "/home/iam/Pictures/AppImages/Colors/blue.png"     # 'Colour_blue.png'
        background_down: "/home/iam/Pictures/AppImages/Colors/white.png"       # 'Colour_white.png'
    
    <CalcGridLayout>:
        id: calculator
        display: entry
        rows: 5
        padding: 10
        spacing: 10
    
        BoxLayout:
            spacing: 100
            size_hint: .5, None
            Cust2:
                text: "Whats the intensity you want?"
    
        BoxLayout:
            size_hint: .5, None
            TextInput:
                id: entry
                font_size: 70
                multiline: False
                hint_text: "Type here"
    
        BoxLayout:
            spacing: 100
            size_hint: .5, None
            Cust4:
                text: "Drag and Drop picture below:"
    
        BoxLayout:
            Image:
                id: img
    
        BoxLayout:
            size_hint: 1, .3
            spacing: 10
    
            CustButton:
                text: "Click here for \n reduced size"
    
            CustButton:
                text: "Click here for pos \n  and intensity of \n      each pixel"
                on_release: root.reduced_image()
    
            CustButton:
                text: "Click here \n for graph"
    
            CustButton:
                text: "Click here \n     for all"
    
            CustButton:
                text: "Extra"
    

    Output

    Img01 Img02