首页 > 解决方案 > 更新 Kivy 中子对象小部件的位置(Python 不是 .kv)

问题描述

我有一个父小部件,可以添加和定位自定义小部件对象,但是当调整窗口大小时,它们不会更新它们的位置......

import kivy
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.graphics import Color, Line, Ellipse, Rectangle
from kivy.metrics import dp
from kivy.uix.widget import Widget


class circleChild(Widget):
    def __init__(self, *args, **kwargs):
        self.pos = kwargs.get('_pos')
        self.size = kwargs.get('_size')
        super(circleChild, self).__init__()
        with self.canvas:
            Color(0.4, 0.6, 0.9, 1)  # ConrflowerBlue
            Ellipse(pos=self.pos, size=self.size, width=dp(2))


class RootWidget(BoxLayout):
    def __init__(self, *args, **kwargs):
        BoxLayout.__init__(self, *args, **kwargs)
        self.bind(pos=self.draw)
        self.bind(size=self.draw)
        self.layout1 = BoxLayout()
        self.layout2 = BoxLayout(opacity=0.8)
        self.add_widget(self.layout1)
        self.add_widget(self.layout2)
        self.childrenAdded = False

    def draw(self, *args):
        with self.canvas.before:
            Color(.8, .8, .8, 1)  # LightGrey
            self.bg = Rectangle(pos=self.pos, size=self.size)
        self.layout1.canvas.clear()
        with self.layout1.canvas:
            Color(0, 0, 0, 1)  # Black
            Line(
                points=[
                    self.center_x, self.center_y - 200, self.center_x,
                    self.center_y + 200
                ],
                width=dp(2))
            Line(
                points=[
                    self.center_x - 200, self.center_y, self.center_x + 200,
                    self.center_y
                ],
                width=dp(2))
        if not self.childrenAdded:
            self.addChildren()

    def addChildren(self, *args):
        circle1 = circleChild(
            _pos=[self.center_x + 100, self.center_y + 100], _size=[100, 100])
        circle2 = circleChild(
            _pos=[self.center_x + 100, self.center_y - 200], _size=[100, 100])
        circle3 = circleChild(
            _pos=[self.center_x - 200, self.center_y + 100], _size=[100, 100])
        circle4 = circleChild(
            _pos=[self.center_x - 200, self.center_y - 200], _size=[100, 100])
        self.layout2.add_widget(circle1)
        self.layout2.add_widget(circle2)
        self.layout2.add_widget(circle3)
        self.layout2.add_widget(circle4)
        self.childrenAdded = True


class PositionChildren(App):
    title = "PositionChildren"

    def build(self):
        return RootWidget()


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

结果是:

在此处输入图像描述

问题是在调整窗口大小时,会发生这种情况:

在此处输入图像描述

如何在 python 中重新定位 childWidgets?

标签: pythonkivy

解决方案


我看到您正在使创建 _pos 或 _size 等新属性变得复杂,相反,您应该只使用现有属性 pos 和 size,另一方面,您每时每刻都在使用画布,而不是重用元素。

考虑到上述情况,简单的解决方案是:

from kivy.app import App
from kivy.graphics import Color, Line, Ellipse, Rectangle
from kivy.metrics import dp
from kivy.uix.widget import Widget

class circleChild(Widget):
    def __init__(self, **kwargs):
        super(circleChild, self).__init__(**kwargs)
        self.draw()
        self.bind(pos=self.redraw, size=self.redraw)

    def draw(self):
        with self.canvas:
            Color(0.4, 0.6, 0.9, 1)  # ConrflowerBlue
            self.ellipse = Ellipse(width=dp(2))

    def redraw(self, *args):
        # reuse
        self.ellipse.pos = self.pos
        self.ellipse.size = self.size

class RootWidget(Widget):
    def __init__(self, **kwargs):
        super(RootWidget, self).__init__(**kwargs)
        self.draw()
        self.bind(pos=self.redraw, size=self.redraw)

        self.circle1 = circleChild(size=[100, 100])
        self.circle2 = circleChild(size=[100, 100])
        self.circle3 = circleChild(size=[100, 100])
        self.circle4 = circleChild(size=[100, 100])
        for c in (self.circle1, self.circle2, self.circle3, self.circle4):
            self.add_widget(c)

    def draw(self):
        with self.canvas.before:
            Color(.8, .8, .8, 1)  # LightGrey
            self.bg = Rectangle(pos=self.pos, size=self.size)
            Color(0, 0, 0, 1)  # Black
            self.vline = Line(width=dp(2))
            self.hline = Line(width=dp(2))

    def redraw(self, *args):
        # reuse
        self.bg.pos = self.pos
        self.bg.size = self.size
        self.vline.points = [
            self.center_x, 
            self.center_y - 200, 
            self.center_x,
            self.center_y + 200
        ]
        self.hline.points=[
            self.center_x - 200, 
            self.center_y, 
            self.center_x + 200,
            self.center_y
        ]
        self.circle1.pos = [self.center_x + 100, self.center_y + 100]
        self.circle2.pos = [self.center_x + 100, self.center_y - 200]
        self.circle3.pos = [self.center_x - 200, self.center_y + 100]
        self.circle4.pos = [self.center_x - 200, self.center_y - 200]

class PositionChildren(App):
    title = "PositionChildren"

    def build(self):
        return RootWidget(size=(100, 100))

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

推荐阅读