Python 3.x 如何在Kivy中将图像放入动态文本中

Python 3.x 如何在Kivy中将图像放入动态文本中,python-3.x,kivy,Python 3.x,Kivy,我正在将自己融入kivy,并希望将图片嵌入到显示的文本中。 文本被加载到一个简单的字符串中,然后显示出来,这很容易做到,但我不知何故找不到如何在所述字符串中显示图像的线索 这个问题的答案是为它们构建一个新的布局,在本例中是TextWrapper 示例代码: from kivy.app import App from kivy.uix.boxlayout import BoxLayout from kivy.uix.button import Label, Button from kivy.lan

我正在将自己融入kivy,并希望将图片嵌入到显示的文本中。 文本被加载到一个简单的字符串中,然后显示出来,这很容易做到,但我不知何故找不到如何在所述字符串中显示图像的线索

这个问题的答案是为它们构建一个新的布局,在本例中是TextWrapper

示例代码:

from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Label, Button
from kivy.lang import Builder
from kivy.properties import BooleanProperty, StringProperty
from kivy.uix.behaviors import FocusBehavior
from kivy.uix.image import Image
from kivy.uix.recycleboxlayout import RecycleBoxLayout
from kivy.uix.recycleview import RecycleView
from kivy.uix.recycleview.layout import LayoutSelectionBehavior
from kivy.uix.recycleview.views import RecycleDataViewBehavior
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.scrollview import ScrollView

Builder.load_string("""
<ScreenSpecies>:
    BoxLayout:
        orientation: 'vertical'

        Label:
            pos_hint: {"x": .45, "top": 1}
            size_hint: .1, .1
            text: "The Species"

        GridLayout:
            id: species_layout
            rows: 1
            cols: 2
            padding: dp(10)
            spacing: dp(10)
            orientation: 'horizontal'

            SpeciesView:
                id: species_list_view

            SpeciesLabel:
                id: species_text
                text_selected: "Text" if not species_list_view.text_selected else species_list_view.text_selected
                name_selected: "" if not species_list_view.name_selected else species_list_view.name_selected


<SpeciesView>:
    viewclass: 'SelectableLabel'
    text_selected: ""
    name_selected: ""

    SelectableRecycleBoxLayout:
        orientation: 'vertical'
        default_size: None, dp(32)
        default_size_hint: .6, None
        size_hint: 1, .9
        multiselect: False
        touch_multiselect: False


<SpeciesLabel>:
    size_hint_y: .85
    Label:
        halign: 'left'
        valign: 'middle'
        size_hint_y: None
        height: self.texture_size[1]
        text_size: self.width, None
        text: root.text_selected



<SelectableLabel>:
    canvas.before:
        Color:
            rgba: (.05, 0.5, .9, .8) if self.selected else (.5, .5, .5, 1)
        Rectangle:
            pos: self.pos
            size: self.size
""")


class TextWrapper(BoxLayout):
    def __init__(self, text="", **kwargs):
        super(TextWrapper, self).__init__(**kwargs)
        self.content = self.wrap_text(text)

    def wrap_text(self, source):
        text = source.split("|")

        for i in range(0, len(text)):
            if "img=" in text[i]:
                self.add_widget(Image(source=text[i][4:]))
            else:
                self.add_widget(Label(text=text[i]))
        return text


class SelectableRecycleBoxLayout(FocusBehavior, LayoutSelectionBehavior,
                                 RecycleBoxLayout):
    pass


