class MyPaintWidget(Widget):
def on_touch_down(self, touch):
userdata = touch.ud
with self.canvas:
Color(1, 1, 0)
d = 30.
Ellipse(pos=(touch.x - d/2, touch.y - d/2), size=(d, d))
userdata['line'] = Line(points=(touch.x, touch.y))
Run Code Online (Sandbox Code Playgroud)
显然Color,d并且Ellipse在命名空间内self.canvas,但Python如何知道userdata不在同一个命名空间内?
编辑:这个答案有点冗长,所以这里是摘要:
with self.canvas为以下代码块定义当前活动的画布.Color或Ellipse在活动画布上绘制.命名空间与它没有任何关系,重要的是上下文(见下文).
该with语句允许您使用所谓的上下文管理器.
语法是这样的
with thing [as foo]:
Run Code Online (Sandbox Code Playgroud)
其中,thing通常是装饰与功能contextlib.contextmanager装饰.上下文管理器究竟做了什么取决于如何thing实现.
但它没有做的是让变量神奇地出现在你的范围内.可以通过可选as foo子句获得对上下文的引用,但就是这样.Color并且Ellipse在你的例子是从别的地方来了(可能是进口的?).
为了找出到底是在上下文管理什么with self.canvas行不,你应该看看API文档或源代码的kivy.graphics.instructions.Canvas.
以下是本教程的相关摘录:
通过对它使用with语句,正确缩进的所有连续绘图命令都将修改此画布.with语句还确保在绘制后,可以正确清理内部状态.
所以使用的Color和Ellipse影响self.canvas,但他们不以任何方式通过with语句定义.
查看源代码,这是它的工作原理:
def class CanvasBase(InstructionGroup):
def __enter__(self):
pushActiveCanvas(self)
def __exit__(self, *largs):
popActiveCanvas()
Run Code Online (Sandbox Code Playgroud)
__enter__并__exit__定义在输入上下文管理器(在with语句之后的第一行缩进代码之前)和退出时会发生什么.
在这种情况下,画布只是被推送到一个堆栈上,该堆栈定义了当前活动的画布(如果退出上下文管理器,则从中弹出).
在kivy.graphics.instructions.Instruction所有绘图指令的明显基类中,父项设置为当前活动的画布:
self.parent = getActiveCanvas()
Run Code Online (Sandbox Code Playgroud)