How to write a program for the user to add a profile picture to the KivyMD application using the button

Viewed 673

I want to write a program for the user to add a profile picture to the KivyMD application using the button. My knowledge of writing a Python program to do this is limited. Please help me.

1 Answers

You can use the MDFileManager class to open up a file browser that returns the location of the image you have selected, for this example to work, make sure you have an image called "i.jpeg" (you can change that in the source code), if you don't have that image in the same directory (same folder) where you have saved this python script, then this example will fail:

from kivy.core.window import Window
from kivy.lang import Builder

from kivymd.app import MDApp
from kivymd.uix.filemanager import MDFileManager
from kivymd.toast import toast
from kivymd.utils.fitimage import FitImage
from kivy.properties import (
    StringProperty,
    BooleanProperty,
    ObjectProperty,
    NumericProperty,
    ListProperty,
    OptionProperty,
)

KV = '''
MDBoxLayout:
    orientation: 'vertical'

    MDToolbar:
        title: "Black-Hands"
        left_action_items: [['menu', lambda x: None]]
        elevation: 10

    MDFloatLayout:
        MDCard:
            id: cbor
            orientation: "vertical"
            size_hint: .95, None
            pos_hint: {"center_x": .5, "center_y": .9}
            #background: "bgg.png"
            GridLayout:
                cols: 2
                MDLabel:
                    id: user20
                    markup: True
                    text: "\\n\\n[b][color=000000]   JOSUE CARRANZA (jbsidis)\\n[/b]   [color=000000]Cód. de Vendedor: 39213\\n[color=000000]   Idioma: \\n"
                    font_style: "Caption"
                    halign: "left" #"left" #"right"
                    height: self.texture_size[1]
                    
                Image: #FitImage
                    id: pic
                    size_hint: None, None
                    source: "i.jpeg"
                    height: root.ids.cbor.height
##                    source: root.newpic #"i.jpeg" #"xbay.png"
##                    size_hint: None, None
##                    height: root.ids.cbor.height

        MDRoundFlatIconButton:
            id: n1
            text: "Change picture"
            icon: "pencil"
            disabled: True
            pos_hint: {'center_x': .5, 'center_y': .6}
            on_release: app.file_manager_open()
        MDCard:
            padding: dp(5)
            size_hint: 1,.1
            MDLabel:
                markup: True
                text: "[b]Subscribe and Watch my KivyMD Videos: [/b]https://www.youtube.com/channel/UCIMmPyY7XjWHk1AHlR_UdWQ"


<ProfilePicture>:
##    id: pic
    source: root.newpic #"i.jpeg" #"xbay.png"
    size_hint: None, None
##    height: root.ids.cbor.height


'''

class ProfilePicture(FitImage):
    newpic=StringProperty()

import os
from kivy.clock import Clock
class Example(MDApp):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        Window.bind(on_keyboard=self.events)
        self.manager_open = False

    def nn(self):
        
        self.file_manager = MDFileManager()
        self.file_manager.exit_manager=self.exit_manager
        self.file_manager.select_path=self.select_path
        self.root.ids.n1.disabled=False
        #preview=False

    def build(self):
        Clock.schedule_once(lambda x: self.nn(),3)
        return Builder.load_string(KV)
    def chpic(self,new):
        if os.path.isfile(new)==True:
            self.root.ids.pic.source=new
            print("The pictura was changed to:",self.root.ids.pic.source)

    def file_manager_open(self):
        self.file_manager.show('/')  # output manager to the screen
        self.manager_open = True

    def select_path(self, path):

        self.exit_manager()
        print(path)
        if os.path.isfile(path)==True:
            Clock.schedule_once(lambda x:self.chpic(path),1)
        #toast(path) #here the location for the image file will be returned
        return path


    def exit_manager(self, *args):
        self.manager_open = False
        self.file_manager.close()

    def events(self, instance, keyboard, keycode, text, modifiers):
        if keyboard in (1001, 27):
            if self.manager_open:
                self.file_manager.back()
        return True


Example().run()

This example comes from me (jbsidis) and it has parts from the kivymd documents, however I changed a lot of things to make it work, if you only copy and paste the MDFileManager example from the docs, it may fail, that's why in this example you will see that the class MDFileManager is located and executed after 3 seconds (this is needed because of a "kivymd bug"), subcribe to my channel in youtube: https://www.youtube.com/channel/UCIMmPyY7XjWHk1AHlR_UdWQ

