KIVY Widget class

Widget class

Jump to API

Module: kivy.uix.widget

Added in 1.0.0

The Widget class is the base class required for creating Widgets. This widget class was designed with a couple of principles in mind:

组件类是基础类, 被需要来创造组件们。  这组件类是掺和着一些智慧里的原则被设计的。

  • Event Driven     事件驱动

  • Widget interaction is built on top of events that occur. If a property changes, the widget can respond to the change in the ‘on_<propname>’ callback. If nothing changes, nothing will be done. That’s the main goal of the Property class.
     组件相互作用 是建立在呈现的事件们之上。 如果一个属性改变, 这组件可以对 on_<propname>返回结果  里的改变做出回应。如果没啥改变,没啥可干的。那是Property类的 主要的目标。

  • Separation Of Concerns (the widget and its graphical representation)
    涉及的间隔  (这组件和它的图像的表现物)

    Widgets don’t have a draw() method. This is done on purpose: The idea is to allow you to create your own graphical representation outside the widget class. Obviously you can still use all the available properties to do that, so that your representation properly reflects the widget’s current state. Every widget has its own Canvas that you can use to draw. This separation allows Kivy to run your application in a very efficient manner.
    组件们没有一个 draw()方法。 这样干是有目的的: 这主意是来允许你来在组件类之外创造你自己个的图像表现。更显然的, 你仍然可以是用所有适合的属性来这么干,以至于你的图像表现物完全地影响着组件当前的状态。 每个组件有它自己个的Canvas 你可以用来画画。 这间隔允许Kivy来运行你的应用程序在一个非常有效率的方式。

  • Bounding Box / Collision  绑定的Box  / 抵触

    Often you want to know if a certain point is within the bounds of your widget. An example would be a button widget where you only want to trigger an action when the button itself is actually touched. For this, you can use the collide_point() method, which will return True if the point you pass to it is inside the axis-aligned bounding box defined by the widget’s position and size. If a simple AABB is not sufficient, you can override the method to perform the collision checks with more complex shapes, e.g. a polygon. You can also check if a widget collides with another widget with collide_widget().
    经常,你想来知道是不是有一个明显的一点来判断里外组件的边界。 一个例子可以是一个按钮组件在你只想来引发一个行为当这按钮它自己个是真正被触摸的。  关于这点,你可以用collide_point()方法,这方法将返回True如果这点你传给它是在 以组件的位置和大小被定义的轴对称关系盒子的条件内。 如果一个简单地AABB 是不充足的, 你可以这方法上伸展来演示这抵触检查同更多复杂的姓张, 例如: 一个多边形。 你也可以使用 collide_widget() 检查是否一个组件与另一个组件抵触 

We also have some default values and behaviors that you should be aware of:|
我们也有许多默认的值和行为 你应该了解的:

  • Widget is not a Layout: it will not change the position or the size of its children. If you want control over positioning or sizing, use a Layout.
    一个组件不是一个布局: 它将不会改变它子类的位置或者大小。 如果你想在位置和大小上有所控制,使用一个 布局Layout。

  • The default size of a widget is (100, 100). This is only changed if the parent is a Layout. For example, if you add a Label inside a Button, the label will not inherit the button’s size or position because the button is not a Layout: it’s just another Widget.
    一个组件默认的大小是(100, 100). 这只有当父类是一个布局才会改变。例如,如果你增加了一个 标签Label 在一个按钮里, 这个标签Label 将不会 继承这个按钮的大小或者位置因为这按钮不是一个布局。 它只是另外一个已组建。

  • The default size_hint is (1, 1). If the parent is a Layout, then the widget size will be the parent layout’s size.
    默认的size_hint  是 (1,1),如果父类是一个布局,然后这组件大小将是父类布局的大小。

  • on_touch_down()on_touch_move()on_touch_up() don’t do any sort of collisions. If you want to know if the touch is inside your widget, use collide_point().
    on_touch_down(), on_touch_move(), on_touch_up() 不做任何种类的抵触。  如果你想知道如果触摸是是不是在你的组件内, 用collide_point()

Using Properties  使用属性

When you read the documentation, all properties are described in the format:
当你阅读当前的文件, 所有的属性都被总体安排地设计好了。

<name> is a <property class> and defaults to <default value>.
<name> 是一个 <property class> 属性类 并且默认是 <default value>

e.g.

text is a StringProperty and defaults to ‘’.
text 是一个StringProperty 字符属性 并且默认是 ' '

If you want to be notified when the pos attribute changes, i.e. when the widget moves, you can bind your own callback function like this:
如果你想被注意当位置属性改变的时候,   当这组件移动时,你可以关联你自己个地返回功能像这样:

def callback_pos(instance, value):
    print('The widget', instance, 'moved to', value)

wid = Widget()
wid.bind(pos=callback_pos)

Read more about Properties.

Basic drawing  基础绘画