class SelectableLabel(RecycleDataViewBehavior, Label):
    ''' Add selection support to the Label '''
    index = None
    selected = BooleanProperty(False)
    selectable = BooleanProperty(True)

    def refresh_view_attrs(self, rv, index, data):
        ''' Catch and handle the view changes '''
        self.index = index
        return super(SelectableLabel, self).refresh_view_attrs(
            rv, index, data)

    def on_touch_down(self, touch):
        ''' Add selection on touch down '''
        if super(SelectableLabel, self).on_touch_down(touch):
            return True
        if self.collide_point(*touch.pos) and self.selectable:
            return self.parent.select_with_touch(self.index, touch)

    def apply_selection(self, rv, index, is_selected):
        ''' Respond to the selection of items in the view. '''
        self.selected = is_selected
        if is_selected:
            print("selection changed to {0}".format(rv.data[index]))
            rv.name_selected = rv.data[index]['text']
            rv.text_selected = rv.data[index]['description']
        else:
            print("selection removed for {0}".format(rv.data[index]))


class ScreenSpecies(Screen):
    pass


class SpeciesView(RecycleView):
    def __init__(self, **kwargs):
        super(SpeciesView, self).__init__(**kwargs)

        self.species_data = [
            {"text": "Test1", "description": "Test1.textbf |img=serveimage.png| Test1.textaf"},
            {"text": "Test2", "description": "Test2.text"},
            {"text": "Test3", "description": "Test3.text"}
        ]

        for species in self.species_data:
            species["description"] = TextWrapper(species["description"])
        # clean keywords out

        self.data = self.species_data


class SpeciesLabel(ScrollView):
    text_selected = StringProperty("")
    name_selected = StringProperty("")


screen_manager = ScreenManager()
screen_manager.add_widget(ScreenSpecies(name="screen_species"))


class TestApp(App):
    def build(self):
        return screen_manager


test_app = TestApp()
test_app.run()
我不知道如何显示视图中每个元素的描述中的TextWrapper

这一切的目的是,我可以根据选项的可选列表来更改文本,并且每个文本中仍然有图像。
结果应该与此类似:

同样,问题是如何根据上一次按下的按钮动态更改右侧的文本和图像

谢谢你的帮助

包装 我还没有在kivy中找到任何特定的包装工具来解决您的问题,所以我已经为此编写了一个临时函数。理想情况下,我认为应该有一个选项,允许在文本中嵌入图像,甚至是一个单独的小部件,但现在这将比什么都没有要好

def wrap_text(target, source):
    text = source.split("|")

    for i in range(0, len(text)):
        if "img=" in text[i]:
            target.add_widget(Image(source=text[i][4:]))
        else:
            target.add_widget(Label(text=text[i]))
提供的代码示例假定您以以下格式将图像引用放入字符串中-
| img=path |
。例如:

class Main(App):

    def build(self):
        base = Builder.load_file("Main.kv")

        text_field = "This is text, below it should be the first image|img=example_1.png|" \
                     "Whereas this text should appear in between the images|img=example_2.png|" \
                     "And this text under the second image"

        wrap_text(base, text_field)

        return base
主要千伏含量

当然,如果您愿意,您可以引入许多改进,例如,您可以自己定制一个标签,而不是添加常规的
标签。或者,可以使图像始终水平添加,除非
\n
字符位于图像引用之前的字符串中。或者,您可以尝试扩展现有的kivy工具,以包含所需的功能(就像人们在kivy中所做的那样)

