查看“︁分类:Kivy”︁的源代码
←
分类:Kivy
跳转到导航
跳转到搜索
因为以下原因,您没有权限编辑该页面:
您请求的操作仅限属于该用户组的用户执行:
用户
您可以查看和复制此页面的源代码。
= Kivy速成教程 = === '''1、引言''' === Kivy是用Python编写的开源跨平台GUI框架,用于开发多平台应用程序(如Windows、macOS、Linux、Android、iOS等)。 它基于OpenGL ES 2构建,采用自绘UI的方式替代依赖原生系统组件,因此能在不同平台上保持界面和交互逻辑的高度一致性。Kivy引入了专门的Kv语言,允许开发者将UI布局与业务逻辑分离,简化复杂界面的设计流程;同时原生支持多点触控、手势识别等交互特性,非常适合开发游戏、多媒体展示、交互式工具等对界面动态性要求较高的应用。此外,Kivy拥有活跃的社区生态,提供了丰富的扩展库(如KivyMD等Material Design风格组件库),帮助开发者快速实现美观且功能完善的跨平台应用。 使用 Kivy,您可以创建运行以下应用程序: * *台式电脑:macOS、Linux、BSD Unix、Windows。 * iOS 设备:iPad、iPhone。 * 安卓设备:平板电脑、手机。 * 任何其他支持TUIO的触控专业/自制设备 (有形用户界面对象) Kivy 赋予你一次编写代码并运行它的自由 不同平台上的现状。 您将使用 Kivy: * '''学习''':使用Kivy语言编程的基础知识。 * '''探索''':Kivy 框架。 * '''创建''':一个简单的跨平台应用程序。 * '''打包''':适用于您选择的平台。 最后, '''Deploy'''您将学习如何在您选择的设备上部署。 === 2、安装 Kivy === 本文Kivy版本基于Kivy 2.3.1 ,支持 Python 版本 '''3.8 - 3.'''13 ==== 使用 pip安装 ==== 安装 Kivy 最简单的方法就是<code>pip</code><code>。</code> 在安装 Kivy 之前,需要预装 Python 和 pip。 然后,启动一个新终端。在终端中, 更新<code>pip</code>以及其他安装 依赖项使您的最新版本如下所示(对于Linux用户,您可能需要替代<code>python3</code>而不是<code>python</code>并添加一个<code>--user</code> <code>flag。</code> <code>Windows:</code> <code>python -m pip install --upgrade pip setuptools virtualenv</code> <code>linux:</code> <code>python3 -m pip install --upgrade pip setuptools virtualenv</code> ==== 创建虚拟环境 ==== 创建一个新的虚拟环境 适用于您的 Kivy 项目。虚拟环境可以避免可能的安装冲突。 与其他 Python 版本和软件包兼容。虽然是可选的 ''',但强烈建议这样做''' : 在当前目录下创建名为 <code>kivy_venv</code> 虚拟环境: <code>python -m venv kivy_venv</code> ==== 激活虚拟环境 ==== <code>source kivy_venv/bin/activate</code> <code>(linux)</code> ==== 安装Kivy ==== 最简单的方法是安装当前稳定版本的 <code>kivy</code> ,还可以选择 <code>kivy_examples</code> 使用 kivy 团队提供的 PyPi wheels。只需执行以下操作: <code>python -m pip install "kivy[base]" kivy_examples</code> ==== 通过源安装 ==== 略 ==== 安装预发布版、预编译的 wheel 文件 ==== 要安装 Kivy 最新'''预发布'''版本的预编译 wheel 文件,而不是当前稳定版本,请在 pip 命令中添加 <code>--pre</code> 标志: <code>python -m pip install --pre "kivy[base]" kivy_examples</code> 只有当 Kivy 发布了开发版本时,此操作才会安装该开发版本。 PyPi 。或者,也可以从 Kivy 服务器安装'''最新'''的 Nightly wheel 包: <code>python -m pip install kivy --pre --no-deps --index-url <nowiki>https://kivy.org/downloads/simple/</nowiki></code> <code>python -m pip install "kivy[base]" --pre --extra-index-url <nowiki>https://kivy.org/downloads/simple/</nowiki></code> ==== 开发安装 ==== 略 === 3. 第一个应用 === ==== 入门 ==== 我们先来创建一个非常简单的 Kivy 应用并让它运行起来。创建一个用于存放游戏的目录,并在其中创建一个名为 ''main.py 的''文件。 <code>from kivy.app import App</code> <code>from kivy.uix.widget import Widget</code> <code>class PongGame(Widget):</code> <code>pass</code> <code>class PongApp(App):</code> <code>def build(self):</code> <code>return PongGame()</code> <code>if __name__ == '__main__':</code> <code>PongApp().run()</code> 运行该应用程序。此时应该只会显示一个黑色窗口。我们创建了一个非常简单的 Kivy <code>App</code> ,它创建了 <code>PongGame</code> Widget 类的一个实例,并将其作为应用程序 UI 的根元素返回。此时,您可以将其想象成一个 Widget 层级树。Kivy 会将这个 Widget 树放置在默认的 Window 窗口中。下一步,我们将通过定义 <code>PongGame widget</code> 外观来绘制 Pong 的背景和分数。 ==== 添加简单图形 ==== 我们将使用 .kv 文件来定义 <code>PongGame</code> 类的外观和风格。由于我们的 <code>App</code> 类名为 <code>PongApp</code> ,我们可以直接在应用程序运行时自动加载同一目录下的 <code>pong.kv</code> 文件。因此,请创建一个名为 ''``pong.kv``'' 的新文件,并添加以下内容。 <code>#:kivy 1.0.9</code> <code><PongGame>: </code> <code> canvas:</code> <code> Rectangle:</code> <code> pos: self.center_x - 5, 0</code> <code> size: 10, self.height</code> <code> </code> <code> Label:</code> <code> font_size: 70 </code> <code> center_x: root.width / 4</code> <code> top: root.top - 50</code> <code> text: "0"</code> <code> </code> <code> Label:</code> <code> font_size: 70 </code> <code> center_x: root.width * 3 / 4</code> <code> top: root.top - 50</code> <code> text: "0"</code> '''kv 文件的名称(例如 pong.kv)必须与应用程序的名称(例如 PongApp)匹配(App 结尾之前的部分)。''' ==== 解释 Kv 文件语法 ==== 在进行下一步之前,您可能需要仔细查看一下我们刚刚创建的 kv 文件的内容,弄清楚它的作用。 每个 kv 文件都必须包含第一行。它应该以 <code>#:kivy</code> 开头。 然后是一个空格,以及它所针对的 Kivy 版本(以便 Kivy 可以创建它)。 请确保您拥有至少所需的版本,或者处理向后兼容性问题。 之后,我们开始定义适用于所有 <code>PongGame</code> 规则。 实例: <code><PongGame>:</code> <code> ...</code> 与 Python 类似,kv 文件使用缩进来定义嵌套代码块。用 <code><</code> 和 <code>></code> 字符括起来的类名定义的代码块是一个 <code>Widget</code> 规则。它将应用于指定类的任何实例。例如,如果将示例中的 <code>PongGame</code> 替换为 <code>Widget</code> ,则所有 Widget 实例都将包含垂直线和两个 Label 组件,因为该规则将应用于所有 Widget 实例。 在规则部分,您可以添加各种代码块来定义它们将应用到的控件的样式和内容。您可以: * 设置属性值 * 添加子控件 * 定义一个区域,您可以在其中添加定义小部件渲染方式的图形指令。 <code><PongGame></code> 规则中的第一个块是一个 canvas块: <code><PongGame>:</code> <code> canvas:</code> <code> Rectangle:</code> <code> pos: self.center_x - 5, 0</code> <code> size: 10, self.height</code> 这个 canvas 块表示 <code>PongGame</code> 组件应该绘制一些图形图元。在本例中,我们在 canvas 中添加一个矩形。我们将矩形的 pos 坐标设置为组件水平中心左侧 5 像素,y 坐标设置为 0。矩形的宽度设置为 10 像素,高度设置为组件的高度。这样定义图形的好处在于,当值表达式中使用的任何组件的属性发生变化时,渲染的矩形也会自动更新。 最后添加的两个部分看起来非常相似。它们都向 <code>PongGame</code> 组件添加了一个 Label 组件作为子组件。目前,这两个组件的文本都设置为 ''“0”'' 。我们将在实现逻辑后将其与实际分数关联起来,但由于我们设置了更大的 font_size 并将其相对于根组件定位,因此标签看起来已经不错了。可以在子组件块中使用 <code>root</code> 关键字来引用规则所应用的父/根组件(在本例中为 <code>PongGame</code> ): <code><PongGame>:</code> <code> # ...</code> <code> Label:</code> <code> font_size: 70</code> <code> center_x: root.width / 4</code> <code> top: root.top - 50</code> <code> text: "0"</code> <code> Label:</code> <code> font_size: 70</code> <code> center_x: root.width * 3 / 4</code> <code> top: root.top - 50</code> <code> text: "0"</code> ==== 添加球 ==== 我们已经有了一个基本的乒乓球场地,但还需要玩家和球。我们先从球开始。我们添加一个新的 创建一个小部件作为我们的球,并让它弹跳起来。 ==== PongBall类 ==== <code>class PongBall(Widget):</code> <code> # velocity of the ball on x and y axis</code> <code> velocity_x = NumericProperty(0)</code> <code> velocity_y = NumericProperty(0)</code> <code> # referencelist property so we can use ball.velocity as</code> <code> # a shorthand, just like e.g. w.pos for w.x and w.y</code> <code> velocity = ReferenceListProperty(velocity_x, velocity_y)</code> <code> # ``move`` function will move the ball one step. This</code> <code> # will be called in equal intervals to animate the ball</code> <code> def move(self):</code> <code> self.pos = Vector(*self.velocity) + self.pos</code> 以下是用于将球画成白色圆圈的 kv 规则: <code><PongBall>:</code> <code> size: 50, 50</code> <code> canvas:</code> <code> Ellipse:</code> <code> pos: self.pos</code> <code> size: self.size</code> 为了使一切正常运行,您还需要添加以下导入语句: Property classes使用以及 <code>Vector</code> 以下是此步骤的完整更新后的 Python 代码和 kv 文件: ; main.py: ; <syntaxhighlight lang="python3" line="1"> from kivy.app import App from kivy.uix.widget import Widget from kivy.properties import NumericProperty, ReferenceListProperty from kivy.vector import Vector class PongBall(Widget): velocity_x = NumericProperty(0) velocity_y = NumericProperty(0) velocity = ReferenceListProperty(velocity_x, velocity_y) def move(self): self.pos = Vector(*self.velocity) + self.pos class PongGame(Widget): pass class PongApp(App): def build(self): return PongGame() if __name__ == '__main__': PongApp().run() </syntaxhighlight> ; <nowiki>pong.kv:</nowiki><syntaxhighlight lang="python" line="1"> #:kivy 1.0.9 <PongBall>: size: 50, 50 canvas: Ellipse: pos: self.pos size: self.size <PongGame>: canvas: Rectangle: pos: self.center_x - 5, 0 size: 10, self.height Label: font_size: 70 center_x: root.width / 4 top: root.top - 50 text: "0" Label: font_size: 70 center_x: root.width * 3 / 4 top: root.top - 50 text: "0" PongBall: center: self.parent.center </syntaxhighlight>不仅添加了控件规则,还在控件规则中添加了子控件 ==== 添加球体动画 ==== <code>Clock.schedule_interval(game.update, 1.0/60.0)</code> 这行代码将导致游戏对象的 <code>update</code> 函数每 1/60 秒调用一次 ==== 对象属性/引用(Object Properties/References) ==== 还有另一个问题。我们想确保乒乓球拥有它的 <code>move</code> 函数会被定期调用,但由于我们只是通过 KV 文件中 <code>PongGame</code> 类的 KV 规则添加了球对象,因此我们的代码中没有任何对球对象的引用。我们游戏的唯一引用是应用程序构建方法中返回的那个。 既然我们要做的功能不只是移动球(例如让球反弹到墙壁上,以及之后反弹到玩家的球拍上),那么我们的 <code>PongGame</code> 类可能无论如何都需要一个 <code>update</code> 方法。此外,鉴于 我们已经有了对游戏对象的引用,我们可以轻松地通过执行<code>update</code> 方法让它执行新任务。 <syntaxhighlight lang="python3" line="1"> class PongGame(Widget): def update(self, dt): # call ball.move and other stuff pass class PongApp(App): def build(self): game = PongGame() Clock.schedule_interval(game.update, 1.0/60.0) return game </syntaxhighlight>However, that still doesn’t change the fact that we don’t have a reference to the <code>PongBall</code> child widget created by the kv rule. To fix this, we can add an <code>ObjectProperty</code> to the PongGame class, and hook it up to the widget created in the kv rule. Once that’s done, we can easily reference the ball property inside the <code>update</code> method and even make it bounce off the edges: 然而,这仍然无法改变一个事实就是,我们没有由 kv 规则创建的 <code>PongBall</code> 子组件的引用。为了解决这个问题,我们可以添加一个 <code>ObjectProperty</code> 将其添加到 PongGame 类,并将其连接到在kv规则中创建的控件。完成之后,我们就可以轻松地引用球的属性了。 在 <code>update</code> 方法内部,甚至可以使其从边缘反弹:<syntaxhighlight lang="python3" line="1"> class PongGame(Widget): ball = ObjectProperty(None) def update(self, dt): self.ball.move() # bounce off top and bottom if (self.ball.y < 0) or (self.ball.top > self.height): self.ball.velocity_y *= -1 # bounce off left and right if (self.ball.x < 0) or (self.ball.right > self.width): self.ball.velocity_x *= -1 <PongGame>: ball: pong_ball # ... (canvas and Labels) PongBall: id: pong_ball center: self.parent.center </syntaxhighlight>别忘了在 kv 文件中进行连接,给子控件指定一个 id,并将 PongGame 的 <code>ball</code> ObjectProperty 设置为该 id。 至此,所有组件都已连接完毕,球可以开始弹跳了。如果您跟着我们一起编写代码,可能会疑惑为什么球没有移动。这是因为球的 x 轴和 y 轴速度都被设置为 0。在下面的代码示例中,我们在 <code>PongGame</code> 类中添加了一个名为 <code>serve_ball</code> 方法,并在应用程序的 <code>build</code> 方法中调用了该方法。该方法会为球设置一个随机的 x 轴和 y 轴速度,并重置球的位置,以便我们稍后在玩家得分后重置球的位置。 ==== 连接输入事件 ==== 添加玩家并对触摸输入做出反应。 在 Kivy 中,控件可以通过实现以下功能来响应输入: <code>on_touch_down</code> , <code>on_touch_move</code> 和 <code>on_touch_up</code> 方法。默认情况下,Widget 类 它通过调用其所有组件上的相应方法来实现这些方法。 子控件会将事件传递下去,直到其中一个子控件返回 <code>True</code> 。 Pong 游戏非常简单。球拍只需要上下移动。事实上,它非常简单,我们甚至不需要让玩家组件自己处理事件。我们只需要实现 <code>on_touch_move</code> 函数即可。 <code>PongGame</code> 类,并根据触摸发生在屏幕左侧还是右侧来设置左侧玩家或右侧玩家的位置。 检查 <code>on_touch_move</code> 处理程序:<syntaxhighlight lang="python3" line="1"> def on_touch_move(self, touch): if touch.x < self.width/3: self.player1.center_y = touch.y if touch.x > self.width - self.width/3: self.player2.center_y = touch.y </syntaxhighlight>我们会记录每个玩家的得分。 <code>NumericProperty</code> 。 <code>PongGame</code> 的得分标签 通过更改 NumericProperty <code>score</code> 来保持分数更新,这反过来又会更新 <code>PongGame</code> 子标签的 text 属性。这种绑定是因为 Kivy <code>properties</code> 会自动绑定到其对应 kv 文件中的任何引用。当球从边线飞出时,我们将通过更改 <code>PongGame</code> 类中的 <code>update</code> 方法来更新分数并再次发球。PongPaddle 的属性是 <code>PongPaddle</code> 。 该类还实现了一个 <code>bounce_ball</code> 方法,以便球能够反弹。 根据击球位置的不同,效果也不同。以下是代码PongPaddle类:<syntaxhighlight lang="python3" line="1"> class PongPaddle(Widget): score = NumericProperty(0) def bounce_ball(self, ball): if self.collide_widget(ball): speedup = 1.1 offset = 0.02 * Vector(0, ball.center_y-self.center_y) ball.velocity = speedup * (offset - ball.velocity) </syntaxhighlight>附全代码: main.py: <syntaxhighlight lang="python3" line="1"> from kivy.app import App from kivy.uix.widget import Widget from kivy.properties import ( NumericProperty, ReferenceListProperty, ObjectProperty ) from kivy.vector import Vector from kivy.clock import Clock class PongPaddle(Widget): score = NumericProperty(0) def bounce_ball(self, ball): if self.collide_widget(ball): vx, vy = ball.velocity offset = (ball.center_y - self.center_y) / (self.height / 2) bounced = Vector(-1 * vx, vy) vel = bounced * 1.1 ball.velocity = vel.x, vel.y + offset class PongBall(Widget): velocity_x = NumericProperty(0) velocity_y = NumericProperty(0) velocity = ReferenceListProperty(velocity_x, velocity_y) def move(self): self.pos = Vector(*self.velocity) + self.pos class PongGame(Widget): ball = ObjectProperty(None) player1 = ObjectProperty(None) player2 = ObjectProperty(None) def serve_ball(self, vel=(4, 0)): self.ball.center = self.center self.ball.velocity = vel def update(self, dt): self.ball.move() # bounce off paddles self.player1.bounce_ball(self.ball) self.player2.bounce_ball(self.ball) # bounce ball off bottom or top if (self.ball.y < self.y) or (self.ball.top > self.top): self.ball.velocity_y *= -1 # went off to a side to score point? if self.ball.x < self.x: self.player2.score += 1 self.serve_ball(vel=(4, 0)) if self.ball.right > self.width: self.player1.score += 1 self.serve_ball(vel=(-4, 0)) def on_touch_move(self, touch): if touch.x < self.width / 3: self.player1.center_y = touch.y if touch.x > self.width - self.width / 3: self.player2.center_y = touch.y class PongApp(App): def build(self): game = PongGame() game.serve_ball() Clock.schedule_interval(game.update, 1.0 / 60.0) return game if __name__ == '__main__': PongApp().run() </syntaxhighlight>pong.kv:<syntaxhighlight lang="python3" line="1"> #:kivy 1.0.9 <PongBall>: size: 50, 50 canvas: Ellipse: pos: self.pos size: self.size <PongPaddle>: size: 25, 200 canvas: Rectangle: pos: self.pos size: self.size <PongGame>: ball: pong_ball player1: player_left player2: player_right canvas: Rectangle: pos: self.center_x - 5, 0 size: 10, self.height Label: font_size: 70 center_x: root.width / 4 top: root.top - 50 text: str(root.player1.score) Label: font_size: 70 center_x: root.width * 3 / 4 top: root.top - 50 text: str(root.player2.score) PongBall: id: pong_ball center: self.parent.center PongPaddle: id: player_left x: root.x center_y: root.center_y PongPaddle: id: player_right x: root.width - self.width center_y: root.center_y </syntaxhighlight> ;__强显目录__
返回
分类:Kivy
。
导航菜单
个人工具
登录
命名空间
分类
讨论
大陆简体
查看
阅读
查看源代码
查看历史
更多
搜索
导航
首页
最近更改
随机页面
特殊页面
工具
链入页面
相关更改
页面信息