Widgets support a range of drawing instructions that you can use to customize the look of your widgets and layouts. For example, to draw a background image for your widget, you can do the following:
组件支持一个范围的画画指令, 你可以用来定制你组件和布局们的外貌。 例如:  画一个背景图片给你的组件, 你可以如下这样做:

def redraw(self, args):
    self.bg_rect.size = self.size
    self.bg_rect.pos = self.pos

widget = Widget()
with widget.canvas:
    widget.bg_rect = Rectangle(source="cover.jpg", pos=self.pos, size=self.size)
widget.bind(pos=redraw, size=redraw)

To draw a background in kv:

Widget:
    canvas:
        Rectangle:
            source: "cover.jpg"
            size: self.size
            pos: self.pos

These examples only scratch the surface. Please see the kivy.graphics documentation for more information.
这些案例仅仅是仓促写了点皮毛。 请看kivy.graphic 文档的更多的知识。

Widget touch event bubbling¶  组件触摸事件冒泡

When you catch touch events between multiple widgets, you often need to be aware of the order in which these events are propagated. In Kivy, events bubble up from the first child upwards through the other children. If a widget has children, the event is passed through its children before being passed on to the widget after it.
当你在多个组件之间抓取 触摸事件, 你经常需要意识到这些事件被传播的顺序。 在kivy里, 事件从第一个子类向上到其他的子类冒泡。 如果一个组件有子类,这事件被它的子类们已经穿过了,然后再被传给这组件。
 

在多个控件之间捕获触摸事件时,你通常需要了解这些事件传播的顺序。在Kivy中,事件是从第一个子控件开始,向上冒泡至其他子控件的。如果一个控件有子控件,那么事件会先在其子控件中传递,然后再传递给其后的控件。

简单地说,这意味着当你触摸一个包含多个子控件的控件时,首先会触发子控件的触摸事件处理函数(如果它们有定义的话),然后这些事件会“冒泡”到父控件,如果父控件也定义了相应的事件处理函数,那么这些函数也会被触发。这种机制使得开发者能够更精细地控制事件在不同层级控件中的处理逻辑

文心扩展:

会传递给最顶层的部件(在这个例子中是 MyLayout),但由于 MyLayout 没有重写 on_touch_down 方法,它会将事件传递给它的子部件。然而,由于你试图将 yourlabel 和 herlabel 添加到 label(一个 Label 部件),这些事件实际上并没有到达它们,因为 label 不是一个容器,不能包含子部件。

关于 on_touch_down 方法的返回值:

  • 如果 on_touch_down 方法返回 True,则表示该事件已被该组件消耗,并且不会继续向下(到子组件)或向上(到父组件)传播。
  • 如果 on_touch_down 方法返回 False,则表示该事件没有被该组件消耗,并且会继续传播。

注意: Label 不是容器部件,它不支持子部件

As the add_widget() method inserts widgets at index 0 by default, this means the event goes from the most recently added widget back to the first one added. Consider the following:

当 add_widget() 方法插入组件在 索引默认为0 时,这意味着这事件从最新添加的组件到第一个添加的。 看下面的代码思考:

box = BoxLayout()
box.add_widget(Label(text="a"))
box.add_widget(Label(text="b"))
box.add_widget(Label(text="c"))

The label with text “c” gets the event first, “b” second and “a” last. You can reverse this order by manually specifying the index:
有”c“文字的标签首先获得 事件, “b” 第二, “a” 最后。 你可以互换这顺序通过手动地说明索引。

box = BoxLayout()
box.add_widget(Label(text="a"), index=0)
box.add_widget(Label(text="b"), index=1)
box.add_widget(Label(text="c"), index=2)

Now the order would be “a”, “b” then “c”. One thing to keep in mind when using kv is that declaring a widget uses the add_widget() method for insertion. Hence, using
现在顺序将是"a" "b" 然后是“c”。  一个事得牢记在脑海 是当使用kv文件时, 声明一个组件使用add_widget()方法来插入。 因此, 使用:

BoxLayout:
    MyLabel:
        text: "a"
    MyLabel:
        text: "b"
    MyLabel:
        text: "c"

would result in the event order “c”, “b” then “a” as “c” was actually the last added widget. It thus has index 0, “b” index 1 and “a” index 2. Effectively, the child order is the reverse of its listed order.
会导致事件顺序 "c"  "b" 然后是  "a"  当 'c'真的是最后被添加的组件。 因为它有索引是 0, “b” 索引1,  以及 “a” 索引 2.   实际上, 子类的顺序是和它陈列的顺序是相反的。

This ordering is the same for the on_touch_move() and on_touch_up() events.
这顺序 是相同的对于 on_touch_move() 和 on_touch_up() 事件。

In order to stop this event bubbling, a method can return True. This tells Kivy the event has been handled and the event propagation stops. For example:
为了停止这事件冒泡, 一个方法可以返回True。 这告诉Kivy 这事儿已经被引用了, 并且这事不传了。  例如:

