如何在屏幕中选择图像并使用 kivy 将其显示在另一个屏幕上?
Posted
技术标签:
【中文标题】如何在屏幕中选择图像并使用 kivy 将其显示在另一个屏幕上?【英文标题】:How to select an image in a screen and display it on another using kivy? 【发布时间】:2021-07-29 11:58:32 【问题描述】:我正在使用 Kivy 创建一个简单的两屏界面,用于执行图像分类任务。在第一个屏幕中,我使用文件选择器选择图像并显示它。在第二个屏幕中,我想显示相同的图像和分类任务的结果。屏幕之间的转换是通过第一个屏幕上的按钮完成的。
我的问题是:当我按下按钮时,如何触发第二屏上图像源属性的更新,以便将所选图像显示在第二屏上? 分类部分只是为了了解我的问题的背景,我没有在代码中包含它。
这是main.py
文件
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.properties import StringProperty
class WindowManager(ScreenManager):
image_source = StringProperty()
def selected(self,filename):
try:
self.image_source = filename[0]
except:
pass
# Screen where the image is selected
class ImageSelector(Screen):
pass
# Display image & classification results
class ClassificationResultWindow(Screen):
pass
class MainApp(App):
def build(self):
self.image_selector = ImageSelector()
self.scan_result_window = ClassificationResultWindow()
if __name__ == "__main__":
MainApp().run()
这是main.kv
文件
#:kivy 2.0.0
WindowManager:
ImageSelector:
ClassificationResultWindow:
<ImageSelector>:
name: "image_selector"
id: image_selector
BoxLayout:
orientation: 'vertical'
id: image_box
FileChooserListView:
id: filechooser
on_selection:
root.manager.selected(filechooser.selection)
print(root.manager.image_source)
size_hint: 1, 10
Image:
id: image
source: root.manager.image_source
size_hint: 1, 4
Button:
id: diagnose
text: "Classify"
on_release:
print(root.manager.image_source)
app.root.current = "classification_result"
<ClassificationResultWindow>:
name: "classification_result"
BoxLayout:
orientation: 'vertical'
id: box
Image:
id: scan
source: root.manager.image_source
size_hint: 1, 10
Label:
text: "Here comes the classification result"
font_size: 30
size_hint: 1, 2
id: label
我尝试以不同的方式绑定属性但没有成功,但由于我是 kivy 的新手,我不知道这是否有意义,所以我没有在此处包含它们。
【问题讨论】:
【参考方案1】:我处理从一个屏幕向另一个屏幕传递信息的方式是让ScreenManager
持有属性,并让Screen
访问它们。
您的 main.py
文件现在应该是:
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.properties import StringProperty
class WindowManager(ScreenManager):
image_source = StringProperty()
def selected(self,filename):
try:
self.image_source = filename[0]
except:
pass
# Screen where the image is selected
class ImageSelector(Screen):
pass
# Display image & classification results
class ClassificationResultWindow(Screen):
pass
class MainApp(App):
pass
if __name__ == "__main__":
MainApp().run()
#:kivy 2.0.0
WindowManager:
ImageSelector:
ClassificationResultWindow:
<ImageSelector>:
name: "image_selector"
id: image_selector
BoxLayout:
orientation: 'vertical'
id: image_box
FileChooserListView:
id: filechooser
on_selection:
root.manager.selected(filechooser.selection)
size_hint: 1, 10
Image:
id: image
screen: image_selector
source: self.screen.manager.image_source
size_hint: 1, 4
Button:
id: diagnose
text: "Classify"
on_release:
app.root.current = "classification_result"
<ClassificationResultWindow>:
name: "classification_result"
id: classification_results
BoxLayout:
orientation: 'vertical'
id: box
Image:
id: scan
screen: classification_results
source: self.screen.manager.image_source
size_hint: 1, 10
Label:
text: "Here comes the classification result"
font_size: 30
size_hint: 1, 2
id: label
发生了什么事?所以首先在ScreenManager
中创建StringProperty
。与这些属性的绑定是自动创建的,因此引用此属性的内容将随着它的更改而更新。
然后每个Screen
中的Image
类引用这个StringProperty
到root.manager.image_source
。
root
是根小部件,
manager
是每个屏幕都有的一个属性,它指向它的父级ScreenManager
image_source
是我们之前创建的属性。
希望这会有所帮助。我没有测试上述内容,所以可能有一两个错误,但我认为让ScreenManager
持有Screen
需要相互传递的对象的一般概念是我解决这个问题的方法。
【讨论】:
我应该补充一点,更改会立即发生(因为自动绑定)。您始终可以通过创建访问该属性的函数来延迟此操作,即在您的selected()
函数中写入self.ids.image.source = self.manager.image_source
。这样您就可以控制一个屏幕何时访问图像。
非常感谢。我做了一些小改动,但我仍然无法让它工作。这行source: root.manager.image_source
抛出错误:AttributeError: 'NoneType' object has no attribute 'image_source'
。按下按钮时,我包含了print(root.manager.image_source)
,这显示了正确的路径。我不明白为什么无法在图像源中访问它。我根据您的建议更新了我的初始代码。
嗯,试试这个的变体。先试试root.parent.manager.image_source
,然后再试试self.parent.parent.manager.image_source
。如果它们都不起作用,请为您的图像添加manager
属性。为此,首先给每个Screen
一个id(在KV 文件中),类似于id: _screen
然后为Image
类给他们一个屏幕属性screen: _screen
。希望您应该能够通过传递 source: self.screen.manager.image_source
来引用图像源
太棒了。最后一个建议奏效了,我给每个屏幕一个 id,然后将其用作Image
类中的screen
属性,并将源称为source: self.screen.manager.image_source
。我更改了您的答案以合并 cmets。你知道它为什么起作用吗?
是的,所以您新创建的 id 是一个 ObjectProperty
,它指向 Screen
,其工作方式与 parent
或 root
的工作方式相同。事实上,这是一种让小部件相互“对话”的好方法。假设您要基于TextInput
更新Label
。为标签创建一个 id,然后使用上述技术在 TextInput 中存储对该标签的引用。最后,您可以通过声明 self.label.text = self.text
来创建绑定。以上是关于如何在屏幕中选择图像并使用 kivy 将其显示在另一个屏幕上?的主要内容,如果未能解决你的问题,请参考以下文章
如何解决“无效的属性名称”错误以使用 kivy 制作文件选择器?
从画廊 Python Kivy for Android 中选择图像