相对于布局放置和移动一组带有 kivy 的图像

Posted

技术标签:

【中文标题】相对于布局放置和移动一组带有 kivy 的图像【英文标题】:Placing and moving a group of images with kivy relative to the layout 【发布时间】:2015-07-19 23:19:00 【问题描述】:

我正在尝试使用 raspberry pi 和 kivy 库创建某种交互式“墙”。

我想在另一个下方垂直显示图像(以后可能还有文本),并在按键上上下移动它们。一种滚动行为,但我想显示许多图像,所以我不想一次加载所有图像并使用滚动视图。

所以我使用 FloatLayout 并在按键后更改图像的位置。我的第一个问题是,我必须使用 Window.width / Window.height 而不是 size_hint / pos_hint 进行操作。我尝试使用 kivy FloatLayout 文档中的示例,但没有成功。

我的问题是,按键后图像会移动,但它们也会改变大小。这是我正在使用的代码。

编辑:

我意识到添加 size_hint=(None, None) 将保持图像大小。这仅表明在布局中使用图像的相对定位和大小可能会更好。如前所述,FloatLayout 文档中的示例对我不起作用。

from kivy.app import App
    from kivy.uix.widget import Widget
    from kivy.uix.button import Button
    from kivy.uix.label import Label
    from kivy.uix.floatlayout import FloatLayout
    from kivy.uix.image import Image
    from kivy.core.window import Window


    class Wall(FloatLayout):
        def __init__(self, **kwargs):
        super(FloatLayout, self).__init__(**kwargs)
        self._keyboard = Window.request_keyboard(self._keyboard_closed, self)
        if not self._keyboard:
            return
        self._keyboard.bind(on_key_down=self.on_keyboard_down)

        self.posts = list()
        self.orientation = 'vertical'

        spacing = 25

        post = Image(source='test.png',
                 allow_stretch=True,
                 keep_ratio=True,
                 size=(Window.width * 0.2z, Window.height * 0.2),
                 center=(Window.width * 0.6, Window.height * 0.5))

        print '#####\nOriginal size and position: width/height', post.width, post.height, ' position x/y', post.x, post.y

        self.posts.append(post)
        self.add_widget(post)
        while self.posts[-1].y + self.posts[-1].height <= Window.height:
            post = Image(source='test.jpg',
                     allow_stretch=True,
                     keep_ratio=True,
                     size=(Window.width * 0.2, Window.height * 0.2),
                     pos=(self.posts[-1].x, self.posts[-1].y + self.posts[-1].height + spacing))

            print '#####\nOriginal size and position: width/height', post.width, post.height, ' position x/y', post.x, post.y

            self.posts.append(post)
            self.add_widget(post)

        def _keyboard_closed(self):
        self._keyboard.unbind(on_key_down=self._on_keyboard_down)
        self._keyboard = None

        def on_keyboard_down(self, keyboard, keycode, text, modifiers):

        key = keycode[1]
        for post in self.children:
            if key == 'up':
            post.y -= 50
            print '#####\nNew size and position: width/height', post.width, post.height, ' position x/y', post.x, post.y
            elif keycode[1] == 'down':
            post.y += 50
            elif key == 'q':
            App.get_running_app().stop()
            #else:
            #    return False
            #return True
        return True

class MessageBoard(App):
    def build(self):
    return Wall()


if __name__ == '__main__':
    MessageBoard().run()

【问题讨论】:

【参考方案1】:

我找到了一个使用 RelativeLayout 并使用 pos_hint / size_hint 属性的解决方案。积极的副作用是,即使窗口调整大小,元素也会保持其大小/位置。

我仍然需要计算绝对坐标来确定元素的位置。缺点是,在 init() 方法中,父元素的大小是未知的,所以我必须使用窗口大小和坐标。如果我的墙不是根元素,这将失败。

元素的移动需要通过pos_hint属性的设置来完成,改变绝对坐标不会产生任何影响。

class ImageAndText(RelativeLayout):
    pass


class Wall(FloatLayout):
    def __init__(self, **kwargs):
        super(Wall, self).__init__(**kwargs)
        self._keyboard = Window.request_keyboard(self._keyboard_closed, self)
        if not self._keyboard:
            return
        self._keyboard.bind(on_key_down=self.on_keyboard_down)

        self.posts = list()
        post = ImageAndText()
        post.size_hint = 1, 0.3
        post.size = (Window.width, Window.height * 0.3)  # needs to be set in order to determine the absolute size
        post.center_y = Window.height * 0.5  # needs to be set in order to determine the absolute coordinates
        post.pos_hint = 'center_y': 0.5
        self.add_widget(post)
        self.posts.append(post)

        while self.posts[-1].top <= Window.height:
            #print 'Old post top:', self.posts[-1].top
            post = ImageAndText()
            post.size_hint = 1, 0.25
            post.size = (Window.width, Window.height * 0.25)
            post.y = self.posts[-1].top  # just above the first one
            post.pos_hint = 'center_y': post.center_y/Window.height
            self.add_widget(post)
            self.posts.append(post)

    def _keyboard_closed(self):
        self._keyboard.unbind(on_key_down=self._on_keyboard_down)
        self._keyboard = None

    def on_keyboard_down(self, keyboard, keycode, text, modifiers):

        key = keycode[1]
        for post in self.posts:
            if key == 'up':
                post.pos_hint = 'center_y': post.pos_hint['center_y']+0.1
            elif keycode[1] == 'down':
                post.pos_hint = 'center_y': post.pos_hint['center_y']-0.1
            elif key == 'q':
                App.get_running_app().stop()
        return True

class MyTestApp(App):
    def build(self):
        return Wall()

if __name__ == "__main__":
    MyTestApp().run()

这是描述 ImageAndText 元素的 .kv 文件。

<ImageAndText>:
    Label:
        font_size: '14sp'
        text: 'Lorem ipsum dolor sit'
        color: (1, 1, 1, 1)
        text_size: (self.parent.width*0.25, None)
        pos_hint: 'center_x': 1.0/6 # set the center to 1/6 of parents width   

    Image:
        source: 'test.png'
        pos_hint: 'center_x': 2.0/3, 'center_y': .5
        size_hint: 0.5, 0.95 # the height will be the same as the parent, the width 0.5 because of the label
        allow_stretch: True

【讨论】:

以上是关于相对于布局放置和移动一组带有 kivy 的图像的主要内容,如果未能解决你的问题,请参考以下文章

Kivy 网格布局固定了某些列的列宽

移动端布局rem em

使用 png 填充图像移动 Raphael 路径,而不破坏 IE 中的图像或相对于元素移动图像?

在 Kivy 中传递自定义小部件属性

在 Android 布局的框架内移动图像

移动WEB开发之rem适配布局