从小部件检索文本
rv.text\u selected=rv.data[index][description']
不起作用,因为
rv.data[index][description']
是一个
TextWrapper
小部件,而不是字符串。请注意,您在以下行中将其指定为包装器:
species[“description”]=TextWrapper(species[“description”])

如果要从小部件内检索文本字段(实际上是小部件内标签内的文本),请使用以下代码:

# Initialise a new, empty string, to add to it later
text = ""
        
# Iterate over widget's children (might as well dynamically assign them an id to find them faster)
for widget in rv.data[index]['description'].walk():
            
    # Add text if a label is found
    if isinstance(widget, Label):
        text += widget.text
        
# Assign the text to the field
rv.text_selected = text
输出:


同样,您也可以用同样的方法检索图像。但是,请注意,如果要同时显示文本和图像,则不必手动检索文本或图像,只需显示
TextWrapper
。您可以通过调用
add_widget()
来添加它,例如到
BoxLayout
要存档,您必须创建一个自定义小部件,首先创建一个
按钮
,然后将
浮动布局
添加到
按钮
。在
浮动布局
中添加一个
图像
标签

这里有一个例子 白痴

.kv文件

<TextImage>:
    lbl: lbl
    img: img
    box: box

    FloatLayout:
        BoxLayout: # add more Image widget and change there orientation
            id: box
            Image:
                id: img
                source: 'myexample.png'
                pos_hint: {'center_x':.5,'center_y':.5}
                size_hint: 1,.9

            Label:
               id: lbl
               size_hint: 1,.1
               pos_hint: {'center_x':.5,'center_y':.5}
               halign:'center'
:
lbl:lbl
img:img
盒子:盒子
浮动布局:
BoxLayout:#添加更多图像小部件并更改方向
id:盒子
图片:
id:img
来源:“myexample.png”
位置提示:{'center_x':.5,'center_y':.5}
尺寸提示:1.9
标签:
id:lbl
大小提示:1、.1
位置提示:{'center_x':.5,'center_y':.5}
哈利格:“中心”

谢谢!虽然这不允许我在文本中添加可变数量的图像,也不允许在我想添加的位置添加图像,因此这不是我的具体问题的答案,但这是一个更静态的方法的好主意。如果您想添加可变图像并更改文本相对于图像的位置,那么您将添加一个BoxLayout(指定id:name)到FloatLayout并使用add widget Image,您可以更改boxlayout的方向,也可以使用widget的索引来归档您想要的内容。我发现了一个新问题并再次编辑了我的问题,感谢您的想法(我在您的答案中制作了TextWrapper),但我不知道如何将TextWrapper添加到视图中,谢谢!!我编辑了我的答案来回答你的一些新问题。就是这样,我只是通过描述中的文本构建TextWrapper,虽然效率不高,但效果很好:)万分感谢!
# Initialise a new, empty string, to add to it later
text = ""
        
# Iterate over widget's children (might as well dynamically assign them an id to find them faster)
for widget in rv.data[index]['description'].walk():
            
    # Add text if a label is found
    if isinstance(widget, Label):
        text += widget.text
        
# Assign the text to the field
rv.text_selected = text
from kivy.app import App
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.button import Button
from kivy.properties import ObjectProperty
from kivy.uix.image import Image

#the TextImage control
class TextImage(Button):
   lbl = ObjectProperty()
   img = ObjectProperty()
   box = ObjectProperty()

   def __init__(self, **kwargs):
        super(TextImage, self).__init__(**kwargs)

   #function to change specific widget position
   def orient1(self):
       children = self.ids.box.children[:]
       self.ids.box.clear_widgets()
       for child in sorted(children):
       wid.add_widget(child) 
    .... # you can create your own funtions for arrangement

class Form(FloatLayout):
    def __init__(self, **kwargs):
        super(Form, self).__init__(**kwargs)

        Textimg = TextImage()
        Textimg.orient1() #for index arrangement
        #an image
        self.Img = Image(source='pic.png', size_hint=(None,None),size=(100,100))   
        # change the widget organization
        Textimg.ids.box.orientation='vertical' 
        Textimg.ids.box.add_widget(self.Img) 
        #change your picture
        Textimg.ids.img.source='myexample.png'
        #Change the text
        Textimg.ids.lbl.text='Picture1'
        self.add_widget(Textimg)

class MainApp(App):
    def build(self):
        return Form()

if __name__=='__main__':
    MainApp().run()
<TextImage>:
    lbl: lbl
    img: img
    box: box

    FloatLayout:
        BoxLayout: # add more Image widget and change there orientation
            id: box
            Image:
                id: img
                source: 'myexample.png'
                pos_hint: {'center_x':.5,'center_y':.5}
                size_hint: 1,.9

            Label:
               id: lbl
               size_hint: 1,.1
               pos_hint: {'center_x':.5,'center_y':.5}
               halign:'center'