如何编写程序让用户使用按钮将个人资料图片添加到KivyMD应用程序

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

我想编写一个程序,让用户使用按钮将个人资料图片添加到 KivyMD 应用程序。我编写 Python 程序来执行此操作的知识有限。请帮助我。

您可以使用 MDFileManager class 打开一个文件浏览器,returns 您选择的图像的位置,为了让这个例子正常工作,请确保您有一个名为“ i.jpeg”(您可以在源代码中更改它),如果您在保存此 python 脚本的同一目录(同一文件夹)中没有该图像,则此示例将失败:

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()

这个例子来自我 (jbsidis),它有部分来自 kivymd 文档,但是我改变了很多东西来让它工作,如果你只从文档中复制和粘贴 MDFileManager 例子,它可能会失败,这就是为什么在这个例子中你会看到 class MDFileManager 被定位并在 3 秒后执行(这是因为一个“kivymd bug”而需要的),订阅我在 youtube 中的频道:https://www.youtube.com/channel/UCIMmPyY7XjWHk1AHlR_UdWQ

jbsidis


@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__'

我认为问题出在我的代码上。但我不明白这是什么问题。我该如何解决?

这是我的代码

.kv文件

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'
    

我想更换 id : profile_picid : cover pic

的图像

.py 文件

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

你能给我一个适合这段代码的代码示例吗

是的,我正在分析你的代码,我会为你的程序提供正确的代码,另外,请阅读代码中的所有评论,我正在添加注释,以便你可以获得有关错误的更多信息,我个人的建议是, 始终执行单个 python 脚本(我的意思是不要将程序分为 kv 文件和 py 文件,除非你使用 HotReloadViewer),所以这里是固定的代码:

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()

所以,这是图像: jbsidis(来自萨尔瓦多的问候)