如何在Kivy中从子widget的尺寸更新父widget的尺寸?

2024-04-26 22:15:45 发布

您现在位置:Python中文网/ 问答频道 /正文

在kivyforpython上运行的这个代码片段绘制了一些矩形(框)作为父窗口小部件(RootWidget)的子窗口小部件。你知道吗

按ALT+D可以创建另一个框(添加到RootWidget)。你知道吗

我正在尝试在父窗口小部件上实现一种触摸和拖动行为,以便在用鼠标拖动所有子框时将它们移动到一起。你知道吗

但是,on\ U touch\ U down方法(请参阅自碰撞点(*触摸.pos))只获取原始子小部件(默认情况下创建的小部件)的位置,而不获取新创建的小部件的位置。你知道吗

为什么?有没有办法更新父对象的大小,以便在触摸第一个框以外的框时将其抓取?你知道吗


from kivy.app import App
from kivy.uix.widget import Widget
from kivy.graphics import Ellipse, Color, Rectangle, Line
from kivy.core.window import Window
from kivy.clock import Clock
from kivy.lang import Builder

from kivy.properties import NumericProperty, ListProperty

from random import randint


Builder.load_string('''


<Box>:
    canvas:
        Color:
            rgba: .1, .1, 1, .9
        Line:
            width: 2.
            rectangle: (self.x, self.y, self.width, self.height)


''')


class Tree(Widget):
    pass

class Node(Widget):
    pass

class Box(Widget):

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

        self.size = [500, 300]
        self.height = self.size[1]
        self.width = self.size[0]        
        self.pos = [500,200]

        # bind change of pos to redraw
        self.bind(pos=self.redraw, size=self.redraw)

    def redraw(self, *args):
        # compute head and sisters' positions
        self.x = self.pos[0]
        self.y = self.pos[1]
        #self.height = self.size[0]
        #self.width = self.size[1]        

class Branches(Widget):
    pass

class Terbranch(Widget):
    pass





class RootWidget(Widget):

    def __init__(self, **kwargs):
        super(RootWidget, self).__init__(**kwargs)
        for i in range(2):
            self.add_widget(Box())

        self._keyboard = Window.request_keyboard(
            self._keyboard_closed, self, 'text')
        if self._keyboard.widget:
            # If it exists, this widget is a VKeyboard object which you can use
            # to change the keyboard layout.
            pass
        self._keyboard.bind(on_key_down=self._on_keyboard_down)

        self.bind(pos=self.redraw, size=self.redraw)

    def redraw (self, *args):
        pass


    def on_touch_down(self, touch):
        if self.collide_point(*touch.pos):
            # if the touch collides with our widget, let's grab it
            touch.grab(self)           
            #print ('touched')
            # and accept the touch.
            return True

        return super(RootWidget, self).on_touch_down(touch)

    def on_touch_up(self, touch):
        # check if it's a grabbed touch event
        if touch.grab_current is self:
            # don't forget to ungrab ourself, or you might have side effects
            touch.ungrab(self)
            # and accept the last up
            return True

        return super(RootWidget, self).on_touch_up(touch)

    def on_touch_move(self, touch):
        # check if it's a grabbed touch event
        if touch.grab_current is self:
            #self.pos = touch.pos
            self.pos[0] +=  touch.dx
            self.pos[1] +=  touch.dy

            #redraw moved children
            for child in self.children:
                child.pos[0] +=  touch.dx
                child.pos[1] +=  touch.dy
                child.redraw()
        # and accept the last move
            return True

        return super(RootWidget, self).on_touch_move(touch)



    def _keyboard_closed(self):
        print('My keyboard have been closed!')
        self._keyboard.unbind(on_key_down=self._on_keyboard_down)
        self._keyboard = None

    def _on_keyboard_down(self, keyboard, keycode, text, modifiers):
        #print('The key', keycode, 'have been pressed')
        #print(' - text is %r' % text)
        #print(' - modifiers are %r' % modifiers)

        # Keycode is composed of an integer + a string
        # If we hit escape, release the keyboard
        if keycode[1] == 'escape':
            keyboard.release()

        elif keycode[1] == 'd' and modifiers[0] == 'alt':
            newbox = Box()
            self.add_widget(newbox)

        # Return True to accept the key. Otherwise, it will be used by
        # the system.
        return True

    def update(self, dt):

        pass





class MyApp(App):
    def build(self):
        rw = RootWidget()
        #Clock.schedule_interval(rw.update, 0.2)
        return rw


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

Tags: thefromposimportselfreturnifon
1条回答
网友
1楼 · 发布于 2024-04-26 22:15:45

我不确定我是否完全理解您的问题,但是在您的on_touch_move方法中,您正在移动所有子Box实例。但是你也在改变RootWidget本身的pos。由于RootWidgetApp的根窗口,因此更改其pos属性不会产生任何视觉效果。但是,该更改会影响self.collide_point方法(它使用possize检查冲突)。所以,如果我理解你的问题,你只需要省去改变RootWidgetpos

def on_touch_move(self, touch):
    # check if it's a grabbed touch event
    if touch.grab_current is self:
        #self.pos = touch.pos

        # comment out the next two lines
        #self.pos[0] +=  touch.dx
        #self.pos[1] +=  touch.dy

        #redraw moved children
        for child in self.children:
            child.pos[0] +=  touch.dx
            child.pos[1] +=  touch.dy
            child.redraw()
    # and accept the last move
        return True

相关问题 更多 >