Kivy:处理事件

2024-07-21 09:37:31 发布

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

类中的Palete是button,它与Paint类中移除画布内容的方法绑定在一起。我认为,解决方法是使用自定义事件。我对事件没有经验,也不了解kivy手册中的描述。我需要保持班级的结构。你能帮帮我吗?在

from kivy.app import App
from kivy.uix.widget import Widget

from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button

from kivy.graphics import Color, Rectangle
from functools import partial


class Paint(Widget):

    def __init__(self, palete,**kwargs):
        # make sure we aren't overriding any important functionality
        super(Paint, self).__init__(**kwargs)
        self.palete = palete
        self.contents = []

    def on_touch_down(self, touch):
        color = self.palete.act_col
        with self.canvas:
            Color(color[0], color[1], color[2])
            sqr = Rectangle(pos = (touch.x, touch.y), size=(20, 40))
            self.contents.append(sqr)

class Palete(BoxLayout):
    def __init__(self, **kwargs):
        super(Palete, self).__init__(**kwargs)

        self.act_col= (1, 0, 0)

        self.licol =[]
        self.licol.append((1, 0, 0))
        self.licol.append((0, 1, 0))

        self.layout = BoxLayout(size_hint=(1, None), height=50)

        for i in range(0, len(self.licol)):
            but = Button( id = str(i))
            col = self.licol[i]
            but.background_normal = ''
            but.background_color = (col[0], col[1], col[2], 1)


            act = partial(self.SetColor, but.id)
            but.bind(on_press=act)
            self. layout.add_widget(but)

        but = Button(text="<--",on_press = self.ClearContents)
        self.layout.add_widget(but)

    def SetColor(self,_col, h):
        ind = int(_col)
        self.act_col = self.licol[ind]
        pass

    def ClearContents(self, obj):
        if len(self.contents)!= 0:
            self.canvas.remove(self.contents[-1])
            self.contents = self.contents[:-1]


class MyPaintApp(App):

    def build(self):
        root = BoxLayout(orientation='vertical')
        self.palete = Palete()

        self.paint =Paint(self.palete)
        root.add_widget(self.paint)

        root.add_widget(self.palete.layout)

        return root


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

Tags: fromimportselfdefcontentscolwidgetact
2条回答

canvascontentsPaint类的属性,您正试图从Palate类访问它。在

如果不想更改结构,可以将Paint类的引用传递给Palete类:

from kivy.app import App
from kivy.uix.widget import Widget

from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button

from kivy.graphics import Color, Rectangle
from functools import partial


class Paint(Widget):

    def __init__(self, palete,**kwargs):
        # make sure we aren't overriding any important functionality
        super(Paint, self).__init__(**kwargs)
        self.palete = palete
        self.palete.paint = self
        self.contents = []


    def on_touch_down(self, touch):
        color = self.palete.act_col
        with self.canvas:
            Color(color[0], color[1], color[2])
            sqr = Rectangle(pos = (touch.x, touch.y), size=(20, 40))
            self.contents.append(sqr)

class Palete(BoxLayout):
    def __init__(self, **kwargs):
        super(Palete, self).__init__(**kwargs)
        self.act_col= (1, 0, 0)
        self.licol =[]
        self.licol.append((1, 0, 0))
        self.licol.append((0, 1, 0))
        self.paint = None

        self.layout = BoxLayout(size_hint=(1, None), height=50)

        for i in range(0, len(self.licol)):
            but = Button( id = str(i))
            col = self.licol[i]
            but.background_normal = ''
            but.background_color = (col[0], col[1], col[2], 1)


            act = partial(self.SetColor, but.id)
            but.bind(on_press=act)
            self. layout.add_widget(but)

        but = Button(text="< ",on_press = self.ClearContents)
        self.layout.add_widget(but)

    def SetColor(self,_col, h):
        ind = int(_col)
        self.act_col = self.licol[ind]
        pass

    def ClearContents(self, obj):
        if not self.paint:
            return
        if self.paint.contents:
            self.paint.canvas.remove(self.paint.contents.pop())


class MyPaintApp(App):

    def build(self):
        root = BoxLayout(orientation='vertical')
        self.palete = Palete()

        self.paint = Paint(self.palete)
        root.add_widget(self.paint)

        root.add_widget(self.palete.layout)

        return root


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

我认为您应该从实现画布的类中删除对象以保留封装。另一个选项是将回调移到Paint类,并将on_press事件绑定到它(来自Paint类):

^{pr2}$

使用list.pop而不是切片从列表中删除最后一项。它更具可读性,而且不必每次都复制列表。在

enter image description here

请参考详细说明和示例。在

重载方法__

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

We overload the method __init__() so as to add widgets and to define their behavior. One should not forget to call super in order to implement the functionality of the original class being overloaded. Also note that it is good practice not to omit the **kwargs while calling super, as they are sometimes used internally.

油漆等级

1。增加Kivy属性

由于您将访问调色板和内容,我们声明如下:

^{pr2}$

2。安丘触地事件

