如何在KivyMD中保存用户输入的图像文件,实现重启应用后仍可访问
解决方案
实现思路
我们用Kivy自带的JsonStore做持久化存储,同时把用户上传的图片复制到应用专属数据目录,避免原文件移动/删除后无法访问,整体逻辑如下:
- 应用启动时读取本地存储的图片路径、日期信息,自动回填到界面
- 用户选择图片后,先将图片复制到应用专属的用户数据目录,再更新界面和存储记录
- 应用退出时自动保存当前所有输入内容
完整修改后的代码
from kivy.lang import Builder from kivymd.app import MDApp from kivy.core.window import Window from plyer import filechooser from kivy.storage.jsonstore import JsonStore import os import shutil Window.size = (300, 530) KV = """ MDBoxLayout: orientation: 'vertical' MDToolbar: id: progress_toolbar title: 'Progress' ScrollView: MDGridLayout: cols: 2 adaptive_height: True spacing: (10, 15) padding: [25, 25] MDLabel: halign: 'center' text: 'Before' MDLabel: halign: 'center' text: 'Now' MDCard: ripple_behavior: True orientation: 'vertical' size_hint_y: None size: 120, 220 elevation: 15 radius: 8 MDIconButton: icon: "camera-outline" user_font_size: "24sp" pos_hint: {"center_x": .5, "center_y": .5} on_release: app.file_chooser1() Image: id: img1 allow_stretch: True keep_ratio: False MDCard: ripple_behavior: True orientation: 'vertical' size_hint_y: None size: 120, 220 elevation: 15 radius: 8 MDIconButton: icon: "camera-outline" user_font_size: "24sp" pos_hint: {"center_x": .5, "center_y": .5} on_release: app.file_chooser2() Image: id: img2 allow_stretch: True keep_ratio: False MDTextField: id: date1 hint_text: 'Date' width: 100 MDTextField: id: date2 hint_text: 'Date' width: 100 """ class Example(MDApp): def build(self): # 初始化存储,配置文件保存在应用专属数据目录 self.store = JsonStore(os.path.join(self.user_data_dir, 'app_data.json')) # 创建保存图片的目录 self.img_dir = os.path.join(self.user_data_dir, 'uploaded_imgs') os.makedirs(self.img_dir, exist_ok=True) return Builder.load_string(KV) def on_start(self): # 启动时读取存储的内容回填到界面 if self.store.exists('data'): data = self.store.get('data') self.root.ids.img1.source = data.get('img1_path', '') self.root.ids.img2.source = data.get('img2_path', '') self.root.ids.date1.text = data.get('date1', '') self.root.ids.date2.text = data.get('date2', '') def on_stop(self): # 退出时保存当前内容 self.store.put('data', img1_path=self.root.ids.img1.source, img2_path=self.root.ids.img2.source, date1=self.root.ids.date1.text, date2=self.root.ids.date2.text) def file_chooser1(self): filechooser.open_file(on_selection=self.selected1, filters=['*.png', '*.jpg', '*.jpeg']) def file_chooser2(self): filechooser.open_file(on_selection=self.selected2, filters=['*.png', '*.jpg', '*.jpeg']) def selected1(self, selection1): if not selection1: return # 复制图片到应用专属目录 src_path = selection1[0] file_name = os.path.basename(src_path) dst_path = os.path.join(self.img_dir, f'img1_{file_name}') shutil.copy2(src_path, dst_path) # 更新界面 self.root.ids.img1.source = dst_path def selected2(self, selection2): if not selection2: return src_path = selection2[0] file_name = os.path.basename(src_path) dst_path = os.path.join(self.img_dir, f'img2_{file_name}') shutil.copy2(src_path, dst_path) self.root.ids.img2.source = dst_path Example().run()
注意事项
- 所有数据默认保存在系统分配给应用的专属目录,无需额外申请存储权限,打包为移动端APP时也可正常运行
- 每次用户上传新图片会覆盖之前的旧图片,如果你需要保留历史记录,只需修改存储结构,添加分组标识即可
- 如果需要限制图片大小,可在复制文件前加压缩逻辑,减少存储空间占用
内容的提问来源于stack exchange,提问作者Edwin
相关产品推荐
相关产品推荐