class MyWidget(Widget):
    def on_touch_down(self, touch):
        If <some_condition>:
            # Do stuff here and kill the event
            return True
        else:
            return super(MyWidget, self).on_touch_down(touch)

This approach gives you good control over exactly how events are dispatched and managed. Sometimes, however, you may wish to let the event be completely propagated before taking action. You can use the Clock to help you here:
这方法给你好的控制基于真正的如何事件们被派遣和被管理。 又是,然而, 你可能希望让事件被完整地派遣在获取行动之前。 你可以使用 Clock 在这来帮助你:

class MyWidget(Label):
    def on_touch_down(self, touch, after=False):
        if after:
            print "Fired after the event has been dispatched!"
        else:
            Clock.schedule_once(lambda dt: self.on_touch_down(touch, True))
            return super(MyWidget, self).on_touch_down(touch)

Usage of Widget.centerWidget.right, and Widget.top

A common mistake when using one of the computed properties such as Widget.right is to use it to make a widget follow its parent with a KV rule such as right: self.parent.right. Consider, for example:
一个常见的错误当使用一个被计算的属性例如: Widget.right 被用来使用它来让一个组件跟随它的父类按着KV规则 例如: 右边: self.parent.right。  值得考虑的是, 例如:

FloatLayout:
    id: layout
    width: 100
    Widget:
        id: wid
        right: layout.right

The (mistaken) expectation is that this rule ensures that wid’s right will always be whatever layout’s right is - that is wid.right and layout.right will always be identical. In actual fact, this rule only says that “whenever layout’s right changes, wid’s right will be set to that value”. The difference being that as long as layout.right doesn’t change, wid.right could be anything, even a value that will make them different.
这(错误)期望 是这规则确保 组件的右边总是无论如何在 布局的右边, 那就是wid.right 和layout.right 将总是完全相同的。 事实是,这规则总是说: 无论何时布局的右边改变, 组件的右边将被设置为其改变的值。  不同时: 只要布局的右边没改变, 组件的右边可能会是任何事儿, 甚至一个让他们不一样的值

Specifically, for the KV code above, consider the following example:
尤其是, 对以上的KV代码,看看下面的例子:

print(layout.right, wid.right)
(100, 100)
wid.x = 200
print(layout.right, wid.right)
(100, 300)

As can be seen, initially they are in sync, however, when we change wid.x they go out of sync because layout.right is not changed and the rule is not triggered.
显而易见的, 初始它们是不一样的, 然而, 当我们改变wid.x, 它们会同步因为 layout.right 是不变的并且是不犯规的。

The proper way to make the widget follow its parent’s right is to use Widget.pos_hint. If instead of right: layout.right we did pos_hint: {‘right’: 1}, then the widgets right will always be set to be at the parent’s right at each layout update.
真正的方式让组件跟随它的父母的右边是使用Widget.pos_hint   如果右边被替代, layout.right, 我们设置 pos_hint:{'right':1}, 然后组件右边将持续被设置为父类的右边每当布局改变。

APIHide Description ⇑

class kivy.uix.widget.Widget(**kwargs)

Bases: kivy.uix.widget.WidgetBase

Widget class. See module documentation for more information.

Events:

on_touch_down: (touch, )

Fired when a new touch event occurs. touch is the touch object.
当一个新的触摸事件呈现时, touch是被触摸的对象

on_touch_move: (touch, )

Fired when an existing touch moves. touch is the touch object.
当一个存在的触摸滑动时,touch 是移动的触摸对象

on_touch_up: (touch, )

Fired when an existing touch disappears. touch is the touch object.
当一个存在的触摸消失时, touch 是触摸对象

on_kv_post: (base_widget, )

Fired after all the kv rules associated with the widget and all other widgets that are in any of those rules have had all their kv rules applied. base_widget is the base-most widget whose instantiation triggered the kv rules (i.e. the widget instantiated from Python, e.g. MyWidget()).
在所有的kv规则同在这些规则被组件和所有其他的组件应用联系时, base_widget 是 最基础的组件,它的实例被引用了kv的规则 (组件从python实例化)
 

on_kv_post 事件是在所有与特定组件(widget)相关的 KV 规则(即在 .kv 文件中定义的规则)以及这些规则中引用的所有其他组件的 KV 规则都被应用之后触发的。base_widget 参数是指触发这些 KV 规则的最顶层组件(即从 Python 代码中实例化的那个组件,如 MyWidget())。

这个事件在 Kivy 1.11.0 版本中引入,它允许开发者在 KV 规则完全应用后执行一些额外的操作或初始化。

Changed in version 1.11.0.

__del__ 方法与垃圾收集   Warning

Adding a __del__ method to a class derived from Widget with Python prior to 3.4 will disable automatic garbage collection for instances of that class. This is because the Widget class creates reference cycles, thereby preventing garbage collection.

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

xinzheng新政

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

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

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

打赏作者

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

抵扣说明:

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

余额充值