默认情况下,触摸事件被调度到所有当前显示的小部件。这意味着无论触摸事件是否发生在它们的物理区域内,小部件都会接收到触摸事件。Kivy将touch事件发送到所有widget,并让它们决定如何对它们做出反应。如果您只想响应widget/按钮内的触摸事件,则必须使用自碰撞点方法。当它发生冲突时,你应该只得到一个widget/按钮。在

在下面的代码片段中,我们重写了Widget类的on_touch_down()方法。在这里,我们检查触摸与我们的小部件的碰撞。在

如果触摸落在我们的小部件中,我们在画布上创建一个正方形并返回True,表示我们已经使用了触摸,不希望它进一步传播。在

最后,如果touch落在我们的widget之外,我们使用super(Paint,self)调用原始事件,并返回结果。这允许触摸事件传播继续进行 通常都发生过。在

def on_touch_down(self, touch):
    if self.collide_point(*touch.pos):
        color = self.palette.act_col
        with self.canvas:
            Color(color[0], color[1], color[2])
            sqr = Rectangle(pos=(touch.x, touch.y), size=(20, 40))
            self.contents.append(sqr)
        return True
    return super(Paint, self).on_touch_down(touch)

调色板类

3。act_col-列表属性

因为act_col将在类Paint中访问,所以我们将其声明为Kivy ListProperty。在

act_col = ListProperty([1, 0, 0])

4。嵌套BoxLayout-已删除

因为Palette类是一个BoxLayout,所以我们不需要嵌套的BoxLayout。因此,它被移除。在

5。新闻发布会

传递给回调的唯一参数是我们绑定到的对象,即按钮。在

def SetColor(self, btn):
    self.act_col = self.licol[int(btn.id)]

def ClearContents(self, btn):

MyPaintApp类

6。生成方法

我们没有把所有的东西放在类MyPaintApp的构建方法中,而是将它们移到类Painting中。我们还必须声明类的对象和调色板。在

类喷漆(方框布局): 调色板=对象属性(无) 绘制=对象属性(无)

def __init__(self, **kwargs):
    super(Painting, self).__init__(**kwargs)
    self.orientation = "vertical"

    self.palette = Palette()
    self.paint = Paint(palette=self.palette)

    self.add_widget(self.paint)
    self.add_widget(self.palette)

示例

在主.py在

from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button
from kivy.graphics import Color, Rectangle
from kivy.properties import ObjectProperty, ListProperty


class Paint(Widget):
    palette = ObjectProperty(None)
    contents = ListProperty([])

    def __init__(self, palette, **kwargs):
        # make sure we aren't overriding any important functionality
        super(Paint, self).__init__(**kwargs)
        self.palette = palette

    def on_touch_down(self, touch):
        """
        We override the on_touch_down() method of the Widget class. Here, we check for
        collision of the touch with our widget.

        If the touch falls inside our widget, we create a square on the canvas and return True,
        indicating that we have consumed the touch and don't want it to propagate any further.

        Finally, if the touch falls outside our widget, we call the original event using super(...)
        and return the result. This allows the touch event propagation to continue as it would
        normally have occurred.

        :param touch:
        :return:
        """
        if self.collide_point(*touch.pos):
            color = self.palette.act_col
            with self.canvas:
                Color(color[0], color[1], color[2])
                sqr = Rectangle(pos=(touch.x, touch.y), size=(20, 40))
                self.contents.append(sqr)
            return True
        return super(Paint, self).on_touch_down(touch)


class Palette(BoxLayout):
    act_col = ListProperty([1, 0, 0])

    def __init__(self, **kwargs):
        super(Palette, self).__init__(**kwargs)
        self.licol = []
        self.licol.append((1, 0, 0))
        self.licol.append((0, 1, 0))

        self.size_hint = (1, None)
        self.height = 50

        for i in range(0, len(self.licol)):
            but = Button(id=str(i))
            col = self.licol[i]
            but.background_normal = ''
            but.background_color = (col[0], col[1], col[2], 1)
            but.bind(on_press=self.SetColor)
            self.add_widget(but)

        but = Button(text="< ", on_press=self.ClearContents)
        self.add_widget(but)

    # The only argument passed to the callback is the
    # object (i.e. button) which we have bound to
    def SetColor(self, btn):
        self.act_col = self.licol[int(btn.id)]

    # The only argument passed to the callback is the
    # object (i.e. button) which we have bound to
    def ClearContents(self, btn):
        if len(self.parent.paint.contents) != 0:
        # list.pop() - removes and returns the last item in the list
            self.parent.paint.canvas.remove(self.parent.paint.contents.pop())


class Painting(BoxLayout):
    palette = ObjectProperty(None)
    paint = ObjectProperty(None)

    def __init__(self, **kwargs):
        super(Painting, self).__init__(**kwargs)
        self.orientation = "vertical"

        self.palette = Palette()
        self.paint = Paint(palette=self.palette)

        self.add_widget(self.paint)
        self.add_widget(self.palette)


class MyPaintApp(App):

    def build(self):
        return Painting()


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

输出

Figure 1 - App Startupenter image description hereenter image description hereenter image description here

相关问题 更多 >