jbsidis enter image description here


@jbsidis Josué Carranza - Sir, first I tried the code you have given above, It has been worked successfully. But when I add that to my code the file manager can be opened. But the picture can't be changed. There was a problem occurred.

File "kivy\properties.pyx", line 864, in kivy.properties.ObservableDict.__getattr__
 AttributeError: 'super' object has no attribute '__getattr__'

I think the problem is with my code. But I can't understand what's the problem. How would I solve that?

Here is my code

.kv file

screen_helper = """

ScreenManager:
    Studio:
<Studio>:
    name : 'studio'
    BoxLayout:
        orientation:'vertical'
        MDToolbar:
            elevation : 8
            adaptive_height: True
            height: '350dp'
            md_bg_color: 0,0,0,.000001
    MDFloatLayout:
        FitImage:
            id: cover_pic
            orientation: "vertical"
            size_hint: 1, .75
            pos_hint: {"center_x": .5, "center_y": 1}
            source: "Photos/3.jpg"
        FitImage: 
            id: profile_pic
            size_hint: 1,1
            size_hint: None, None
            source: "Photos/Kusal.png"
            pos_hint: {"center_x": .172, "center_y": .583}
            radius: 60, 60, 60, 60
        TooltipMDIconButton:
            tooltip_text : 'Edit Cover Picture'
            id: edit_cover_pic
            icon: "image-edit-outline"
            disabled: False
            pos_hint: {'center_x':0.95,'center_y':0.97}
            user_font_size: "25sp"
            on_release: app.file_manager_open()
        TooltipMDIconButton:
            tooltip_text : 'Edit Profile Picture'
            id: edit_profile_pic
            icon: "image-edit-outline"
            disabled: False
            pos_hint: {'center_x':0.95,'center_y':0.585}
            user_font_size: "25sp"
            on_release: app.file_manager_open()
        TooltipMDIconButton:
            tooltip_text : 'Edit Bio'
            id: edit_profile_pic
            icon: "pencil"
            disabled: False
            pos_hint: {'center_x':0.91,'center_y':0.585}
            user_font_size: "25sp"
            on_release: app.file_manager_open()
    MDIconButton:
        icon: 'arrow-left'
        pos_hint: {'center_x':0.03,'center_y':0.97}
        user_font_size: "25sp"
        theme_text_color : 'Custom'
        text_color : 0,0,0,1
        on_release : 
            root.manager.current = 'navigator'
            root.manager.transition.direction = 'right'
    MDIconButton:
        icon: 'home'
        pos_hint: {'center_x':0.08,'center_y':0.97}
        user_font_size: "25sp"
        theme_text_color : 'Custom'
        text_color : 0,0,0,1
        on_release : 
            root.manager.current = 'home'
            root.manager.transition.direction = 'right'
    

I want to change the images of id : profile_pic and id : cover pic

.py file

from kivy.lang.builder import Builder
from kivy.uix.screenmanager import Screen, ScreenManager
from kivymd.app import MDApp
from widgets import screen_helper
from kivymd.toast import toast
from kivymd.uix.filemanager import MDFileManager
from kivy.properties import (
    StringProperty,
    BooleanProperty,
    ObjectProperty,
    NumericProperty,
    ListProperty,
    OptionProperty,
)

class Studio(Screen):
    pass

import os
from kivy.clock import Clock

class Mode(MDApp):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        Window.bind(on_keyboard=self.events)
        self.manager_open = False

    def nn(self):
        self.file_manager = MDFileManager()
        self.file_manager.exit_manager=self.exit_manager
        self.file_manager.select_path=self.select_path
        #preview=False

    def build(self):
        Clock.schedule_once(lambda x: self.nn(), 3)

        return Builder.load_string(screen_helper)

    def edit_pic(self,new):
        if os.path.isfile(new)==True:
            self.root.ids.cover_pic.source=new

    def file_manager_open(self):
        self.file_manager.show('/')  # output manager to the screen
        self.manager_open = True

    def select_path(self, path):

        self.exit_manager()
        print(path)
        if os.path.isfile(path)==True:
            Clock.schedule_once(lambda x:self.edit_pic(path),1)
        toast(path) #here the location for the image file will be returned
        return path


    def exit_manager(self, *args):
        self.manager_open = False
        self.file_manager.close()

    def events(self, instance, keyboard, keycode, text, modifiers):
        if keyboard in (1001, 27):
            if self.manager_open:
                self.file_manager.back()
        return True

Can you give me a suitable code example for this code

Yes, I was analizing your code and I will give you the right code for your program, also, Read all comments in the code, I was adding notes so you can get more info about errors, my personal recommendation is, alway do a single python script (I mean do not divide the program in kv files and py files, unless you are using HotReloadViewer), so here is the code fixed:

from kivy.core.window import Window
from kivy.lang import Builder

from kivy.uix.screenmanager import Screen, ScreenManager

try:
    from widgets import screen_helper
except:
    pass #ModuleNotFoundError: No module named 'widgets'

from kivymd.app import MDApp
from kivymd.uix.filemanager import MDFileManager
from kivymd.toast import toast
from kivymd.utils.fitimage import FitImage
from kivy.properties import (
    StringProperty,
    BooleanProperty,
    ObjectProperty,
    NumericProperty,
    ListProperty,
    OptionProperty,
)

class Studio(Screen):
    #this is a good idea, to implement it, you should add it using clock
    pass



KV = '''
Screen:
    ScreenManager:
        id: manager #this is needed
        Screen:
            name : 'studio'
            MDFloatLayout:
                Image: #if we use FitImage: is not good, because FitImage does not update images, but Image does
                    id: cover_pic
                    orientation: "vertical"
                    size_hint: 1, .75
                    pos_hint: {"center_x": .5, "center_y": 1}
                    source: "Photos/20190907_154525.jpg"
                Image: #the FitImage: class does not update media, but Image does
                    id: profile_pic
                    size_hint: None, None
                    source: "Photos/pro.jpg"
                    pos_hint: {"center_x": .172, "center_y": .583}
                    radius: 60, 60, 60, 60
                    #
                TooltipMDIconButton:  #kivy.factory.FactoryException: Unknown class <TooltipMDIconButton>
                    tooltip_text : 'Edit Profile Picture'
                    id: edit_profile_pic
                    icon: "image-edit-outline"
                    disabled: True
                    pos_hint: {'center_x':0.95,'center_y':0.585}
                    user_font_size: "25sp"
                    on_release: app.file_manager_open_for_profile()
                TooltipMDIconButton: #kivy.factory.FactoryException: Unknown class <TooltipMDIconButton>
                    tooltip_text : 'Edit Bio'
                    id: edit_profile_pic2
                    icon: "pencil"
                    disabled: False #False
                    pos_hint: {'center_x':0.91,'center_y':0.585}
                    user_font_size: "25sp"
                    #on_release: app.file_manager_open()
            MDToolbar:
                pos_hint: {'top': 1}
                md_bg_color: [1,1,1,.3] #if you need a fully transparent Toolbar use [0,0,0,0]
                FloatLayout:
                    BoxLayout:
                        pos_hint: {'center_x': -.5,'center_y':0.2}
                        MDIconButton:
                            icon: 'arrow-left'
                            pos_hint: {'center_x':0.03,'center_y':0.97}
                            user_font_size: "25sp"
                            theme_text_color : 'Custom'
                            text_color : 0,0,0,1
                            on_release : 
                                app.goto("navigator") #root.ids.manager.current = 'navigator' #you should have another screen called navigator
                                #root.ids.manager.transition.direction = 'right'
                                print(1111)
                        MDIconButton:
                            icon: 'home'
                            pos_hint: {'center_x':0.1,'center_y':0.97}
                            user_font_size: "25sp"
                            theme_text_color : 'Custom'
                            text_color : 0,0,0,1
                            on_release :
                                app.goto("home") 
                                #root.manager.current = 'home' #you should have another screen called home
                                #this does not work root.manager.transition.direction = 'right'
                                print(2222)
                FloatLayout:
                    BoxLayout:
                        pos_hint: {'center_x':1.2,'center_y':0.3}
                        TooltipMDIconButton: #kivy.factory.FactoryException: Unknown class <TooltipMDIconButton>
                            tooltip_text : 'Edit Cover Picture'
                            id: edit_cover_pic
                            icon: "image-edit-outline"
                            disabled: False
                            pos_hint: {'center_x':0.03,'center_y':0.97}
                            user_font_size: "25sp"
                            on_release: app.file_manager_open_for_cover()

<TooltipMDIconButton@MDIconButton+MDTooltip>

<ScreenB>:
    name: "home"
    MDToolbar:
        pos_hint: {'top': 1}
        title: "Home Screen"
        left_action_items: [['arrow-left', lambda x: app.goto("studio")]]
        #md_bg_color: [1,0,1,.3] #if you need a fully transparent Toolbar use [0,0,0,0]
<ScreenC>:
    name: "navigator"
    MDToolbar:
        pos_hint: {'top': 1}
        title: "Navigator Screen"
        left_action_items: [['arrow-left', lambda x: app.goto("studio")]]
        #md_bg_color: [1,0,1,.3] #if you need a fully transparent Toolbar use [0,0,0,0]


'''

from kivymd.uix.button import MDIconButton
from kivymd.uix.tooltip import MDTooltip
class TooltipMDIconButton(MDIconButton, MDTooltip):
    pass


class ScreenB(Screen):
    pass

class ScreenC(Screen):
    pass

class ProfilePicture(FitImage):
    newpic=StringProperty()
#jbsidis
import os
from kivy.clock import Clock
class Example(MDApp):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        Window.bind(on_keyboard=self.events)
        self.manager_open = False
        self.image_is_profile_or_cover="none"

    def goto(self,name_of_the_screen):
        self.root.ids.manager.current = name_of_the_screen #'navigator'

    def nn(self):
        self.file_manager = MDFileManager()
        self.file_manager.exit_manager=self.exit_manager
        self.file_manager.select_path=self.select_path  
## This error is bacause in your own example, the ID of the widgets are different or they must
## be accessed in a different way
##        self.root.ids.n1.disabled=False
##   File "kivy/properties.pyx", line 864, in kivy.properties.ObservableDict.__getattr__
## AttributeError: 'super' object has no attribute '__getattr__'
        ##the id "n1" doesnot exists in the kivy Lang section, so we should specify which one is it
        ##the id "edit_profile_pic" does exists in the kivy Lang section
        #BAD ===== self.root.ids.n1.disabled=False
        #GOOD
        self.root.ids.edit_profile_pic.disabled=False
        self.root.ids.edit_cover_pic.disabled=False
        #preview=False
        #if you will be using a lot of screens add all of them by doing this
        #This must be executed once only, at the beginning
        self.root.ids.manager.add_widget(ScreenB())
        self.root.ids.manager.add_widget(ScreenC())

    def build(self):
        image_is_profile_or_cover="none"
        Clock.schedule_once(lambda x: self.nn(),3)
        return Builder.load_string(KV)
    def chpic(self,new):
        if os.path.isfile(new)==True:
            if self.image_is_profile_or_cover=="cover":
                self.root.ids.cover_pic.source=new
                print("The picture on 'id: cover_pic' was changed to:",self.root.ids.cover_pic.source)
            if self.image_is_profile_or_cover=="profile":
                self.root.ids.profile_pic.source=new
                print("The picture on 'id: profile_pic' was changed to:",self.root.ids.profile_pic.source)

    def file_manager_open_for_profile(self):
        self.image_is_profile_or_cover="profile"
        self.file_manager.show('/')  # output manager to the screen
        self.manager_open = True

    def file_manager_open_for_cover(self):
        self.image_is_profile_or_cover="cover"
        self.file_manager.show('/')  # output manager to the screen
        self.manager_open = True

    def select_path(self, path):

        self.exit_manager()
        print(path)
        if os.path.isfile(path)==True:
            Clock.schedule_once(lambda x:self.chpic(path),1)
        #toast(path) #here the location for the image file will be returned
        return path


    def exit_manager(self, *args):
        self.manager_open = False
        self.file_manager.close()

    def events(self, instance, keyboard, keycode, text, modifiers):
        if keyboard in (1001, 27):
            if self.manager_open:
                self.file_manager.back()
        return True


Example().run()

So, here is the image: jbsidis (Greetings from El Salvador)

enter image description here

Related