Kivy tutorial 008: More kv language

Kivy tutorial 008: More kv language – Kivy Blog

Central themes: Event binding and canvas instructions in kv language
中心主题: 事件绑定 和 kv语言里的画布结构

This tutorial directly follows on from the previous, so start by retrieving the previous code, as below:
这节导师课直接地跟随上节的,因此从上次的代码找了些代码开始。

main.py:

from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.slider import Slider

from kivy.uix.boxlayout import BoxLayout
from kivy.uix.label import Label
from kivy.uix.slider import Slider

from kivy.uix.widget import Widget
from kivy.graphics import Rectangle, Color, Line

from random import random

class DrawingWidget(Widget):
    def __init__(self):
        super(DrawingWidget, self).__init__()

        with self.canvas:
            Color(1, 1, 1, 1)
            self.rect = Rectangle(size=self.size,
                                  pos=self.pos)
        self.bind(pos=self.update_rectangle,
                  size=self.update_rectangle)

    def update_rectangle(self, instance, value):
        self.rect.pos = self.pos
        self.rect.size = self.size

    def on_touch_down(self, touch):
        super(DrawingWidget, self).on_touch_down(touch)

        if not self.collide_point(*touch.pos):
            return

        with self.canvas:
            Color(random(), random(), random())
            self.line = Line(points=[touch.pos[0], touch.pos[1]], width=2)

    def on_touch_move(self, touch):
        if not self.collide_point(*touch.pos):
            return

        self.line.points = self.line.points + [touch.pos[0], touch.pos[1]]


class Interface(BoxLayout):
    pass

class DrawingApp(App):

    def build(self):
        root_widget = Interface()
        return root_widget

DrawingApp().run()

drawing.kv:

<Interface>:
    orientation: 'vertical'
    DrawingWidget:
    Slider:
        min: 0
        max: 1
        value: 0.5
        size_hint_y: None
        height: 80
    Slider:
        min: 0
        max: 1
        value: 0.5
        size_hint_y: None
        height: 80
    Slider:
        min: 0
        max: 1
        value: 0.5
        size_hint_y: None
        height: 80
    BoxLayout:
        orientation: 'horizontal'
        size_hint_y: None
        height: 80
        Label:
            text: 'output colour:'
        Widget:

The first thing to do is draw the coloured Rectangle that the final Widget uses to display an output colour, and for this we need to know how to draw canvas instructions in kv language. The syntax is as below:
第一件事 是 画多彩的矩形, 这矩形是最后的组件 用来演示一个output颜色, 对这个颜色,我们需要知道kv语言中画图结构如何。

Widget:
    canvas:
        Color:
            rgb: 0, 1, 0  # using a fixed colour for now
        Rectangle:
            size: self.size
            pos: self.pos

Run the code, and you’ll see another of kv language’s most important features; automatic event binding. In the original Python code of tutorial 7 we needed an extra .bind(...) call to make the be updated to always be placed within its Widget. In kv language this is not necessary, the dependency on self.size and self.pos is automatically detected, and a binding automatically created!
运行代码, 并且你将看到kv语言另一个最重要的特征;自动地事件绑定。 在导师课7中的Python源始代码,我们需要一个巨大的  .extra() 召唤, 让更新 总是在它组件内。 在kv语言中是不必要的, self.size 和self.pos独自自动地执行并且绑定了自动地创建!

This is also the generic syntax for canvas instructions; first add canvas: (or canvas.before or canvas.after), then, indent by 4 spaces, and add canvas instructions much like you would Widgets. However, note that canvas instructions are not widgets.
这也是通用的语法给canvas结构;第一 添加canvas: (或者canvas.before 或者 canvas.after )然后, 4个空格缩进, 并且增加尽可能你想要的组件到canvas结构。 然而, 注意canvas 结构不是组件。

The only thing now missing from the original Python interface implementation in tutorial 7 is having the Sliders automatically update the output colour rectangle. Change the <Interface>: rule to the following:
在导师课第7节中从源码界面执行中唯一缺少的事情是 有sliders 自动地更新到 输出颜色矩形。 改变<interface>: 规则在下面:

