如何编写程序让用户使用按钮将头像添加到 KivyMD 应用程序

Posted

技术标签:

【中文标题】如何编写程序让用户使用按钮将头像添加到 KivyMD 应用程序【英文标题】:How to write a program for the user to add a profile picture to the KivyMD application using the button 【发布时间】:2021-10-17 22:07:07 【问题描述】:

我想为用户编写一个程序,以使用按钮将个人资料图片添加到 KivyMD 应用程序。我编写 Python 程序来做到这一点的知识是有限的。请帮帮我。

【问题讨论】:

【参考方案1】:

您可以使用 MDFileManager 类打开一个文件浏览器,该浏览器返回您选择的图像的位置,为了使本示例正常工作,请确保您有一个名为“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 例子,它可能会失败,那就是为什么在这个例子中你会看到 MDFileManager 类在 3 秒后被定位并执行(这是因为“kivymd 错误”而需要),订阅我在 youtube 中的频道:https://www.youtube.com/channel/UCIMmPyY7XjWHk1AHlR_UdWQ

jbsidis


@jbsidis Josué Carranza - 先生,首先我尝试了您提供的代码 以上,已成功运行。但是当我将它添加到我的代码中时 可以打开文件管理器。但图片无法更改。 出现问题。

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

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

是的,我正在分析您的代码,我将为您的程序提供正确的代码,此外,阅读代码中的所有 cmets,我正在添加注释,以便您可以获得有关错误的更多信息,我个人的建议是,总是做一个单一的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(来自萨尔瓦多的问候)

【讨论】:

非常感谢

以上是关于如何编写程序让用户使用按钮将头像添加到 KivyMD 应用程序的主要内容,如果未能解决你的问题,请参考以下文章

如何显示用户头像

让按钮快速将文本添加到 UITextField

注册新用户时如何上传用户头像到服务器?

使用ivx画布组件打印微信头像的经验总结

使用按钮添加用户输入的数据

小程序新版uniapp登录流程以及获取头像和昵称