<Interface>:
    orientation: 'vertical'
    DrawingWidget:
    Slider:
        id: red_slider
        min: 0
        max: 1
        value: 0.5
        size_hint_y: None
        height: 80
    Slider:
        id: green_slider
        min: 0
        max: 1
        value: 0.5
        size_hint_y: None
        height: 80
    Slider:
        id: blue_slider
        min: 0
        max: 1
        value: 0.5
        size_hint_y: None
        height: 80
    BoxLayout:
        orientation: 'horizontal'
        size_hint_y: None
        height: 80
        Label:
            text: 'output colour:'
        Widget:
            canvas:
                Color:
                    rgb: red_slider.value, green_slider.value, blue_slider.value
                Rectangle:
                    size: self.size
                    pos: self.pos

There are actually only two changes here; we gave each Slider an id declaration, and in the canvas Color referred to the sliders with this name. Giving a widget an id is just like naming it in Python so that you can refer to it elsewhere.
这只有2个改变: 我们给每个slider 一个id声明, 并且在canvas 颜色中提及了sliders 和这个名字。 给与一个widget组件一个id 就像在python中命名它一样,因此你可以在其他的地方提及它。

Thanks to kv’s automatic binding, this is all we need to do to have the Color update automatically whenever a slider value changes. Run the code, and you should see that things work exactly as they did in the original Python interface.
感谢kv自动地绑定, 这是所有我们需要做的是 让颜色更新自动地当一个slider值改变时。 运行代码,并且你应该看到事儿们严谨地像在源码python界面中做的一样。

We can finish this tutorial with a couple of extra kv conveniences. First, just as we added an automatically updating Rectangle in the Widget kv, we can do the same for the background of the DrawingWidget. Delete the __init__ and update_rectangle methods in the Python DrawingWidget code, and add a new rule in the kv file:
我们可以完成这节导师课同一些kv的巨大方便性。 首先,像我们添加的一个自动地更新的矩形在widget kv中一样, 我们可以在DrawingWidget的背景中做相同的事情。 删除__init__ 和  update_rectangle 方法在python 的DrawingWidget代码中, 并且添加一个新的规则在kv文件中:

<DrawingWidget>:
    canvas:
        Color:
            rgba: 1, 1, 1, 1
        Rectangle:
            pos: self.pos
            size: self.size

Second, you might have noticed that there’s a lot of code duplication in each of the Slider rules - we set the same min, max, initial value`, ``size_hint_y` and height for every one. As is normal in Python, it would be natural to abstract this in a new class, so as to set each value only once. You can probably already see how to do this with what we’ve learned so far (make a new class YourSlider(Slider): in the Python and add a new <YourSlider>: rule in the kv), but I’ll note that you can even do this entirely in kv:
其次, 你可能已经注意到了那有一些复制代码在每个slider规则中,我们设置了相同的 min, initial value 'size_hint_y'  和高度给每一个Slider。 像平常在Python中一样, 它总是本能的使分离在一个新的类中,因此像每次设置每个值。你大概可以已经看到如何同我们学到的来这么做, (制作一个新的类: YourSlider(Slider): 在python 代码中,并且增加一个新的<YourSlider>: 规则在kv中, 但是我将意识到 你可以在kv中全部这么干:

<ColourSlider@Slider>:
    min: 0
    max: 1
    value: 0.5
    size_hint_y: None
    height: 80


<Interface>:
    orientation: 'vertical'
    DrawingWidget:
    ColourSlider:
        id: red_slider
    ColourSlider:
        id: green_slider
    ColourSlider:
        id: blue_slider
    BoxLayout:
        orientation: 'horizontal'
        size_hint_y: None
        height: 80
        Label:
            text: 'output colour:'
        Widget:
            canvas:
                Color:
                    rgb: red_slider.value, green_slider.value, blue_slider.value
                Rectangle:
                    size: self.size
                    pos: self.pos

The new <ColourSlider@Slider>: rule defines a dynamic class, a Python class kv rule without a corresponding Python code definition. This is convenient if you want to do something repeatedly only in kv, and never access it from Python.

新的 <ColourSlider@Slider>: 规则定义了一个动力的类, 一个python 类kv规则没有一个相关的python编码定义。 这是方便的如果你只想做些重复的事在kv中, 并且绝不从python中访问它。

At this point, we’ve reached feature parity with the original Python code, and seen all the basics of kv language. In the next tutorial we’ll finish off the original purpose of all these sliders; letting the user set the colour of line that is drawn by the DrawingWidget.
这时候,我们已经达到了和源码python代码相同的效果, 并且看到了所有的kv的基础元素。 在下面的导师课中,我们将完成这些sliders 原始的目的,让用户设置DrawingWidget画的线的颜色。

Full code

main.py:

from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.slider import Slider

from kivy.uix.boxlayout import BoxLayout
from kivy.uix.label import Label
from kivy.uix.slider import Slider

from kivy.uix.widget import Widget
from kivy.graphics import Rectangle, Color, Line

from random import random

class DrawingWidget(Widget):
    def on_touch_down(self, touch):
        super(DrawingWidget, self).on_touch_down(touch)

        if not self.collide_point(*touch.pos):
            return

        with self.canvas:
            Color(random(), random(), random())
            self.line = Line(points=[touch.pos[0], touch.pos[1]], width=2)

    def on_touch_move(self, touch):
        if not self.collide_point(*touch.pos):
            return

        self.line.points = self.line.points + [touch.pos[0], touch.pos[1]]


class Interface(BoxLayout):
    pass

class DrawingApp(App):

    def build(self):
        root_widget = Interface()
        return root_widget

DrawingApp().run()

drawing.kv:

<DrawingWidget>:
    canvas:
        Color:
            rgba: 1, 1, 1, 1
        Rectangle:
            pos: self.pos
            size: self.size

<ColourSlider@Slider>:
    min: 0
    max: 1
    value: 0.5
    size_hint_y: None
    height: 80


<Interface>:
    orientation: 'vertical'
    DrawingWidget:
    ColourSlider:
        id: red_slider
    ColourSlider:
        id: green_slider
    ColourSlider:
        id: blue_slider
    BoxLayout:
        orientation: 'horizontal'
        size_hint_y: None
        height: 80
        Label:
            text: 'output colour:'
        Widget:
            canvas:
                Color:
                    rgb: red_slider.value, green_slider.value, blue_slider.value
                Rectangle:
                    size: self.size
                    pos: self.pos

这段代码是使用Kivy框架(一个用于开发多触摸应用的Python库)来创建一个可以绘制线条的DrawingWidget类。让我们逐步分析这段代码:

  1. 类定义

class DrawingWidget(Widget):

这里定义了一个名为DrawingWidget的类,它继承自Kivy的Widget类。
      2. on_touch_down方法
当触摸屏幕并按下时,这个方法会被调用

* 首先,它调用了`super(DrawingWidget, self).on_touch_down(touch)`,这是为了确保父类(即`Widget`类)的`on_touch_down`方法也能得到执行(如果有需要的话)。

* 接着,它检查触摸点是否在`DrawingWidget`的区域内(使用`self.collide_point(*touch.pos)`)。如果不在,方法就返回,不执行后续的绘制代码。

* 如果在区域内,它会进入`with self.canvas:`块,这意味着它将对`canvas`(即绘图表面)执行一些操作。 + 它首先使用`Color(random(), random(), random())`随机选择一个颜色。 + 然后,它创建了一个`Line`对象,该对象从触摸点开始,但只有一个点(即触摸点的位置)。注意这里有个小问题:`Line`对象的`points`应该是一个二维列表,即列表的每个元素都是一个坐标(x, y)。但在这里,它只是一个包含两个元素的列表,这可能会导致问题。

小问题:如果触摸点不在DrawingWidget区域内,return 返回的是什么?

在给出的代码片段中,如果触摸点不在DrawingWidget的区域内,return语句将直接返回None,因为它没有指定要返回的具体值。在Python中,如果函数或方法中没有明确的return语句或return后面没有跟任何值,那么该函数或方法将默认返回None

on_touch_downon_touch_move方法中,当self.collide_point(*touch.pos)返回False(即触摸点不在DrawingWidget区域内)时,方法会立即通过return退出,不执行后续的代码。由于没有指定返回值,所以返回的是None

这种设计是为了避免在不必要的情况下执行绘图或更新操作,从而提高代码效率和响应速度。

        3. on_touch_move方法
当触摸点在屏幕上移动时,这个方法会被调用。

* 同样,它首先检查触摸点是否在`DrawingWidget`的区域内。

* 如果在区域内,它会更新`line`对象的`points`属性,将新的触摸点坐标添加到列表的末尾。但这里也有一个小问题:由于`line.points`是一个二维列表(至少它应该是一个),但之前我们设置它时似乎没有将其作为一个二维列表。所以,这里应该是`self.line.points += [[touch.pos[0], touch.pos[1]]]`,以确保我们添加的是一个坐标点。

  • 30
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

xinzheng新政

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值