├── .gitignore ├── SUMMARY.md ├── README.md ├── 00-Kivy-CN.md ├── 04-Kivy-Config.md ├── 16-Kivy-VM.md ├── 12-Kivy-IDE.md ├── 09-Kivy-Graphics.md ├── 19-Kivy-Pack-License.md ├── 18-Kivy-Pack-iOS.md ├── 03-Kivy-Environment.md ├── 21-Kivy-VMS.md ├── 11-Kivy-Integration.md ├── 15-Kivy-Pack-Android.md ├── 05-Kivy-Architecture.md ├── 14-Kivy-Android.md ├── 20-Kivy-Garden FileBrowser Problem.md ├── 02-Kivy-Basics.md ├── 13-Kivy-Pack-Windows.md ├── 17-Kivy-Pack-Mac.md ├── 07-Kivy-Input.md ├── 10-Kivy-Lang.md ├── 06-Kivy-Events and Properties.md ├── 01-Kivy-Installation.md └── 08-Kivy-Widgets.md /.gitignore: -------------------------------------------------------------------------------- 1 | # Node rules: 2 | ## Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 3 | .grunt 4 | 5 | ## Dependency directory 6 | ## Commenting this out is preferred by some people, see 7 | ## https://docs.npmjs.com/misc/faq#should-i-check-my-node_modules-folder-into-git 8 | node_modules 9 | 10 | # Book build output 11 | _book 12 | 13 | # eBook build output 14 | *.epub 15 | *.mobi 16 | *.pdf -------------------------------------------------------------------------------- /SUMMARY.md: -------------------------------------------------------------------------------- 1 | # Summary 2 | 3 | * [前言](README.md) 4 | * [简介](00-Kivy-CN.md) 5 | * [安装](01-Kivy-Installation.md) 6 | * [基础](02-Kivy-Basics.md) 7 | * [环境](03-Kivy-Environment.md) 8 | * [配置](04-Kivy-Config.md) 9 | * [架构](05-Kivy-Architecture.md) 10 | * [事件和属性](06-Kivy-Events and Properties.md) 11 | * [输入管理](07-Kivy-Input.md) 12 | * [控件](08-Kivy-Widgets.md) 13 | * [图形](09-Kivy-Graphics.md) 14 | * 语言 15 | * [整合](11-Kivy-Integration.md) 16 | * [开发环境](12-Kivy-IDE.md) 17 | * [Windows 打包](13-Kivy-Pack-Windows.md) 18 | * [Android](14-Kivy-Android.md) 19 | * [Android 打包](15-Kivy-Pack-Android.md) 20 | * [Android 虚拟机](16-Kivy-VM.md) 21 | * [Mac 打包](17-Kivy-Pack-Mac.md) 22 | * [iOS 打包](18-Kivy-Pack-iOS.md) 23 | * [协议相关](19-Kivy-Pack-License.md) 24 | * [Bug-Garden on Mac](20-Kivy-Garden FileBrowser Problem.md) 25 | 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Kivy中文编程指南 2 | 3 | > 注意 4 | > 5 | > 译者无法提供任何技术支持。如果你需要帮助,请在 [SegmentFault](https://segmentfault.com/) 或 [StackOverflow](https://stackoverflow.com/) 上提问。谢谢合作。 6 | 7 | ## Kivy 是什么? 8 | 9 | Kivy 是一个开源的 Python 框架,用于快速开发应用,实现各种当前流行的用户界面,比如多点触摸等等。 10 | 11 | Kivy 可以运行于 Windows, Linux, MacOS, Android, iOS 等当前绝大部分主流桌面/移动端操作系统。 12 | 13 | Kivy 基于 Python,界面文件和程序文件相互分离的设计思路,设计简洁优雅,语法易学,适合新人入门。 14 | 15 | 目前 Kivy 的官方文档还不算很完善,中文翻译版本之前也有过,但往往没有进行持续更新,或者内容覆盖不全面,所以我们这次来一个长期持久的跟进。同时期待你的参与! 16 | 17 | 如果你想参与进来,可以加入我们的 Kivy 交流QQ群号:248136053,也可以关注我的\[知乎专栏\]\(https://zhuanlan.zhihu.com/python-kivy) 18 | 19 | 从去年开始的Kivy 编程指南中文翻译项目,今天基本算是弄完了,把 Kivy Programming Guide 里面的全部内容翻译了一遍。 20 | 21 | 当然了,质量还是不怎么样好,所以希望大家多批评指正,我会尽快改正。 22 | 23 | 最开始用 Kivy 的时候,感觉有各种各样的 bug ,觉得安装和配置各种繁琐扯皮麻烦,心情也容易变得特别臭。 24 | 25 | 然后开始翻译文档的时候,也还是容易经常变得很暴躁,尤其是遇到一些原文的语法错误、逻辑错误、自己鬼扯也扯不通顺的地方等等。 26 | 27 | 但是后来我逐渐地开始钦佩这些创建了 Kivy 的人们,我意识到他们也跟我一样是一群热爱 Python 的人,想为更多的同样使用 Python 的开发者提供一个完整的工具链,以便于能更简洁轻快地实现跨平台开发。 28 | 29 | 所以,我觉得 Kivy 是一个因为热爱而驱动去追寻自由的项目,这也让我逐渐对 Kivy 产生了更多的好感。 30 | 31 | 事到如今我可能并不一定会有机会深入使用 Kivy 去开发,也依然希望 Kivy 能够发展壮大,生根发芽,开花散种,给更多的跟我一样初入门无所适从的新手一个友好又高效的选择。 32 | 33 | 我对 Kivy 官方文档的翻译,暂告一段落。后面的 API 翻译,有一位知乎上的朋友表示有兴趣进行,一位非常年轻有为的少年。看到现在的青少年人都有如此的学习动力和探索精神,不由得让我感慨时代发展之快,自己奔四的路上,还有幸结识了众多初升的太阳。我相信他们会在未来闪耀,那个时代一定更美好。 34 | 35 | 36 | GitBoox 在线阅读地址: 37 | https://www.gitbook.com/book/cycleuser/kivy-guide-chinese/details 38 | -------------------------------------------------------------------------------- /00-Kivy-CN.md: -------------------------------------------------------------------------------- 1 | Title: Kivy CN 2 | Date: 2017-02-12 3 | Category: Kivy 4 | Tags: Python,Kivy 5 | 6 | 7 | # Kivy中文编程指南:我为什么对Kivy官方文档进行翻译 8 | 9 | 10 | 11 | 从去年开始,我陆续翻译了一些Kivy官方文档中的开发指南的内容,地址在[这里](http://blog.cycleuser.org/tag/kivy.html)。 12 | 13 | 然后我又觉得有必要找一个更大的平台,以便于能给更多人提供一点便利,所以我又开了一个[知乎专栏](https://zhuanlan.zhihu.com/python-kivy)。 14 | 15 | 然而新年这一阵,我做了个手术,身体状况不太好,感觉理解能力和表达能力也有所下降(其实本来也不行),所以我就想,不如按照之[前ThinkPython的中文翻译](https://github.com/cycleuser/ThinkPython-en-cn)那样,直接把翻译稿开源放到Github吧,地址在[这里](https://github.com/cycleuser/Kivy-CN)。虽然我并没有想出来这样有什么更好的。 16 | 17 | 接触Kivy时间不长,一年多前最开始知道有这个项目的,当时的观感很差,因为遇到若干个Bug,反馈了之后也没见他们有什么动静。然后时间长了,发现跨平台的Python除了QT基本就只有这个了,相比之下,这个好歹不那么庞大,还是挺好玩的。但也就这样了,没有进一步关注。 18 | 19 | 然后是要写[GeoPython](https://github.com/cycleuser/GeoPython),一些基础的方法都实现了之后,遇到了一些数学上的问题,然后学了一些数学相关的内容,大概有了解决思路之后,才意识到,TMD没有GUI啊,这样常规的地球科学领域的同行们根本懒得看对不对?日常用户才懒得吭哧吭哧学习如何在Bash或者Powershell之下使用iPython运行某个脚本对不对?所以我需要GUI,然而QT太庞大繁杂了,衡量了一下自己的智力水平,估计至少要花费半年才能大概入门。所以我又捡起来Kivy了。 20 | 21 | 这个过程中我发现Kivy相关的中文资料还真不多,那我就从最基础的官方文档开始翻译一下吧,好歹自己边学习边相当于做笔记,以教促学,还能给人提供一点有用的参考,哪怕一丁点用处也好。 22 | 23 | 就像我当年给人辅导研究生的C++和考博英语一样,其实也是给自己的持续学习找一个持久的动力,也是争取有一点能够积攒努力产生一个突破口。就像我的启蒙老师许先生当年给我讲的庞中华老前辈一样,一点一点积累总会有收获。 24 | 25 | 我这些翻译的水平良莠不齐,其中有些简单的部分,我基本可以直接进行双语转换,这就不费什么力气。而由于我在编程的经验和水平两方面都比较差,有的部分一些术语名词翻译得不伦不类,所以我又只能心虚地标记上英文,避免对读者产生太严重的误导。 26 | 27 | 但我还是会继续下去的,学习和翻译两个过程还不能停下来。我不能因为自己现在三十多岁了而且水平还很差,就停止学习提高的尝试,因为一旦停下来,就更是一点希望都没有了,那就是直接向命运举白旗投降了。 28 | 29 | 虽然时代已经不同了,我还是很钦佩王江民老前辈,专注和持久而创造了传奇。我没有那么大的野心,也不奢求什么辉煌成就,只是觉得有生之年,做点不后悔的事情吧。 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /04-Kivy-Config.md: -------------------------------------------------------------------------------- 1 | Title: Kivy Configure 2 | Date: 2017-02-6 3 | Category: Kivy 4 | Tags: Python,Kivy 5 | 6 | 7 | # Kivy中文编程指南:配置修改 8 | 9 | [英文原文](https://kivy.org/docs/guide/config.html) 10 | 11 | Kivy的配置文件是一个名为config.ini的文本,符合[标准INI格式](http://en.wikipedia.org/wiki/INI_file)。 12 | 13 | 14 | 15 | ## 找到配置文件位置 16 | 17 | Kivy的配置文件存放在环境变量KIVY_HOME所制定的位置: 18 | 19 | ```Bash 20 | KIVY_HOME>/config.ini 21 | ``` 22 | 23 | 24 | 在桌面平台上,默认的位置如下: 25 | 26 | ```Bash 27 | HOME_DIRECTORY>/.kivy/config.ini 28 | ``` 29 | 30 | 31 | 32 | 所以,假设你的用户名是“tito”,在各个操作系统下的配置文件位置则如下所示: 33 | 34 | * Windows: `C:\Users\tito\.kivy\config.ini` 35 | * OS X: `/Users/tito/.kivy/config.ini` 36 | * Linux: `/home/tito/.kivy/config.ini` 37 | 38 | (译者注:这里要注意,tito只是原文的一个示范,相当于张三李四这样,新手可别照着复制找不到,要用自己操作系统中具体的用户名。) 39 | 40 | 41 | 在Android系统中位置如下: 42 | 43 | ```Bash 44 | ANDROID_APP_PATH>/.kivy/config.ini 45 | ``` 46 | 47 | 48 | 49 | 50 | 51 | 假如你的Kivy应用的包名称为“org.kivy.launcher”,那么该Kivy应用的配置文件位于: 52 | 53 | ```Bash 54 | /data/data/org.kivy.launcher/files/.kivy/config.ini 55 | ``` 56 | 57 | 58 | 59 | 60 | 61 | 在iOS上Kivy的默认配置文件位于: 62 | 63 | ```Bash 64 | HOME_DIRECTORY>/Documents/.kivy/config.ini 65 | ``` 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | ## 本地配置 76 | 77 | 有时候用户或者开发者可能需要针对特定的应用来修改配置,或者对Kivy的某个组件进行测试,比如输入模块之类的。这时候就可以用如下命令创建一份新的配置文件: 78 | 79 | 80 | 81 | ```Python 82 | from kivy.config import Config 83 | Config.read(file>) 84 | # set config 85 | Config.write() 86 | ``` 87 | 88 | 89 | 90 | 91 | 92 | 有时候本地配置只有一个.ini文件还不够用,比如说可能你要单独使用某个garden、Kivy日志或者其他什么模块,这时候就要把KIVY_HOME这个环境变量进行修改了,指定到目标位置就行: 93 | 94 | 95 | ```Python 96 | import os 97 | os.environ['KIVY_HOME'] = folder> 98 | ``` 99 | 100 | 101 | 还有一种思路,就是在运行Kivy应用之前,在终端中手动修改一下这个环境变量: 102 | 103 | 104 | 105 | 1. Windows: 106 | `set KIVY_HOME=folder>` 107 | 108 | 2. Linux & OSX: 109 | `export KIVY_HOME=folder>` 110 | 111 | 112 | 113 | 在设置了KIVY_HOME之后,所指定的这个文件夹就会被当做默认的.kivy文件夹来用。 114 | 115 | 116 | 117 | 118 | 119 | ## 详细理解配置项 120 | 121 | 在[kivy.config](http://kivy.org/docs/api-kivy.config.html#module-kivy.config "kivy.config") 模块中可以看到全部的配置项的解释。 122 | 123 | -------------------------------------------------------------------------------- /16-Kivy-VM.md: -------------------------------------------------------------------------------- 1 | Title: Kivy VM 2 | Date: 2017-03-6 3 | Category: Kivy 4 | Tags: Python,Kivy 5 | 6 | 7 | # Kivy中文编程指南:Kivy 虚拟机 8 | 9 | 10 | [英文原文](https://kivy.org/docs/guide/packaging-android-vm.html) 11 | 12 | ## 简介[¶](https://kivy.org/docs/guide/packaging-android-vm.html#introduction "Permalink to this headline") 13 | 14 | 目前,Kivy 的 Android 应用程序构建只能在配置有 python-for-android、 Android SDK 和 NDK 的 Linux 环境进行。这对于 Windows 或者 OS X 的用户来说,搭建起来就有点麻烦,所以 Kivy 官方提供了一个完全配置好的 [VirtualBox](http://www.virtualbox.org/) 虚拟机磁盘镜像,用来减轻自己搭建的哀伤与痛苦。 15 | 16 | 如果你对于虚拟机不太了解,建议去阅读以下[维基百科上面的虚拟机页面](http://en.wikipedia.org/wiki/Virtualization)。 17 | 18 | ## 上手[¶](https://kivy.org/docs/guide/packaging-android-vm.html#getting-started "Permalink to this headline") 19 | 20 | 1. 首先是到[ Kivy 下载页面](http://kivy.org/#download) 找到 **Virtual Machine** 这一部分。下载的文件超过 2GB ,解压缩之后是大概 6GB。解压缩文件之后别忘掉 vdi 虚拟磁盘的位置。 21 | 2. 根据你机器的操作系统版本,去[ VirtualBox 下载页面](https://www.virtualbox.org/wiki/Downloads) 下载对应的安装包,然后安装。 22 | 3. 启动 VirtualBox,点击新建按钮。然后选择操作系统为 “linux” ,版本设置为 “Ubuntu 64-bit”。 23 | 4. 在 “Hard drive” 硬盘这个选项,选择“Use an existing virtual hard drive file”,即使用已有的虚拟硬盘文件。这时候找到上面你下载并解压出来的那个 vdi 文件,选中使用它。 24 | 5. 到虚拟机设置的页面。在“Display -> Video” 显示器->显卡,这一部分,吧显存增加到至少 32MB 以上。启用 3D 加速来提高用户体验。 25 | 6. 启动虚拟机,然后看看桌面上的 readme 文件,根据指示操作就行了。 26 | 27 | 28 | 29 | ## 构建 APK[¶](https://kivy.org/docs/guide/packaging-android-vm.html#building-the-apk "Permalink to this headline") 30 | 31 | 32 | 虚拟机家在之后,就根据 python-for-android 打包指南里面的讲解来构建 APK 文件里了:[英文原版](https://kivy.org/docs/guide/packaging-android.html#packaging-your-application-into-apk),[中文翻译版本](http://blog.cycleuser.org/kivy-pack-android.html)或者[知乎专栏的镜像](https://zhuanlan.zhihu.com/p/25571974)。也根本不用使用 git clone 下载什么的了,因为虚拟机里面的 python-for-android 已经安装配置好了,就在虚拟系统的 home 目录里面了。 33 | 34 | 35 | ## 提示建议[¶](https://kivy.org/docs/guide/packaging-android-vm.html#hints-and-tips "Permalink to this headline") 36 | 37 | 1. 共享文件夹 38 | 通常情况下,你的开发环境和工具链都在宿主机中,而 APK 的构建在客户机里面。好在 VirtualBox 提供了共享文件夹的功能,允许你的客户机直接读取宿主机中的某个文件夹。 39 | 可以选中‘Permanent’(永久挂载)和 ‘Auto-mount’(自动挂载)这两个选项,这样把构建好的 APK 文件复制到宿主机就更方便了。写一个小脚本就可以很简单地实现自动复制或者移动这个步骤。 40 | 2. 复制粘贴 41 | 默认情况下,宿主机和客户机的剪贴板是不能共享的。可以在“Settings -> General -> Advanced”(设置->通用->高级)中启用 “bi-directional”(双向复制粘贴)的选项。 42 | 3. 虚拟机快照 43 | 如果你正在用 Kivy 开发环境的分支,同步最新版本有时候可能会出问题(Kivy 开发者尽量在避免这种情况)。所以可以在更新之前建立一个虚拟机快照来避免这类问题。这能让你很方便恢复到之前能用的状态。 44 | 4. 补充内存 45 | 如果虚拟机分配的内存不够,可能会因为一些很神奇的错误导致编译失败,比如: 46 | ```Bash 47 | arm-linux-androideabi-gcc: Internal error: Killed (program cc1) 48 | ``` 49 | 如果出现了上面这种情况,检查一下 Kivy 虚拟机的剩余内存,如果内存不足,就在虚拟机设置里面多增加一些吧。 50 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /12-Kivy-IDE.md: -------------------------------------------------------------------------------- 1 | Title: Kivy IDE 2 | Date: 2017-02-19 3 | Category: Kivy 4 | Tags: Python,Kivy 5 | 6 | 7 | # 在各种流行的 Python IDE 中配置 Kivy 集成开发环境 8 | 9 | 10 | * [英文原文](https://github.com/kivy/kivy/wiki/Setting-Up-Kivy-with-various-popular-IDE's) 11 | 12 | 13 | ## 在 Windows 系统上配置 PyCharm 使用 Kivy 14 | 15 | 16 | 从 1.9.1 开始, Kivy 就可以安装到你系统中已有的 Python 解释器中,所以在 Windows 系统上面的安装非常简单直接。 17 | 18 | 19 | * 1 在 Windows 系统上安装 Kivy;可以参考[英文原版安装指南](http://kivy.org/docs/installation/installation-windows.html)或者[我博客里的安装指南](http://blog.cycleuser.org/kivy-installment-tutorial.html),或者参考[我的知乎专栏](https://zhuanlan.zhihu.com/p/24632231?refer=python-kivy)。 20 | * 2 然后就在 PyCharm 里面建立或者打开你的项目就可以了。 21 | 22 | 23 | 24 | 理论上就这么简单,两步就搞定了。如果你有多个 Python 解释器,那就需要选择安装了 Kivy 的那个才行。具体步骤是在 PyCharm 里面,按照如下流程操作: 25 | 26 | * 1 File 文件 -> Settings 设置 -> Project 项目 -> Project Interpreter 项目解释器 27 | * 2 取消掉当前的项目解释器,选择你要用的安装了 Kivy 的 Python 解释器就好了。 28 | 29 | 这就完毕了,接下来就可以用 Kivy 来玩耍了。 30 | 31 | 32 | ## 在 macOS 系统上配置 PyCharm 使用 Kivy 33 | 34 | 35 | 36 | Kivy 开发团队推荐 macOS 用户使用 [homebrew](http://brew.sh) 来安装 Kivy。这很简单,在 Mac 系统里面打开 Terminal 终端就可以了。下面的代码输入或者复制粘贴到终端提示符后面就可以了。 37 | 要注意这些代码特别长,所以可能因为文字换行等等导致出现多行的情况,这时候一定要注意要复制完整。 38 | 除了用 brew 和 pip 来安装 Kivy 的方法之外,还可以参考其他的详细安装指南,比如[我博客里的安装指南](http://blog.cycleuser.org/kivy-installment-tutorial.html)或者[我的知乎专栏](https://zhuanlan.zhihu.com/p/24644473?refer=python-kivy)。 39 | 40 | 41 | * 1 安装 Homebrew 42 | 43 | ```bash 44 | /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" 45 | ``` 46 | 47 | * 2 通过 Brew 来安装 Python 3 48 | 49 | ```bash 50 | brew install python3 51 | ``` 52 | 53 | 或者 Python 2 54 | ```bash 55 | brew install python 56 | ``` 57 | 58 | * 3 安装 Kivy (参考[我博客里的安装指南](http://blog.cycleuser.org/kivy-installment-tutorial.html)或者[我的知乎专栏](https://zhuanlan.zhihu.com/p/24644473?refer=python-kivy))。这里一定要注意,下面的命令使用了 pip3 ,意思是说安装到了 Python3 里面,如果你要用 Python2 ,那就把下面命令中的 pip3 替换成 pip: 59 | 60 | ```bash 61 | brew install hg sdl sdl2 sdl2_image sdl2_ttf sdl2_mixer gstreamer 62 | pip3 install --upgrade pip 63 | pip3 install cython 64 | USE_OSX_FRAMEWORKS=0 pip3 install kivy 65 | ``` 66 | 67 | 68 | PyCharm 应该能选择你默认的 Python 解释器,然后(估计差不多)就是你刚刚把 Kivy 座位一个模块来安装好的那个解释器。 69 | 70 | 可以通过下面的路径来对已有模块进行检查: File 文件 -> Settings 设置 -> Project 项目 -> Project Interpreter 项目解释器 71 | 72 | 73 | ## Kivy 语言自动补齐以及代码高亮 74 | 75 | ID 为 Xuton 的一位好心朋友开发了一个扩展文件,可以提供 Kivy 语言的自动补齐和代码高亮,安装方法如下: 76 | 77 | 78 | * 下载[这个文件](https://github.com/Zen-CODE/kivybits/blob/master/IDE/PyCharm_kv_completion.jar?raw=true); 79 | * 打开 Pycharm 的主菜单,点击 File 文件 -> Import 导入 ( 或者 Import Settings 导入设置); 80 | * 选择刚刚下载的那个 jar 文件,然后 PyCharm 会弹出一个对话框让你来确认,点击 OK 就行了。 81 | * 重新启动 PyCharm ,看看是不是有效果了? 82 | 83 | # 更多其他 IDE 84 | 85 | 这些我就不翻译了,大家可以去看看。 86 | 87 | * [How to use Python Tools for Visual Studio to develop and run Kivy Applications](https://groups.google.com/forum/#!topic/kivy-users/tZTuUzUHBwc/) 88 | * [kivy-eclipse-and-pydev-also-pypy](http://stackoverflow.com/questions/9768489/kivy-eclipse-and-pydev-also-pypy) 89 | * [How to Set up Wing IDE for Kivy on Windows](http://www.blog.pythonlibrary.org/2013/11/18/how-to-set-up-wing-ide-for-kivy-on-windows/) 90 | * [Kv language definition file for gedit](https://wiki.gnome.org/Projects/GtkSourceView/LanguageDefinitions?action=AttachFile&do=view&target=kv.lang) 91 | 92 | 93 | -------------------------------------------------------------------------------- /09-Kivy-Graphics.md: -------------------------------------------------------------------------------- 1 | Title: Kivy Graphics 2 | Date: 2017-02-12 3 | Category: Kivy 4 | Tags: Python,Kivy 5 | 6 | 7 | # Kivy中文编程指南:图形 8 | 9 | [英文原文](https://kivy.org/docs/guide/graphics.html) 10 | 11 | ##译者前言 12 | 这一章节比前两章节简单很多,翻译的也比较顺了。 13 | 14 | 15 | 16 | ## 简介Canvas 17 | 18 | Kivy中控件图形呈现是使用Canvas完成的,可以将其看作一个无限的绘图板,也是一组绘图指令。有很多种绘图指令都可以应用或者添加到你的Canvas伤,不过总体上分为两类: 19 | 20 | 21 | * [`context instructions`环境指令](https://kivy.org/docs/api-kivy.graphics.context_instructions.html#module-kivy.graphics.context_instructions "kivy.graphics.context_instructions") 22 | * [`vertex instructions`顶点指令](https://kivy.org/docs/api-kivy.graphics.vertex_instructions.html#module-kivy.graphics.vertex_instructions "kivy.graphics.vertex_instructions") 23 | 24 | 25 | [`context instructions`环境指令](https://kivy.org/docs/api-kivy.graphics.context_instructions.html#module-kivy.graphics.context_instructions "kivy.graphics.context_instructions")不绘制任何图形,但会改变[`vertex instructions`顶点指令](https://kivy.org/docs/api-kivy.graphics.vertex_instructions.html#module-kivy.graphics.vertex_instructions "kivy.graphics.vertex_instructions")的绘制结果。 26 | 27 | Canvas都包含两个指令分支。分别是[`canvas.before`](https://kivy.org/docs/api-kivy.graphics.html#kivy.graphics.Canvas.before "kivy.graphics.Canvas.before")和[`canvas.after`](https://kivy.org/docs/api-kivy.graphics.html#kivy.graphics.Canvas.after "kivy.graphics.Canvas.after") 这两种指令群。这两组指令分别在`Canvas`图形绘制前后执行。 28 | 绘制前的会被绘制的图形覆盖掉,绘制后的会覆盖在图形上层。这些指令都在用户对它们读取之后才会被创建。 29 | 30 | 31 | 要对一个控件添加Canvas绘图指令,需要使用Canvas环境指令: 32 | 33 | 34 | 35 | 36 | ```Python 37 | class MyWidget(Widget): 38 | def __init__(self, **kwargs): 39 | super(MyWidget, self).__init__(**kwargs) 40 | with self.canvas: 41 | # add your instruction for main canvas here 42 | # 这里是增加一个座位主绘图的指令 43 | 44 | with self.canvas.before: 45 | # you can use this to add instructions rendered before 46 | # 这里可以在绘图之前添加指令 47 | 48 | with self.canvas.after: 49 | # you can use this to add instructions rendered after 50 | # 这里可以在绘图之后添加指令 51 | ``` 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | ## 环境指令 62 | 63 | 环境指令是用于操作opengl环境。 可以旋转,翻译和缩放画布。还可以附加纹理或更改绘图颜色。下面这段代码里面的是最常用到的更改颜色的指令,其他的环境指令也都很有用处: 64 | 65 | ```Python 66 | with self.canvas.before: 67 | Color(1, 0, .4, mode='rgb') 68 | ``` 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | ## 绘图指令 81 | 82 | 83 | 绘图指令可简可繁,最简单的比如画一个多边形,更复杂的比如绘制网格或者贝塞尔曲线都可以: 84 | 85 | 86 | 87 | ```Python 88 | with self.canvas: 89 | # draw a line using the default color 90 | # 用默认颜色画一条线 91 | Line(points=(x1, y1, x2, y2, x3, y3)) 92 | 93 | # lets draw a semi-transparent red square 94 | # 接下来画一个半透明的红方块 95 | Color(1, 0, 0, .5, mode='rgba') 96 | Rectangle(pos=self.pos, size=self.size) 97 | ``` 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | ## 操作指令 109 | 110 | 111 | 有时候可能需要把之前添加到Canvas绘图上的指令进行更改或者删除,这可以有很多种办法,要根据具体需求来选择: 112 | 113 | 可以给指令创建一个引用然后对其进行更新: 114 | 115 | ```Python 116 | class MyWidget(Widget): 117 | def __init__(self, **kwargs): 118 | super(MyWidget, self).__init__(**kwargs) 119 | with self.canvas: 120 | self.rect = Rectangle(pos=self.pos, size=self.size) 121 | 122 | self.bind(pos=self.update_rect) 123 | self.bind(size=self.update_rect) 124 | 125 | def update_rect(self, *args): 126 | self.rect.pos = self.pos 127 | self.rect.size = self.size 128 | ``` 129 | 130 | 131 | 或者也可以清空Canvas画布然后重新画: 132 | 133 | ```Python 134 | class MyWidget(Widget): 135 | def __init__(self, **kwargs): 136 | super(MyWidget, self).__init__(**kwargs) 137 | self.draw_my_stuff() 138 | 139 | self.bind(pos=self.draw_my_stuff) 140 | self.bind(size=self.draw_my_stuff) 141 | 142 | def draw_my_stuff(self): 143 | self.canvas.clear() 144 | 145 | with self.canvas: 146 | self.rect = Rectangle(pos=self.pos, size=self.size) 147 | ``` 148 | 149 | 150 | 要注意更新指令的方法是更好的选择,因为这样减少了开销,并且避免了创建新指令。 151 | 152 | -------------------------------------------------------------------------------- /19-Kivy-Pack-License.md: -------------------------------------------------------------------------------- 1 | Title: Kivy Pack License 2 | Date: 2017-03-07 3 | Category: Kivy 4 | Tags: Python,Kivy 5 | 6 | # Kivy中文编程指南:授权协议 7 | 8 | [英文原文](https://kivy.org/docs/guide/licensing.html) 9 | 10 | 11 | #### 警告 12 | 13 | 这并不是一个律师咨询指南! Kivy 的开发组织,本指南的作者以及参与者,对任何信息缺失、产生误导,以及任何基于这份指南的行为产生的任何后果都不负任何责任。这个指南只是提供一些信息,目的是帮助缺乏经验的用户。 14 | 15 | 你的代码本身并不一定需要包括协议信息和对其他用到的软件的版权声明,不过二进制文件就不一样了。 16 | 17 | 18 | 当你创建一个二进制文件(比如 exe,app 或者 APK 等等)的时候,里面包括了 Kivy 以及其他的一些依赖项目或者你的应用程序用到的其他的包,其中的某些就可能有声明需要你再自己的应用程序中进行版权信息声明。在你对这些二进制文件进行发布之前,一定要检查所有不属于你源代码的**创建出来的文件**,(比如 dll,pyd,so 等等)然后如果某一个文件需要有版权信息,记得加进去版权声明。这样你才能满足 Kivy 开发需要的版权要求。 19 | 20 | 21 | ## 依赖包[¶](https://kivy.org/docs/guide/licensing.html#dependencies "Permalink to this headline") 22 | 23 | 在 Kivy 支持的每个平台上都或多或少地用到了下面这些依赖包,所以你需要添加这些授权协议进去,基本都是只要你粘贴一段版权声明到你的应用中,而不能当作自己写了这些功能代码。 24 | 25 | * [docutils](https://sf.net/p/docutils/code/HEAD/tree/trunk/docutils/COPYING.txt) 26 | * [pygments](https://bitbucket.org/birkenfeld/pygments-main/src/tip/LICENSE) 27 | * [sdl2](https://www.libsdl.org/license.php) 28 | * [glew](http://glew.sourceforge.net/glew.txt) 29 | * [gstreamer](https://github.com/GStreamer/gstreamer/blob/master/COPYING) (如果用到了再添加) 30 | * 图像和音频库(例如 [SDL_mixer](http://hg.libsdl.org/SDL_mixer/file/default/VisualC/external/lib/x86)) 31 | 32 | 对于图像和音频库,可能需要你手动去检查一下,一般都是以 `lib` 这三个字母开头的。这些程序的 `LICENSE*` 授权协议文件会在 PyInstaller 里面包含,但在 python-for-android 则没有,所以你得自己查找一下。 33 | 34 | 35 | ## Windows 操作系统 (PyInstaller)[¶](https://kivy.org/docs/guide/licensing.html#windows-pyinstaller "Permalink to this headline") 36 | 37 | 要使用 Windows API 功能, Kivy 使用了 [pypiwin32](https://pypi.python.org/pypi/pypiwin32) 。这个包是基于 [PSF 协议](https://opensource.org/licenses/Python-2.0)发布的。 38 | 39 | 40 | 41 | ### VS 可再发行组件[¶](https://kivy.org/docs/guide/licensing.html#vs-redistributables "Permalink to this headline") 42 | 43 | 使用 Visual Studio 编译的 Python(官方版本)使用了来自微软的一些文件,在特定条件下基于 CRT license 可以重新发布这些组件。包括这些文件名以及[Py2 CRT 协议](https://hg.python.org/sandbox/2.7/file/tip/Tools/msi/crtlicense.txt) 或者 [Py3 CRT 协议](https://hg.python.org/cpython/file/tip/Tools/msi/exe/crtlicense.txt),主要看你用的是哪个版本的解释器,所以要针对你的发布对象来具体情况具体对待。 44 | 45 | * [可再发行组件列表](https://msdn.microsoft.com/en-us/library/8kche8ah(v=vs.90).aspx) 46 | 47 | 48 | 49 | ### 其他链接库[¶](https://kivy.org/docs/guide/licensing.html#other-libraries "Permalink to this headline") 50 | 51 | * [zlib](https://github.com/madler/zlib/blob/master/README) 52 | 53 | 54 | 55 | #### 特别注意 56 | 57 | 对那些没有直接使用,但是打包的时候用到的包要列出,比如在 Windows 系统上面用的 PyInstaller。 58 | 59 | 60 | 61 | ## Linux[¶](https://kivy.org/docs/guide/licensing.html#linux "Permalink to this headline") 62 | 63 | GNU/Linux 操作系统现在有好多发行版,所以没有一个能够通用给所有发行版的指南。这部分也属于 RPi (不知道是什么鬼东西)。然而可以简化成两种打包方式,(还是用 PyInstaller 来打包)提供包含的二进制文件,或者不提供。 64 | 65 | 如果包含了二进制文件,应该逐个检查这些文件,比如 so 为扩展名的,除了你的代码之外,要找到对应这些文件的授权协议。根据这个协议你可能需要在你的程序里面添加一条对应的版权信息。 66 | 67 | 如果没有包含二进制文件,比如你用 deb 等格式的文件进行打包,那就[把麻烦扔给你的用户了](https://kivy.org/docs/guide/licensing.html#avoid)。你可以自己决定是否要满足其他授权的要求,例如在你的应用中是否添加额外的版权信息。 68 | 69 | 70 | 71 | ## Android[¶](https://kivy.org/docs/guide/licensing.html#android "Permalink to this headline") 72 | 73 | APK 实际上只是一个文件压缩包,所以可以解压缩这个文件(就像 Windows 里面那样做)然后检查每个文件。 74 | 75 | `APK/assets/private.mp3/private.mp3/`这个文件夹内有所有包含的文件。大多数的都是和 Kivy 、Python 或者你的代码相关的,不过那些与这些无关的就需要检查一下了。 76 | 77 | 已知的包: 78 | 79 | * [pygame](https://bitbucket.org/pygame/pygame/src/tip/LGPL) (如果用了旧的工具链) 80 | * [sqlite3](https://github.com/ghaering/pysqlite/blob/master/LICENSE) 81 | * [six](https://bitbucket.org/gutworth/six/src/tip/LICENSE) 82 | 83 | 84 | 有的包含的链接库是 Kivy 直接使用或者通过 Pygame/SDL2 来使用的,他们的位置在 `APK/lib/armeabi/`。大多数都是和依赖包相关,要么就是由 python-for-android 产生,并且可能就是 python-for-android 的一部分。例如`libapplication.so`等。 85 | 86 | 87 | 88 | 89 | ## Mac[¶](https://kivy.org/docs/guide/licensing.html#mac "Permalink to this headline") 90 | 91 | Missing. 92 | 这部分 Kivy 官方文档没写其他内容。 93 | 94 | 95 | ## iOS[¶](https://kivy.org/docs/guide/licensing.html#ios "Permalink to this headline") 96 | 97 | Missing. 98 | 这部分 Kivy 官方文档没写其他内容。 99 | 100 | 101 | 102 | 103 | ## 避免二进制文件[¶](https://kivy.org/docs/guide/licensing.html#avoiding-binaries "Permalink to this headline") 104 | 105 | 有一种方法也许能够避免这种很狗很麻烦的授权协议什么的鬼东西,就是不用任何第三方的鬼扯玩意来构建你的应用。你可以用 Python 来自己创立一个模块,在其中的 `__main__.py`都只有你自己的代码,而 `setup.py` 列出需要的依赖包。 106 | 107 | 这样你依然可以发布你的应用—就是你的**代码**,然后你就不用管任何其他的授权协议了。不过这样就更像是搭配使用,而不太算是发布程序了。这时候满足各种授权的依赖关系,就转移到你的程序的用户身上了,他们需要自行搞定运行环境来使用这个模块。如果你比较关心自己的用户,建议你还是花点时间来阅读一下[可能导致的后果](http://programmers.stackexchange.com/a/234295)。 108 | 109 | -------------------------------------------------------------------------------- /18-Kivy-Pack-iOS.md: -------------------------------------------------------------------------------- 1 | Title: Kivy Pack iOS 2 | Date: 2017-03-07 3 | Category: Kivy 4 | Tags: Python,Kivy 5 | 6 | # Kivy中文编程指南:打包为 iOS 系统可执行文件 7 | 8 | [英文原文](https://kivy.org/docs/guide/packaging-ios.html) 9 | 10 | 11 | #### 特别注意 12 | 13 | 目前还只能用 Python 2.7 来针对 iOS 平台打包应用程序。 Python 3.3 以上的支持还在开发中。 14 | 15 | 16 | `The overall process for creating a package for IOS can be explained in 4 steps:` 17 | 18 | 总体上创建一个 iOS 应用程序需要四步: 19 | (译者注:对,你没有看错,官方文档就是写的 4 steps,所以我特地留下了上面这行原文,可见估计 Kivy 的开发者们也没太注意这点小错误吧。。。) 20 | 21 | 1. 针对 iOS 编译 Python 和 需要的模块; 22 | 2. 创建一个 Xcode 项目,链接你的源代码; 23 | 3. 进行定制修改。 24 | 25 | 26 | 27 | ## 预先准备[¶](https://kivy.org/docs/guide/packaging-ios.html#prerequisites "Permalink to this headline") 28 | 29 | 首先要安装一些依赖包,比如 cython,autotools 等等。Kivy 的开发者推荐你使用 [Homebrew](http://mxcl.github.com/homebrew/) 来安装这些依赖包: 30 | 31 | ```Bash 32 | brew install autoconf automake libtool pkg-config 33 | brew link libtool 34 | sudo easy_install pip 35 | sudo pip install cython==0.23 36 | ``` 37 | 38 | 更多细节参考 [IOS Prerequisites](https://kivy.org/docs/guide/packaging-ios-prerequisites.html#packaging-ios-prerequisites)。一定要在下一步开始之前保证依赖关系都满足了。 39 | 40 | ## 编译发布版[¶](https://kivy.org/docs/guide/packaging-ios.html#compile-the-distribution "Permalink to this headline") 41 | 42 | Open a terminal, and type: 43 | 44 | 打开终端,输入下面的命令: 45 | 46 | ```Bash 47 | git clone git://github.com/kivy/kivy-ios 48 | cd kivy-ios 49 | ./toolchain.py build kivy 50 | ``` 51 | 52 | Python 发型版中大部分内容都会被打包到 python27.zip 这个文件中。如果遇到了问题,可以参考[谷歌论坛用户组](https://groups.google.com/forum/#!forum/kivy-users) 或者 [kivy-ios 项目页面](https://github.com/kivy/kivy-ios)。 53 | 54 | 55 | 56 | ## 创建一个 Xcode 项目[¶](https://kivy.org/docs/guide/packaging-ios.html#create-an-xcode-project "Permalink to this headline") 57 | 58 | 在进行下一步之前,要保证你的程序运行起点是一个名为 main.py 的文件。 59 | 60 | Kivy 官方提供了一个脚本,可以创建一个初始的 Xcode 项目。在下面的代码样例中,把 Touchtracer 这个换成你的项目名字。名字一定不能有空格或者其他非法字符。(译者注:吐槽一下,那什么算是非法字符倒是说说啊。) 61 | 62 | 63 | ```Bash 64 | ./toolchain.py create <app_directory> 65 | ./toolchain.py create Touchtracer ~/code/kivy/examples/demo/touchtracer 66 | ``` 67 | 68 | 69 | #### 特别注意 70 | 上面这一步中,应用程序的路径一定要用完整路径。 71 | 72 | 接下来会有一个名字为` <title>`-ios 的目录被创建,里面就是 Xcode 项目了。可以打开这个项目: 73 | 74 | ```Bash 75 | open touchtracer-ios/touchtracer.xcodeproj 76 | ``` 77 | 78 | 然后点击 Play 运行,就可以了。 79 | 80 | #### 特别注意 81 | 82 | 每次点击 Play 的时候, 你的应用目录都会同步到` <title>`-ios/YourApp 这个目录。不要直接对这个目录进行修改。 83 | 84 | 85 | ## 更新 Xcode 项目project[¶](https://kivy.org/docs/guide/packaging-ios.html#updating-an-xcode-project "Permalink to this headline") 86 | 87 | 举个例子,加入你要在你的项目中添加 numpy,但在之前创建这个 Xcode 项目的时候没有编译进去。那首先就构建 numpy : 88 | 89 | 90 | ```Bash 91 | ./toolchain.py build numpy 92 | ``` 93 | 94 | 然后更新一下你的 Xcode 项目: 95 | ```Bash 96 | ./toolchain.py update touchtracer-ios 97 | ``` 98 | 99 | 这样所有相关的链接库、框架就都被添加到你的 Xcode 项目里去了。 100 | 101 | 102 | ## 定制修改[¶](https://kivy.org/docs/guide/packaging-ios.html#customize "Permalink to this headline") 103 | 104 | 有很多方法能对你的应用进行修改和设置。可以参考 [kivy-ios](http://www.github.com/kivy/kivy-ios) 的文档来查看更详细的信息。 105 | 106 | 107 | ## 已知的问题[¶](https://kivy.org/docs/guide/packaging-ios.html#known-issues "Permalink to this headline") 108 | 109 | 目前关于 iOS 打包的所有已知问题都可以在 [Kivy-iOS 的 GitHub issues 页面](https://github.com/kivy/kivy-ios/issues) 查看到。如果你遇到的问题不在其中,请创建一个新的 issue,Kivy 开发者会尽快跟进处理。 110 | 111 | 已知的问题中绝大部分都太技术性了,没必要在这里写了,其中一个重要的问题是目前没办法移除一些链接库(比如 SDL_Mixer) ,因为 Kivy 项目需要这些链接库。在后续的版本中, Kivy 开发者会解决掉这些问题。 112 | 113 | 114 | 115 | ## FAQ[¶](https://kivy.org/docs/guide/packaging-ios.html#faq "Permalink to this headline") 116 | 117 | 118 | 119 | ### 程序异常退出![¶](https://kivy.org/docs/guide/packaging-ios.html#application-quit-abnormally "Permalink to this headline") 120 | 121 | 默认情况下,所有控制台和文件中的 print 语句都被忽视了。如果你运行程序的时候碰到异常状况了,可以激活 log 日志功能,在 main.m 文件中把下面这一行去掉注释: 122 | 123 | 124 | ```Bash 125 | putenv("KIVY_NO_CONSOLELOG=1"); 126 | ``` 127 | 然后你就可以在 Xcode 控制台中看到 Kivy 的日志了。 128 | 129 | 130 | 131 | 132 | ### 渣果公司怎样才能接受一个 Python APP?[¶](https://kivy.org/docs/guide/packaging-ios.html#how-can-apple-accept-a-python-app "Permalink to this headline") 133 | 134 | Kivy 开发者将所有链接库的 app 二进制文件合并成了一个名为 libpython 的二进制文件。这就意味着所有二进制模块都会提前价值,所以不会有动态加载。 135 | 136 | 137 | ### 是否已经向渣果的 App store 提交过 Kivy 应用?[¶](https://kivy.org/docs/guide/packaging-ios.html#have-you-already-submited-a-kivy-application-to-the-app-store "Permalink to this headline") 138 | 139 | 是,例如下面的就是: 140 | 141 | * [Defletouch on iTunes](http://itunes.apple.com/us/app/deflectouch/id505729681), 142 | * [ProcessCraft on iTunes](http://itunes.apple.com/us/app/processcraft/id526377075) 143 | 144 | 更详细的列表可以参考 [Kivy wiki](https://github.com/kivy/kivy/wiki/List-of-Kivy-Projects). 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | -------------------------------------------------------------------------------- /03-Kivy-Environment.md: -------------------------------------------------------------------------------- 1 | Title: Kivy Environment 2 | Date: 2017-02-5 3 | Category: Kivy 4 | Tags: Python,Kivy 5 | 6 | 7 | # Kivy中文编程指南:环境变量 8 | 9 | [英文原文](https://kivy.org/docs/guide/environment.html) 10 | 11 | 12 | Kivy的初始化和很多行为都可以通过各种环境变量来控制。 13 | 14 | 15 | 例如,若要严格设定用PIL进行文本渲染,可以通过如下方式来实现: 16 | 17 | 18 | ```Bash 19 | $ KIVY_TEXT=pil python main.py 20 | ``` 21 | (译者注:PIL,Python Imaging Library, Python 下常用的绘图库) 22 | 23 | 24 | 所有的这些环境变量的修改设定都需要在导入Kivy之前进行,具体如下所示: 25 | 26 | 27 | 28 | ```Python 29 | import os 30 | os.environ['KIVY_TEXT'] = 'pil' 31 | import kivy 32 | ``` 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | ## 路径控制 41 | 42 | 43 | * 从Kivy1.0.7版本开始提供 44 | 45 | 46 | 47 | You can control the default directories where config files, modules and kivy data are located. 48 | 49 | Kivy的配置文件、模块以及数据存储的默认目录,都可手动设定所在位置。 50 | 51 | 52 | >KIVY_DATA_DIR 53 | 54 | 55 | 这个是Kivy的数据目录,默认值为/data 。 56 | 57 | 58 | >KIVY_MODULES_DIR 59 | 60 | 这个是Kivy的模块目录,默认值为/modules 。 61 | 62 | >KIVY_HOME 63 | 64 | 这个是Kivy的HOME目录,该目录是用来存放本地配置文件的,必须是一个可以写入的位置。对应不同系统也有不同位置: 65 | 66 | * Desktop: /.kivy 67 | * Android: /.kivy 68 | * iOS: /Documents/.kivy 69 | 70 | * 从Kivy1.9.0版本开始提供 71 | 72 | 73 | 74 | 75 | 76 | >KIVY_SDL2_PATH 77 | 78 | 79 | 这个变量若设定了,编译Kivy的时候就会使用该位置的SDL2库文件,而不再使用系统的库文件。在环境变量PATH的开头部位就要设定好这个变量,这样在运行一个Kivy应用的时候才能也使用相同的SDL2库文件。 80 | 81 | 82 | 83 | * 从Kivy1.9.0版本开始提供 84 | 85 | 86 | 87 | 88 | 89 | ####特别注意 90 | 91 | 刚刚这个SDL2路径是用来编译Kivy的。运行程序的话就用不着了。 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | ## 配置文件 104 | 105 | 106 | >KIVY_USE_DEFAULTCONFIG 107 | 108 | 若设定了此环境变量,Kivy会读取制定的配置文件。 109 | 110 | 111 | >KIVY_NO_CONFIG 112 | 113 | 若设定了此环境变量,Kivy将不会读取也不会写入任何配置文件。也适用于用户配置文件夹的位置。(译者注:这句话我还没弄明白,因为没有这样尝试。) 114 | 115 | >KIVY_NO_FILELOG 116 | 117 | 若设定了此环境变量,日志将不再输出到文件内。 118 | 119 | 120 | >KIVY_NO_CONSOLELOG 121 | 122 | 若设定了此环境变量,日志将不再输出到控制台。 123 | 124 | 125 | >KIVY_NO_ARGS 126 | 127 | 若设定了此环境变量,命令行传递的参数将不会被Kivy解析和使用。也就是说,可以不用 – 定义符,就能随便创建一个使用自己参数的脚本或者应用: 128 | 129 | 130 | ```Python 131 | import os 132 | os.environ["KIVY_NO_ARGS"] = "1" 133 | import kivy 134 | ``` 135 | 136 | 137 | 138 | 139 | 140 | * 从Kivy1.9.0版本开始提供 141 | 142 | 143 | 144 | ## 限定Kivy.core核心,使用特定版本 145 | 146 | Kivy.core会尝试使用所在平台的最优实现。如果要测试或者定制安装,你可能要把选择器设定为某个特定版本的kivy.core。 147 | 148 | 149 | 150 | 151 | >KIVY_WINDOW 152 | 153 | 这一变量是用来设定如何创建窗口,可用值:sdl2, pygame, x11, egl_rpi 154 | 155 | 156 | 157 | >KIVY_TEXT 158 | 159 | 这一变量是用来设定如何渲染文本,可用值:sdl2, pil, pygame, sdlttf 160 | 161 | 162 | 163 | >KIVY_VIDEO 164 | 165 | 这一变量是用来设定如何渲染视频,可用值:pygst, gstplayer, pyglet, ffpyplayer, ffmpeg, gi, null 166 | 167 | 168 | 169 | >KIVY_AUDIO 170 | 171 | 这一变量是用来设定如何播放声音,可用值:sdl2, gstplayer, pygst, ffpyplayer, pygame, gi, avplayer 172 | 173 | 174 | 175 | >KIVY_IMAGE 176 | 177 | 这一变量是用来设定如何读取图像,可用值:sdl2, pil, pygame, imageio, tex, dds, gif 178 | 179 | 180 | 181 | >KIVY_CAMERA 182 | 183 | 这一变量是用来设定如何读取摄像头,可用值:videocapture, avfoundation, pygst, opencv 184 | 185 | 186 | 187 | >KIVY_SPELLING 188 | 189 | 这一变量是用来设定拼写,可用值: enchant, osxappkit 190 | 191 | 192 | 193 | >KIVY_CLIPBOARD 194 | 195 | 196 | 这一变量是用来设定剪切板管理组件,可用值:sdl2, pygame, dummy, android 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | ## 设置单位 207 | 208 | 209 | 210 | >KIVY_DPI 211 | 212 | 这个是用来设定Metrics.dpi的dpi值的。 213 | 214 | * 从Kivy1.4.0版本开始提供 215 | 216 | 217 | 218 | >KIVY_METRICS_DENSITY 219 | 220 | 这个是用来设定Metrics.density,像素密度。 221 | 222 | * 从Kivy1.5.0版本开始提供 223 | 224 | 225 | 226 | >KIVY_METRICS_FONTSCALE 227 | 228 | 这个是用来设定Metrics.fontscale,字体大小。 229 | 230 | * 从Kivy1.5.0版本开始提供 231 | 232 | 233 | 234 | 235 | 236 | 237 | ## 图形输出 238 | 239 | 240 | 241 | >KIVY_GL_BACKEND 242 | 243 | 此变量用于设定使用的OpenGL后端,更多细节参考[cgl](http://kivy.org/docs/api-kivy.graphics.cgl.html#module-kivy.graphics.cgl "kivy.graphics.cgl"). 244 | 245 | >KIVY_GL_DEBUG 246 | 247 | 此变量用于设定是否对OpenGL调用进行日志记录,更多细节参考[cgl](http://kivy.org/docs/api-kivy.graphics.cgl.html#module-kivy.graphics.cgl "kivy.graphics.cgl"). 248 | 249 | >KIVY_GRAPHICS 250 | 251 | 此变量用于设定是否使用OpenGL ES2,更多细节参考[cgl](http://kivy.org/docs/api-kivy.graphics.cgl.html#module-kivy.graphics.cgl "kivy.graphics.cgl"). 252 | 253 | >KIVY_GLES_LIMITS 254 | 255 | 此变量用于设定是否强制设定GLES2(默认值为启用,设置为1)。如果设定为false,Kivy将不再兼容GLES2。(译者注:这部分我不懂,就直接生硬翻译了原文,建议大家参考一下原文去理解。)如果设置为true,可能有下表中所示的潜在的不兼容情况: 256 | 257 | 258 | 259 | | Mesh indices | If true, the number of indices in a mesh is limited to 65535 | 260 | | ------------- |:-------------:| 261 | | Texture blit | When blitting to a texture, the data (color and buffer) format must be the same format as the one used at the texture creation. On desktop, the conversion of different color is correctly handled by the driver, while on Android, most of devices fail to do it. Ref: [https://github.com/kivy/kivy/issues/1600](https://github.com/kivy/kivy/issues/1600) | 262 | 263 | 264 | 265 | * 从Kivy1.8.1版本开始提供 266 | 267 | 268 | 269 | 270 | >KIVY_BCM_DISPMANX_ID 271 | 272 | 此变量是针对Raspberry Pi树莓派平台的,用于设定所选择的视频输出端口。默认值为0,下面列表中是在vc_dispmanx_types.h这个头文件中存储的可供选择的变量值: 273 | 274 | * 0: DISPMANX_ID_MAIN_LCD 275 | * 1: DISPMANX_ID_AUX_LCD 276 | * 2: DISPMANX_ID_HDMI 277 | * 3: DISPMANX_ID_SDTV 278 | * 4: DISPMANX_ID_FORCE_LCD 279 | * 5: DISPMANX_ID_FORCE_TV 280 | * 6: DISPMANX_ID_FORCE_OTHER 281 | 282 | (译者注:上面0-6分别是不同的显示输出端口,相信很容易看懂,大家探索一下吧。) 283 | 284 | 285 | 286 | -------------------------------------------------------------------------------- /21-Kivy-VMS.md: -------------------------------------------------------------------------------- 1 | Title: Kivy 虚拟机 2 | Date: 2017-03-13 3 | Category: Work 4 | Tags: Python,Kivy 5 | 6 | 7 | # Kivy中文编程指南:更好用 Android 打包虚拟机 8 | 9 | 10 | [英文原文地址](http://brizanmedia.com/wp/2016/07/10/the-fool-proof-guide/) 11 | 12 | ## 译者的废话 13 | 14 | 15 | 开头先给干货,本文提到的[虚拟机镜像的下载地址](https://pan.baidu.com/s/1mhIUz3q)。 16 | 17 | 从去年开始,我开始了 [Kivy 编程指南中文翻译项目](https://github.com/cycleuser/Kivy-CN),把 Kivy Programming Guide 里面的全部内容翻译了一遍。大家可以去我的[知乎专栏](https://zhuanlan.zhihu.com/python-kivy)或者我的 [GitHub](https://github.com/cycleuser) 查看详细内容。 18 | 19 | Kivy 的多平台支持以及使用 Python 这一新手友好的语言的两大特性都很棒,然而世事难求全,APK 生成和搭建有时候挺繁琐的,尤其对于一些不太熟悉 Linux 的纯新人。所以官方提供了很多文档,我也进行了翻译,包括[KV Android 详细指南](https://zhuanlan.zhihu.com/p/25576296),[打包为 Android 系统可执行文件](https://zhuanlan.zhihu.com/p/25571974),以及一个[ Kivy 开发团队提供的 Android 打包用的虚拟机镜像](https://zhuanlan.zhihu.com/p/25583908)。国内的大拿 [nkiiiiid](https://github.com/nkiiiiid/) 也提供了一个他的定制版本的[虚拟机镜像](https://github.com/nkiiiiid/kivy-apk-)。更推荐用[nkiiiiid](https://github.com/nkiiiiid/) 提供的这个版本,16.04 用着更舒服。群里面大家也普遍喜欢用这个版本。 20 | 21 | 22 | 然后进有一位@郝好 的朋友提供了重要信息,说[brizanmedia.com](http://brizanmedia.com) 提供的这个 lubuntu 14.04.3 的 32bit 虚拟机镜像用着很不错。 23 | 24 | 然后作为常年搬运工的我,就顺手下载下来发到百度云,并且翻译一下原文咯。 25 | 原文有很多叹号,我个人不喜欢用叹号,不过在本文我还是忠于原文的风格,在措辞和符号上与原文保持一致。 26 | 27 | 废话完毕,以下是 [brizanmedia.com](http://brizanmedia.com) 的原文翻译。 28 | 29 | ##使用 Python + Kivy 创建 Android 应用的防呆指南~ 30 | 31 | Kivy 是一个支持多点触摸的 Python 框架,可以运行于 Windows,OS X,Linux ,iOS 以及 Android 系统。不过在 Android 上运行 Kivy,还挺麻烦的,因为需要先把代码打包成一个应用。下面的指南是让你从 Python 代码打包到 Android 应用的方法,一定能够成功的哦~ 32 | 33 | 34 | Kivy 官方的指南上面,有一个[如何给 Android 系统打包的指南文档](https://kivy.org/docs/guide/packaging-android.html),(译者也翻译了一份[中文版本的 Android 打包指南](https://zhuanlan.zhihu.com/p/25571974))。不过这些方法都不能用在 Windows 或者 OS X 上面,另外官方的指南很简略,略过了很多步骤。 35 | 36 | 本文提供的这个方案很简单,所有事情都在虚拟机里面解决,包括打包的步骤。目前来说,Kivy 团队确实做了开创性的工作,不过还有以下的问题: 37 | 1. 他们提供的虚拟机使用的是 Ubuntu 操作系统,这样性能开销比较大,用起来运行速度很慢; 38 | 2. 从代码打包生成应用的必备步骤并没有明确给出清晰透彻的指南。 39 | 40 | 于是本文作者自己创建了一个虚拟机镜像,尽可能提高运行速度,争取做到和本机原生操作接近的体验。 41 | 42 | ### 初始步骤 43 | 44 | 第一步就是要下载本文作者提供的 [Linux 虚拟机硬盘镜像](http://brizanmedia.com/wp/wp-content/LXLE14.04.3\(32bit\).vdi.zip)。这个镜像文件挺大的,4G 左右,不过值得你为下载它而付出的等待。(译者注:毕竟能用就不错,而且平心而论这个 Lubuntu 14.04.4 32bit 的虚拟机镜像确实速度比较快,性能开销压力不大。)然后你还需要下载[ Oracle VM Virtualbox](http://www.oracle.com/technetwork/server-storage/virtualbox/downloads/index.html) ,并且安装到你的系统中。关于怎么弄虚拟机这些就不给讲了,都很简单而且网上资料很多。 45 | 46 | 47 | **下面这个特别重要**:安装完毕之后,运行 VirtualBox,然后创建一个新的虚拟机,使用刚刚下载的这个 vdi 文件作为硬盘。你唯一需要设置的是把操作系统设置为 Linux,版本**必须**设置为 Ubuntu 32bit。如果你需要进一步的指南,可以看[这个视频](https://www.youtube.com/watch?v=1P_l7iVKfgs)。这个视频展示了如何安装 VirtualBox 以及用一个已有的 vdi 文件创建新的虚拟机,你就可以按照这个指南来做。(译者注:国内也有很多类似的视频,推荐自己搜索一下,这里就不搬运原版视频了。) 48 | 49 | ### 开始构建吧! 50 | 51 | 52 | 打开虚拟机,启动到登录界面,**用户名和密码都是**`osboxes.org`。 53 | 54 | ![vbox1](http://brizanmedia.com/wp/wp-content/uploads/2016/07/vbox1.jpg) 55 | 56 | 这里顺路要感谢一下 [osboxes.org](http://www.osboxes.org/)。(译者注:这个网站分享各种已经装好的虚拟机镜像,VirtualBox 和 Vmware 的都有,非常赞,可以下载来当做各种测试环境。) 57 | 58 | 登陆之后就能看到桌面了: 59 | ![vbox2](http://brizanmedia.com/wp/wp-content/uploads/2016/07/vbox2-1024x640.jpg) 60 | 61 | 本文作者把所有构建 APK 的相关指南都放到了桌面壁纸上面,不过这里还是会用很多屏幕截图来给讲述一遍。 62 | 63 | 64 | 1\. 点击图示的按钮启动终端,(名字通常是 ROXTerm 之类的)。 65 | 66 | ![vbox3](http://brizanmedia.com/wp/wp-content/uploads/2016/07/vbox3-1024x640.jpg) 67 | 68 | 2\. 在终端中输入下面的命令,(或者也可以用向上的方向键来查看之前的输入历史,里面能找到,下同): 69 | 70 | ```Bash 71 | cd ~/Desktop/kivycode 72 | ``` 73 | 74 | 75 | 输入之后,按回车键。这样就让你进入到 `kivycode` 这个目录了。你必须进入这个目录,这样接下来的第 4 步才能成功。 76 | 77 | 3\. 在终端中输入下面的命令: 78 | ```Bash 79 | cp ~/Desktop/buildozer.spec ~Desktop/kivycode 80 | ``` 81 | 输入之后还是按回车键。这回把 buildozer.spec 文件复制到这个 `kivycode` 目录以供使用。当然你也可以在图形界面下来复制粘贴过来。 82 | 83 | 4\. 在终端中输入下面的命令: 84 | ```Bash 85 | buildozer android debug 86 | ``` 87 | 88 | 输入之后按回车咯。这一步是真正在创建 APK 文件。如果所有步骤都没问题,你的 APK 文件就会被生成放到桌面上。接下来就把 APK 文件安装到你的 Android 设备上面去试试吧! 89 | 90 | ![linux4Python4Android](http://brizanmedia.com/wp/wp-content/uploads/2016/07/linux4Python4Android-1024x640.jpg) 91 | 92 | 以上这样,你就创建了第一个 Android 安装包! 93 | 94 | ### 接下来开始用你的代码来创建! 95 | 96 | 你刚刚构建过一个 APK 了,不过这个 APK 并没有怎么充分利用这个虚拟机。而且代码还不是你自己的。所以咱们来试试你自己的代码。 97 | 98 | 首先咱们要让虚拟机能和外界交换文件。本文作者的选择是使用了一个外置硬盘。把外置硬盘插到机器(的宿主系统)中,然后把要变异的内容复制进去。接下来把 USB 设备从宿主机器移除,添加给虚拟机,这个操作反过来也可以,只需要在 VirtualBox 菜单栏中的 `Devices -> USB Devices` 中对选中的设备进行点击即可。 99 | 100 | 101 | ![vbox4](http://brizanmedia.com/wp/wp-content/uploads/2016/07/vbox4-1024x640.jpg) 102 | 103 | 磁盘就会出现在虚拟机系统中了: 104 | 105 | ![vbox5](http://brizanmedia.com/wp/wp-content/uploads/2016/07/vbox5-1024x640.jpg) 106 | 107 | 如果你没有外置磁盘,可以用浏览器来把文件传递到谷歌硬盘之类的云盘,然后虚拟机里面再下载。 108 | 109 | ![vbox8](http://brizanmedia.com/wp/wp-content/uploads/2016/07/vbox8-1024x640.jpg) 110 | 111 | 112 | VirtualBox 本来还是有一个共享文件夹功能的,可以让宿主机和虚拟机之间共用一个文件夹,不过本文作者没弄明白怎么搞定这个功能。如果有人能搞定这个请告诉**本文作者**怎么实现,非常感谢。(译者注:^_^,不用留言给中文版这里,是英文原版作者不会实现共享文件夹。) 113 | 114 | 现在文件能够拷入拷出了,就可以编译你自己的代码了。把你要编译的代码放到桌面上的 `kivycode` 这个目录。只要把这个文件夹里面的所有文件都用你的代码文件替换了,就可以打包你自己的应用了。视频之类的一些东西还需要额外打包设定,你还得使用 Kivy 框架,不过目前来看,Python 2.7 的代码都能打包成功没问题。 115 | 116 | ![vbox6](http://brizanmedia.com/wp/wp-content/uploads/2016/07/vbox6-1024x640.jpg) 117 | 118 | 编译你自己代码之前的最后一件事了,就是把 `buildozer.spec` 这个文件从桌面复制到 `kivycode` 文件夹,然后对副本进行必要的编辑。各种选项相关的信息可以参考 [Buildozer 的官方在线文档](https://buildozer.readthedocs.io/en/latest/specifications.html)。 119 | 120 | 比如你可能要修改加载图像 loading.png 以及图标文件 icon.png 等等,反正就那些了。接下来你就可以把你的 Python 代码构建成 Android 的 APK,然后从虚拟机的桌面找到这个 APK ,安装到你的 Android 设备上面来试试了。 121 | 122 | 好好玩吧! 123 | -------------------------------------------------------------------------------- /11-Kivy-Integration.md: -------------------------------------------------------------------------------- 1 | Title: Kivy Integration 2 | Date: 2017-02-23 3 | Category: Kivy 4 | Tags: Python,Kivy 5 | 6 | 7 | # Kivy中文编程指南:整合其他框架 8 | 9 | [英文原文](https://kivy.org/docs/guide/other-frameworks.html) 10 | 11 | 12 | 13 | 这是在 Kivy 1.0.8 版本以后添加的新功能。 14 | 15 | 16 | 17 | ## 在 Kivy 内使用 Twisted 18 | 19 | 20 | #### 特别注意 21 | 22 | 可以使用 kivy.support.install_twisted_reactor 这个函数来安装一个 twisted 反应器(reactor),这个反应器会在 Kivy 的事件循环内运行。 23 | 24 | 25 | 传递给此函数(kivy.support.install_twisted_reactor )的任何参数、关键字参数将在线程选择反应器交叉函数上传递(threadedselect reactors interleave function 这个我不懂是什么,强行翻译了,抱歉)。 这些参数通常是传递给twisted 的反应器启动函数(reactor.startRunning)的。 26 | 27 | 28 | #### 警告 29 | 30 | Kivy 这里面的这个 reactore 和默认的 twisted reactor 反应器不一样,只有当你把 ‘installSignalHandlers’ 关键词参数设置为 1 来才去处理信号。这样做是为了保证 Kivy 能够按照常规情况来处理信号,而当你指定让 twisted reactor 来处理信号的时候再换用 twisted。(比如 SIGINT 智能信号等情境。) 31 | 32 | 33 | Kivy 的样例代码中有一个例子,是一个简单的 twisted 服务端和客户端。服务端应用开启了一个 twisted 服务器,并对任何信息都进行日志记录。客户端的应用可以向服务端发送信息,然后接收服务端返回的信息并且输出显示。这些样例代码是基于 twisted 官方文档里面的简单的回声样例进行修改而实现的,原版代码可以在下面的地址中找到: 34 | 35 | 36 | * [简单的服务端代码](http://twistedmatrix.com/documents/current/_downloads/simpleserv.py) 37 | * [简单的客户端代码](http://twistedmatrix.com/documents/current/_downloads/simpleclient.py) 38 | 39 | 40 | 41 | 请按照如下步骤来尝试这个样例:先运行 echo_server_app.py, 然后运行 echo_client_app.py。在客户端的文本框中输入随便一些什么内容都可以,然后回车发送给服务端,服务端会把接收到的信息都原样返回,就像是回声一样。 42 | 43 | 44 | ### 服务端应用 45 | 46 | ```Python 47 | # install_twisted_rector must be called before importing and using the reactor 48 | # 一定要先要导入反应器,然后才能调用install_twisted_rector 49 | 50 | 51 | 52 | from kivy.support import install_twisted_reactor 53 | install_twisted_reactor() 54 | 55 | from twisted.internet import reactor 56 | from twisted.internet import protocol 57 | 58 | class EchoProtocol(protocol.Protocol): 59 | def dataReceived(self, data): 60 | response = self.factory.app.handle_message(data) 61 | if response: 62 | self.transport.write(response) 63 | 64 | class EchoFactory(protocol.Factory): 65 | protocol = EchoProtocol 66 | 67 | def __init__(self, app): 68 | self.app = app 69 | 70 | from kivy.app import App 71 | from kivy.uix.label import Label 72 | 73 | class TwistedServerApp(App): 74 | def build(self): 75 | self.label = Label(text="server started\n") 76 | reactor.listenTCP(8000, EchoFactory(self)) 77 | return self.label 78 | 79 | def handle_message(self, msg): 80 | self.label.text = "received: %s\n" % msg 81 | 82 | if msg == "ping": 83 | msg = "pong" 84 | if msg == "plop": 85 | msg = "kivy rocks" 86 | self.label.text += "responded: %s\n" % msg 87 | return msg 88 | 89 | if __name__ == '__main__': 90 | TwistedServerApp().run() 91 | ``` 92 | 93 | 94 | 95 | ### 客户端应用 96 | 97 | 98 | ```Python 99 | # install_twisted_rector must be called before importing the reactor 100 | # 一定要先要导入反应器,然后才能调用install_twisted_rector 101 | 102 | from kivy.support import install_twisted_reactor 103 | install_twisted_reactor() 104 | 105 | # A simple Client that send messages to the echo server 106 | # 这个简单的客户端是用来给回声服务器发送信息的 107 | 108 | from twisted.internet import reactor, protocol 109 | 110 | class EchoClient(protocol.Protocol): 111 | def connectionMade(self): 112 | self.factory.app.on_connection(self.transport) 113 | 114 | def dataReceived(self, data): 115 | self.factory.app.print_message(data) 116 | 117 | class EchoFactory(protocol.ClientFactory): 118 | protocol = EchoClient 119 | 120 | def __init__(self, app): 121 | self.app = app 122 | 123 | def clientConnectionLost(self, conn, reason): 124 | self.app.print_message("connection lost") 125 | 126 | def clientConnectionFailed(self, conn, reason): 127 | self.app.print_message("connection failed") 128 | 129 | from kivy.app import App 130 | from kivy.uix.label import Label 131 | from kivy.uix.textinput import TextInput 132 | from kivy.uix.boxlayout import BoxLayout 133 | 134 | # A simple kivy App, with a textbox to enter messages, and 135 | # a large label to display all the messages received from 136 | # the server 137 | # 这里的样例是一个很简单的 Kivy 应用,有一个字符输入框 textbox 来输入消息 138 | # 还有一个大的文本标签 label 来显示从服务器接收到的信息。 139 | 140 | 141 | 142 | class TwistedClientApp(App): 143 | connection = None 144 | 145 | def build(self): 146 | root = self.setup_gui() 147 | self.connect_to_server() 148 | return root 149 | 150 | def setup_gui(self): 151 | self.textbox = TextInput(size_hint_y=.1, multiline=False) 152 | self.textbox.bind(on_text_validate=self.send_message) 153 | self.label = Label(text='connecting...\n') 154 | self.layout = BoxLayout(orientation='vertical') 155 | self.layout.add_widget(self.label) 156 | self.layout.add_widget(self.textbox) 157 | return self.layout 158 | 159 | def connect_to_server(self): 160 | reactor.connectTCP('localhost', 8000, EchoFactory(self)) 161 | 162 | def on_connection(self, connection): 163 | self.print_message("connected successfully!") 164 | self.connection = connection 165 | 166 | def send_message(self, *args): 167 | msg = self.textbox.text 168 | if msg and self.connection: 169 | self.connection.write(str(self.textbox.text)) 170 | self.textbox.text = "" 171 | 172 | def print_message(self, msg): 173 | self.label.text += msg + "\n" 174 | 175 | if __name__ == '__main__': 176 | TwistedClientApp().run() 177 | ``` 178 | -------------------------------------------------------------------------------- /15-Kivy-Pack-Android.md: -------------------------------------------------------------------------------- 1 | Title: Kivy Pack Android 2 | Date: 2017-03-06 3 | Category: Kivy 4 | Tags: Python,Kivy 5 | 6 | # Kivy中文编程指南:打包为 Android 系统可执行文件 7 | 8 | [英文原文](https://kivy.org/docs/guide/packaging-android.html) 9 | 10 | 11 | 你可以通过 [python-for-android](https://github.com/kivy/python-for-android) 这个项目来打包一个 Android 应用。本页面详细讲解如何下载和打包,可以在你自己的机器上直接进行(参考[此页面](https://kivy.org/docs/guide/packaging-android.html#packaging-your-application-into-apk)),或者使用预先构建好的[Kivy Android 虚拟机](https://kivy.org/docs/guide/packaging-android-vm.html#kivy-android-vm),或者使用[Buildozer](https://kivy.org/docs/guide/packaging-android.html#buildozer) 来自动化完成整个过程。还可以参考 [针对 Kivy Launcher 进行打包](https://kivy.org/docs/guide/packaging-android.html#packaging-your-application-for-kivy-launcher) 这样就不用编译就能运行 Kivy 应用。 12 | 13 | 对新手,Kivy 官方推荐使用 [Buildozer](https://kivy.org/docs/guide/packaging-android.html#buildozer) ,这是制作完整 APK 的最简单的途径。或者也可以使用 [Kivy Launcher](https://kivy.org/docs/guide/packaging-android.html#packaging-your-application-for-kivy-launcher) 这个应用来运行你的 Kivy 应用,而不用编译了。 14 | 15 | Kivy 应用可以[发布到 Android 应用市场](https://kivy.org/docs/guide/packaging-android.html#release-on-the-market),比如谷歌的 Play 市场等等,只需要额外几步来创建一个完整签名的 APK 就可以了。 16 | 17 | Kivy 项目包含了一系列读取 Android API 的工具,可以实现震动、传感器读取、信息发送等等功能。相关的详细信息都可以参考[ Kivy 的 Android 专题页面](https://kivy.org/docs/guide/android.html)。 18 | 19 | #### 特别注意 20 | 21 | Android 平台目前已经支持 Python 3 了,不过还处于实验阶段。 22 | 23 | 24 | 25 | ## Buildozer[¶](https://kivy.org/docs/guide/packaging-android.html#buildozer "Permalink to this headline") 26 | 27 | Buildozer 是一个将整个构建过程自动化的工具。它会下载和设置 python-for-android 需要的所有依赖项目,包括 Android 的 SDK 和 NDK,然后会构建 APK ,这个 APK 可以自动推送到设备上。 28 | 29 | 目前 Buildozer 只能用在 Linux 上面,而且还不是正式版,处于测试阶段,发布的是 alpha 版本,不过目前用起来还不错,能显著简化 APK 构建的过程。 30 | 31 | 可以到[ Buildozer 的项目页面](https://github.com/kivy/buildozer) 下载获取 Buildozer。 32 | 33 | ```Bash 34 | git clone https://github.com/kivy/buildozer.git 35 | cd buildozer 36 | sudo python2.7 setup.py install 37 | ``` 38 | 39 | 上面的命令就会把 Buildozer 安装到你的操作系统中。接下来就是到你的项目目录然后运行如下命令: 40 | 41 | ```Bash 42 | buildozer init 43 | ``` 44 | 45 | 这会在你的目录下创建一个名为 buildozer.spec 的文件,这个文件是控制项目构建选项的。估计你需要编辑修改一下这个文件,比如设置你应用的名字等等。在这里可以设置传递给 python-for-android 的全部或者大部分参数。 46 | 47 | 安装[ Buildozer 的依赖项目](https://buildozer.readthedocs.io/en/latest/installation.html#targeting-android)。 48 | 49 | 最后一步了,连接上你的 Android 设备然后运行下面的命令: 50 | 51 | ```Bash 52 | buildozer android debug deploy run 53 | ``` 54 | 55 | 这样就可以创建、推送 APK 到你的设备上,然后就可以自动运行了。 56 | 57 | Buildozer 有很多可以控制的选项和工具,对你都会游泳,上面这些步骤只是创建 APK 的最简单的方法。可以到[ Buildozer 的官方文档页面](http://buildozer.readthedocs.org/en/latest/)查看完整说明。也可以看看[ Buildozer 项目页面](https://github.com/kivy/buildozer)的 README 文件。 58 | 59 | ## 通过 python-for-android 打包[¶](https://kivy.org/docs/guide/packaging-android.html#packaging-with-python-for-android "Permalink to this headline") 60 | 61 | 你还可以直接用 python-for-android 来打包应用,这样你可以有更多控制选项,但需要手动下载和设置 Android 工具链。 62 | 63 | 参考[python-for-android 官方文档](https://python-for-android.readthedocs.io/en/latest/quickstart/) 查看全部细节。 64 | 65 | 66 | ## 针对 Kivy Launcher 打包[¶](https://kivy.org/docs/guide/packaging-android.html#packaging-your-application-for-the-kivy-launcher "Permalink to this headline") 67 | 68 | [Kivy launcher](https://play.google.com/store/apps/details?id=org.kivy.pygame&hl=en) 是一个 Android 应用,可以运行存储到 SD 卡里面的 Kivy 样例。可以用下面的方法来安装 Kivy launcher: 69 | 70 | 1. 前往[谷歌 Play 市场中的 Kivy Launcher 页面](https://market.android.com/details?id=org.kivy.pygame); 71 | 2. 点击安装; 72 | 3. 选择你的设备,然后就搞定了。 73 | 74 | 如果你的设备无法访问谷歌 Play 市场(我大天朝么。。。),可以从[ Kivy 官网的下载页面](http://kivy.org/#download) 手动下载安装 APK 文件。 75 | 76 | 安装了 Kivy launcher 之后,就可以把你的 Kivy 应用放到外置存储的 Kivy 文件夹中,(通常是在 `/sdcard` 目录下),例如: 77 | 78 | ```Bash 79 | /sdcard/kivy/yourapplication> 80 | ``` 81 | 82 | `<yourapplication>`你的应用应该是一个**文件夹**,包含以下文件: 83 | 84 | ```Bash 85 | # 程序主文件: 86 | main.py 87 | # Kivy 需要的关于你应用的信息: 88 | android.txt 89 | ``` 90 | 以下信息是 android.txt 这个文件**必须包含**的: 91 | 92 | ```Bash 93 | title=<Application Title> #这是应用的标题 94 | author=<Your Name> #这是作者签名 95 | orientation=<portrait|landscape> #设定屏幕方向为水平或竖直 96 | ``` 97 | 98 | 上面这些都是非常基础的设置。如果你要用上面的工具来构建自己的 APK,还得调整很多其他的设定。 99 | 100 | 101 | ### 安装样例项目[¶](https://kivy.org/docs/guide/packaging-android.html#installation-of-examples "Permalink to this headline") 102 | 103 | Kivy 自带了很多歌样例,可以先用这些来试一试 Kivy Launcher。可以用如下的方法来运行: 104 | 105 | 106 | 1. 下载 [`Kivy demos for Android`](https://storage.googleapis.com/google-code-archive-downloads/v2/code.google.com/kivy/kivydemo-for-android.zip) 107 | 2. 解压缩然后进入目录`kivydemo-for-android` 108 | 3. 把目录内所有子目录等内容复制到 `/sdcard/kivy` 这个目录 109 | 4. 运行 Kivy Launcher 然后从样例中选择一个来试试,Pictures, Showcase, Touchtracer, Cymunk 等等都可以。 110 | 111 | 112 | ## 发布到应用市场[¶](https://kivy.org/docs/guide/packaging-android.html#release-on-the-market "Permalink to this headline") 113 | 114 | 如果你用 Buildozer 或者 python-for-android 构建了 APK 文件,就可以创建一个 release 版本来发布到谷歌 Play 市场或者其他 Android 应用市场。 115 | 116 | 要想发布,就必须在运行 Buildozer 的时候添加上 `release` 参数,例如 `buildozer android release`,如果用了 python-for-android 就在 build.py 进行编译的时候加上`--release`。 117 | 118 | 这样就能在 `bin` 目录里面创建一个正式发布的 release 版的 APK 文件,需要你做好签名和 zipalign 压缩优化(译者注:zipalign,优化apk应用程序的工具,使包内未压缩的数据能够有序的排列)。 119 | 120 | 上面这些操作的详细过程可以参考 [Android 官方文档](https://developer.android.com/studio/publish/app-signing.html#signing-manually) ,所有用到的工具都在 Android SDK 里面了。 121 | 122 | 123 | ## 设定 Android [¶](https://kivy.org/docs/guide/packaging-android.html#targeting-android "Permalink to this headline") 124 | 125 | Kivy 的设计定位是提供跨平台的相同操作体验,因此也有一些清晰地设计特点。Kivy 包含了自己独有的一套控件,在默认情况下,用所有需要的依赖包和链接库来构建 APK 文件。 126 | 127 | 也可以指定特定的 Android 功能,可以直接进行,也可以用(某些)跨平台的方式来实现。更多细节可以参考[ Kivy 的 Android 专题页面](https://kivy.org/docs/guide/android.html) 中关于使用 Android API 的部分。 128 | -------------------------------------------------------------------------------- /05-Kivy-Architecture.md: -------------------------------------------------------------------------------- 1 | Title: Kivy Architecture 2 | Date: 2017-02-7 3 | Category: Kivy 4 | Tags: Python,Kivy 5 | 6 | 7 | # Kivy中文编程指南:架构概览 8 | 9 | 10 | [英文原文](https://kivy.org/docs/guide/architecture.html) 11 | 12 | 13 | 本章我们将从软件工程的角度,来简单介绍一下Kivy的设计。这对于理解各个部分如何配合工作会有帮助。如果你只关注代码,可能有时候会遇到这样一种情况,就是你已经有了一个初步的想法了,但具体怎么去实现可能还是一头雾水,所以本章就针对这种情况,来更深入地讲解一下Kivy的一些基本思想。你也可以先跳过这一章,等以后再翻回来看,不过我们建议开发者还是先看一下这些内容比较好,起码可以快速略读一下有个印象。 14 | 15 | 16 | Kivy包含的若干个模块,我们将对这些模块一一进行简要说明。下面这幅图是Kivy整个架构的概括图示: 17 | 18 | ![../_images/architecture.png](http://kivy.org/docs/_images/architecture.png) 19 | 20 | 21 | 22 | ## 核心模块和输入模块 23 | 24 | 25 | 对理解Kivy的设计内涵,模块化和抽象化的思想是至关重要的。我们试图把各种基本的任务进行抽象,比如打开窗口、显示图像和文本、播放音频、从摄像头获取图像、拼写校正等等。我们将这些部分称为**核心**任务。这样也使得API接口用起来比较简单,扩展起来也容易。更重要的是,这种思路可以让Kivy应用在运行的时候,使用各个运行平台所提供的对应功能的API接口。例如,在苹果的MacOS操作系统、Linux操作系统和Windows操作系统中,就都有各自不同的原生API接口提供各种核心功能。所以就有一部分代码,调用这些不同接口中的某一个,一方面与操作系统进行通信,另一方面与Kivy进行交互,起到中间人的角色,我们称之为**核心模块**。针对不同的操作系统平台要使用各自对应的核心模块,这样的好处是达到一种均衡状态,既能够充分利用操作系统提供的功能,又能尽量提高开发效率。(译者注:我的理解是这样大家平时不用针对不同操作系统去学习和使用各自的API,而只要专心使用Kivy的核心模块进行调用就行了。)这也允许用户来自由选择,使用Kivy提供的核心模块,或者直接使用各个操作系统的API接口。此外,由于使用了各个平台所提供的链接库文件,我们大大减小了Kivy发型版本的体积,也使得打包发布更加容易。这有助于将Kivy应用移植到其他平台。比如Android平台上的Kivy应用就体现了这一特性的好处了。 26 | 27 | 28 | 在输入模块这部分,我们也遵循了同样的思路。**输入模块**,是一段代码,用于针对各种输入设备提供支持,比如苹果公司的Trackpad触摸板,TUIO多点触摸设备,或者是鼠标模拟器等等。如果你需要对某一种新的输入设备添加支持,只需要提供一个新的类,用这个类来读取输入设备的数据,然后传递给Kivy基本事件,就可以了。 29 | 30 | 31 | 32 | 33 | ## 图形接口 34 | 35 | Kivy的图形接口是对OpenGL的抽象。在最底层,Kivy使用OpenGL的命令来进行硬件加速的图形绘制。不过写OpenGL的代码可还是挺复杂的,新手就更难以迅速掌握了。所以我们就提供了一系列的图形接口,利用这些接口可以很简单地进行图形绘制,这些接口中用到了例如画布Canvas、矩形Rectangle等几何概念,比OpenGL里面简单不少。 36 | 37 | Kivy自带的所有控件,都使用了这个图形接口;出于性能的考虑,此图形接口是用C语言来实现的。 38 | 39 | 这个图形接口的另一个好处是可以对你代码中的绘图指令进行自动优化。这个很有用,尤其是在你对OpenGL的优化不太熟悉的情况下。这能让你的绘图代码更高效。 40 | 41 | 当然了,你也可以坚持使用原生的OpenGL命令。目前Kivy在所有操作系统平台上用的都是是OpenGL 2.0 ES (GLES2),所以如果你希望保持跨平台的兼容性,我们建议你只是用GLES2兼容的函数。 42 | 43 | 44 | ## 核心模块 45 | 46 | 47 | 核心模块也就是kivy.core,这个包里面提供了常用的各种功能,比如: 48 | 49 | 50 | * Clock 51 | 52 | 时钟类,可以用于安排计时器事件。同时支持一次性计时和周期性计时。 53 | 54 | * Cache 55 | 56 | If you need to cache something that you use often, you can use our class for that instead of writing your own. 57 | 58 | 缓存类,如果有一些经常用到的数据需要缓存,就可以用这个类,而不用自己写了。 59 | 60 | * Gesture Detection 61 | 62 | 手势识别,这个可以用来识别各种划动行为,比如画个圆圈或者方块之类的。可以训练来识别你自己设计的图形。 63 | 64 | * Kivy Language 65 | 66 | Kivy语言,这个是用来简洁高效地描述Kivy应用的用户界面的。 67 | 68 | * Properties 69 | 70 | 这里这些属性和Python语言中的属性不同。这里是我们专门写的一些类,通过用户界面描述来连接控件代码。 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | ## UIX(控件和布局) 79 | 80 | UIX用户界面模块,包含了常用的各种控件和布局,可以通过复用来快速构建用户界面。 81 | 82 | 83 | 84 | 85 | * Widgets 控件 86 | 87 | 控件是各种用户界面元素,可以添加到程序中来提供各种功能。有的可见,有的不可见。文件浏览器,按钮、滑动页、列表等等,这都属于控件。控件接收动作事件。 88 | 89 | 90 | * Layouts 布局 91 | 92 | 布局是控件的排列方式。当然,你也可以自己自定义控件的位置,不过从我们提供的预设布局中选择一个来使用,会更方便很多。网格布局、箱式布局等等,都是布局了。你还可以试试复杂的多层网状布局。 93 | 94 | 95 | 96 | ## 模块化 97 | 98 | 如果你用某一种现代的网络浏览器,并且通过一些附加组件对其进行定制,那么你应该就理解了我们提供的各种模块类的基本思想了。各种模块可以用来向Kivy程序中添加功能,即便原作者没有提供的功能也可以加进去了。 99 | 100 | 例如,有一个模块就能显示当前应用的FPS(Frame Per Second,每秒帧数,即帧率),然后还能统计一段时间的FPS变化。 101 | 102 | 你可以自己写各种模块添加到应用中。 103 | 104 | 105 | 106 | 107 | 108 | ## 输入事件(Touches) 109 | 110 | Kivy抽象了各种输入类型和输入设备,比如触控,鼠标按键,多点触摸等等。这些输入类型有一个共同点,就是都可以把各种输入事件映射成屏幕上对应的一种2D形态。(当然了,还有的输入设备就没法用2D形态来表示,比如通过加速度传感器来衡量设备倾斜角度等。这种情况就得另外考虑了。下面我们讨论的只是那些能用2D形态表示的输入事件,复杂的类型以后再说。) 111 | 112 | 113 | 这些输入类型,在Kivy中都用Touch()类的实例来表示。(请注意,这里可不仅仅是针对手指去触摸的那种touch,而是所有可以这样抽象表示的输入事件。这里用**Touch**只是为了方便而这么简称一下。就想象一下,这些**Touches**就是在用户界面或者显示屏上面的那些个**点击行为**。 )Touch的实例或者对象,有三种状态。当这个Touch进入了其中的某一个状态,你的程序就会被告知此事件的发生。Touch的三种状态如下: 114 | 115 | 116 | 117 | 118 | * Down 落下 119 | 120 | 处于落下状态,只能有一次,就是在发生Touch事件的初始时刻。 121 | 122 | 123 | 124 | * Move 移动 125 | 126 | 这个状态的时间无上限。在一个Touch的生命周期中可以没有这个状态。移动状态只发生在Touch的2D平面位置发生变化的情况下。 127 | 128 | * Up 抬起 129 | 130 | A touch goes up at most once, or never. In practice you will almost always receive an up event because nobody is going to hold a finger on the screen for all eternity, but it is not guaranteed. If you know the input sources your users will be using, you will know whether or not you can rely on this state being entered. 131 | 132 | 一个Touch要么只能抬起一次,要么就不发生。而实际应用中你会经常遇到Up时间,因为没有人会一直把手指按到屏幕上,不过也有未必就绝对不会有这种情况。若事先知道用户用的输入设备,就可以确定能否完全依靠用户的输入状态。 133 | 134 | (译者注:以手指触摸屏幕为例,只有开始接触的时候是Down手指落下这个状态,之后移动就是接下来的Move移动状态,手指抬起来的时候就是Up即抬起状态了;如果以鼠标左键点击为例,按下去左键的时候是Down,按住左键不放进行拖动就是Move,松开左键就是Up了。这段我特别解释一下,因为自己翻译的太生硬了。) 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | ## 控件和事件调度 143 | 144 | 145 | 在图形化的软件开发语境下,**控件**这个词经常出现,一般是来描述程序中用于和用户进行交互的组件。在Kivy中,控件是用来接收各种输入事件的。所以并不一定非要在屏幕上能看得到。Kivy当中所有控件都以**控件树**的形式来管理,学过计算机科学中数据结构相关知识的话,就会意识到这是一种树形结构:一个控件可以有任意多个子控件,也可以没有子控件。**根控件**就只能有一个,处于树形结构的顶端,根控件不具有父控件,并且所有其他控件都是根控件的直接或者间接子控件(就像树根一样,所以叫根控件)。 146 | 147 | 148 | 149 | 150 | 当新的输入数据可用的时候,Kivy会针对每一个Touch发出一个事件。控件树种的根控件首先接收到这个事件。Touch的不同状态,on_touch_down, on_touch_move和on_touch_up (Down落下、Move移动和Up),会作为Touch的参数,提供给根控件,根控件会调用对应的事件Handler来作出反应。 151 | 152 | 153 | 154 | 包括根控件在内,控件树种的每个控件都可以有两种选择,处理该事件,或者将该事件传递下去。如果一个事件的Handler返回True,就意味着这个事件已经被接收并妥善处理。这个事件就也到此为止了。如果不是这样,事件的Handler会跳过此处的空间,调用父类中的对应事件的Handler实现,传递给该控件的子控件。这样的过程可以一路走到最基础的控件类Widget,在它的Touch事件Handler中,只是把Touch传递给子控件,而不进行其他的操作。 155 | 156 | 157 | ```Python 158 | # This is analogous for move/up: 159 | def on_touch_down(self, touch): 160 | for child in self.children[:]: 161 | if child.dispatch('on_touch_down', touch): 162 | return True 163 | ``` 164 | 165 | 166 | 说起来挺麻烦,看上去挺复杂,实际上要简单得多。下一章就会讲解如何使用这种特性来快速创建应用了。 167 | 168 | 169 | 经常有一种情况,就是你可能要让一个控件只在屏幕上某个特定的**区域**来监听Touch事件。这时候就可以使用控件的collide_point()方法来实现此目的。只需要把Touch的位置发给该方法,然后如果此位置位于**监听区域**则返回True,反之返回False。默认情况下,这个方法会监听屏幕上的一个矩形区域,根据控件的中心坐标(x & y坐标系),以及空间尺寸(宽度和高度),不过你也可以用自己的类覆盖掉这一行为。 170 | 171 | 172 | -------------------------------------------------------------------------------- /14-Kivy-Android.md: -------------------------------------------------------------------------------- 1 | Title: Kivy Android 2 | Date: 2017-03-07 3 | Category: Kivy 4 | Tags: Python,Kivy 5 | 6 | 7 | # Kivy中文编程指南:KV Android 详细指南 8 | 9 | 10 | [英文原文](https://kivy.org/docs/guide/android.html) 11 | 12 | 在 Android 设备上,只要是支持 OpenGL ES 2.0 (至少为 Android 2.2 以及其后的版本),就基本都能运行 Kivy 应用程序。OpenGL ES 2.0 基本上是现代设备的标准了;根据谷歌的报道说,至少有 [99.9% 的设备都是支持的](https://developer.android.com/about/dashboards/index.html)。 13 | 14 | Kivy 的 APK 就是常规的 Android APP,和其他的 APP 一样可以四处发布,比如谷歌 Play 商店等等。在暂停或者重启的时候这些应用的行为也都很正常,下面要介绍道的是 Kivy APP 用到的 Android 服务和需要用到的大多数常规的 Java API。 15 | 16 | 下面的内容依次讲解了如何 [针对 Android 平台打包 APP](https://kivy.org/docs/guide/android.html#package-for-android), [在设备上调试 APP](https://kivy.org/docs/guide/android.html#debug-android),以及使用震动或者读取传感器等等 [Android API](https://kivy.org/docs/guide/android.html#using-android-apis)。 17 | 18 | 19 | 20 | 21 | ## 针对 Android 平台打包 APP[¶](https://kivy.org/docs/guide/android.html#package-for-android "Permalink to this headline") 22 | 23 | Kivy 项目提供了针对 Android 平台打包 APP 所需的全部必备工具,可以构建单个的 APK 文件发布到谷歌 Play 市场之类的应用商店。详细内容可以参考[针对 Android 打包应用程序的英文原版文档](https://kivy.org/docs/guide/packaging-android.html#packaging-android)或者中文翻译版本:[个人博客地址](http://blog.cycleuser.org/kivy-pack-android.html),[知乎专栏地址](https://zhuanlan.zhihu.com/p/25571974)。 24 | 25 | 26 | ## 在 Android 设备上调试 APP[¶](https://kivy.org/docs/guide/android.html#debugging-your-application-on-the-android-platform "Permalink to this headline") 27 | 28 | 通过 Android Logcat 流,可以观察代码的常规输出(比如 stdout,stderr),也可以查看常规的 Kivy 日志。这需要使用 adb 来查看,adb 包含在 [Android SDK](http://developer.android.com/sdk/index.html) 内。这首先就要求你再设备上开启**开发者模式**,然后启用 USB 调试功能来启用 adb,接着把设备连接到计算机,在终端中运行下面的命令: 29 | 30 | 31 | ```Bash 32 | adb logcat 33 | ``` 34 | 35 | 这样就能看到日志输出了,包括标准输出和出错信息( stdout/stderr )以及 Kivy 的日志。 36 | 37 | 如果你用 Buildozer 打包的 APP,那么有可能 adb 工具没有包含在你的 `$PATH` 环境变量中,这样上面的命令就可能没有效果。这时候可以用下面的方法: 38 | 39 | 40 | ```Bash 41 | buildozer android logcat 42 | ``` 43 | 44 | 上面这样就是运行了 Buildozer 伴随安装的 adb 工具,或者还可以去`$HOME/.buildozer/android/platform` 这个目录找到 Buildozer 伴随安装的 SDK。 45 | 46 | 或者还可以下载[Kivy Launcher](https://play.google.com/store/apps/details?id=org.kivy.pygame&hl=en)来运行和调试应用程序。如果用这种方法运行 Kivy 应用程序,可以在你的应用程序所在目录下找到一个名字为 `/.kivy/logs` 的子目录,里面就是日志文件。 47 | 48 | 49 | 50 | ## 使用 Android API[¶](https://kivy.org/docs/guide/android.html#using-android-apis "Permalink to this headline") 51 | 52 | 虽然 Kivy 是一个 Python 框架,Kivy 项目也还维护了一套用来调用常规 Java API 的工具,可以用来处理震动、传感器、发送短信或邮件等等。 53 | 54 | 对新用户来说,推荐阅读 [Plyer](https://kivy.org/docs/guide/android.html#plyer)。要想有更深入的使用或者调用一些目前没有封装的 API,可以直接使用 [Pyjnius](https://kivy.org/docs/guide/android.html#pyjnius)。Kivy 还内置了一个 [Android 模块](https://kivy.org/docs/guide/android.html#android-module) 来实现 Android 的一些基础功能。 55 | 56 | 在 [Kivy wiki](https://github.com/kivy/kivy/wiki#mobiles) 上可以找到用户提供的 Android 代码和样例。 57 | 58 | ### Plyer[¶](https://kivy.org/docs/guide/android.html#plyer "Permalink to this headline") 59 | 60 | [Plyer](https://github.com/kivy/plyer) 是一个 Python 风格的,独立于平台的 API,用于使用各种平台上都普遍具有的功能,尤其是移动平台。其设计思路是你的应用可以简单地调用一个 Plyer 函数,例如给用户一个消息通知,然后 Ply会处理在不同的平台或者操作系统下分别如何把这件事完成。在 Plyer 的内部,在 Android 平台使用的是 Pyjnius,在 iOS 平台使用了 Pyobjus,在桌面平台又用了其他的特定 API。 61 | 62 | 例如,下面的代码就会让你的 Android 设备震动,或者当你在其他平台不恰当地使用的时候就会跑出一个 NotImplementError,例如在桌面平台等没有对应硬件的情况下: 63 | 64 | ```Python 65 | from plyer import vibrator 66 | vibrator.vibrate(10) # vibrate for 10 seconds 67 | ``` 68 | 69 | Plyer 支持的 API 越来越多了,可以在 [ Plyer GitHub 页面的 README 文件](https://github.com/kivy/plyer)中查看完整的支持列表。 70 | 71 | ### Pyjnius[¶](https://kivy.org/docs/guide/android.html#pyjnius "Permalink to this headline") 72 | 73 | Pyjnius 是一个 Python 模块,它允许你直接在 Python 中读取 Java 类,自动转换参数成正确的类型,还允许你把 Java 的运行结果转换给 Python。 74 | 75 | Pyjnius 可以从 [它的 GitHub 地址](https://github.com/kivy/pyjnius)下载获得,并且有一份[详细的文档](http://pyjnius.readthedocs.org/en/latest/)。 76 | 77 | 下面的代码是一个简单的小例子,展示了如何使用 Pyjnius 来读取常规的 Android 震动 API,就跟上面 Plyer 的代码效果一样: 78 | 79 | ```Python 80 | # 'autoclass' 接收一个Java 类,然后打包给 Python; 81 | from jnius import autoclass 82 | 83 | # Context 是 Android API 中一个常用的 Java 类; 84 | Context = autoclass('android.content.Context') 85 | 86 | # PythonActivity 是在 python-for-android 内由 Kivy bootstrap app 提供的一个类; 87 | PythonActivity = autoclass('org.renpy.android.PythonActivity') 88 | 89 | # 这里的 PythonActivity 存储了一个指向当前运行的 Activity 的引用; 90 | # 我们要用它来读取 震动服务 91 | activity = PythonActivity.mActivity 92 | 93 | # 底下的这个振动器代码和 Java 里面基本一样的; 94 | vibrator = activity.getSystemService(Context.VIBRATOR_SERVICE) 95 | 96 | vibrator.vibrate(10000) # 这个值是毫秒为单位,这里设置的 10 000 毫秒相当于 10 秒。 97 | ``` 98 | 99 | 上面的代码直接用了 Java API 函数来调用了振动器,Pyjnius 自动把 API 转换出给了 Python 代码使用,而又把我们的调用都回传给了 Java。相比 Plyer 的实现,这种方法更繁琐一些,也更像 Java 的风格,在这个例子中没有什么优势。不过 Plyer 也并没有对 Pyjnius 的所有 API 都进行了封装。 100 | 101 | Pyjnius 还有一个强大的功能就是实现 Java 接口,这在封装某些 API 的时候非常重要,不过这里就不详细讲这么多了,有兴趣的话去[ Pyjnius 的官方文档](http://pyjnius.readthedocs.org/en/latest/)来了解更深层次内容吧。 102 | 103 | 104 | ### Android 模块[¶](https://kivy.org/docs/guide/android.html#android-module "Permalink to this headline") 105 | 106 | Python-for-android 项目中包含了一个 Python 模块(实际上是用 cython 封装的 Java)来读取一系列有限的 Android API。这个很大程度上已经被上面的 Pyjnius 和 Pyler 取代了,因为后者更加灵活方便,不过有时候可能这个模块还有些用处。所有可用的文档都可以在 [python-for-android 官方文档](http://python-for-android.readthedocs.org/en/latest/)中查阅到。 107 | 108 | 这其中就包括了计费/应用内购买的代码,以及创建或者读取某些 Android 服务的代码,其他工具目前还没能提供这方面的功能。 109 | 110 | 111 | ## 项目状态以及通过测试的设备[¶](https://kivy.org/docs/guide/android.html#status-of-the-project-and-tested-devices "Permalink to this headline") 112 | 113 | 前面的章节讲述了 Kivy 在 Android 系统的构建工具,以及他们各自的缺陷还有就是已知能够使用的设备。 114 | 115 | Android 工具链现在挺稳定的,一定程度上基本能适用于各种设备了;Kivy 的最低要求是 OpenGL ES 2.0 以及 Android 2.2。这现在绝对是覆盖面很广泛了— Kivy 已经都可以在 Android 智能手表上面运行了。 116 | 117 | 当前在技术上存在的一个限制就是 Android 构建工具只能生成 ARM 平台的 APK 文件,这些文件不能运行于 X86 处理器的 Android 设备上,好在目前 这类 X86 的 Android 设备还不是主流。不过对 X86 处理器的 Android 设备的支持是后续要添加的。 118 | 119 | 因为目前 Kivy 基本上能在绝大多数 Android 设备上面良好运行了,所以之前的那个设备支持列表就关荣退休了—只要满足上面的要求的 Android 设备,基本就都能够使用。 120 | 121 | -------------------------------------------------------------------------------- /20-Kivy-Garden FileBrowser Problem.md: -------------------------------------------------------------------------------- 1 | Title: Kivy-Desinger on Mac ImportError: No module named filebrowser 2 | Date: 2016-12-31 3 | Category: Kivy 4 | Tags: Python,Mac,Kivy 5 | 6 | 7 | 8 | ##解决Mac系统上Kivy-Desinger因Garden安装位置不匹配导致的filebrowser无法导入的问题 9 | 10 | 11 | 根据官方文档,首先要 12 | 13 | 14 | ```Bash 15 | kivy -m pip install -U watchdog pygments docutils jedi gitpython six kivy-garden 16 | ``` 17 | 18 | 19 | 20 | 然后 21 | ```Bash 22 | garden install filebrowser 23 | ``` 24 | 25 | 26 | 然后你以为一切都很好,尝试运行Kivy-Designer,你会遇到类似下面的错误提示: 27 | 28 | ```Bash 29 | [WARNING ] stderr: from designer.app import DesignerApp 30 | [WARNING ] stderr: File "/Users/cycleuser/kivy-designer/designer/app.py", line 27, in <module> 31 | [WARNING ] stderr: from kivy.garden.filebrowser import FileBrowser 32 | [WARNING ] stderr: ImportError: No module named filebrowser 33 | ``` 34 | 35 | 36 | 37 | 这是因为,garden在Mac OS X下安装的位置是Linux下的 ~/.kivy/garden 目录下,而在Mac OS X下这个位置是无效的,必须要手动复制到 /Applications/Kivy.app/Contents/Resources/.kivy/garden 目录下。 38 | 39 | 读到这里你应该就能解决问题了,仔细阅读官方文档,虽然在garden安装位置这个bug上并没什么用。 40 | 41 | 42 | 43 | 44 | 45 | _____ 46 | 47 | 下面的内容是我在去年时候无脑尝试的记录,仅仅作为教训有参考意义而已,不要像我一样蠢。 48 | 分割线下面的内容就不用看了,没什么意义~ 49 | 50 | 51 | _____ 52 | 53 | At first, I ran the commands below to install Kivy on my Mac: 54 | >最开始是安装依赖包,我用的是 brew,官方这么推荐就这么用了哈: 55 | 56 | ```Bash 57 | brew install sdl2 sdl2_image sdl2_ttf sdl2_mixer gstreamer 58 | pip install -I Cython==0.21.2 59 | USE_OSX_FRAMEWORKS=0 pip install git+https://github.com/kivy/kivy.git@1.9.0 60 | ``` 61 | After that, I download the Kivy dmg from the official website. 62 | >然后呢,就去官网下载最新的那个 kivy 的 dmg,这个是用来在 Mac 上面建立一个 Kivy 官方给打包好的 Python 虚拟环境,就不用自己折腾了。最下面哪句点击 MakeSymlinks 就是用来建立系统映射的一个脚本,到时候在终端直接输入 kivy 就是运行的 kivy.app 内部的一个 Python2.7了,而不用自己折腾配置了。你看这一句英文我翻译解释出这么多,是因为我觉得身边的小白蛮多,解释清楚点比较好。 63 | >(虽然英文版的也是我写的,但我懒得写的那么细,网上英语资料很多,就让他们自己搜去吧。。。) 64 | 65 | ``` 66 | Download the latest version from http://kivy.org/#download 67 | Double-click to open it 68 | Drag the Kivy.app into your Applications folder 69 | Double click the makesymlinks script. 70 | ``` 71 | 72 | Then I used git to download the kivy-designer. 73 | I thought it would work. 74 | So I typed in the command below following the official guide with hope: 75 | >接着就用 git 下载来 kivy-designer。 76 | >满心开心希望能用了。 77 | >所以就根据官方指南输入下面的命令,满眼星星的期待呢: 78 | 79 | ```Bash 80 | kivy main.py 81 | ``` 82 | But I got this error: 83 | >尼玛给老子来了个错误: 84 | 85 | ```Bash 86 | [WARNING ] stderr: ImportError: No module named filebrowser 87 | ``` 88 | 89 | Details here: 90 | >细节是这样的: 91 | 92 | ```Bash 93 | [INFO ] Logger: Record log in /Applications/Kivy.app/Contents/Resources/.kivy/logs/kivy_15-12-29_18.txt 94 | [INFO ] Kivy: v1.9.0 95 | [INFO ] Python: v2.7.10 (default, Jul 14 2015, 19:46:27) 96 | [GCC 4.2.1 Compatible Apple LLVM 6.0 (clang-600.0.39)] 97 | [INFO ] Image: Providers: img_tex, img_imageio, img_dds, img_gif, img_sdl2 (img_pil, img_ffpyplayer ignored) 98 | [INFO ] Factory: 173 symbols loaded 99 | [INFO ] Text: Provider: sdl2 100 | [INFO ] OSC: using <multiprocessing> for socket 101 | [INFO ] Window: Provider: sdl2 102 | [INFO ] GL: OpenGL version <2.1 INTEL-10.6.33> 103 | [INFO ] GL: OpenGL vendor <Intel Inc.> 104 | [INFO ] GL: OpenGL renderer <Intel HD Graphics 4000 OpenGL Engine> 105 | [INFO ] GL: OpenGL parsed version: 2, 1 106 | [INFO ] GL: Shading version <1.20> 107 | [INFO ] GL: Texture max size <16384> 108 | [INFO ] GL: Texture max units <16> 109 | [INFO ] Window: auto add sdl2 input provider 110 | [INFO ] Window: virtual keyboard not allowed, single mode, not docked 111 | [WARNING ] stderr: Traceback (most recent call last): 112 | [WARNING ] stderr: File "main.py", line 2, in <module> 113 | [WARNING ] stderr: from designer.app import DesignerApp 114 | [WARNING ] stderr: File "/Users/cycleuser/kivy-designer/designer/app.py", line 27, in <module> 115 | [WARNING ] stderr: from kivy.garden.filebrowser import FileBrowser 116 | [WARNING ] stderr: ImportError: No module named filebrowser 117 | ``` 118 | 119 | 120 | 121 | Yep, I found that the filebrowser was missing. 122 | So I run: 123 | >对呗,filebrowser 没安装是吧,那就安装咯。 124 | >就运行一下安装工具就是了: 125 | 126 | 127 | ```Bash 128 | kivy -m pip install -U watchdog pygments docutils jedi gitpython six kivy-garden 129 | garden install filebrowser 130 | ``` 131 | 132 | 133 | 134 | 135 | 136 | If you run: 137 | >当然,最开始其实我运行的是: 138 | 139 | ```Bash 140 | pip install -U watchdog pygments docutils jedi gitpython six kivy-garden 141 | ``` 142 | instead of 143 | >而没注意官方告诉的要运行: 144 | 145 | ```Bash 146 | kivy -m pip install -U watchdog pygments docutils jedi gitpython six kivy-garden 147 | ``` 148 | you may waste a lot of time... 149 | Because you can still run 150 | >这样就会浪费好多时间。。。 151 | >因为两种方式安装之后,会发现都能运行下面的命令来安装 filebrowser : 152 | 153 | ```Bash 154 | garden install filebrowser 155 | ``` 156 | But the location of garden would be in the user path of "~/.kivy/garden" instead of the right location as below: 157 | >但安装位置是不一样的!!!如果像我那样安装就跑到用户目录下面安装了,而不是安装在正确位置,下面的位置是正确位置: 158 | 159 | ```Bash 160 | /Applications/Kivy.app/Contents/Resources/.kivy 161 | ``` 162 | 163 | The kivy.app run when you type " kivy main.py " from the location below: 164 | >当运行 kivy.app 的时候,跑的是 kivy.app 路径里面的 Python,也会在这个里面找 filebrowser,如果安装到用户路径去了,当然就找不到了啊: 165 | 166 | ```Bash 167 | /Applications/Kivy.app/Contents/Resources/.kivy 168 | ``` 169 | 170 | So if you install garden and filebrowser in the home dir, you can copy the garden dir from " ~/.kivy " to " /Applications/Kivy.app/Contents/Resources/.kivy ". 171 | >所以如果你跟我一样安装到用户目录了,就把东西从" ~/.kivy "复制到" /Applications/Kivy.app/Contents/Resources/.kivy "就可以了。 172 | 173 | Then try to run "kivy main.py" and everything is OK now. 174 | >然后再运行"kivy main.py",就发现可以跑界面设计工具了。 175 | 176 | Always remember to add "kivy -m " before "pip install"! 177 | I hope that this could help other on similar problems. 178 | >一定要记住,在"pip install"的前面要添加"kivy -m ",这样才能安装到 Kivy.app 的路径内,而不是系统路径中! 179 | >唉,希望能帮助其他遇到类似问题的小伙伴吧。 180 | 181 | I hope kivy can give a tip about the location of garden installed so we careless people may save a lot of time. 182 | >其实安装 garden 的时候 kivy 如果能给提示一下安装路径该有多好,这样起码容易注意到这个问题了。 183 | -------------------------------------------------------------------------------- /02-Kivy-Basics.md: -------------------------------------------------------------------------------- 1 | Title: Kivy Basics 2 | Date: 2017-01-22 3 | Category: Kivy 4 | Tags: Python,Kivy 5 | 6 | 7 | # Kivy中文编程指南:基础知识 8 | 9 | 10 | [原文地址](https://kivy.org/docs/guide/basic.html)。 11 | 12 | 13 | ## Kivy环境安装搭建 14 | 15 | Kivy要依赖很多Python包,比如 pygame, gstreamer, PIL, Cairo 等等还有好多。这些包并非都是必需的,要根据你的运行平台来看具体情况,有时候缺那么一两个包就可能导致安装失败,或者运行过程中出错等等,这就挺痛苦的。所以Kivy官方针对Windows和MacOS X提供了集成好关键部件的压缩包,解压缩之后直接就能用。具体的安装过程可以参考下面链接中的中文安装指南: 16 | 17 | * [Kivy中文安装指南](http://blog.cycleuser.org/kivy-installment-tutorial.html) 18 | 19 | 如果你非要自己从零开始安装,那最起码要确保安装有[Cython](http://cython.org/)和[Pygame](http://pygame.org/)。这两个包可以通过pip来安装,如下所示: 20 | 21 | ```Bash 22 | pip install cython 23 | pip install hg+http://bitbucket.org/pygame/pygame 24 | pip install kivy 25 | ``` 26 | 27 | 28 | [Kivy的开发版本](https://github.com/kivy/kivy)也可以通过git来安装: 29 | 30 | 31 | 32 | 33 | ```Bash 34 | git clone https://github.com/kivy/kivy 35 | make 36 | ``` 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | ## 创建一个应用 46 | 47 | 48 | 创建一个Kivy应用挺简单的,大概步骤如下: 49 | 50 | * 基于App类创建一个子类; 51 | * 把build()方法实现为返回一个控件实例(这个控件的实例也就是你整个应用的根控件)。 52 | * 创建一个这个类的实例,然后调用run()方法。 53 | 54 | 下面的代码就是上述思路的最小化实现: 55 | 56 | 57 | ```Python 58 | import kivy 59 | kivy.require('1.0.6') # 注意要把这个版本号改变成你现有的Kivy版本号! 60 | 61 | from kivy.app import App # 译者注:这里就是从kivy.app包里面导入App类 62 | from kivy.uix.label import Label # 译者注:这里是从kivy.uix.label包中导入Label控件,这里都注意开头字母要大写 63 | 64 | class MyApp(App): 65 | 66 | def build(self): # 译者注:这里是实现build()方法 67 | return Label(text='Hello world') # 译者注:在这个方法里面使用了Label控件 68 | 69 | if __name__ == '__main__': 70 | MyApp().run() # 译者注:这里就是运行了。 71 | 72 | ''' 73 | 译者注:这一段的额外添加的备注是给萌新的. 74 | 就是要告诉萌新们,一定要每一句每一个函数每一个变量甚至每一个符号,都要读得懂!!! 75 | 如果是半懂不懂的状态,一定得学透了,要不然以后早晚得补课. 76 | 这时候又让我想起了结构化学。 77 | 总之更详细的内容后面会有,大家加油。 78 | ''' 79 | ``` 80 | 81 | 82 | 83 | 把上面的代码以文本形式复制到一个文本文件中,保存成py文件,例如main.py,然后运行,就行了。 84 | 85 | 86 | 87 | ## Kivy应用的生命周期 88 | 89 | 跟学习开发Android应用的时候类似,咱们首先也是要了解一下Kivy应用的生命周期: 90 | 91 | ![](https://kivy.org/docs/_images/Kivy_App_Life_Cycle.png) 92 | 93 | 如上图所示,不论什么用途和目的,咱们应用的入口都是这个run()方法,在本文的样例代码中,就是“MyApp().run()”。 94 | 95 | 下面就一行一行开始详细解释了: 96 | 97 | 98 | ```Python 99 | from kivy.app import App 100 | ``` 101 | 102 | 为什么要导入这个App类呢?因为咱们自定义的这个App要继承这个类。这个类的位置在kivy安装目录下的kivy目录下的app.py文件中。 103 | 104 | 105 | 106 | 107 | ####特别注意 108 | 109 | 如果你想要深入挖掘一下,去了解这个Kivy的App类到底是怎么个内容,你可以打开这个app.py文件,亲自来看看。Kivy作者特别鼓励大家去阅读源码。Kivy基于Python,用Sphinx编写的文档,所以每个类的文档都在对应的文件内。 110 | 111 | 112 | 然后咱们回过头来,继续看本文这次的代码的第二行: 113 | 114 | 115 | 116 | ```Python 117 | from kivy.uix.label import Label 118 | ``` 119 | 120 | 121 | 这里一定要特别注意各种包和类的导入。"kivy.uix"这个包的作用是容纳用户界面元素,比如各种输出布局和控件。 122 | 123 | 124 | 接下来看到这一行: 125 | 126 | ```Python 127 | class MyApp(App): 128 | ``` 129 | 130 | 131 | 这一行定义了咱们这次的Kivy应用的基类。如果你要做修改的话,把MyApp改成你要设定的应用名字就可以了。 132 | 133 | 134 | 接着往下看: 135 | 136 | ```Python 137 | def build(self): 138 | ``` 139 | 140 | 141 | 在上面的生命周期图中加粗强调的部分表明,build函数所处的是要进行初始化和返回根控件的位置。根控件返回的操作在下面这一行中实现: 142 | 143 | 144 | ```Python 145 | return Label(text='Hello world') 146 | ``` 147 | 148 | 149 | 150 | 这里我们用文本‘Hello World’对Label这一控件进行了初始化,并且返回了其实例。这个Label就是咱们这个应用的根控件了。 151 | 152 | 153 | 154 | ####特别注意 155 | 156 | Python是用缩进来区别代码块的,所以一定要注意上面代码的缩进和层次,尤其是函数定义那部分。 157 | 158 | 159 | 然后咱们继续,到了真正让应用开始运行的这部分了: 160 | 161 | 162 | 163 | ```Python 164 | if __name__ == '__main__': 165 | MyApp().run() 166 | ``` 167 | 168 | 169 | 170 | 这里对MyApp这个类进行了初始化,然后调用了这个类的run()方法。这样就初始化并启动了我们的Kivy应用了。 171 | 172 | 173 | ## 运行应用 174 | 175 | 接下来就是要在不同操作系统平台上来运行咱们刚刚写好的应用了: 176 | 177 | To run the application, follow the instructions for your operating system: 178 | 179 | * Linux 终端中以如下方式运行: 180 | 181 | ```Bash 182 | $ python main.py 183 | ``` 184 | 185 | * Windows 可以在CMD中以如下方式运行: 186 | 187 | ```CMD 188 | $ python main.py #用系统Python运行 189 | C:\appdir>kivy.bat main.py #用kivy.bat来运行,注意这里要设定好正确的路径 190 | ``` 191 | 192 | * Mac OS X 跟Linux差不多,也在终端中运行,不过是要用Kivy官方提供的集成解释器: 193 | 194 | ```Bash 195 | $ kivy main.py 196 | ``` 197 | 198 | * Android 下面要运行还需要一些复杂的文件,所以等以后深入了之后再给讲解这部分了。 199 | 200 | 201 | 这个应用运行之后的具体效果就是下面图片所示这样,会打开一个窗口,然后展示出一个Label,上面写着文本‘Hello World’,这个Label会覆盖该窗口的全部区域。就这样了。 202 | 203 | ![](https://kivy.org/docs/_images/quickstart.png) 204 | 205 | 206 | 207 | ## 修改定制这个应用 208 | 209 | 接下来咱们扩展一下这个应用的功能,增加一个用户名/密码输入的页面吧。 210 | 211 | 212 | 213 | ```Python 214 | from kivy.app import App 215 | from kivy.uix.gridlayout import GridLayout 216 | from kivy.uix.label import Label 217 | from kivy.uix.textinput import TextInput 218 | 219 | class LoginScreen(GridLayout): 220 | 221 | def __init__(self, **kwargs): 222 | super(LoginScreen, self).__init__(**kwargs) 223 | self.cols = 2 224 | self.add_widget(Label(text='User Name')) 225 | self.username = TextInput(multiline=False) 226 | self.add_widget(self.username) 227 | self.add_widget(Label(text='password')) 228 | self.password = TextInput(password=True, multiline=False) 229 | self.add_widget(self.password) 230 | 231 | class MyApp(App): 232 | 233 | def build(self): 234 | return LoginScreen() 235 | 236 | if __name__ == '__main__': 237 | MyApp().run() 238 | ``` 239 | 240 | 241 | 242 | 243 | 在下面这行代码中,我们导入了一种名为Gridlayout的布局: 244 | 245 | 246 | 247 | 248 | ```Python 249 | from kivy.uix.gridlayout import GridLayout 250 | ``` 251 | 252 | 253 | 254 | 这个类被我们用作基类来制作根控件LoginScreen,在如下代码中进行了定义: 255 | 256 | 257 | ```Python 258 | class LoginScreen(GridLayout): 259 | ``` 260 | 261 | 262 | 263 | 如下代码中,我们在LoginScreen类中重新定义了初始化方法__init__(),这样来增加一些控件,并且定义了这些控件的行为: 264 | 265 | ```Python 266 | def __init__(self, **kwargs): 267 | super(LoginScreen, self).__init__(**kwargs) 268 | ``` 269 | 270 | 271 | 一定要注意这里要加super,才能把现有的新初始化方法覆盖掉继承来的旧初始化方法。另外也要注意,这里调用super的时候没有省略掉**kwargs,这是一种好习惯。 272 | 273 | 274 | 275 | 然后继续往下看: 276 | 277 | 278 | ```Python 279 | self.cols = 2 280 | self.add_widget(Label(text='User Name')) 281 | self.username = TextInput(multiline=False) 282 | self.add_widget(self.username) 283 | self.add_widget(Label(text='password')) 284 | self.password = TextInput(password=True, multiline=False) 285 | self.add_widget(self.password) 286 | ``` 287 | 288 | 289 | 290 | 291 | 上面的代码中,我们让GridLayout来管理子控件,把子控件设置为两栏,然后加上用户名和密码的Label字符显示控件和TextInput字符输入控件。 292 | 293 | 运行上面的代码,得到的窗口效果大概如下图: 294 | 295 | ![](https://kivy.org/docs/_images/guide_customize_step1.png) 296 | 297 | 298 | 299 | 尝试着重新缩放一下窗口大小,你会发现上面的控件会相对整个窗口的尺寸而自行调整大小,并不需要人为去操作了。这是因为这些控件都使用了默认的尺寸。 300 | 301 | 上面这个代码虽然有输入框,但是并没有提供用户输入的支持和处理,所以并不能进行用户名/密码验证,也没有任何其他用处。后续的练习中咱们再来深入去探讨这些功能,并且还会讲一讲空间的尺寸和位置等话题。 302 | 303 | 304 | -------------------------------------------------------------------------------- /13-Kivy-Pack-Windows.md: -------------------------------------------------------------------------------- 1 | Title: Kivy Pack Windows 2 | Date: 2017-03-01 3 | Category: Kivy 4 | Tags: Python,Kivy 5 | 6 | # Kivy中文编程指南:打包为 Windows 系统可执行文件 7 | 8 | [英文原文](https://kivy.org/docs/guide/packaging-windows.html) 9 | 10 | #### 特别注意 11 | 12 | 本文档仅适用于`1.9.1`以及更新版本的 Kivy。 13 | 14 | 要打包 Windows 平台的应用程序,**只能在 Windows 操作系统下完成**。另外一定要注意,本文后续内容中都是在 **wheels** 安装的 Kivy 下通过测试的,如果你用其他安装方法,参考结尾部分吧。 15 | 16 | 打包出来的程序是 32 位还是 64 位**只取决于**你打包使用的 Python,而不取决于 Windows 操作系统的版本。 17 | 18 | ## 依赖包 19 | 20 | * **最新版本**的Kivy (参考安装指南 [Installation on Windows](https://kivy.org/docs/installation/installation-windows.html#installation-windows)) 21 | * PyInstaller 3.1或者更新的版本 (`pip install --upgrade pyinstaller`)。 22 | 23 | (译者注:PyInstaller 目前(2017年03月01日)还不支持 Python 3.6 哦~,好多朋友都坑到这里了,所以推荐使用 3.5.2。) 24 | 25 | # PyInstaller 的基本用法 26 | 27 | 本节内容是要让 PyInstaller(3.1或者更新版本)包含 Kivy 的 Hook(钩子, Windows 消息处理机制的一个平台)。要覆盖默认的 Hook ,下面的样例代码需要稍微修改一下。参考 [ 覆盖默认 Hook](https://kivy.org/docs/guide/packaging-windows.html#overwrite-win-hook)。 28 | 29 | ## 打包一个简单的 APP 30 | 31 | 这个例子里面,咱们要把样例中的 **touchtracer** 这个项目进行打包,并且添加一个自定义图标。这里 Kivy 的样例目录要注意,如果是用 wheels 安装的,在 `python\\share\\kivy-examples` 这个位置,如果从 github 上面下载的,就在 `kivy\\examples` 这个位置。为了避免混乱,这里就用 `examples-path` 来指代这个目录的完整路径。然后 touchtracer 这个样例在 `examples-path\\demo\\touchtracer` 这个文件夹里,代码文件是 `main.py`。 32 | 33 | 34 | ###1 确保 Python 35 | 打开命令行确保 Python 包含在环境变量内,也就是说,输入 `python` 会出现解释器提示符。(译者注:cmd 或者 powershell 都可以,更推荐用后者,语法和 Bash 比较相似。) 36 | 37 | ###2 创建文件夹 38 | 在要打包 APP 的位置创建一个文件夹。比如咱们这次就创建一个名字为 `TouchApp` 的文件夹,然后用类似 `cd TouchApp` 这样的命令[进入到这个新建目录内](http://www.computerhope.com/cdhlp.htm)。之后输入: 39 | 40 | 41 | ```Python 42 | python -m PyInstaller --name touchtracer examples-path\demo\touchtracer\main.py 43 | ``` 44 | 45 | 还可以增加一个 icon.ico 文件到这个应用目录,这样就可以让程序有自己的图标了。如果没有自己的 .ico 图标文件,可以把你的 icon.png 文件转换成 ico,用这个 [ConvertICO](http://www.convertico.com/) 在线的应用就可以了。保存 icon.ico 到 touchtracer 这个目录里面,然后输入: 46 | 47 | ```Python 48 | python -m PyInstaller --name touchtracer --icon examples-path\demo\touchtracer\icon.ico examples-path\demo\touchtracer\main.py 49 | ``` 50 | 51 | 更多其它选项,请参考 [PyInstaller 官方说明](http://pythonhosted.org/PyInstaller/)。 52 | 53 | ###3 编辑配置文件 54 | 在 `TouchApp` 里面会有一个配置文件 `touchtracer.spec`。咱们需要编辑修改一下这个文件,在里面增加一些依赖包的 hook,这样才能保证正确创建 exe。接下来就是打开编辑器了,爱用啥都行,然后在配置文件的开头添加上下面这句:(这里是假设用的是 sdl2, 现在 Kivy 默认使用这个) 55 | 56 | ```Python 57 | from kivy.deps import sdl2, glew 58 | ``` 59 | 60 | 然后,用搜索,找到 `COLLECT()` 这个位置,添加上 touchtracer 用到的其他文件(touchtracer.kv, particle.png,等等):修改示例中的行位置,添加一个 `Tree()` 对象,例如这里的是 `Tree('examples-path\\demo\\touchtracer\\')`。这个 `Tree()` 会搜索在当前这个 touchtracer 文件夹的所有文件,并添加到你最终打包的程序中。 61 | 62 | 63 | 64 | 要添加额外的依赖包,就要在 COLLECT 的**第一个关键词参数的前面**,为每一个依赖包的路径添加一个 Tree 对象。例如下面的就是以 `*[Tree(p) for p in(sdl2.dep_bins + glew.dep_bins)]` 为例: 65 | 66 | 67 | ```Python 68 | coll = COLLECT(exe, Tree('examples-path\\demo\\touchtracer\\'), 69 | a.binaries, 70 | a.zipfiles, 71 | a.datas, 72 | *[Tree(p) for p in (sdl2.dep_bins + glew.dep_bins)], 73 | strip=False, 74 | upx=True, 75 | name='touchtracer') 76 | ``` 77 | 78 | ###4 进行构建 79 | 接下来就用 `TouchApp` 里面这个 spec 配置文件来进行构建了: 80 | 81 | ```Python 82 | python -m PyInstaller touchtracer.spec 83 | ``` 84 | 85 | ###5 生成位置 86 | 编译好的包会在 TouchApp\dist\touchtracer 这个目录。 87 | 88 | 89 | ## 使用 gstreamer 创建一个视频应用 90 | 91 | 92 | 接下来就是修改一下上面的这个样例了,这回要打包的 APP 是一个使用了 gstreamer 的视频应用。咱们这回用样例中的视频播放器的例子 `videoplayer`,代码在`examples-path\widgets\videoplayer.py`。另外创建一个名字为 `VideoPlayer` 的文件夹,然后在命令行中进入到这个文件夹,之后操作如下: 93 | 94 | 95 | ```Python 96 | python -m PyInstaller --name gstvideo examples-path\widgets\videoplayer.py 97 | ``` 98 | 99 | 这回要修改 `gstvideo.spec` 这个文件。跟上文的方法类似,也就是把 gstreamer 的依赖包放进去: 100 | 101 | ```Python 102 | from kivy.deps import sdl2, glew, gstreamer 103 | ``` 104 | 105 | 然后就是增加 `Tree()` 来包含好要用的视频文件,`Tree('examples-path\\widgets')` 和 gstreamer 依赖都得弄好,大概如下所示: 106 | 107 | ```Python 108 | coll = COLLECT(exe, Tree('examples-path\\widgets'), 109 | a.binaries, 110 | a.zipfiles, 111 | a.datas, 112 | *[Tree(p) for p in (sdl2.dep_bins + glew.dep_bins + gstreamer.dep_bins)], 113 | strip=False, 114 | upx=True, 115 | name='gstvideo') 116 | ``` 117 | 118 | 接下来就是使用 `VideoPlayer` 文件夹中的这个 spec 配置文件来进行构建了: 119 | 120 | ```Python 121 | python -m PyInstaller gstvideo.spec 122 | ``` 123 | 124 | 然后你就能在 `VideoPlayer\dist\gstvideo` 这个位置找到 gstvideo.exe 这个文件了,运行一下就能播放视频了。 125 | 126 | #### 特别注意 127 | 128 | 如果你用了 Pygame,或者你打包的程序需要 Pygame,那在你的 spec 文件里面就还得添加如下的代码,在 import 导入语句的后面添加(详情参考 [kivy issue #1638](github.com/kivy/kivy/issues)): 129 | 130 | ```Python 131 | def getResource(identifier, *args, **kwargs): 132 | if identifier == 'pygame_icon.tiff': 133 | raise IOError() 134 | return _original_getResource(identifier, *args, **kwargs) 135 | 136 | import pygame.pkgdata 137 | _original_getResource = pygame.pkgdata.getResource 138 | pygame.pkgdata.getResource = getResource 139 | ``` 140 | 141 | 142 | # 覆盖默认 Hook 143 | 144 | 145 | ## 包含/移除视频音频以及缩小应用体积 146 | 147 | PyInstallers 默认会将 Kivy 用到的所有核心模块和这些模块的依赖包,**全部**都添加成 hook,比如音频,视频,拼写等等(然而 gstreamer 的 dll 还是需要你用 `Tree()` 来手动添加,参考上文)。有的 Hook 并没有用到或者想要缩小应用的体积,就都可以尝试着移除一些模块,比如如果没有用到音频和视频,就可以用自定义的 Hook了。 148 | 149 | Kivy 在[`hookspath()`](https://kivy.org/docs/api-kivy.tools.packaging.pyinstaller_hooks.html#kivy.tools.packaging.pyinstaller_hooks.hookspath "kivy.tools.packaging.pyinstaller_hooks.hookspath") 提供了可选的 Hook。 150 | 151 | 此外,当且仅当 PyInstaller 没有默认的 hook 的时候,就必须得提供一个[`runtime_hooks()`](https://kivy.org/docs/api-kivy.tools.packaging.pyinstaller_hooks.html#kivy.tools.packaging.pyinstaller_hooks.runtime_hooks "kivy.tools.packaging.pyinstaller_hooks.runtime_hooks")。 覆盖 hook的时候,这个[`runtime_hooks()`](https://kivy.org/docs/api-kivy.tools.packaging.pyinstaller_hooks.html#kivy.tools.packaging.pyinstaller_hooks.runtime_hooks "kivy.tools.packaging.pyinstaller_hooks.runtime_hooks") 不需要覆盖。 152 | 153 | 154 | 可选自定义的[`hookspath()`](https://kivy.org/docs/api-kivy.tools.packaging.pyinstaller_hooks.html#kivy.tools.packaging.pyinstaller_hooks.hookspath "kivy.tools.packaging.pyinstaller_hooks.hookspath") hook不包含任何 Kivy 的 provider。要添加电话,就要用[`get_deps_minimal()`](https://kivy.org/docs/api-kivy.tools.packaging.pyinstaller_hooks.html#kivy.tools.packaging.pyinstaller_hooks.get_deps_minimal "kivy.tools.packaging.pyinstaller_hooks.get_deps_minimal") 或者 [`get_deps_all()`](https://kivy.org/docs/api-kivy.tools.packaging.pyinstaller_hooks.html#kivy.tools.packaging.pyinstaller_hooks.get_deps_all "kivy.tools.packaging.pyinstaller_hooks.get_deps_all")来添加。可以看看相关的文档以及[`pyinstaller_hooks`](https://kivy.org/docs/api-kivy.tools.packaging.pyinstaller_hooks.html#module-kivy.tools.packaging.pyinstaller_hooks "kivy.tools.packaging.pyinstaller_hooks")来了解更多信息。不过[`get_deps_all()`](https://kivy.org/docs/api-kivy.tools.packaging.pyinstaller_hooks.html#kivy.tools.packaging.pyinstaller_hooks.get_deps_all "kivy.tools.packaging.pyinstaller_hooks.get_deps_all")跟默认的 hook一样,都是把所有 provider 都添加进去;而[`get_deps_minimal()`](https://kivy.org/docs/api-kivy.tools.packaging.pyinstaller_hooks.html#kivy.tools.packaging.pyinstaller_hooks.get_deps_minimal "kivy.tools.packaging.pyinstaller_hooks.get_deps_minimal") 只添加在应用程序运行的时候加载了的内容。 155 | 156 | 这两个方法都提供了一个 Kivy 隐藏导入列表,以及排除的导入,可以传递出来给 `Analysis`。 157 | 158 | 还可以生成一个自定义 hook,一个个列出每一个 kivy 的 provider 模块,然后把其中用不上的就注释掉就行了。 159 | 160 | 参考 [`pyinstaller_hooks`](https://kivy.org/docs/api-kivy.tools.packaging.pyinstaller_hooks.html#module-kivy.tools.packaging.pyinstaller_hooks "kivy.tools.packaging.pyinstaller_hooks"). 161 | 162 | 要在上面的例子中使用自定义 hook,要按照下面给出的范例来修改,以`hookspath()` 和 `runtime_hooks`(必要情况下),然后是`**get_deps_minimal()` 或者 `**get_deps_all()`来制定好各种 provider。 163 | 164 | 165 | 例如,增加了导入语句 `from kivy.tools.packaging.pyinstaller_hooks import  get_deps_minimal, get_deps_all, hookspath,runtime_hooks` ,然后按照如下方式修改`Analysis`: 166 | 167 | ```Python 168 | a = Analysis(['examples-path\\demo\\touchtracer\\main.py'], 169 | ... 170 | hookspath=hookspath(), 171 | runtime_hooks=runtime_hooks(), 172 | ... 173 | **get_deps_all()) 174 | ``` 175 | 176 | 上面这个实际上跟默认 hook 一样包含全部了。或者可以: 177 | 178 | ```Python 179 | a = Analysis(['examples-path\\demo\\touchtracer\\main.py'], 180 | ... 181 | hookspath=hookspath(), 182 | runtime_hooks=runtime_hooks(), 183 | ... 184 | **get_deps_minimal(video=None, audio=None)) 185 | ``` 186 | 这样就是移除了声音视频的 provider,这就只加载了用到的核心模块了。 187 | 188 | 关键就是要提供自定义的 [`hookspath()`](https://kivy.org/docs/api-kivy.tools.packaging.pyinstaller_hooks.html#kivy.tools.packaging.pyinstaller_hooks.hookspath "kivy.tools.packaging.pyinstaller_hooks.hookspath"),这个默认并不会列出全部的 kivy provider,而是手动的来设定隐藏导入的模块和需要用的 provider,通过[`get_deps_minimal()`](https://kivy.org/docs/api-kivy.tools.packaging.pyinstaller_hooks.html#kivy.tools.packaging.pyinstaller_hooks.get_deps_minimal "kivy.tools.packaging.pyinstaller_hooks.get_deps_minimal")来移除用不上的模块 (比如上面的是声音影像)。 189 | 190 | 191 | 192 | 193 | 194 | ## 其他安装方式 195 | 196 | 前面的这些例子都用到了 `*[Tree(p) for p in (sdl2.dep_bins + glew.dep_bins + gstreamer.dep_bins)],` 这样的语句来保证 PyInstaller 把所有依赖包用到的 dll 都添加进去。如果不是用 wheel 的方法安装的 Kivy,那么这些命令就很可能失败,比如 `kivy.deps.sdl2` 可能就无法导入。这时候,你就必须得找到这些 dll 文件的位置,然后手动地一个个传递给 `Tree` 类,传递方法和上面说的基本差不多了。 197 | 198 | (译者注:Windows 平台还是推荐用 wheel 二进制安装,省心多了。) 199 | 200 | 201 | -------------------------------------------------------------------------------- /17-Kivy-Pack-Mac.md: -------------------------------------------------------------------------------- 1 | Title: Kivy Pack Mac 2 | Date: 2017-03-02 3 | Category: Kivy 4 | Tags: Python,Kivy 5 | 6 | # Kivy中文编程指南:打包为 Mac 系统可执行文件 7 | 8 | [英文原文](https://kivy.org/docs/guide/packaging-osx.html) 9 | 10 | #### 特别注意 11 | 12 | 本文所提供的打包 Kivy 应用程序的方法必须在 OS X 系统内进行,而且不再支持 32 位平台。 13 | 14 | ## 使用 Buildozer 15 | 16 | ```Bash 17 | pip install git+http://github.com/kivy/buildozer cd /to/where/I/Want/to/package buildozer init 18 | ``` 19 | (译者注:这里的/to/where/I/Want/to/package 就是你要打包的应用所在目录。) 20 | 21 | 然后就还是修改 buildozer.spec 文件,在里面添加好你的应用需要用到的信息。添加依赖包的位置在 requirements= 的那个位置。 22 | 23 | 默认情况下,requirements 位置所指定的 Kivy 版本会被忽略掉。 24 | 25 | 如果你在应用程序目录下有 Kivy.app (/Applications/Kivy.app),那就会用这个来打包。如果没有,还可以从 Kivy.org 下载最新版来用了。 26 | 27 | 如果你要用 Python3 来打包,就就直接从 Kivy.org 的下载页面下载 Kivy3.7z 这个包,然后把它解压缩到应用目录 /Applications 下,命名为 Kivy.app,然后运行: 28 | 29 | 30 | ```Bash 31 | buildozer osx debug 32 | ``` 33 | 34 | 打包好应用之后,就可以移除用不上的包了,比如如果你不用视频功能,那就可以去掉 gstreamer。同理,其他的用不上的功能,也都可以去掉,这就可以保证打包出来的应用能够有尽量小的体积,足够运行就好了。 35 | 36 | 作为示例,我们用这个方法打包好了一个应用,Python2 的版本大概 9MB 多一点,Python3 的是 15MB 左右,可以在[官方提供的谷歌网盘](https://drive.google.com/drive/folders/0B1WO07-OL50_alFzSXJUajBFdnc)下载来体验一下。(译者注:如果你身处大陆而无法访问谷歌这种不存在的网站,那么可以试试[我的百度网盘分享](https://pan.baidu.com/s/1gfBSD4B)。) 37 | 38 | 就这么多,动手试试吧。 39 | 40 | 目前的 Buildozer 使用了 Kivy SDK 来打包你的应用程序。如果你想对你的程序进行更深入的修改定制,而 buildozer 不足以满足你的需求,你可以试试直接使用 SDK,下面就要详细介绍一下这部分。 41 | 42 | 43 | ## 使用 Kivy SDK 44 | 45 | 从 1.9.0 版本开始,Kivy 就开始发布针对 OS X 平台的自我包含的便捷包。 46 | 47 | 用下面描述的方法就可以使用 Kivy SDK 来打包和发布应用程序了,要添加一些诸如 SDL2 或者 GStreamer 之类的包也都更简单了。 48 | 49 | 1 首先要确保有未修改过的原版 Kivy SDK,也就是从下载页面获取的 Kivy.app 这个文件。 50 | 51 | 2 然后运行下面的命令: 52 | 53 | ```Bash 54 | mkdir packaging 55 | cd packaging 56 | packaging> git clone https://github.com/kivy/kivy-sdk-packager 57 | packaging> cd kivy-sdk-packager/osx 58 | osx> cp -a /Applications/Kivy.app ./Kivy.App 59 | ``` 60 | 61 | #### 特别注意 62 | 63 | 上面这一步是至关重要的,一定要确保目录和权限都没有问题。`cp -rf` 这样的命令也能实现复制,但会让应用程序无法运行,并且在后续步骤中导致各种错误。 64 | 65 | 66 | 3 接下来就是要把你用 Kivy.app 编译好的应用程序包含进目标文件夹,使用如下命令: 67 | 68 | ```Bash 69 | osx> ./package-app.sh /path/to/your/app_folder_name>/ 70 | ``` 71 | <app_folder_name> 就是你应用程序的名字。 72 | 73 | 这个命令会把 Kivy.app 复制成 <app_folder_name>.app,并把应用程序的一份编译好的副本包含进去。 74 | 75 | 76 | 4 就这些了,你的应用程序已经打包完毕,可以拿出去安装了。接下来可以按照下面的方法对你的应用进行更进一步的定制了。 77 | 78 | ### 安装模块 79 | 80 | OS X 上的 Kivy 包邮自己的虚拟环境,当你使用 kivy 命令来运行的时候就会激活这个虚拟环境。如果要安装额外的一些模块,可以用如下命令: 81 | 82 | ```Bash 83 | kivy -m pip install 84 | ``` 85 | 86 | 87 | ### 模块和文件安到哪了? 88 | 89 | 在 Kivy.app 这个文件内部,虚拟环境位置如下: 90 | 91 | ```Bash 92 | Kivy.app/Contents/Resources/venv/ 93 | ``` 94 | 95 | 如果你安装了一个安装二进制的模块,比如 kivy-garden。那么这些二进制文件只能在虚拟环境中才是可用的,就比如你先运行了下面这个命令: 96 | 97 | ```Bash 98 | kivy -m pip install kivy-garden 99 | ``` 100 | 101 | 102 | 然后安装的 garden lib 就只在你激活这个虚拟环境的时候才可用。 103 | 104 | ```Bash 105 | source /Applications/Kivy.app/Contents/Resources/venv/bin/activate garden install mapview deactivate 106 | ``` 107 | 108 | ### 安装二进制文件 109 | 110 | 这个比较简单,就把二进制文件复制到虚拟目录下的 bin 文件夹就可以了。(Kivy.app/Contents/Resources/venv/bin/) 111 | 112 | 113 | 114 | ### 包含其他框架 115 | 116 | Kivy.app 已经自带了 SDL2 和 Gstreamer 这两个框架。要包含其他框架可以参考下面的方法: 117 | 118 | ```Bash 119 | git clone http://github.com/tito/osxrelocator 120 | export PYTHONPATH=~/path/to/osxrelocator 121 | cd Kivy.app 122 | python -m osxrelocator -r . /Library/Frameworks/<Framework_name>.framework/ \ 123 | @executable_path/../Frameworks/<Framework_name>.framework/ 124 | ``` 125 | 126 | Do not forget to replace with your framework. This tool osxrelocator essentially changes the path for the libs in the framework such that they are relative to the executable within the .app, making the Framework portable with the .app. 127 | 128 | 一定别忘了把上面样例中的 <Framework_name> 替换成你要安装的框架名字。osxrelocator 这个工具可以改变框架中的链接库的路径,这样就能让它们指向 .app 文件内的可执行文件,也就让此框架成为 .app 文件内可用的内置框架了。 129 | 130 | 131 | #### 缩小应用体积 132 | 133 | 现在这个应用程序的体积可能已经相当大了,好在很多没有用上的部分可以从包中移除。 134 | 135 | 举例来说,如果你没有使用 Gstreamer,就可以从你应用程序的 .app 文件内的 /Contents/Frameworks 目录中把它删除掉。类似的像是在 /Applications/Kivy.app/Contents/Resources/kivy/ 目录下的 examples,tools,docs 等等这些文件夹都可以删掉的。 136 | 137 | 这样就可以让你的包只包含你的应用程序用到的内容。 138 | 139 | #### 修改设置 140 | 141 | 通过修改应用程序的 .app 文件内 /Contents/info.plist 这个文件,就可以修改图标和其他的设置了。 142 | 143 | 144 | #### 创建 DMG 145 | 146 | 用如下命令就可以创建一个 DMG 镜像文件了: 147 | 148 | ```Bash 149 | osx> ./create-osx-dmg.sh YourApp.app 150 | ``` 151 | 152 | 一定要注意末尾没有额外的 /。 这样就能生成一个压缩的 DMG 文件,能进一步缩小应用发布时候的体积了。 153 | 154 | 155 | 156 | ## 使用 PyInstaller,无 HomeBrew 157 | 158 | 首先是安装 Kivy 和依赖包,不用 HomeBrew 的方法可以在[官方文档](http://kivy.org/docs/installation/installation.html#development-version) 或者[译者的博客](http://blog.cycleuser.org/kivy-installment-tutorial.html)或者[译者的专栏](https://zhuanlan.zhihu.com/p/24644473)中查找。 159 | 160 | 安装好了Kivy 以及依赖包之后,就需要安装 PyInstaller 了。 161 | 162 | (译者注:PyInstaller 目前不支持 Python3.6,时间为2017-03-02。) 163 | 164 | 假设用一个名为 testpackaging 的文件夹: 165 | 166 | 167 | ```Bash 168 | cd testpackaging 169 | git clone http://github.com/pyinstaller/pyinstaller 170 | ``` 171 | 172 | 在这个目录中创建一个名为 touchtracer.spec 的配置文件,然后添加如下的代码到该文件中: 173 | 174 | 175 | ```Bash 176 | # -*- mode: python -*- 177 | 178 | block_cipher = None 179 | from kivy.tools.packaging.pyinstaller_hooks import get_deps_all, hookspath, runtime_hooks 180 | 181 | a = Analysis(['/path/to/yout/folder/containing/examples/demo/touchtracer/main.py'], 182 | pathex=['/path/to/yout/folder/containing/testpackaging'], 183 | binaries=None, 184 | win_no_prefer_redirects=False, 185 | win_private_assemblies=False, 186 | cipher=block_cipher, 187 | hookspath=hookspath(), 188 | runtime_hooks=runtime_hooks(), 189 | **get_deps_all()) 190 | pyz = PYZ(a.pure, a.zipped_data, 191 | cipher=block_cipher) 192 | exe = EXE(pyz, 193 | a.scripts, 194 | exclude_binaries=True, 195 | name='touchtracer', 196 | debug=False, 197 | strip=False, 198 | upx=True, 199 | console=False ) 200 | coll = COLLECT(exe, Tree('../kivy/examples/demo/touchtracer/'), 201 | Tree('/Library/Frameworks/SDL2_ttf.framework/Versions/A/Frameworks/FreeType.framework'), 202 | a.binaries, 203 | a.zipfiles, 204 | a.datas, 205 | strip=False, 206 | upx=True, 207 | name='touchtracer') 208 | app = BUNDLE(coll, 209 | name='touchtracer.app', 210 | icon=None, 211 | bundle_identifier=None) 212 | ``` 213 | 214 | 215 | 把路径改到你的相对路径: 216 | 217 | ```Bash 218 | a = Analysis(['/path/to/yout/folder/containing/examples/demo/touchtracer/main.py'], 219 | pathex=['/path/to/yout/folder/containing/testpackaging'], 220 | ... 221 | ... 222 | coll = COLLECT(exe, Tree('../kivy/examples/demo/touchtracer/'), 223 | ``` 224 | 225 | 然后运行如下命令: 226 | 227 | ```Bash 228 | pyinstaller/pyinstaller.py touchtracer.spec 229 | ``` 230 | 231 | 232 | 233 | 把这里的 touchtracer 替换成你的应用名称。之后就可以在 dist 文件夹下看到你的 .app 文件了。 234 | 235 | 236 | ## 使用 PyInstaller + HomeBrew 237 | 238 | 239 | 240 | #### 特别注意 241 | 242 | 打包你的应用程序的时候,你定要在你要兼容的最老版本的 OS X 系统上进行。 243 | 244 | 245 | 246 | ### 完整指南 247 | 248 | 1 安装 [Homebrew](http://brew.sh/) 249 | 250 | 2 安装 Python: 251 | 252 | ```Bash 253 | brew install python 254 | ``` 255 | 256 | #### 特别注意 257 | 如果要用 Python3 ,就用 `brew install python3` ,然后把下文中的 `pip` 改成 `pip3` 就可以了。 258 | 259 | 260 | 261 | 3 (Re)install your dependencies with `--build-bottle` to make sure they can be used on other machines: 262 | 263 | ```Bash 264 | brew reinstall --build-bottle sdl2 sdl2_image sdl2_ttf sdl2_mixer 265 | ``` 266 | 267 | 268 | #### 特别注意 269 | 270 | 如果你的项目依赖 Gstreamer 或者其他的链接库,一定要按照下文的方法添加 `--build-bottle` 来安装。 271 | 272 | 4 安装 Cython 和 Kivy: 273 | 274 | ```Bash 275 | pip install -I Cython==0.23 276 | USE_OSX_FRAMEWORKS=0 pip install -U kivy 277 | ``` 278 | 279 | 280 | 281 | 5 安装 PyInstaller: 282 | 283 | ```Bash 284 | pip install -U pyinstaller 285 | ``` 286 | 287 | 6 使用到 main.py 的路径来打包应用: 288 | 289 | ```Bash 290 | pyinstaller -y --clean --windowed --name touchtracer \ 291 | --exclude-module _tkinter \ 292 | --exclude-module Tkinter \ 293 | --exclude-module enchant \ 294 | --exclude-module twisted \ 295 | /usr/local/share/kivy-examples/demo/touchtracer/main.py 296 | 297 | 298 | #### 特别注意 299 | 300 | 这样不能把额外的图像和声音文件复制进去。要添加这些内容还是要创建一个专门的`.spec`配置文件。 301 | 302 | ### 编辑`.spec` 配置文件 303 | 304 | 咱们用的这个配置文件是 touchtracer.spec , 位置在刚刚运行了 pyinstaller 的目录。 305 | 306 | 需要对配置文件中的 COLLECT() 调用的部分进行修改,要添加上 touchtracer 用到的资源(比如touchtracer.kv, particle.png,等等)。修改这一行,添加一个 Tree() 对象。这个 Tree 会搜索 touchtracer 目录下的所有文件,并添加到你的包当中。 COLLECT 的那部分代码应该大概如下所示: 307 | 308 | 309 | ```Bash 310 | coll = COLLECT(exe, Tree('/usr/local/share/kivy-examples/demo/touchtracer/'), 311 | a.binaries, 312 | a.zipfiles, 313 | a.datas, 314 | strip=None, 315 | upx=True, 316 | name='touchtracer') 317 | ``` 318 | 319 | 这样会把需要的文件都添加进去,这样 PyInstaller 就能包含需要用到的 Kivy 文件了。弄妥了之后,你的 spec 配置文件就可以执行了。 320 | 321 | 322 | ### 使用 spec 来构建并打包成 DMG 323 | 324 | 325 | 1 打开终端。 326 | 327 | 2 进入到 PyInstaller 的目录,然后用如下命令进行构建: 328 | 329 | ```Bash 330 | pyinstaller -y --clean --windowed touchtracer.spec 331 | ``` 332 | 333 | 3 运行来试试: 334 | 335 | ```Bash 336 | pushd dist 337 | hdiutil create ./Touchtracer.dmg -srcfolder touchtracer.app -ov 338 | popd 339 | ``` 340 | 341 | 4 然后就能在 dist 目录下找到 Touchtracer.dmg 这个文件了。 342 | 343 | ### 额外的链接库 344 | 345 | #### GStreamer 346 | 347 | 如果你的项目需要 GStreamer,那就运行如下命令: 348 | 349 | ```Bash 350 | brew reinstall --build-bottle gstreamer gst-plugins-{base,good,bad,ugly} 351 | ``` 352 | 353 | #### 特别注意 354 | 355 | 如果你的项目需要对 Ogg Vorbis(音频压缩格式,类似于MP3,完全免费、开放和没有专利限制,支持多声道) 的支持,一定要在上面的命令后加上 `--with-libvorbis`。 356 | 357 | 如果你用的是通过 HomeBrew 安装的 Python,那就还需要下面这一步,除非[这个问题](https://github.com/Homebrew/homebrew/pull/46097)弄妥了: 358 | 359 | ```Bash 360 | brew reinstall --with-python --build-bottle https://github.com/cbenhagen/homebrew/raw/patch-3/Library/Formula/gst-python.rb 361 | ``` -------------------------------------------------------------------------------- /07-Kivy-Input.md: -------------------------------------------------------------------------------- 1 | Title: Kivy Input management 2 | Date: 2017-02-12 3 | Category: Kivy 4 | Tags: Python,Kivy 5 | 6 | 7 | # Kivy中文编程指南:输入管理 8 | 9 | [英文原文](kivy.org/docs/guide/inputs.html) 10 | 11 | ##译者前言 12 | 这一章节比上一章节翻译的还差,最近睡眠不太好,术后恢复比较差,大家凑合看看,看不下去给指出来一下比较不好理解和绕的地方,以及错误的地方,我一定即时修改。 13 | 14 | 15 | 16 | ## 输入体系 17 | 18 | Kivy能处理绝大多数的输入类型:鼠标,触摸屏,加速器,陀螺仪等等。并且针对以下平台能够处理多点触控的原生协议:Tuio, WM_Touch, MacMultitouchSupport, MT Protocol A/B 以及 Android。(译者注:第一个TUIO应该是通用多点触控,第二个怀疑是WindowsMobile的,第三个是苹果的多点触控,第四个不知道是啥,最后一个是Android的。) 19 | 20 | 整体上输入体系的结构概括起来如下所示: 21 | 22 | 23 | ```HTML 24 | Input providers -> Motion event -> Post processing -> Dispatch to Window 25 | 26 | 输入源 -> 动作事件 -> 事后处理 -> 分派到窗口 27 | ``` 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 所有输入事件的类是[`MotionEvent`](https://kivy.org/docs/api-kivy.input.motionevent.html#kivy.input.motionevent.MotionEvent "kivy.input.motionevent.MotionEvent")。这个类生成两种事件: 36 | 37 | 38 | * Touch触控事件:包含位置信息,至少X和Y坐标位置的一种Motion动作事件。所有这种Touch事件都通过控件树进行分派。 39 | 40 | * Non-Touch非触控事件:其余的各种事件。例如加速度传感器就是一个持续的事件,不具有坐标位置。这一事件没有起止,一直在发生。这类的事件都不通过控件树来分派。 41 | 42 | 43 | Motion动作事件是由[`InputProvider`](https://kivy.org/docs/api-kivy.input.providers.html#module-kivy.input.providers "kivy.input.providers")生成的。 44 | InputProvider这个类就是负责读取输入事件,这些输入事件的来源可以是操作系统,网络或者其他的应用程序。如下这几个都是已有的输入源: 45 | 46 | * [`TuioMotionEventProvider`](https://kivy.org/docs/api-kivy.input.providers.tuio.html#kivy.input.providers.tuio.TuioMotionEventProvider "kivy.input.providers.tuio.TuioMotionEventProvider"):创建一个UDP服务端,侦听TUIO/OSC信息。 47 | * `WM_MotionEventProvider`:使用Windows API来读取多点触控信息并发送给Kivy。 48 | * `ProbeSysfsHardwareProbe`:在Linux中,遍历连接到计算机的所有硬件,并为找到的每个多点触摸设备附加一个多点触摸输入提供程序。 49 | * 还有很多很多啦! 50 | 51 | 当你写一个应用程序的时候,就不用再去重造一个输入源了。Kivy会自动检测可用的硬件。然而,如果你想要支持某些特殊定制的专门硬件,就可能得对Kivy的配置进行一下调整才行。 52 | 53 | 在新建的Motion动作事件被传递给用户之前,Kivy会先对输入进行处理。Kivy会对每一个动作事件进行分析来检查和纠正错误输入,也是保证能提供有意义的解释,比如: 54 | 55 | * 根据姿势和持续时间来检测双击或三次点击; 56 | * 在硬件设备精度不佳的情况下提高事件精确度; 57 | * 原生触摸硬件若在近似相同位置发送事件则降低生成事件数量。 58 | 59 | 60 | 61 | 经过上面这些步骤之后,这个Motion动作事件就会被分派给对应的窗口。正如之前解释过的,并非所有事件都分派给整个控件树,程序窗口要对事件进行过滤筛选。对于一个给定的事件: 62 | 63 | 64 | * 如果仅仅是一个Motion动作事件,那它就会被分派给[`on_motion()`](https://kivy.org/docs/api-kivy.core.window.html#kivy.core.window.WindowBase.on_motion "kivy.core.window.WindowBase.on_motion"); 65 | 66 | * 如果是一个Touch事件,这个触摸控件的坐标位置(x,y)(范围在0-1)会被调整到与窗口尺寸(宽高)相适应,然后对应发给下面这些方法: 67 | * [`on_touch_down()`](https://kivy.org/docs/api-kivy.uix.widget.html#kivy.uix.widget.Widget.on_touch_down "kivy.uix.widget.Widget.on_touch_down") 68 | * [`on_touch_move()`](https://kivy.org/docs/api-kivy.uix.widget.html#kivy.uix.widget.Widget.on_touch_move "kivy.uix.widget.Widget.on_touch_move") 69 | * [`on_touch_up()`](https://kivy.org/docs/api-kivy.uix.widget.html#kivy.uix.widget.Widget.on_touch_up "kivy.uix.widget.Widget.on_touch_up") 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | ## Motion动作事件的属性 78 | 79 | 80 | 你用的硬件和输入源可能允许你能获取到更多信息。比如一个Touch触摸输入不仅有坐标位置(x,y),还可能有压力强度信息,触摸范围大小,加速度矢量等等。 81 | 82 | 在Motion动作事件中,有一个字符串作为profile属性,用于说明该事件内都有那些可用的效果。假如咱们有下面这样的一个`on_touch_move`方法: 83 | 84 | 85 | 86 | ```Python 87 | def on_touch_move(self, touch): 88 | print(touch.profile) 89 | return super(..., self).on_touch_move(touch) 90 | ``` 91 | 92 | 93 | 94 | 95 | 在控制台的打印输出可能是: 96 | 97 | 98 | 99 | ```Bash 100 | ['pos', 'angle'] 101 | ``` 102 | 103 | 104 | 105 | 106 | #### 特别注意 107 | 108 | 109 | 很多人可能会把这里Motion事件的Profile属性的名字与对应的Property属性弄混。一定要注意,可用Profile属性中存在`angle`,并不意味着Touch事件对象也必须有一个`angle`的Property属性。 110 | 111 | 112 | 对应profile属性`'pos'`,property属性中有位置信息`pos`,`x`,`y`。profile属性`angle`,property属性对应的是有角度`a`。刚刚我们就说了,对touchTouch事件来说,profile属性中按照惯例是必须有位置属性`pos`的,但不一定有角度属性`angle`。对角度属性`angle`是否存在,可以用下面的方法来检测一下: 113 | 114 | 115 | 116 | ```Python 117 | def on_touch_move(self, touch): 118 | print('The touch is at position', touch.pos) 119 | if 'angle' in touch.profile: 120 | print('The touch angle is', touch.a) 121 | ``` 122 | 123 | 124 | 125 | 在[`motionevent`](https://kivy.org/docs/api-kivy.input.motionevent.html#module-kivy.input.motionevent "kivy.input.motionevent")文档中,可以找到所有可用profile属性的列表。 126 | 127 | 128 | ##Touch事件 129 | 130 | 131 | 有一种特殊的[`MotionEvent`动作事件](https://kivy.org/docs/api-kivy.input.motionevent.html#kivy.input.motionevent.MotionEvent "kivy.input.motionevent.MotionEvent") ,这种事件的[`is_touch`](https://kivy.org/docs/api-kivy.input.motionevent.html#kivy.input.motionevent.MotionEvent.is_touch "kivy.input.motionevent.MotionEvent.is_touch") 方法返回的是True,这就是Touch事件。 132 | 133 | 134 | 所有的Touch事件,都默认就有X和Y的坐标信息,与窗口的宽度和高度相匹配。换句话说就是所有的Touch事件都有`pos`这一profile属性。 135 | 136 | ### 基本简介 137 | 138 | 139 | 默认情况下,Touch事件会被分派给所有当前显示的控件。也就是说无论这个Touch是否发生在控件的物理范围内,控件都会收到它。 140 | 141 | 如果你接触过其他的GUI框架,可能觉得这特点挺违背直觉的。一般的GUI框架里面,都是把屏幕分割成多个几何区域,然后只在发生区域内的控件才会被分派到触摸或者鼠标事件。 142 | 143 | 这个设定对触摸输入的情景来说就过于严格了。因为用手指划,之间点戳,还有长时间按,都可能会有偏移导致落到 用户希望进行交互的控件外的情景。 144 | 145 | 为了提供最大的灵活性,Kivy会把事件分派给所有控件,然后让控件来自行决定如何应对这些事件。如果你只希望在某个控件内对Touch事件作出反应,只需要按照如下方法进行一下检测: 146 | 147 | 148 | 149 | ```Python 150 | def on_touch_down(self, touch): 151 | if self.collide_point(*touch.pos): 152 | # The touch has occurred inside the widgets area. Do stuff! 153 | pass 154 | ``` 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | ### 坐标位置 165 | 166 | 167 | 一旦你使用一个带有矩阵变换的控件,就一定要处理好Touch事件中的矩阵变换。例如[`Scatter`](https://kivy.org/docs/api-kivy.uix.scatter.html#kivy.uix.scatter.Scatter "kivy.uix.scatter.Scatter")这样的某些控件,自身会有矩阵变换,这就意味着Touch事件也必须用Scatter矩阵进行处理,这样才能正确地把Touch事件的位置分派给Scatter的子控件。 168 | 169 | 170 | 171 | * 从上层空间到本地空间获取坐标: [`to_local()`](https://kivy.org/docs/api-kivy.uix.widget.html#kivy.uix.widget.Widget.to_local "kivy.uix.widget.Widget.to_local") 172 | * 从本地空间到上层空间获取坐标: [`to_parent()`](https://kivy.org/docs/api-kivy.uix.widget.html#kivy.uix.widget.Widget.to_parent "kivy.uix.widget.Widget.to_parent") 173 | * 从本地空间到窗口空间获取坐标: [`to_window()`](https://kivy.org/docs/api-kivy.uix.widget.html#kivy.uix.widget.Widget.to_window "kivy.uix.widget.Widget.to_window") 174 | * 从窗口空间到本地空间获取坐标: [`to_widget()`](https://kivy.org/docs/api-kivy.uix.widget.html#kivy.uix.widget.Widget.to_widget "kivy.uix.widget.Widget.to_widget") 175 | 176 | 177 | 一定要使用上面方法当中的某一种来确保内容坐标系适配正确。然后下面这段代码里是Scatter的实现: 178 | 179 | 180 | 181 | ```Python 182 | def on_touch_down(self, touch): 183 | # push the current coordinate, to be able to restore it later 184 | # 这里用push先把当前的坐标位置存留起来,以后就还可以恢复到这个坐标 185 | touch.push() 186 | 187 | # transform the touch coordinate to local space 188 | # 接下来就是把Touch的坐标转换成本地空间的坐标 189 | touch.apply_transform_2d(self.to_local) 190 | 191 | # dispatch the touch as usual to children 192 | # the coordinate in the touch is now in local space 193 | # 转换之后把这个Touch事件按照惯例分派给子控件 194 | # Touch事件的坐标位置现在就是本地空间的了 195 | ret = super(..., self).on_touch_down(touch) 196 | 197 | # whatever the result, don't forget to pop your transformation 198 | # after the call, so the coordinate will be back in parent space 199 | #无论结果如何,一定记得把这个转换用pop弹出 200 | # 之后,坐标就又恢复成上层空间的了 201 | touch.pop() 202 | 203 | # return the result (depending what you want.) 204 | # 最后就是返回结果了 205 | return ret 206 | ``` 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | ### Touch事件的形状 217 | 218 | If the touch has a shape, it will be reflected in the ‘shape’ property. Right now, only a [`ShapeRect`](https://kivy.org/docs/api-kivy.input.shape.html#kivy.input.shape.ShapeRect "kivy.input.shape.ShapeRect") can be exposed: 219 | 220 | 如果你的Touch事件有某个形状,这个信息会反映在`shape`这一property属性中。目前能用的就是一个 [`ShapeRect`](https://kivy.org/docs/api-kivy.input.shape.html#kivy.input.shape.ShapeRect "kivy.input.shape.ShapeRect"): 221 | 222 | 223 | ```Python 224 | from kivy.input.shape import ShapeRect 225 | def on_touch_move(self, touch): 226 | if isinstance(touch.shape, ShapeRect): 227 | print('My touch have a rectangle shape of size', 228 | (touch.shape.width, touch.shape.height)) 229 | # ... 230 | ``` 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | ### 双击 241 | 242 | A double tap is the action of tapping twice within a time and a distance. It’s calculated by the doubletap post-processing module. You can test if the current touch is one of a double tap or not: 243 | 244 | 双击是一种特定动作,在一小段时间和很短的一小段特定距离内敲击两下。双击的计算识别是通过一个双击后处理模块来实现的。可以用如下代码来检测当前的Touch是否是双击动作中的一下: 245 | 246 | 247 | ```Python 248 | def on_touch_down(self, touch): 249 | if touch.is_double_tap: 250 | print('Touch is a double tap !') 251 | print(' - interval is', touch.double_tap_time) 252 | print(' - distance between previous is', touch.double_tap_distance) 253 | # ... 254 | ``` 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | ### 三次点击 265 | 266 | A triple tap is the action of tapping thrice within a time and a distance. It’s calculated by the tripletap post-processing module. You can test if the current touch is one of a triple tap or not: 267 | 268 | 三次点击和双击的概念类似,只不过是变成了点击三次。这个是通过一个三次点击后处理模块来计算识别的。可以用如下代码来检测当前的Touch是否是三次点击动作中的一下: 269 | 270 | 271 | 272 | ```Python 273 | def on_touch_down(self, touch): 274 | if touch.is_triple_tap: 275 | print('Touch is a triple tap !') 276 | print(' - interval is', touch.triple_tap_time) 277 | print(' - distance between previous is', touch.triple_tap_distance) 278 | # ... 279 | ``` 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | ### 拖放事件 292 | 293 | 父控件可能会从`on_touch_down`中分派Touch事件到子控件,而不从`on_touch_move`或`on_touch_up`分派。这可能发生在某些特定情况知悉啊,比如一个Touch处于父控件的边界之外,这样父控件就会决定不对子控件通知这个Touch。 294 | 295 | 296 | But you might want to do something in `on_touch_up`. Say you started something in the `on_touch_down` event, like playing a sound, and you’d like to finish things on the `on_touch_up` event. Grabbing is what you need. 297 | 298 | 不过有可能你还是得处理一下`on_touch_up`。比方说,你开始是`on_touch_down`事件,假设是按下播放语音之类的,然后你希望当手指抬起的时候`on_touch_up`事件发生的时候就结束任务。这时候就需要有Grab拖放事件了。 299 | 300 | 301 | When you grab a touch, you will always receive the move and up event. But there are some limitations to grabbing: 302 | 303 | 拖放一个Touch的时候,总会收到移动和抬起事件。但对拖放有如下的限制: 304 | 305 | * 至少会两次收到这个事件:一次是从父控件正常收到的事件,还有一次是从窗口获取的Grab拖放事件。 306 | 307 | * 有可能你没有进行拖放,但还是会收到一个拖放Touch事件:这可能是因为在子控件处于拖放状态时,父控件发来了一个Touch事件。 308 | 309 | * 在拖放状态下,Touch事件的坐标不会转换成控件空间的坐标,因为这个Touch事件是直接来自窗口的。所以要手动将坐标转换到本地空间。 310 | 311 | 312 | 下面这段代码展示了对拖放的使用: 313 | 314 | 315 | ```Python 316 | def on_touch_down(self, touch): 317 | if self.collide_point(*touch.pos): 318 | 319 | # if the touch collides with our widget, let's grab it 320 | touch.grab(self) 321 | 322 | # and accept the touch. 323 | return True 324 | 325 | def on_touch_up(self, touch): 326 | # here, you don't check if the touch collides or things like that. 327 | # you just need to check if it's a grabbed touch event 328 | if touch.grab_current is self: 329 | 330 | # ok, the current touch is dispatched for us. 331 | # do something interesting here 332 | print('Hello world!') 333 | 334 | # don't forget to ungrab ourself, or you might have side effects 335 | touch.ungrab(self) 336 | 337 | # and accept the last up 338 | return True 339 | ``` 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | ### Touch事件管理 350 | 351 | 352 | 想要了解更多Touch事件如何控制以及如何在控件之间传递,可以阅读一下[Widget touch event bubbling](https://kivy.org/docs/api-kivy.uix.widget.html#widget-event-bubbling)这部分内容。 353 | 354 | 355 | 356 | -------------------------------------------------------------------------------- /10-Kivy-Lang.md: -------------------------------------------------------------------------------- 1 | Title: Kivy language 2 | Date: 2017-02-23 3 | Category: Kivy 4 | Tags: Python,Kivy 5 | 6 | 7 | # Kivy中文编程指南:KV 语言 8 | 9 | 10 | [英文原文](https://kivy.org/docs/guide/lang.html) 11 | 12 | 13 | 14 | ## 语言背后的概念 15 | 16 | 17 | 18 | 随着你的应用程序越写越复杂,就往往会发现控件树的结构/各种绑定的声明等等,都越来越繁琐复杂了,维护起来也很费力气。KV 语言就是为了解决这个问题而设计出来的。 19 | 20 | (译者注:这种情况在 GUI 界面的 APP 开发中很常见,比如在 Android 开发的过程中,就用到了 xml 来定义界面元素的关系等等。) 21 | 22 | KV 语言(英文缩写也叫 kvlang 或者 kivy 语言),可以让开发者用描述的方式来创建控件树,以及绑定控件对应的属性,以实现一种自然地调用。这一设计可以允许用户能够快速建立应用雏形,然后对界面进行灵活调整。此外,这样的设计还使得运行逻辑与用户界面相互分离不干扰。 23 | 24 | ## 载入 KV 的方法 25 | 26 | 27 | 28 | 通过以下两种方法都可以在你的应用程序中载入 KV 代码: 29 | 30 | 31 | 32 | * 通过同名文件查找: 33 | Kivy 会找跟 App 类同名的小写字母的 Kv 扩展名的文件,如果你的应用类尾部有 App 字样,查找的时候会找去掉这个 App 字样的文件,例如: 34 | MyApp -> my.kv 35 | 如果这个文件定义了一个根控件,这个文件就会被添加到应用的根属性中去,然后用作整个程序的控件树基础。 36 | 37 | * `Builder`: 也可以直接指定让 Kivy 去加载某个字符串或者文件。如果这个字符串或者文件定义了一个根控件,就会被下面这个方法返回: 38 | `Builder.load_file('path/to/file.kv')`或者`Builder.load_string(kv_string)` 39 | 40 | 41 | 42 | ## 规则语义 43 | 44 | 45 | 46 | Kv 源文件包含有各种规则,这些规则是用来描述控件的环境设定的,可以有一个根规则,然后其他的各种类的或者模板的规则就都不限制数量来。 47 | 48 | 根规则是用来描述你的根控件类的,不能有任何缩进,跟着一个英文冒号:,在应用程序的实例当中这就会被设置成根属性: 49 | 50 | `Widget:` 51 | 52 | 一类规则,声明方式为将控件类的名字用尖括号括起来的,然后跟着一个英文冒号:,这类规则用来定义这个类的实例图形化呈现的方式: 53 | 54 | `<MyWidget>:` 55 | 56 | 57 | Kv 文件中各种规则都用缩进来进行区块划分,就像 Python 里面一样,这些缩进得是四个空格作为一层缩进,就跟 Python 里面推荐的做法是一样的。 58 | 59 | 60 | 以下是三个 Kv 语言的关键词: 61 | * app: 指向你应用程序的实例。 62 | * root: 指向当前规则中的基础控件或者基础模板。 63 | * self: 指向当前的控件。 64 | 65 | 66 | 67 | 68 | ## 特殊语法 69 | 70 | 71 | 有两种特殊的语法,能定义整个 Kv 环境下的各种值: 72 | 73 | 读取 Kv 中的 Python 模块和各种类: 74 | 75 | ```Python 76 | #:import name x.y.z 77 | #:import isdir os.path.isdir 78 | #:import np numpy 79 | ``` 80 | 81 | 等价于 Python 中的: 82 | 83 | ```Python 84 | from x.y import z as name 85 | from os.path import isdir 86 | import numpy as np 87 | ``` 88 | 89 | 设置各种全局变量: 90 | 91 | ```Python 92 | #:set name value 93 | ``` 94 | 95 | 等价于 Python 中的: 96 | 97 | ```Python 98 | name = value 99 | ``` 100 | 101 | 102 | 103 | ## 子对象实例化 104 | 105 | 106 | To declare the widget has a child widget, instance of some class, just declare this child inside the rule: 107 | 108 | 给一个控件声明子控件,比如某个类的实例,只要在规则内部声明一下这个子对象就可以类: 109 | 110 | 111 | ```Python 112 | MyRootWidget: 113 | BoxLayout: 114 | Button: 115 | Button: 116 | ``` 117 | 118 | 119 | 120 | 121 | 上面的样例代码定义了根控件,是一个 MyRootWidget 的实例,它有一个子控件,是一个 [`BoxLayout`](https://kivy.org/docs/api-kivy.uix.boxlayout.html) 实例。这个 [`BoxLayout`](https://kivy.org/docs/api-kivy.uix.boxlayout.html) 还有自己的两个子对向,是两个 [`Button`](https://kivy.org/docs/api-kivy.uix.button.html) 类的实例。 122 | 123 | 124 | 与上面代码等价的 Python 代码大致如下: 125 | 126 | 127 | 128 | ```Python 129 | root = MyRootWidget() 130 | box = BoxLayout() 131 | box.add_widget(Button()) 132 | box.add_widget(Button()) 133 | root.add_widget(box) 134 | ``` 135 | 136 | 你可能会发现直接用 Python 来实现的代码不那么好阅读,写起来也不那么简便。 137 | 138 | 139 | 用 Python 可以在创建控件的时候传递关键词参数过去,来指定这些控件的行为。例如下面的这个代码就是设定一个 [`gridlayout`](https://kivy.org/docs/api-kivy.uix.gridlayout.html) 中的栏目数: 140 | 141 | 142 | ```Python 143 | grid = GridLayout(cols=3) 144 | ``` 145 | 146 | 147 | 同样目的也可以用 Kv 来实现,可以直接在规则内指定好子控件的属性: 148 | 149 | 150 | 151 | ```Python 152 | GridLayout: 153 | cols: 3 154 | ``` 155 | 156 | 157 | 这个值会作为一个 Python 表达式来进行计算,然后所有在表达式中用到的属性都是可见的,就好比下面的 Python 代码一样(这里假设 self 是一个有 `ListProperty` 数据的控件): 158 | 159 | 160 | ```Python 161 | grid = GridLayout(cols=len(self.data)) 162 | self.bind(data=grid.setter('cols')) 163 | ``` 164 | 165 | 如果想要在数据修改的时候就更新显示,可以用如下方法实现: 166 | 167 | ```Python 168 | GridLayout: 169 | cols: len(root.data) 170 | ``` 171 | #### 特别注意 172 | 173 | 174 | 175 | 控件的名字一定要用大写字母打头,而属性的名字一定要用小写的。推荐遵循[PEP8 命名惯例](https://www.python.org/dev/peps/pep-0008/#naming-conventions)。 176 | 177 | 178 | 179 | ## 事件绑定 180 | 181 | 182 | 在 Kv 中,使用英文冒号 ":" 就可以来进行事件绑定,也就是将某个回调和一个事件联系起来: 183 | 184 | ```Python 185 | Widget: 186 | on_size: my_callback() 187 | ``` 188 | 189 | 190 | 使用 args 关键词的信号,就能把分派来的值传递过去类: 191 | 192 | ```Python 193 | TextInput: 194 | on_text: app.search(args[1]) 195 | ``` 196 | 197 | 还可以用更加复杂的表达式,例如: 198 | 199 | 200 | ```Python 201 | pos: self.center_x - self.texture_size[0] / 2., self.center_y - self.texture_size[1] / 2. 202 | ``` 203 | 204 | 上面这段表达式中,监听了`center_x`, `center_y`, `texture_size`这三个属性的变化。只要其中有一个发生了变化,表达式就会重新计算来更新 `pos` 的区域。 205 | 206 | 你还看以在 kv 语言中处理 `on_` 事件。例如 TextInput 这个类就有一个 `focus` 属性,这个数行自动生成的 `on_focus` 事件可在 kv 语言内进行读取: 207 | 208 | 209 | ```Python 210 | TextInput: 211 | on_focus: print(args) 212 | ``` 213 | 214 | ## 扩展画布 215 | 216 | Kv 语言也已用来定义你控件的画布,如下所示: 217 | 218 | 219 | ```Python 220 | MyWidget: 221 | canvas: 222 | Color: 223 | rgba: 1, .3, .8, .5 224 | Line: 225 | points: zip(self.data.x, self.data.y) 226 | ``` 227 | 228 | 当属性发生变化的时候,这些画布就会更新。当然也可以用 canvas.before 和 canvas.after。 229 | 230 | ## 定位控件 231 | 232 | 在一个控件树当中,经常会需要去读取或者定位其他的控件。 Kv 语言提供了一种快速的方法来实现这一目的,就是使用 id。(译者注:在 Android 的开发中就是这样的。) 233 | 可以把这些控件当作是类这以层次的变量,只能在 Kv 语言中使用。例如下面的: 234 | 235 | 236 | ```Python 237 | <MyFirstWidget>: 238 | Button: 239 | id: f_but 240 | TextInput: 241 | text: f_but.state 242 | 243 | <MySecondWidget>: 244 | Button: 245 | id: s_but 246 | TextInput: 247 | text: s_but.state 248 | ``` 249 | 250 | An `id` is limited in scope to the rule it is declared in, so in the code above `s_but` can not be accessed outside the `<MySecondWidget>` rule. 251 | 252 | `id` 只能再所处的规则内使用,也就是声明它的位置,所以在上面的代码中,`s_but` 就不能在 `<MySecondWidget>` 规则外被读取到。 253 | 254 | 255 | #### 特别注意 256 | 257 | 258 | 给一个 `id` 赋值的时候,一定要记住这个值不能是字符串。所以不能有引号:这是正确的 -> `id: value`, 这样就不对 -> `id: 'value'` 259 | `id` 是对空间的一个 `weakref` (弱引用),而不是控件本身。所以,在垃圾回收的时候要保存控件,就不能仅仅保存 `id`。 260 | 261 | 下面的代码中: 262 | 263 | ```Python 264 | <MyWidget>: 265 | label_widget: label_widget 266 | Button: 267 | text: 'Add Button' 268 | on_press: root.add_widget(label_widget) 269 | Button: 270 | text: 'Remove Button' 271 | on_press: root.remove_widget(label_widget) 272 | Label: 273 | id: label_widget 274 | text: 'widget' 275 | ``` 276 | 277 | 虽然 `MyWidget` 中已经存储了一个对 `label_widget` 的引用,但是这个只是一个弱引用,其他引用被移除的时候还不足以保证对象依然可用。因此,在移除按钮被点击(这时候也就是移除类所有对这个控件的引用)之后,或者窗口大小被调整了(这会调用垃圾回收器,导致删掉 `label_widget`),这时候如果点击添加按钮来重新把控件增加回来的话,就会有一个引用错误(`ReferenceError`)被抛出来:因为弱引用的对象已经不存在类。 278 | 279 | 280 | ```Python 281 | <MyWidget>: 282 | label_widget: label_widget.__self__ 283 | ``` 284 | 285 | ## Python 代码读取在 Kv 中定义的控件 286 | 287 | 假如在 my.kv 文件中有如下的代码: 288 | 289 | ```Python 290 | <MyFirstWidget>:: 291 | # both these variables can be the same name and this doesn't lead to 292 | # an issue with uniqueness as the id is only accessible in kv. 293 | txt_inpt: txt_inpt 294 | Button: 295 | id: f_but 296 | TextInput: 297 | id: txt_inpt 298 | text: f_but.state 299 | on_text: root.check_status(f_but) 300 | ``` 301 | 302 | 在 myapp.py 这个文件中: 303 | 304 | 305 | ```Python 306 | ... 307 | class MyFirstWidget(BoxLayout): 308 | 309 | txt_inpt = ObjectProperty(None) 310 | 311 | def check_status(self, btn): 312 | print('button state is: {state}'.format(state=btn.state)) 313 | print('text input text is: {txt}'.format(txt=self.txt_inpt)) 314 | ... 315 | ``` 316 | 317 | txt_inpt 是一个[`ObjectProperty`](https://kivy.org/docs/api-kivy.properties.html#kivy.properties.ObjectProperty "kivy.properties.ObjectProperty")对象,在类内被初始化为 None。 318 | 319 | ```Python 320 | txt_inpt = ObjectProperty(None) 321 | ``` 322 | 323 | 324 | 目前位置,这个 self.txt_inpt 还是 None。在 Kv 语言中,这个属性会进行更新,保存 txt_input 这个 id 所引用的 `TextInput` 实例: 325 | 326 | 327 | ```Python 328 | txt_inpt: txt_inpt 329 | ``` 330 | 331 | 从这以后,self.txt_inpt 久保存了一个到控件的引用,通过 txt_input 这个 id 来识别,可以在类内的各个地方来使用,就跟在 check_status 函数里一样。当然也可以不这么做,可以把 id 传给需要用到它的函数,例如上面代码中那个 f_but 这个例子。 332 | 333 | 通过 id 标签,在 kv 语言中可以查找对象,这是一种更简单的读取对象的方法。比如下面这段代码: 334 | 335 | 336 | ```Python 337 | <Marvel> 338 | Label: 339 | id: loki 340 | text: 'loki: I AM YOUR GOD!' 341 | Button: 342 | id: hulk 343 | text: "press to smash loki" 344 | on_release: root.hulk_smash() 345 | ``` 346 | 347 | 348 | 在你的 Python 代码中: 349 | ```Python 350 | class Marvel(BoxLayout): 351 | def hulk_smash(self): 352 | self.ids.hulk.text = "hulk: puny god!" 353 | self.ids["loki"].text = "loki: >_ # alternative syntax 354 | ``` 355 | 356 | 当你的 kv 文件被解析的时候,kivy 会选中所有带有标签 id 的控件,然后把它们放到 self.ids 这样一个辞典类型的属性里面去。所以你就可以对这些控件进行遍历,然后像是辞典数据一样来进行读取类: 357 | 358 | 359 | ```Python 360 | for key, val in self.ids.items(): 361 | print("key={0}, val={1}".format(key, val)) 362 | ``` 363 | 364 | #### 特别注意 365 | 366 | 虽然这种 self.ids 方法非常简便,但通常最推荐的还是用对象属性。这样会创建一个直接的引用,能提供更快地读取速度,并且也更加准确可靠。 367 | 368 | ## 动态类型 369 | 370 | 参考下面的代码: 371 | ```Python 372 | <MyWidget>: 373 | Button: 374 | text: "Hello world, watch this text wrap inside the button" 375 | text_size: self.size 376 | font_size: '25sp' 377 | markup: True 378 | Button: 379 | text: "Even absolute is relative to itself" 380 | text_size: self.size 381 | font_size: '25sp' 382 | markup: True 383 | Button: 384 | text: "Repeating the same thing over and over in a comp = fail" 385 | text_size: self.size 386 | font_size: '25sp' 387 | markup: True 388 | Button: 389 | ``` 390 | 391 | 如果这里使用一个模板,就不用那么麻烦地去重复对每一个按钮进行设置了,例如下面这样就可以了: 392 | 393 | ```Python 394 | <MyBigButt@Button>: 395 | text_size: self.size 396 | font_size: '25sp' 397 | markup: True 398 | 399 | <MyWidget>: 400 | MyBigButt: 401 | text: "Hello world, watch this text wrap inside the button" 402 | MyBigButt: 403 | text: "Even absolute is relative to itself" 404 | MyBigButt: 405 | text: "repeating the same thing over and over in a comp = fail" 406 | MyBigButt: 407 | ``` 408 | 409 | 上面这个类是在这个规则的声明内建立的,继承了按钮类 Button,然后我们就可以用这个类来对默认值进行修改,并且建立所有实例的链接绑定,而不用在 Python 弄一大堆新代码了。 410 | 411 | ## 在多个控件中复用样式 412 | 413 | 参考下面的代码,在 my.kv 文件中: 414 | ```Python 415 | <MyFirstWidget>: 416 | Button: 417 | on_press: root.text(txt_inpt.text) 418 | TextInput: 419 | id: txt_inpt 420 | 421 | <MySecondWidget>: 422 | Button: 423 | on_press: root.text(txt_inpt.text) 424 | TextInput: 425 | id: txt_inpt 426 | ``` 427 | 428 | 429 | 在 myapp.py 这个文件中: 430 | 431 | ```Python 432 | class MyFirstWidget(BoxLayout): 433 | def text(self, val): 434 | print('text input text is: {txt}'.format(txt=val)) 435 | 436 | class MySecondWidget(BoxLayout): 437 | writing = StringProperty('') 438 | def text(self, val): 439 | self.writing = val 440 | ``` 441 | 442 | 好多类都要用到同样的 .kv 样式文件,这样就可以通过让所有控件都对样式进行复用,就能简化一下设计。这就可以在 kv文件中来实现。例如下面这个就是 my.kv 文件中的代码: 443 | 444 | 445 | ```Python 446 | <MyFirstWidget,MySecondWidget>: 447 | Button: 448 | on_press: self.text(txt_inpt.text) 449 | TextInput: 450 | id: txt_inpt 451 | ``` 452 | 只要把各个类的名字用英文冒号:分隔开,声明当中包含的类就都会使用相同的 kv 属性了。 453 | 454 | ## 使用 Kivy 语言来设计 455 | Kivy 语言的设计目标之一就是希望能够[做好分工](https://en.wikipedia.org/wiki/Separation_of_concerns),把界面和内部逻辑相互分离。输出的样式由你的 kv 文件来确定,运行逻辑靠你的 python 代码来执行。 456 | 457 | ### Python 文件中的代码 458 | 459 | 来一个简单的小例子。首先要有一个名字为 main.py 的 Python 源文件: 460 | 461 | ```Python 462 | import kivy 463 | kivy.require('1.0.5') 464 | 465 | from kivy.uix.floatlayout import FloatLayout 466 | from kivy.app import App 467 | from kivy.properties import ObjectProperty, StringProperty 468 | 469 | class Controller(FloatLayout): 470 | ''' 471 | 创建一个控制器,从 kv 文件中接收一个定制的控件。 472 | 增加一个由 kv 文件进行调用的动作。 473 | ''' 474 | label_wid = ObjectProperty() 475 | info = StringProperty() 476 | def do_action(self): 477 | self.label_wid.text = 'My label after button press' 478 | self.info = 'New info text' 479 | 480 | class ControllerApp(App): 481 | def build(self): 482 | return Controller(info='Hello world') 483 | 484 | if __name__ == '__main__': 485 | ControllerApp().run() 486 | ``` 487 | 488 | 刚刚这个代码样例中,我们创建了一个有两个属性的控制器: 489 | 490 | * `info` 该属性用于接收文本 491 | * `label_wid` 该属性用于接收文本标签控件 492 | 493 | 此外还创建了一个 `do_action()` 方法,这个方法会使用上面的属性。这个方法会改变 `info`里面的文本,以及 `label_wid` 控件中的文本。 494 | 495 | ### controller.kv 文件中的布局样式 496 | 497 | 没有对应的 kv 文件,应用程序也能运行,只不过是屏幕上不会有任何显示输出。这个是符合情理的,因为毕竟控制器 `Controller` 这个类是没有任何控件的,就只是一个`FloatLayout`(流动输出?)咱们可以创建一个名字为 controller.kv 的文件,来围绕着这个控制器类 `Controller` 搭建 UI (用户界面),这个文件会在运行 `ControllerApp` 的时候被加载。这个具体怎么实现的,以及加载类哪些文件,可以参考 [`kivy.app.App.load_kv()`](https://kivy.org/docs/api-kivy.app.html#kivy.app.App.load_kv "kivy.app.App.load_kv") 方法里的描述。 498 | 499 | 500 | ```Python 501 | #:kivy 1.0 502 | <Controller>: 503 | label_wid: my_custom_label 504 | 505 | BoxLayout: 506 | orientation: 'vertical' 507 | padding: 20 508 | 509 | Button: 510 | text: 'My controller info is: ' + root.info 511 | on_press: root.do_action() 512 | 513 | Label: 514 | id: my_custom_label 515 | text: 'My label before button press' 516 | ``` 517 | 518 | 519 | 520 | 上面的代码中就是一个竖直的箱式布局(BoxLayout)。看着就挺简单的。这个代码主要功能有以下三个: 521 | 522 | 1 使用来自控制器类 Controller 的数据。只要 controller 中的 info 属性发生了改变,表达式 'My controller info is: ' + root.info 就会自动重新计算,改变按钮(Button)上面的值。 523 | 524 | 2 传递数据给控制器类 Controller。my_custom_label 这个 id 会赋值给 id 为 my_custom_label 的新建文本标签(Label)。此后,使用 label_wid:my_custom_label 中的 my_custom_label 就能得到一个控制器中的 Label 控件实例了。 525 | 526 | 3 在按钮 Button 中使用控制器类 Controller 的 on_press 方法来创建一个自定义回调。 527 | root 和 self 都是保留关键词,任何地方都不可见的。root 代表的是规则中的顶层控件,self 表示的是当前控件。 528 | 你可以在当前规则中使用任意的已经声明过的 id, root 和 self 也可以这样来用。比如下面就是在 on_press() 里面使用 root: 529 | 530 | 531 | 532 | ```Python 533 | Button: 534 | on_press: root.do_action(); my_custom_label.font_size = 18 535 | ``` 536 | 537 | 就这么多了。现在当我们再次运行 main.py的时候,controller.kv 就会被加载,然后 Button 按钮和 Label 文本标签就会出现,并且根据触摸事件进行响应了。 538 | 539 | 540 | -------------------------------------------------------------------------------- /06-Kivy-Events and Properties.md: -------------------------------------------------------------------------------- 1 | Title: Kivy Events and Properties 2 | Date: 2017-02-9 3 | Category: Kivy 4 | Tags: Python,Kivy 5 | 6 | 7 | # Kivy中文编程指南:事件和属性 8 | 9 | [英文原文](https://kivy.org/docs/guide/events.html) 10 | 11 | ## 译者前言 12 | 这一章节是我有史以来翻译质量的低谷,一来是我自己也是刚学,半懂不懂,二来本身语言基础各方面也薄弱,三来是笔记本坏掉了,搞个ChromeOS折腾中。 13 | 14 | 大家凑合看看,看不下去给指出来一下比较不好理解和绕的地方,以及错误的地方,我一定即时修改。 15 | 16 | 17 | 18 | ## 简要介绍 19 | 20 | 在Kivy开发过程中,事件是最重要的一部分了。如果之前有过GUI图形界面开发的经验的话,你可能对此习以为常了,但对新手来说,这个概念很重要。一旦你理解了事件的应用和搭配,你就会发现在Kivy开发的过程中,事件是无处不在的。有了各种事件的搭配,你就可以用Kivy来搭建你想要的各种功能了。 21 | 22 | 23 | 24 | 下面这幅图展示了Kivy框架中事件的处理过程: 25 | 26 | ![../_images/Events.png](http://kivy.org/docs/_images/Events.png) 27 | 28 | ![Events_zh](https://user-images.githubusercontent.com/58334061/208930458-4a4cc4eb-1025-4ea1-950f-73108d64c386.jpg) 29 | 30 | 31 | 32 | 33 | ## 事件分发器 34 | 35 | 36 | 37 | 38 | 事件分发器[EventDispatcher](http://kivy.org/docs/api-kivy.event.html#kivy.event.EventDispatcher "kivy.event.EventDispatcher") c是Kivy框架中最重要的基类之一。通过这个类,用户可以注册各种事件,然后分发给对应的部件(一般情况下是其他的事件分发器)。控件类[Widget](http://kivy.org/docs/api-kivy.uix.widget.html#kivy.uix.widget.Widget "kivy.uix.widget.Widget"), 动画类[Animation](http://kivy.org/docs/api-kivy.animation.html#kivy.animation.Animation "kivy.animation.Animation") 以及时间类[Clock](http://kivy.org/docs/api-kivy.clock.html#kivy.clock.Clock "kivy.clock.Clock") 都属于事件分发器。 39 | 40 | 41 | 42 | 事件分发器对象要在整个程序的循环流程的基础上来生成和处理各种事件。 43 | 44 | 45 | 46 | ## 主流程 47 | 48 | 上文的简介概括起来是说,Kivy有一个主循环体。这个循环体会在Kivy应用的整个生命周期中一直运行,直到退出应用的时候才结束。 49 | 50 | 在循环内部,每一步迭代都伴随有各种事件生成,这些事件可以来自用户输入、硬件传感器,或者是其他的各种来源,然后一帧一帧地渲染到屏幕上。 51 | 52 | 你写的应用程序将要指定好各种由主循环进行调用而产生的**回调**(callback,稍后再详细介绍相关内容)。如果一次**回调**花费很长时间或者根本不退出,主循环就被打破了,你的应用也就不能正常工作了。 53 | 54 | 在Kivy应用里面,一定要避免用特别长的循环、无限循环,或者休眠。下面这个代码就同时是死循环+休眠,就是一个反例了: 55 | 56 | 57 | ```Python 58 | while True: 59 | animate_something() 60 | time.sleep(.10) 61 | ``` 62 | 63 | 如果把上面这段代码拿去运行,那程序就会无法退出循环了,就让Kivy卡住了,什么后续步骤都不能进行了。用户就只能看到一个黑色的窗口,什么操作都没有响应。不能死循环也不能休眠,所以就得想其他办法,比如有计划地重复调用对animate_something()这样的函数。(animate_something 的意思是让某个东西动起来,作者是用来指代类似的这种需要时不时重复调用的函数。) 64 | 65 | 66 | 67 | 68 | ### 计划周期事件 69 | 70 | 71 | 利用schedule_interval()这个函数,你就可以每秒对某个函数或者方法进行指定次数的调用了。下面就是一个例子,在这段代码的第三行,实现了每秒钟调用my_callback(dt)函数三十次: 72 | 73 | ```Python 74 | def my_callback(dt): 75 | print 'My callback is called', dt 76 | event = Clock.schedule_interval(my_callback, 1 / 30.) 77 | #译者注:这里的1/30明显就是频率的倒数了,如果是每秒钟50次就应该是1/50,以此类推了,大家可以自己修改试试看。 78 | ``` 79 | 80 | 要取消之前的计划事件有多种方法。可以用cancel(),也可以用 unschedule(): 81 | 82 | ```Python 83 | event.cancel() 84 | 85 | #或者用下面这种方法 86 | 87 | Clock.unschedule(event) 88 | ``` 89 | 90 | 再有一种方法,就是在回调的时候返回False,这样这个事件就会被自动取消计划,不再重复: 91 | 92 | 93 | ``` Python 94 | count = 0 95 | def my_callback(dt): 96 | global count 97 | count += 1 98 | if count == 10: 99 | print 'Last call of my callback, bye bye !' 100 | return False 101 | print 'My callback is called' 102 | Clock.schedule_interval(my_callback, 1 / 30.) 103 | ``` 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | ### 计划一次性事件 113 | 114 | 使用schedule_once()函数,可以对一个函数**稍后调用**的效果,可以是在下一帧,也可以是在指定时间X之后: 115 | 116 | 117 | ```Python 118 | def my_callback(dt): 119 | print 'My callback is called !' 120 | Clock.schedule_once(my_callback, 1) 121 | ``` 122 | 上面这段代码会在一秒钟后再对my_callback(dt)进行调用。schedule_once()函数的第二个变量X就是延迟调用的时间,以秒为单位。具体这个变量的用法有以下三种: 123 | 124 | * 若X大于零,则作为时间长度的秒数,延迟X秒之后进行下一次调用 125 | * 若X等于零,则在下一帧进行调用 126 | * 若X为-1,调用则发生在下一帧渲染之前 127 | 128 | 假如你已经有了一个计划事件,但又想要在下一帧渲染之前计划一次调用,这种情况就适合使用-1这种用法。 129 | 130 | 131 | 这里就有了一种衍生出来的重复调用某个函数的方法,就是在函数体内放一个schedule_once(),然后在第二次调用该函数的时候,函数内的schedule_once()就会继续对本身进行调用了: 132 | 133 | 134 | ```Python 135 | def my_callback(dt): 136 | print 'My callback is called !' 137 | Clock.schedule_once(my_callback, 1) 138 | Clock.schedule_once(my_callback, 1) 139 | ``` 140 | 141 | 主循环会一直按照代码的要求来保持各种计划调用的实现,但一次计划调用发生的具体时间是具有一些不确定性的。有时候其他的调用或者应用中的其他任务可能会比想象中执行得更久一些,这时候用计时的方法制定计划就不太合适了。 142 | 143 | 后面介绍的这种用内置schedule_once()来进行重复回调问题的解决方案中,在最后一次迭代结束后,下一次迭代将至少要一秒之后才能被调用。 而使用schedule_interval()这种方法就可以每秒都进行回调。 144 | 145 | 146 | ### 触发事件 147 | 148 | 149 | 有时候可能一个函数只需要计划在下一帧调用一次,而不允许重复调用。这时候就可以用下面这样的思路来实现: 150 | 151 | ```Python 152 | 153 | # 首先是用schedule_once()计划调用一次 154 | event = Clock.schedule_once(my_callback, 0) 155 | 156 | # 然后在另外一个位置,就用unschedule()取消计划调用,这样就能避免重复调用。接下来就是再次用schedule_once()进行计划调用。 157 | Clock.unschedule(event) 158 | event = Clock.schedule_once(my_callback, 0) 159 | 160 | #译者注:我这部分理解的也不够深,翻译得很生硬,我的大概理解就是这样可以精确控制调用次数,避免一次计划调用之后发生的调用次数不可控。 161 | ``` 162 | 163 | 上面这种方法构建触发器可谓费时费力,因为你得经常用到unschedule,即使一个事件已经结束。此外,每次还都产生新事件。所以可以用下面这个trigger()来作为触发器: 164 | 165 | 166 | ```Python 167 | trigger = Clock.create_trigger(my_callback) 168 | # later 169 | trigger() 170 | ``` 171 | 172 | 173 | 这样你每次调用trigger()就可以了,这个触发器会对你的my_callback回调进行单次计划调用。如果之前存在计划调用了,则不重新产生计划调用。 174 | 175 | 176 | 177 | 178 | 179 | ## 控件事件 180 | 181 | 控件有两种默认事件: 182 | 183 | * 属性事件:比如你的控件改变了位置或者大小,就会触发一个事件。 184 | 185 | * 控件定义的事件:比如一个Button按钮控件被按下或者松开,也会触发一个事件。 186 | 187 | 188 | 关于控件的Touch事件的管理和传播,可以参考[API文档中这部分相关内容](http://kivy.org/docs/api-kivy.uix.widget.html#widget-event-bubbling)。 189 | 190 | 191 | 192 | ## 创建自定义事件 193 | 194 | 195 | 要使用自定义事件创建事件分发器,需要首先在类中注册事件名称,然后创建同名的方法。 196 | 197 | 例如下面这段代码所示: 198 | 199 | ```Python 200 | class MyEventDispatcher(EventDispatcher): 201 | def __init__(self, **kwargs): 202 | self.register_event_type('on_test') 203 | super(MyEventDispatcher, self).__init__(**kwargs) 204 | 205 | def do_something(self, value): 206 | # when do_something is called, the 'on_test' event will be 207 | # dispatched with the value 208 | self.dispatch('on_test', value) 209 | 210 | def on_test(self, *args): 211 | print "I am dispatched", args 212 | ``` 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | ## 附加回调 223 | 224 | 225 | 226 | 要利用一个事件,必须要对其绑定回调。当事件被分发的时候,该特定事件相关的参数将被用于调用回调。 227 | 228 | 回调可以使Python中能进行调用的任意内容,函数或者方法都可以,但一定要确保回调要接收**事件**发出的参数。最安全的常规做法是接收* args参数,将所有参数都存放成一个参数列表。 229 | 230 | 231 | 例如: 232 | 233 | ```Python 234 | def my_callback(value, *args): 235 | print "Hello, I got an event!", args 236 | 237 | ev = MyEventDispatcher() 238 | ev.bind(on_test=my_callback) 239 | ev.do_something('test') 240 | ``` 241 | 242 | 243 | 244 | 245 | 246 | 请阅读参考 [kivy.event.EventDispatcher.bind()](http://kivy.org/docs/api-kivy.event.html#kivy.event.EventDispatcher.bind "kivy.event.EventDispatcher.bind") 方法的文档来查看更多附加调用相关的样例。 247 | 248 | 249 | 250 | 251 | ## 简介属性Properties 252 | 253 | 254 | >群友`十月的天空` 提示:attribute 和 property 都翻译成了 属性, 字面上确实没错,但是读起来就莫名其妙了。 从本质上讲 property是 kivy 特色,个人理解 property 包含于attitude 而且绑定 widget 类,是否可以翻译成`控件属性` 或者 `构件属性` 之类。 255 | 256 | `控件属性`(Properties)是定义和绑定事件的一种很赞的办法。关键就是属性能生成事件,这样当你的某个对象中有一个属性(attribute)发生改变的时候,所有引用该属性(attribute)的`控件属性`(Properties)都会被自动更新 257 | 258 | 译者注:我汉语词汇量匮乏了,很痛苦,这里说不明白了,所以就放了原文的单词作为对比,避免混淆了。 259 | 260 | 261 | 262 | 针对你要处理的数据类型,存在很多种不同类型的`控件属性`性(Properties): 263 | 264 | * [字符串属性StringProperty](http://kivy.org/docs/api-kivy.properties.html#kivy.properties.StringProperty "kivy.properties.StringProperty") 265 | * [数值属性NumericProperty](http://kivy.org/docs/api-kivy.properties.html#kivy.properties.NumericProperty "kivy.properties.NumericProperty") 266 | * [有界数值属性BoundedNumericProperty](http://kivy.org/docs/api-kivy.properties.html#kivy.properties.BoundedNumericProperty "kivy.properties.BoundedNumericProperty") 267 | * [对象属性ObjectProperty](http://kivy.org/docs/api-kivy.properties.html#kivy.properties.ObjectProperty "kivy.properties.ObjectProperty") 268 | * [词典属性DictProperty](http://kivy.org/docs/api-kivy.properties.html#kivy.properties.DictProperty "kivy.properties.DictProperty") 269 | * [列表属性ListProperty](http://kivy.org/docs/api-kivy.properties.html#kivy.properties.ListProperty "kivy.properties.ListProperty") 270 | * [选项属性OptionProperty](http://kivy.org/docs/api-kivy.properties.html#kivy.properties.OptionProperty "kivy.properties.OptionProperty") 271 | * [别名属性AliasProperty](http://kivy.org/docs/api-kivy.properties.html#kivy.properties.AliasProperty "kivy.properties.AliasProperty") 272 | * [布尔属性BooleanProperty](http://kivy.org/docs/api-kivy.properties.html#kivy.properties.BooleanProperty "kivy.properties.BooleanProperty") 273 | * [引用属性ReferenceListProperty](http://kivy.org/docs/api-kivy.properties.html#kivy.properties.ReferenceListProperty "kivy.properties.ReferenceListProperty") 274 | 275 | 276 | 277 | 278 | 279 | ## 属性声明 280 | 281 | 要声明`控件属性`(Properties),必须要在类的层次上进行声明。接下来这个类才能在你创建对象的时候对真是的属性(attributes)进行实例化。此`控件属性`(Properties)非彼属性(attributes),`控件属性` Properties是根据你的attributes来创建事件的机制,例如: 282 | 283 | 284 | ```Python 285 | class MyWidget(Widget): 286 | text = StringProperty('') 287 | ``` 288 | 289 | 290 | 291 | 当覆盖初始化方法__init__的时候,**一定要**接收**kwargs做参数,并且一定要用super()来调用基类的初始化方法__init__,传递自定义类的实例过去: 292 | 293 | ```Python 294 | def __init__(self, **kwargs): 295 | super(MyWidget, self).__init__(**kwargs) 296 | ``` 297 | 298 | 299 | 300 | ## 分发属性事件 301 | 302 | 303 | Kivy的`控件属性`Property,默认提供了一个on_事件。在属性被改变的时候,就会调用这个事件了。 304 | 305 | 306 | #### 特别注意 307 | 308 | 如果属性的新值与当前已有的值相等,那么on_事件就不会被调用了。 309 | 310 | 例如下面这段代码: 311 | 312 | ```Python 313 | class CustomBtn(Widget): 314 | 315 | pressed = ListProperty([0, 0]) 316 | 317 | def on_touch_down(self, touch): 318 | if self.collide_point(*touch.pos): 319 | self.pressed = touch.pos 320 | return True 321 | return super(CustomBtn, self).on_touch_down(touch) 322 | 323 | def on_pressed(self, instance, pos): 324 | print ('pressed at {pos}'.format(pos=pos)) 325 | ``` 326 | 327 | 328 | 329 | 上面代码的第三行中: 330 | 331 | 332 | ```Python 333 | pressed = ListProperty([0, 0]) 334 | ``` 335 | 336 | 337 | 这一句中,基于[ListProperty](http://kivy.org/docs/api-kivy.properties.html#kivy.properties.ListProperty "kivy.properties.ListProperty")定义了一个pressed按下的属性,默认值是[0,0]。从这往后,只要这个属性被改变了,on_presses事件就会被调用。 338 | 339 | 340 | 341 | 第五行有如下代码: 342 | 343 | ```Python 344 | def on_touch_down(self, touch): 345 | if self.collide_point(*touch.pos): 346 | self.pressed = touch.pos 347 | return True 348 | return super(CustomBtn, self).on_touch_down(touch) 349 | ``` 350 | 351 | 352 | 353 | 这部分代码覆盖了控件类的_touch_down()方法。这段代码中,用控件对touch触碰的位置进行了检测。 354 | 355 | 356 | 如果touch的位置在控件范围内,就把pressed的值改变成touch.pos这个值,然后返回True,这表明程序已经处理好了这个touch了,就把这个touch消耗掉了,不用再传播了。 357 | 358 | 359 | 360 | 如果touch的位置在控件外部,就通过super(...)了调用原始事件,并返回结果。这就和常规情况一样了,touch事件会被继续传递下去。 361 | 362 | 363 | 在第十一行: 364 | 365 | ```Python 366 | def on_pressed(self, instance, pos): 367 | print ('pressed at {pos}'.format(pos=pos)) 368 | ``` 369 | 370 | 371 | 这里定义了一个on_pressed函数,只要属性值发生改变了,这个函数就会被调用。 372 | 373 | 374 | 375 | #### 特别注意 376 | 377 | 378 | 这个on_事件是在类内定义属性的位置被调用。在定义该属性的类之外,若要监控/观察一个属性的任何变动,就必须丢这个属性进行bind绑定操作。 379 | 380 | 381 | 只能读取到一个控件实例的时候,要怎么去监控属性的变化呢?这时候用**bind**绑定一下属性就行了: 382 | 383 | 384 | ```Python 385 | your_widget_instance.bind(property_name=function_name) 386 | ``` 387 | 388 | 389 | 390 | 391 | 例如下面这段代码: 392 | 393 | 394 | ```Python 395 | class RootWidget(BoxLayout): 396 | 397 | def __init__(self, **kwargs): 398 | super(RootWidget, self).__init__(**kwargs) 399 | self.add_widget(Button(text='btn 1')) 400 | cb = CustomBtn() 401 | cb.bind(pressed=self.btn_pressed) 402 | self.add_widget(cb) 403 | self.add_widget(Button(text='btn 2')) 404 | 405 | def btn_pressed(self, instance, pos): 406 | print ('pos: printed from root widget: {pos}'.format(pos=.pos)) 407 | 408 | ``` 409 | 410 | 411 | 如果运行上面这段代码,会发现有两次print输出语句出现在控制台中。第一个是来自_pressed事件,在CustomBtn类内部调用;另外一次print是来自我们用bind绑定到了属性变化上的btn_pressed函数。 412 | 413 | (译者注:在用bind绑定了之后,属性的变化都会通过bind的函数被看到了。) 414 | 415 | 两个函数都被调用的原因很简单。Bind绑定操作并不意味着覆盖。这两个函数同时保留就冗余了,所以一般情况你只选择一个来对属性变化进行监听/反应就行了。 416 | 417 | 418 | 你还得注意一下传递给on_事件或者绑定到属性的函数的参数。 419 | 420 | 421 | ```Python 422 | def btn_pressed(self, instance, pos): 423 | ``` 424 | 425 | 426 | 427 | 428 | 第一个参数是self,这就是该函数所在类本身的一个实例。也可以用内联函数,如下代码所示: 429 | 430 | 431 | ```Python 432 | cb = CustomBtn() 433 | 434 | def _local_func(instance, pos): 435 | print ('pos: printed from root widget: {pos}'.format(pos=pos)) 436 | 437 | cb.bind(pressed=_local_func) 438 | self.add_widget(cb) 439 | ``` 440 | 441 | 442 | 第一个参数是定义属性的类的实例。第二个参数是一个值,这个值是属性的新值。 443 | 上面那一段只是代码片段,下面这一段代码是完整的样例了,可以复制粘贴到编辑器里面然后测试一下: 444 | 445 | ```Python 446 | from kivy.app import App 447 | from kivy.uix.widget import Widget 448 | from kivy.uix.button import Button 449 | from kivy.uix.boxlayout import BoxLayout 450 | from kivy.properties import ListProperty 451 | 452 | class RootWidget(BoxLayout): 453 | 454 | def __init__(self, **kwargs): 455 | super(RootWidget, self).__init__(**kwargs) 456 | self.add_widget(Button(text='btn 1')) 457 | cb = CustomBtn() 458 | cb.bind(pressed=self.btn_pressed) 459 | self.add_widget(cb) 460 | self.add_widget(Button(text='btn 2')) 461 | 462 | def btn_pressed(self, instance, pos): 463 | print ('pos: printed from root widget: {pos}'.format(pos=pos)) 464 | 465 | class CustomBtn(Widget): 466 | 467 | pressed = ListProperty([0, 0]) 468 | 469 | def on_touch_down(self, touch): 470 | if self.collide_point(*touch.pos): 471 | self.pressed = touch.pos 472 | # we consumed the touch. return False here to propagate 473 | # the touch further to the children. 474 | return True 475 | return super(CustomBtn, self).on_touch_down(touch) 476 | 477 | def on_pressed(self, instance, pos): 478 | print ('pressed at {pos}'.format(pos=pos)) 479 | 480 | class TestApp(App): 481 | 482 | def build(self): 483 | return RootWidget() 484 | 485 | if __name__ == '__main__': 486 | TestApp().run() 487 | 488 | 489 | ``` 490 | 491 | 492 | 493 | 运行上面这段完整的样例代码,会得到如下图所示的输出: 494 | 495 | ![../_images/property_events_binding.png](http://kivy.org/docs/_images/property_events_binding.png) 496 | 497 | 498 | 咱们这个CustomBtn没有做任何视觉上的调整,所以就是个大黑块。你可以触摸/点击这个黑色的区域,来看看控制台里面的输出。 499 | 500 | 501 | ## 复合属性 502 | 503 | 504 | 定义一个[别名属性AliasProperty](http://kivy.org/docs/api-kivy.properties.html#kivy.properties.AliasProperty "kivy.properties.AliasProperty")的时候,通常要定义一个getter函数和一个setter函数,前者用来读取值,后者用来设定值。这时候,你就得通过bind绑定参数来确定好getter和setter函数的调用时间。 505 | 506 | 507 | 例如下面这段代码: 508 | 509 | ```Python 510 | cursor_pos = AliasProperty(_get_cursor_pos, None, bind=( 511 | 'cursor', 'padding', 'pos', 'size', 'focus', 512 | 'scroll_x', 'scroll_y')) 513 | '''Current position of the cursor, in (x, y). 514 | 515 | :attr:`cursor_pos` is a :class:`~kivy.properties.AliasProperty`, read-only. 516 | ''' 517 | ``` 518 | 519 | 520 | 这里的cursor_pos(光标位置的意思)就是一个[别名属性AliasProperty](http://kivy.org/docs/api-kivy.properties.html#kivy.properties.AliasProperty "kivy.properties.AliasProperty"),它有一个getter函数,名为_get_cursor_pos(),然后没有设置setter函数,这就说明这个属性是**只读**的。 521 | 522 | 最末尾那一段的bind参数的意思是,当在bind=这个等号后括号内的属性中有任意的一个发生变化,都会分发on_cursor_pos事件。 523 | -------------------------------------------------------------------------------- /01-Kivy-Installation.md: -------------------------------------------------------------------------------- 1 | Title: Kivy Installment Tutorial 2 | Date: 2016-12-30 3 | Category: Kivy 4 | Tags: Python,Kivy 5 | 6 | 7 | # Kivy 中文安装指南 8 | 9 | 译者的话: 10 | 接触Python有一段时间了,之前翻译过[ThinkPython2E](https://zhuanlan.zhihu.com/p/24644499),我也仍然还是个很菜很弱很入门的外行人。 11 | 我接下来翻译的关于Kivy的各种内容,不出意外的话也必将充满了各种低级错误。 12 | 如果这些错误有影响到大家阅读理解,提前表示一下歉意。 13 | 特别希望大家能把错误的地方指出来,让我学习的同时也及时改正。 14 | 我的编程水平很差,然而我热爱计算机这一工具,所以我喜欢做各种探索; 15 | 我的英语水平也差,不过我喜欢从英语世界发现有意思的事物并且分享给中文世界的朋友们。 16 | 本次翻译将仅仅翻译官方正式版部分的安装指南,每夜版以及更进阶的安装内容,不做翻译。 17 | 为什么呢? 18 | 一来是我自身水平有限,二来你都折腾每夜版了还不好好学英文还要看别人翻译也太不靠谱了对不对? 19 | 20 | 以下是对 Kivy 官方网站安装文档部分的翻译,下面三个链接是原文地址: 21 | [Installation on Windows](https://kivy.org/docs/installation/installation-windows.html) 22 | [Installation on Linux](https://kivy.org/docs/installation/installation-linux.html) 23 | [Installation on Mac OS](https://kivy.org/docs/installation/installation-osx.html) 24 | 25 | # [Windows系统安装Kivy指南](https://kivy.org/docs/installation/installation-windows.html) 26 | 27 | 自从1.9.1版本开始,Kivy 官方提供了二进制 [wheels](https://wheel.readthedocs.org/en/latest/) 文件,可以用安装Kivy以及所需的一切依赖包到一个已经安装好的Python环境中,在下文会有讲解。 28 | 29 | 此外还有每夜版wheels文件,可供用户安装,或者用于将之前安装的Kivy更新到新版本;另外本文的后文中也会讲解如何将Kivy安装到**自定义位置**,而不是安装到默认的site-packages文件夹。 30 | 31 | 32 | ####特别注意 33 | 34 | 【译者注:这段内容是对官方文档比较忠实的翻译和还原,其中提到的MinGW和Python3.5的兼容问题,翻译者没遇到也没有测试过,因为没有Windows的机器。在Mac和Linux上3.5和3.6都成功安装了Kivy,运行过程也没发现问题。】 35 | 36 | 37 | 目前因为MinGW和Python3.5的兼容问题,在Windows平台上还没有办法通过Python3.5来使用Kivy,至少相当一段时间内是没指望了,更多细节参考[这里的这个issue](http://bugs.python.org/issue4709)。 想要解决这个问题,需要用MSVC来编译的3.5,不过目前还没能实现,所以如果你搞定了MSVC编译的话一定反馈一下。 38 | 39 | 40 | ##必要前提 41 | 42 | 要使用Kivy,首先就得安装[Python](https://www.python.org/downloads/windows/)。Python有好多版本,你可以同时安装其中的好多个,如果你在其中某一个版本的Python里面要使用Kivy,就要在这个版本里面单独按照一次Kivy,其他版本要使用Kivy需要另外再进行安装,就是说每一次安装Kivy只对一份Python环境有效。 43 | 44 | 45 | 46 | 47 | ## 安装过程 48 | 49 | 安装了Python之后,打开命令行工具cmd,然后按照下面的命令来进行Kivy的安装。 50 | 51 | 1 首先要保证已经安装了最新的pip和wheel: 52 | 53 | ```Bash 54 | python -m pip install --upgrade pip wheel setuptools 55 | ``` 56 | 57 | 58 | 59 | 60 | 2 然后安装必要的依赖包(其中gstreamer大小接近90MB,如果不需要用,就可以跳过不安装这个包: 61 | 62 | 63 | 64 | ```Python 65 | python -m pip install docutils pygments pypiwin32 kivy.deps.sdl2 kivy.deps.glew 66 | python -m pip install kivy.deps.gstreamer --extra-index-url https://kivy.org/downloads/packages/simple/ 67 | ``` 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 3 如果上一步都成功了没什么报错,就可以按照Kivy了: 77 | 78 | 79 | 80 | 81 | ```Bash 82 | python -m pip install kivy 83 | ``` 84 | 85 | 86 | 87 | 88 | 89 | 4 在环境变量中添加一些路径到PATH来避免遇到[各种issues](https://github.com/kivy/kivy/issues/3957) (在你的python.exe所在的路径下运行下面的命令): 90 | 91 | 92 | 93 | 94 | ```Bash 95 | set PATH=%PATH%;%cd%\share\sdl2\bin;%cd%\share\glew\bin 96 | ``` 97 | 98 | 99 | 100 | 101 | 到现在为止就搞定了,你就可以在这份Python环境中通过import kivy命令来导入和使用Kivy了。 102 | 103 | 104 | 105 | ####特别注意 106 | 107 | 如果你遇到了**permission denied**或者**访问被拒绝**之类的错误提示,你可以试试[以管理员权限来运行命令行工具cmd](https://technet.microsoft.com/en-us/library/cc947813%28v=ws.10%29.aspx)。 108 | 109 | 110 | 111 | # [Linux系统安装Kivy指南](https://kivy.org/docs/installation/installation-linux.html) 112 | 113 | 114 | 115 | ## 使用包管理器进行安装 116 |   117 | 本节是给各种发行版用对应的deb或者rpm之类的包进行安装s .deb/.rpm/... 118 | 119 | 120 | 121 | ### Ubuntu / Kubuntu / Xubuntu / Lubuntu (13.10 Saucy Salamander以及之后更新的版本) 122 | 123 | 1 首先要根据你的喜好来选择一个PPA源添加到你的系统里: 124 | 125 | (译者注:这里稳定版和每夜版二选一就可以,如果要体验最新特性,可以使用每夜版,但是如果用于长期使用追求稳定,推荐用稳定版,二者千万不要同时添加,避免出现混乱和错误。) 126 | 127 | ```Bash 128 | sudo add-apt-repository ppa:kivy-team/kivy #稳定版 129 | sudo add-apt-repository ppa:kivy-team/kivy-daily #每夜版 130 | ``` 131 | 132 | 133 | 2 然后就要用包管理器来更新一下包列表了: 134 | 135 | 136 | ```Bash 137 | sudo apt-get update 138 | ``` 139 | 140 | 141 | 142 | 143 | 3 更新列表完毕之后,如果没有错误,就可以安装了: 144 | 145 | ```Bash 146 | sudo apt-get install python-kivy #Python2 用这个来安装 147 | sudo apt-get install python3-kivy #Python3 要加一个3 148 | sudo apt-get install python-kivy-examples #可选的样例代码 149 | ``` 150 | 151 | 152 | 153 | 154 | 155 | ### Debian (8.0 Jessie或者更新的版本) 156 | 157 | ####特别注意 158 | Debian 7 Wheezy 已经不支持了,你至少要升级到Debian 8 Jessie 才能安装Kivy。 159 | 160 | 1 通过Synaptic新立得包管理器把下面的PPA源添加到你的sources.list列表中,手动添加也可以: 161 | 162 | * Jessie/Testing: 163 | 164 | ```Bash 165 | #稳定版: 166 | 167 | deb http://ppa.launchpad.net/kivy-team/kivy/ubuntu trusty main 168 | 169 | #每夜版: 170 | 171 | deb http://ppa.launchpad.net/kivy-team/kivy-daily/ubuntu trusty main 172 | ``` 173 | 174 | 175 | * Sid/Unstable: 176 | 177 | ```Bash 178 | #稳定版: 179 | 180 | deb http://ppa.launchpad.net/kivy-team/kivy/ubuntu utopic main 181 | 182 | #每夜版: 183 | deb http://ppa.launchpad.net/kivy-team/kivy-daily/ubuntu utopic main 184 | ``` 185 | 186 | 187 | 188 | 189 | 190 | 2 添加了源之后,就是要添加一些GPG key到你的apt keyring里面了,运行下面的命令: 191 | 192 | ```Bash 193 | #非root用户: 194 | sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys A863D2D6 195 | 196 | #root用户: 197 | apt-key adv --keyserver keyserver.ubuntu.com --recv-keys A863D2D6 198 | ``` 199 | 200 | 3 然后跟Ubuntu里面那个类似,更新列表完毕之后,如果没有错误,就可以安装了: 201 | 202 | ```Bash 203 | sudo apt-get update #安装之前一定要先这样更新一下列表 204 | sudo apt-get install python-kivy #Python2 用这个来安装 205 | sudo apt-get install python3-kivy #Python3 要加一个3 206 | sudo apt-get install python-kivy-examples #可选的样例代码 207 | ``` 208 | 209 | 210 | 211 | 212 | ###Mint/Bodhi/Suse/Gentoo 这部分省略 213 | Mint的安装基本与对应的Ubuntu版本一样,Bodhi估计用的人不多我懒得翻译了,OpenSuse/Gentoo 的用户应该比较有经验了还用得着我翻译么? 214 | 215 | ### Fedora 216 | 217 | 1 在终端里添加repo(注意版本不要弄错): 218 | 219 | ```Bash 220 | #Fedora 18: 221 | sudo yum-config-manager --add-repo=http://download.opensuse.org\ 222 | /repositories/home:/thopiekar:/kivy/Fedora_18/home:thopiekar:kivy.repo 223 | 224 | #Fedora 17: 225 | sudo yum-config-manager --add-repo=http://download.opensuse.org\ 226 | /repositories/home:/thopiekar:/kivy/Fedora_17/home:thopiekar:kivy.repo 227 | 228 | #Fedora 16: 229 | sudo yum-config-manager --add-repo=http://download.opensuse.org\ 230 | /repositories/home:/thopiekar:/kivy/Fedora_16/home:thopiekar:kivy.repo 231 | ``` 232 | 233 | 234 | 2 跟Ubuntu和Debian里面一样,添加源之后还是要用包管理器更新一下包列表。 235 | 236 | 3 更新列表之后通过包管理器就可以安装**python-Kivy**和**python-Kivy-examples**了。 237 | 238 | 239 | # 在虚拟环境中安装 240 | 241 | 242 | 243 | ## 必备的依赖包 244 | 245 | 246 | 247 | ### Cython 248 | 249 | 一定要注意,这里超级重要,不同版本的Kivy只能用特定版本的Cython配合才能使用,二者一定要匹配,关系如下表: 250 | 251 | | Kivy | Cython | 252 | | --- | --- | 253 | | 1.8 | 0.20.2 | 254 | | 1.9 | 0.21.2 | 255 | | 1.9.1 | 0.23 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | ## SDL2框架相关的依赖包 264 | 265 | 266 | 267 | ### 以Ubuntu为例 268 | 269 | 在下面的命令样例中,用**python**和**python-dev**就表明是给**Python2**安装,而**python3**和**python3-dev**是针对**Python3**的。 270 | 271 | ```Bash 272 | # 先要安装这些必备的组件,注意上面刚提示过,如果要用Python3,在python后面加上一个3就可以了: 273 | sudo apt-get install -y \ 274 | python-pip \ 275 | build-essential \ 276 | git \ 277 | python \ 278 | python-dev \ 279 | ffmpeg \ 280 | libsdl2-dev \ 281 | libsdl2-image-dev \ 282 | libsdl2-mixer-dev \ 283 | libsdl2-ttf-dev \ 284 | libportmidi-dev \ 285 | libswscale-dev \ 286 | libavformat-dev \ 287 | libavcodec-dev \ 288 | zlib1g-dev 289 | ``` 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | ####特别注意 300 | 301 | 在某些特定的Linux版本上,你可能会收到一个与ffmpeg包有关的错误信息。这种情况下,就可以用libav-tools替换掉上文命令中的ffmpeg,另一种解决方法是使用ppa来安装ffmpeg,使用的命令如下所示: 302 | 303 | 304 | ```Bash 305 | sudo add-apt-repository ppa:mc3man/trusty-media 306 | sudo apt-get update 307 | sudo apt-get install ffmpeg 308 | ``` 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | ### 要在虚拟环境中安装Kivy了 318 | 319 | 320 | 321 | 322 | 首先要确保Pip, Virtualenv 和 Setuptools 这几个包都更新到最新: 323 | 324 | ```Bash 325 | sudo pip install --upgrade pip virtualenv setuptools 326 | ``` 327 | 328 | 然后创建一个名为"kivyinstall"的新的虚拟环境,这时候你有两种选择: 329 | 330 | * 第一种是用系统自带的默认Python解释器: 331 | 332 | ```Bash 333 | virtualenv --no-site-packages kivyinstall 334 | ``` 335 | 336 | * 第二种是设定一个指定位置的Python解释器,这里举例就假设要用的解释器路径在 /usr/bin/python2.7 337 | 338 | ```Bash 339 | virtualenv --no-site-packages -p /usr/bin/python2.7 kivyinstall 340 | ``` 341 | 342 | 建立好虚拟环境之后,就是进入里面了: 343 | 344 | ```Bash 345 | . kivyinstall/bin/activate 346 | ``` 347 | 348 | 千万要注意,这里要安装正确的Cython版本: 349 | 350 | ```Bash 351 | pip install Cython==0.23 352 | ``` 353 | 354 | 然后就可以在这个虚拟环境里面安装Kivy的稳定版了: 355 | 356 | ```Bash 357 | pip install kivy 358 | ``` 359 | 360 | 如果要用开发版本的Kivy,就换成下面的命令来安装: 361 | 362 | ```Bash 363 | pip install git+https://github.com/kivy/kivy.git@master 364 | ``` 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | ## 古老的PyGame相关的依赖包 377 | 378 | 379 | 380 | ### Ubuntu 系统 381 | 382 | 首先还是要安装一大堆必要的系统组件了: 383 | 384 | 385 | ```Bash 386 | sudo apt-get install -y \ 387 | python-pip \ 388 | build-essential \ 389 | mercurial \ 390 | git \ 391 | python \ 392 | python-dev \ 393 | ffmpeg \ 394 | libsdl-image1.2-dev \ 395 | libsdl-mixer1.2-dev \ 396 | libsdl-ttf2.0-dev \ 397 | libsmpeg-dev \ 398 | libsdl1.2-dev \ 399 | libportmidi-dev \ 400 | libswscale-dev \ 401 | libavformat-dev \ 402 | libavcodec-dev \ 403 | zlib1g-dev 404 | ``` 405 | 406 | 407 | 408 | ### Fedora 系统 409 | 410 | Fedora 系统就要用yum来实现组件安装: 411 | 412 | 413 | ```Bash 414 | sudo yum install \ 415 | make \ 416 | mercurial \ 417 | automake \ 418 | gcc \ 419 | gcc-c++ \ 420 | SDL_ttf-devel \ 421 | SDL_mixer-devel \ 422 | khrplatform-devel \ 423 | mesa-libGLES \ 424 | mesa-libGLES-devel \ 425 | gstreamer-plugins-good \ 426 | gstreamer \ 427 | gstreamer-python \ 428 | mtdev-devel \ 429 | python-devel \ 430 | python-pip 431 | ``` 432 | 433 | 434 | 435 | ### OpenSuse 系统 436 | 这里示范的是用zypper作为包管理器: 437 | 438 | ```Bash 439 | sudo zypper install \ 440 | python-distutils-extra \ 441 | python-gstreamer-0_10 \ 442 | python-enchant \ 443 | gstreamer-0_10-plugins-good \ 444 | python-devel \ 445 | Mesa-devel \ 446 | python-pip 447 | 448 | sudo zypper install -t pattern devel_C_C++ 449 | ``` 450 | 451 | 452 | 453 | 454 | 455 | 456 | 457 | 458 | 459 | 460 | ### 然后又到了在虚拟环境中安装Kivy的时候了 461 | 462 | 463 | 首先要确保Pip, Virtualenv 和 Setuptools 这几个包都更新到最新: 464 | 465 | 466 | ```Bash 467 | sudo pip install --upgrade pip virtualenv setuptools 468 | ``` 469 | 470 | 然后创建一个名为"kivyinstall"的新的虚拟环境,这时候你有两种选择: 471 | 472 | * 第一种是用系统自带的默认Python解释器: 473 | 474 | ```Bash 475 | virtualenv --no-site-packages kivyinstall 476 | ``` 477 | 478 | * 第二种是设定一个指定位置的Python解释器,这里举例就假设要用的解释器路径在 /usr/bin/python2.7 479 | 480 | ```Bash 481 | virtualenv --no-site-packages -p /usr/bin/python2.7 kivyinstall 482 | ``` 483 | 484 | 建立好虚拟环境之后,就是进入里面了: 485 | 486 | ```Bash 487 | . kivyinstall/bin/activate 488 | ``` 489 | 490 | 千万要注意,这里要安装numpy以及正确的Cython版本: 491 | 492 | ```Bash 493 | pip install numpy 494 | pip install Cython==0.23 495 | ``` 496 | 497 | 这里注意,如果你不想用sdl2,而想要用pygame,你可以通过export USE_SDL2=0来强制使用pygame。这样一来,Kivy在安装过程中找不到sdl2的链接,就会自动设置这个值为0,然后尝试用pygame来构建。 498 | 499 | ```Bash 500 | pip install hg+http://bitbucket.org/pygame/pygame 501 | ``` 502 | 503 | 接下来就可以在这个虚拟环境里面安装Kivy的稳定版了: 504 | 505 | ```Bash 506 | pip install kivy 507 | ``` 508 | 509 | 如果要用开发版本的Kivy,就换成下面的命令来安装: 510 | 511 | ```Bash 512 | pip install git+https://github.com/kivy/kivy.git@master 513 | ``` 514 | 515 | 516 | 517 | 518 | 519 | 520 | 521 | 522 | 523 | 524 | ### 虚拟环境中安装额外的包 525 | 526 | 527 | 528 | 529 | 530 | 在该虚拟环境中安装开发版的buildozer: 531 | 532 | ```Bash 533 | pip install git+https://github.com/kivy/buildozer.git@master 534 | ``` 535 | 536 | 安装开发版plyer 537 | 538 | ```Bash 539 | pip install git+https://github.com/kivy/plyer.git@master 540 | ``` 541 | 542 | 其他的两个可能用到的包: 543 | 544 | ```Bash 545 | pip install -U pygments docutils 546 | ``` 547 | 548 | 549 | 550 | 551 | 552 | 553 | 554 | 555 | 556 | 557 | 558 | ## 从命令行中启动 559 | 560 | Kivy官方提供的样例代码中有一些是可以在安装配置好Kivy环境后立即就能运行的,这些例子就集成在Kivy包之内。所以,如果你要尝试这些样例,你得实现确定好easy_install把你当前在用的Kivy安装到了哪里: 561 | 562 | 563 | ```Bash 564 | python -c "import pkg_resources; print(pkg_resources.resource_filename('kivy', '../share/kivy-examples'))" 565 | ``` 566 | 567 | 然后估计你会得到一个路径了,类似下面这样: 568 | (译者注:这个路径是根据上面那个命令来输出的,每个人不同配置都产生不同结果,千万别无脑复制哦!) 569 | 570 | ```Bash 571 | /usr/local/lib/python2.6/dist-packages/Kivy-1.0.4_beta-py2.6-linux-x86_64.egg/share/kivy-examples/ 572 | ``` 573 | 574 | 575 | 576 | 然后你知道位置了,就进入这个路径,然后运行一下样例吧。 577 | 比如你可以尝试一下触控追踪的样例touchtracer: 578 | 579 | ```Bash 580 | cd <path to kivy-examples #把这里替换成你自己的kivy-examples目录 581 | cd demo/touchtracer 582 | python main.py 583 | ``` 584 | 585 | 586 | 这还有一个图片示意程序pictures: 587 | 588 | ```Bash 589 | cd <path to kivy-examples #把尖括号内容替换成你自己的kivy-examples目录 590 | cd demo/pictures 591 | python main.py 592 | ``` 593 | 594 | 595 | 596 | 597 | 598 | 599 | If you are familiar with Unix and symbolic links, you can create a link directly in your home directory for easier access. For example: 600 | 601 | 如果你对Unix和符号链接比较熟悉,你可以把这个目录在你的home目录里面创建一个链接,这样以后访问更方便,举例如下: 602 | 603 | 604 | 1 通过上面演示过的命令获取样例代码所在位置; 605 | 606 | 2 把获取的路径补齐到下列命令中,然后粘贴到终端中: 607 | 608 | 609 | 610 | 611 | ```Bash 612 | ln -s <path to kivy-examples ~/#把尖括号内容替换成你自己的kivy-examples目录 613 | cd ~/kivy-examples 614 | ``` 615 | 616 | 617 | 618 | 619 | 3 接下来你就可以用如下这种特别简单的方式来访问样例代码了: 620 | 621 | 622 | 623 | 624 | ```Bash 625 | cd ~/kivy-examples 626 | ``` 627 | 628 | 629 | 如果你想更省事,把Kivy程序当做常规脚本来运行(比如输入./main.py),或者双击来运行,你就需要创建一个正确的Python链接。例如下面这样: 630 | 631 | ```Bash 632 | sudo ln -s /usr/bin/python2.7 /usr/bin/kivy 633 | ``` 634 | 635 | 636 | 637 | 或者如果你想要在某个虚拟环境中运行Kivy,那给对应该环境的Python做个链接就行了: 638 | 639 | ```Bash 640 | sudo ln -s /home/your_username/Envs/kivy/bin/python2.7 /usr/bin/kivy 641 | ``` 642 | 643 | 644 | 还没完,接下来你还要在每一个main.py的开头添加如下内容作为第一行: 645 | 646 | 647 | 648 | ```Bash 649 | #!/usr/bin/kivy 650 | ``` 651 | 652 | 653 | 654 | ####特别注意 655 | 656 | 一定要小心哈,Windows系统下的Python保存的文件结尾类型很可能是(CR-LF),Linux系统不会忽略掉其中的<CR,并且依然当做文件名字的一部分来读取。这就会导致很多乱七八糟的出错信息,所以记得先确定把文件转换成Unix风格的结尾。 657 | 658 | 659 | 660 | 661 | 662 | ## 设备权限 663 | 664 | 665 | 当你启动app的时候,Kivy会用到[Mtdev](http://wiki.ubuntu.com/Multitouch)来搜索是否有可用的多指触摸设备,如果找到就拿来用作输入。然而这类设备的使用权通常都被严格限制到了特定的用户或者用户组。 666 | 667 | 如果你的用户没有这些权限,Kivy就会记下一个错误,然后给出一个与这些设备相关的警告,大概如下所示: 668 | 669 | ```Bash 670 | Permission denied:'/dev/input/eventX' 671 | ``` 672 | 673 | 所以你要使用这些信息,就必须赋予当前用户或者用户组所必要的权限。可以通过如下命令实现: 674 | 675 | ```Bash 676 | sudo chmod u+r /dev/input/eventX 677 | ``` 678 | 679 | 680 | 上面这个是给当前用户赋予权限,如果要给当前用户组权限,可以用下面这个命令实现: 681 | 682 | 683 | ```Bash 684 | sudo chmod g+r /dev/input/eventX 685 | ``` 686 | 687 | 688 | 689 | 这个授权是非永久性的,这次授权后可用,以后又要重新授权才能用。所以有个更好的永久解决方案,就是把当前用户添加到有权限的用户组中。例如,在Ubuntu系统里面,你可以把这个用户添加到input这个用户组: 690 | 691 | ```Bash 692 | sudo adduser $USER input 693 | ``` 694 | 695 | 696 | ####特别注意 697 | 698 | 修改完用户权限之后,你要注销然后再登录才能使用这些权限。 699 | 700 | 701 | 702 | 703 | 704 | 705 | # [Mac系统安装Kivy指南](https://kivy.org/docs/installation/installation-osx.html) 706 | 707 | 708 | 709 | ## 使用官方提供的Kivy.app 710 | 711 | 712 | ####特别注意 713 | 714 | 715 | 716 | 官方提供的Kivy.app仅仅适用于OS X 10.7以及更新版本的系统(都是64位的)。对10.7之前的系统以及10.7的32位系统的用户,你就只能自己手动安装各种组件了。建议通过 [homebrew](http://brew.sh/) 来安装。 717 | 718 | 719 | 720 | 对OS X 10.7 64位版本以及更新版本系统,Kivy官方提供了一个Kivy.app的包,里面集成好了所有需要的依赖包。可以从[这个链接](http://kivy.org/#download)来下载压缩包,解压缩之后就能发现一个名为**Kivy.app**的应用文件。 721 | 722 | 723 | 724 | 要怎么安装呢?具体思路如下: 725 | 726 | 727 | 728 | 1 从[官网的这个链接](http://kivy.org/#download)下载压缩包,其中Kivy2.7z用的是Python 2,而Kivy3.7z用的是Python 3。 729 | 730 | 731 | 2 使用解压缩工具把压缩包进行解压,可以试试[Keka](http://www.kekaosx.com/)这个应用。 732 | 733 | 734 | 3 把解压缩出来的Kivy2.app或者Kivy3.app这两个文件当中选择一个,重命名成Kivy.app,复制到应用程序目录/Applications 下,这个过程可以在终端中通过下面的命令来实现 735 | 736 | ```Bash 737 | sudo mv Kivy2.app /Applications/Kivy.app 738 | ``` 739 | 740 | 741 | 4 然后是创建一个名为kivy的系统链接,以便于方便访问kivy环境来启动app: 742 | 743 | ```Bash 744 | ln -s /Applications/Kivy.app/Contents/Resources/script /usr/local/bin/kivy 745 | ``` 746 | 747 | 748 | 5 样例代码以及所有常规的Kivy工具都可以在/Applications/Kivy.app/Contents/Resources/kivy 这个目录里面找到了。 749 | 750 | 751 | 6 译者注:你完全可以同时拥有Kivy2.app和Kivy3.app,可以不重命名他们,而直接把这两个都复制到/Applications/下,然后用如下方式分别创建名为kivy2和kivy3的链接(这样以后你就可以通过kivy2来使用Python2版本的Kivy,而用kivy3来使用Python3版本的Kivy了。): 752 | 753 | ```Bash 754 | ln -s /Applications/Kivy2.app/Contents/Resources/script /usr/local/bin/kivy2 755 | ln -s /Applications/Kivy3.app/Contents/Resources/script /usr/local/bin/kivy3 756 | ``` 757 | 758 | 759 | 760 | 现在你就可以在终端中用Kivy脚本文件来启动Kivy的app了,也可以把你的main.py直接拽到终端中就能运行了。 761 | 762 | 763 | ### 安装模块 764 | 765 | OS X上的Kivy使用自己集成的一个python环境,只在你用kivy命令的时候才被激活。所以要在这里安装模块,要在pip命令前面加上kivy -m的前缀,如下所示(记得把<modulename>替换成你要安装的模块名): 766 | 767 | ```Bash 768 | kivy -m pip install <modulename> 769 | ``` 770 | 771 | 772 | 773 | 774 | ### 这些模块安装到哪里了呢? 775 | 776 | 777 | 安装位置在Kivy.app目录内的venv目录下: 778 | 779 | ```Bash 780 | Kivy.app/Contents/Resources/venv/ 781 | ``` 782 | 783 | 784 | 如果你安装一个二进制的模块,例如kivy-garden,这些二进制文件就只能在venv一级以上的目录使用: 785 | 786 | 787 | ```Bash 788 | kivy -m pip install kivy-garden 789 | ``` 790 | 791 | 792 | 上面这个命令安装的garden的链接库文件,只有通过如下命令激活这个虚拟环境了才能使用: 793 | 794 | 795 | ```Bash 796 | source /Applications/Kivy.app/Contents/Resources/venv/bin/activate 797 | garden install mapview 798 | deactivate 799 | ``` 800 | 801 | 802 | ### 二进制文件安装 803 | 直接复制到/Applications/Kivy.app/Contents/Resources/venv/bin/这个目录就行了。 804 | 805 | 806 | 807 | 808 | 809 | ### 安装其他框架 810 | 811 | Kivy.app自带了SDL2和Gstreamer这两个框架。要增加其他的框架让Kivy使用,可以按照如下思路实现: 812 | 813 | ```Bash 814 | git clone http://github.com/tito/osxrelocator 815 | export PYTHONPATH=~/path/to/osxrelocator 816 | cd /Applications/Kivy.app 817 | python -m osxrelocator -r . /Library/Frameworks/<Framework_name>.framework/ \ 818 | @executable_path/../Frameworks/<Framework_name>.framework/ 819 | ``` 820 | 821 | 822 | 一定要记得把<Framework_name>替换成你需要的框架名。osxrelocator这个工具是用来改变框架中的链接库目录,这样就可以让这些框架可以在Kivy.app中使用了。 823 | 824 | 825 | 826 | 827 | 828 | 829 | ### 启动任意一个Kivy应用 830 | 831 | 832 | 要运行Kivy应用,只要把源码拖拽到Kivy.app图标上,就可以了。样例代码目录中的任何Python文件都可以拿来试试。 833 | 834 | 835 | 836 | 837 | 838 | ### 从命令行启动 839 | 840 | 841 | 如果要在命令行中运行Kivy,把Kivy.app复制到应用目录后,双击Make Symlinks script 这个脚本文件,就可以了。要测试是否成功,可以按照如下方式: 842 | 843 | 844 | 1 打开终端,输入: 845 | 846 | ```Bash 847 | kivy 848 | ``` 849 | 850 | 你就应该能得到一个Python解释器环境了。 851 | 852 | 853 | 2 然后在这个Python解释器内输入如下代码: 854 | 855 | ```Python 856 | import kivy 857 | ``` 858 | 859 | 860 | 如果什么反应都没有,没有出错,那就说明搞定了。ut errors, it worked. 861 | 862 | 863 | 3 经过上面的验证,说明配置成功了。这样在命令行终端中运行Kivy应用就很简单了,只是执行一下脚本就可以,如下所示: 864 | 865 | ```Bash 866 | kivy yourapplication.py 867 | ``` 868 | 869 | 870 | 871 | 872 | ## 使用HomeBrew安装Kivy 873 | 874 | 875 | 使用HomeBrew和Pip也可以安装Kivy,具体步骤如下所示: 876 | 877 | 878 | 1 首先要先安装[homebrew](http://brew.sh/),然后安装必备组件: 879 | 880 | ```Bash 881 | brew install sdl2 sdl2_image sdl2_ttf sdl2_mixer gstreamer 882 | ``` 883 | 884 | 885 | 886 | 2 然后是通过pip安装cython 0.23和kivy(一定要注意,要确保设置环境变量USE_OSX_FRAMEWORKS=0): 887 | 888 | ```Bash 889 | pip install -I Cython==0.23 890 | USE_OSX_FRAMEWORKS=0 pip install kivy 891 | ``` 892 | 893 | 894 | 895 | 3 如果不想安装稳定版而想使用开发版,第二步就要改用如下命令了: 896 | 897 | ```Bash 898 | USE_OSX_FRAMEWORKS=0 pip install https://github.com/kivy/kivy/archive/master.zip 899 | ``` 900 | 901 | 902 | 903 | 904 | 905 | 906 | 907 | 908 | 909 | 910 | 911 | 912 | 913 | ## 使用MacPorts和Pip来进行安装 914 | 915 | 916 | 917 | ####特别注意 918 | 919 | 如果你希望自己的Kivy应用能够支持视频播放,就得手动安装gstreamer。可以供过MacPorts来安装[py-gst-python port](https://trac.macports.org/ticket/44813). 用MacPorts和Pip安装Kivy的过程如下: 920 | 921 | 922 | 923 | 1 安装[Macports](https://www.macports.org/) 924 | 925 | 926 | 2 安装Python 3.4并且设定成默认的: 927 | 928 | 929 | ```Bash 930 | port install python34 931 | port select --set python python34 932 | ``` 933 | 934 | 935 | 936 | 937 | 938 | 939 | 3 然后安装Pip并设置为默认: 940 | 941 | ```Bash 942 | port install pip-34 943 | port select --set pip pip-34 944 | ``` 945 | 946 | 947 | 948 | 949 | 950 | 4 使用[Macports](https://www.macports.org/)安装必备组件: 951 | 952 | 953 | 954 | ```Bash 955 | port install libsdl2 libsdl2_image libsdl2_ttf libsdl2_mixer 956 | ``` 957 | 958 | 959 | 960 | 961 | 962 | 963 | 5 使用Pip安装cython 0.23和kivy(一定要注意,要确保设置环境变量USE_OSX_FRAMEWORKS=0): 964 | 965 | 966 | 967 | ```Bash 968 | pip install -I Cython==0.23 969 | USE_OSX_FRAMEWORKS=0 pip install kivy 970 | ``` 971 | 972 | 973 | 974 | 975 | 976 | 977 | 978 | 979 | 6 如果不想安装稳定版而想使用开发版,第二步就要改用如下命令了: 980 | 981 | ```Bash 982 | USE_OSX_FRAMEWORKS=0 pip install https://github.com/kivy/kivy/archive/master.zip 983 | ``` 984 | 985 | 986 | ####特别注意 987 | 988 | 如果你在Mac系统下使用Kivy-Designer的时候遇到如下错误: 989 | 990 | ```language 991 | [WARNING ] stderr: from designer.app import DesignerApp 992 | [WARNING ] stderr: File "/Users/cycleuser/kivy-designer/designer/app.py", line 27, in <module> 993 | [WARNING ] stderr: from kivy.garden.filebrowser import FileBrowser 994 | [WARNING ] stderr: ImportError: No module named filebrowser 995 | ``` 996 | 997 | 那么不要犹豫,肯定是Garden的安装位置你没有调整,你需要参考我的[这篇文章](http://blog.cycleuser.org/kivy-on-mac-importerror-no-module-named-filebrowser.html)来解决这个问题。 998 | -------------------------------------------------------------------------------- /08-Kivy-Widgets.md: -------------------------------------------------------------------------------- 1 | Title: Kivy Widgets 2 | Date: 2017-02-26 3 | Category: Kivy 4 | Tags: Python,Kivy 5 | 6 | 7 | # Kivy中文编程指南:控件 8 | 9 | 10 | [英文原文](https://kivy.org/docs/guide/widgets.html) 11 | 12 | 13 | 14 | ## 控件简介 15 | 16 | [控件`Widget`](https://kivy.org/docs/api-kivy.uix.widget.html#kivy.uix.widget.Widget "kivy.uix.widget.Widget")是 Kivy 图形界面中的基本元素。控件提供了一个[画布`Canvas`](https://kivy.org/docs/api-kivy.graphics.html#kivy.graphics.Canvas "kivy.graphics.Canvas"),这是用来在屏幕上进行绘制的。控件接收事件,并且对事件作出反应。想要对 [控件`Widget`](https://kivy.org/docs/api-kivy.uix.widget.html#kivy.uix.widget.Widget "kivy.uix.widget.Widget")进行更深入的了解,可以去看看这个模块的文档。 17 | 18 | 19 | 20 | ## 操作控件树 21 | 22 | Kivy 以树的形式来组织控件。你的应用程序会有一个根控件,通常会含有若干的[子控件 `children`](https://kivy.org/docs/api-kivy.uix.widget.html#kivy.uix.widget.Widget.children "kivy.uix.widget.Widget.children"),这些子控件还可以有自己的子控件。一个控件的子控件会以 [`children`](https://kivy.org/docs/api-kivy.uix.widget.html#kivy.uix.widget.Widget.children "kivy.uix.widget.Widget.children")属性的形式表述,这个属性是 Kivy 中的一个[列表属性 `ListProperty`](https://kivy.org/docs/api-kivy.properties.html#kivy.properties.ListProperty "kivy.properties.ListProperty") 23 | 24 | 可以用一下方法来操作控件树: 25 | 26 | * [`add_widget()`](https://kivy.org/docs/api-kivy.uix.widget.html#kivy.uix.widget.Widget.add_widget "kivy.uix.widget.Widget.add_widget"): 添加一个控件作为子控件; 27 | * [`remove_widget()`](https://kivy.org/docs/api-kivy.uix.widget.html#kivy.uix.widget.Widget.remove_widget "kivy.uix.widget.Widget.remove_widget"): 从子控件列表中去掉一个控件; 28 | * [`clear_widgets()`](https://kivy.org/docs/api-kivy.uix.widget.html#kivy.uix.widget.Widget.clear_widgets "kivy.uix.widget.Widget.clear_widgets"): 清空一个控件的所有子控件。 29 | 30 | 例如下面的代码,就是在一个盒式布局 BoxLayout 中添加一个按钮: 31 | 32 | ```Python 33 | layout = BoxLayout(padding=10) 34 | button = Button(text='My first button') 35 | layout.add_widget(button) 36 | ``` 37 | 38 | 这个按钮就添加到布局当中去了:按钮的 parent 属性会被设置为这个布局;这个按钮也会被添加到布局中的子控件列表。要把这个按钮从这个布局中删掉也很简单: 39 | 40 | ```Python 41 | layout.remove_widget(button) 42 | ``` 43 | 移除了之后,这个按钮的 parent 属性就会被设置为 None,也会被从布局的子控件列表中移除。 44 | 45 | 要是想清空一个控件中的所有自科技,那就用 [`clear_widgets()`](https://kivy.org/docs/api-kivy.uix.widget.html#kivy.uix.widget.Widget.clear_widgets "kivy.uix.widget.Widget.clear_widgets")方法就可以了: 46 | 47 | ```Python 48 | layout.clear_widgets() 49 | ``` 50 | 51 | 52 | #### 特别注意 53 | 54 | 千万别自己手动去操作子控件列表,除非你确定自己掌控得非常深入透彻。因为控件树是和绘图树联系在一起的。例如,如果你添加了一个控件到子控件列表,但没有添加这个新子控件的画布到绘图树上,那么就会出现这种情况:这个控件确实成了一个子控件,但是屏幕上不会显示出来。此外,如果你后续使用添加、移除、清空控件这些操作,可能还会遇到问题。 55 | 56 | 57 | ## 遍历控件树 58 | 59 | 控件类实例的[子控件`children`](https://kivy.org/docs/api-kivy.uix.widget.html#kivy.uix.widget.Widget.children "kivy.uix.widget.Widget.children")列表属性中包含了所有的子控件。所以可以用如下的方式来进行遍历: 60 | 61 | ```Python 62 | root = BoxLayout() 63 | # ... add widgets to root ... 64 | for child in root.children: 65 | print(child) 66 | ``` 67 | 68 | 然而,这样的操作可得谨慎使用。如果你要用之前一节中提到的方法来修改这个子控件列表电话,请一定用下面这种方法来做一下备份: 69 | 70 | 71 | ```Python 72 | for child in root.children[:]: 73 | # manipulate the tree. For example here, remove all widgets that have a 74 | # width 75 | if child.width 100: 76 | root.remove_widget(child) 77 | ``` 78 | 79 | 默认情况下,控件是不会对子控件的尺寸/位置进行改变的。[位置属性 `pos`](https://kivy.org/docs/api-kivy.uix.widget.html#kivy.uix.widget.Widget.pos "kivy.uix.widget.Widget.pos")是屏幕坐标系上的绝对值(除非你使用[相对布局`relativelayout`](https://kivy.org/docs/api-kivy.uix.relativelayout.html#module-kivy.uix.relativelayout "kivy.uix.relativelayout"),这个以后再说),而[尺寸属性 `size`](https://kivy.org/docs/api-kivy.uix.widget.html#kivy.uix.widget.Widget.size "kivy.uix.widget.Widget.size")就是一个绝对的尺寸大小。 80 | 81 | ## 控件索引Z 82 | 83 | 控件绘制的顺序,是基于各个控件在控件树中的位置。[添加控件方法 `add_widget`](https://kivy.org/docs/api-kivy.uix.widget.html#kivy.uix.widget.Widget.add_widget "kivy.uix.widget.Widget.add_widget") 可以接收一个索引参数,这样就能指定该新增控件在控件树中的位置。 84 | 85 | ```Python 86 | root.add_widget(widget, index) 87 | ``` 88 | 89 | 索引值小的控件会被绘制在索引值大的控件之上。一定要记住,默认值是 0 ,所以后添加的控件总会在所有控件的最顶层,除非指定了索引值。 90 | 91 | 92 | 93 | ## 整理布局 94 | 95 | [布局 `layout`](https://kivy.org/docs/api-kivy.uix.layout.html#module-kivy.uix.layout "kivy.uix.layout")是一种特别的控件,它会控制自己子控件的尺寸和位置。有各种不同的布局,这些布局分别为子控件提供拜托你个的自动组织整理。这些布局使用[尺寸推测 `size_hint`](https://kivy.org/docs/api-kivy.uix.widget.html#kivy.uix.widget.Widget.size_hint "kivy.uix.widget.Widget.size_hint")和[位置推测 `pos_hint`](https://kivy.org/docs/api-kivy.uix.widget.html#kivy.uix.widget.Widget.pos_hint "kivy.uix.widget.Widget.pos_hint")这两个属性来决定[子控件`children`](https://kivy.org/docs/api-kivy.uix.widget.html#kivy.uix.widget.Widget.children "kivy.uix.widget.Widget.children")的[尺寸 `size`](https://kivy.org/docs/api-kivy.uix.widget.html#kivy.uix.widget.Widget.size "kivy.uix.widget.Widget.size") 和 [位置`pos`](https://kivy.org/docs/api-kivy.uix.widget.html#kivy.uix.widget.Widget.pos "kivy.uix.widget.Widget.pos")。 96 | 97 | 98 | **盒式布局 BoxLayout**: 所有控件充满整个空间,以互相挨着的方块的方式来分布,横着或者竖着排列都可以。子控件的 size_hint 属性可以用来改变每个子控件的比例,也可以设置为固定尺寸。 99 | 100 | 101 | ![../_images/boxlayout1.gif](https://kivy.org/docs/_images/boxlayout1.gif) ![../_images/gridlayout1.gif](https://kivy.org/docs/_images/gridlayout1.gif) ![../_images/stacklayout1.gif](https://kivy.org/docs/_images/stacklayout1.gif) ![../_images/anchorlayout1.gif](https://kivy.org/docs/_images/anchorlayout1.gif)![../_images/floatlayout1.gif](https://kivy.org/docs/_images/floatlayout1.gif) 102 | 103 | **网格布局 GridLayout**: 以一张网格的方式来安排控件。你必须指定好网格的维度,确定好分成多少格,这样 Kivy 才能计算出每个元素的尺寸并且确定如何安排这些元素的位置。 104 | 105 | **栈状布局 StackLayout**: 挨着放一个个控件,彼此邻近,在某一个维度上有固定大小,而使它们填充整个空间。 这适合用来显示相同预定义大小的子控件。 106 | 107 | **锚式布局 AnchorLayout**: 一种非常简单的布局,只关注子控件的位置。 将子控件放在布局的边界位置。 不支持size_hint。 108 | 109 | **浮动布局 FloatLayout**: 允许放置具任意位置和尺寸的子控件,可以是绝对尺寸,也可以是相对布局的相对尺寸。 默认的 size_hint(1,1)会让每个子控件都与整个布局一样大,所以如果你多个子控件就要修改这个值。可以把 size_hint 设置成 (None, None),这样就可以使用 size 这个绝对尺寸属性。控件也支持 pos_hint,这个属性是一个 dict 词典,用来设置相对布局的位置。 110 | 111 | **相对布局 RelativeLayout**: 和浮动布局 FloatLayout 差不多,不同之处在于子控件的位置是相对于布局空间的,而不是相对于屏幕。 112 | 113 | 想要深入理解各种布局的话,可以仔细阅读各种文档。 114 | 115 | [`size_hint`](https://kivy.org/docs/api-kivy.uix.widget.html#kivy.uix.widget.Widget.size_hint "kivy.uix.widget.Widget.size_hint") 和 [`pos_hint`](https://kivy.org/docs/api-kivy.uix.widget.html#kivy.uix.widget.Widget.pos_hint "kivy.uix.widget.Widget.pos_hint"): 116 | 117 | * [`floatlayout`](https://kivy.org/docs/api-kivy.uix.floatlayout.html#module-kivy.uix.floatlayout "kivy.uix.floatlayout") 118 | * [`boxlayout`](https://kivy.org/docs/api-kivy.uix.boxlayout.html#module-kivy.uix.boxlayout "kivy.uix.boxlayout") 119 | * [`gridlayout`](https://kivy.org/docs/api-kivy.uix.gridlayout.html#module-kivy.uix.gridlayout "kivy.uix.gridlayout") 120 | * [`stacklayout`](https://kivy.org/docs/api-kivy.uix.stacklayout.html#module-kivy.uix.stacklayout "kivy.uix.stacklayout") 121 | * [`relativelayout`](https://kivy.org/docs/api-kivy.uix.relativelayout.html#module-kivy.uix.relativelayout "kivy.uix.relativelayout") 122 | * [`anchorlayout`](https://kivy.org/docs/api-kivy.uix.anchorlayout.html#module-kivy.uix.anchorlayout "kivy.uix.anchorlayout") 123 | 124 | [`size_hint`](https://kivy.org/docs/api-kivy.uix.widget.html#kivy.uix.widget.Widget.size_hint "kivy.uix.widget.Widget.size_hint") 是一个 [引用列表属性 `ReferenceListProperty`](https://kivy.org/docs/api-kivy.properties.html#kivy.properties.ReferenceListProperty "kivy.properties.ReferenceListProperty") ,包括 [`size_hint_x`](https://kivy.org/docs/api-kivy.uix.widget.html#kivy.uix.widget.Widget.size_hint_x "kivy.uix.widget.Widget.size_hint_x") 和[`size_hint_y`](https://kivy.org/docs/api-kivy.uix.widget.html#kivy.uix.widget.Widget.size_hint_y "kivy.uix.widget.Widget.size_hint_y") 两个变量。接收的变量值是从0到1的各种数值,或者 None, 默认值为 (1, 1)。这表示如果控件处在布局之内,布局将会在两个方向分配全部尺寸(相对于布局大小)给该控件。 125 | 126 | 举个例子,设置[`size_hint`](https://kivy.org/docs/api-kivy.uix.widget.html#kivy.uix.widget.Widget.size_hint "kivy.uix.widget.Widget.size_hint") 为 (0.5, 0.8),就会给该[控件`Widget`](https://kivy.org/docs/api-kivy.uix.widget.html#kivy.uix.widget.Widget "kivy.uix.widget.Widget") 分配[布局 `layout`](https://kivy.org/docs/api-kivy.uix.layout.html#module-kivy.uix.layout "kivy.uix.layout") 内50% 宽,80% 高的尺寸。 127 | 128 | 129 | 例如下面这个例子: 130 | 131 | 132 | 133 | 134 | ```Python 135 | BoxLayout: 136 | Button: 137 | text: 'Button 1' 138 | # default size_hint is 1, 1, we don't need to specify it explicitly 139 | # however it's provided here to make things clear 140 | size_hint: 1, 1 141 | ``` 142 | 143 | 加载 Kivy 目录: 144 | 145 | ```Python 146 | cd $KIVYDIR/examples/demo/kivycatalog 147 | python main.py 148 | ``` 149 | 150 | 151 | 152 | 153 | 把上面代码中的 $KIVYDIR 替换成你的 Kivy 安装位置。在左边点击标注有 Box Layout 的按钮。 然后将上面的代码粘贴到窗口右侧的编辑器内。 154 | 155 | ![../_images/size_hint[B].jpg](https://kivy.org/docs/_images/size_hint[B].jpg) 156 | 157 | 158 | 然后你就可以看到上图这样的界面了,这个按钮 Button 会占据整个布局[尺寸 `size`](https://kivy.org/docs/api-kivy.uix.widget.html#kivy.uix.widget.Widget.size "kivy.uix.widget.Widget.size")的 100%。 159 | 160 | 修改[`size_hint_x`](https://kivy.org/docs/api-kivy.uix.widget.html#kivy.uix.widget.Widget.size_hint_x "kivy.uix.widget.Widget.size_hint_x")/[`size_hint_y`](https://kivy.org/docs/api-kivy.uix.widget.html#kivy.uix.widget.Widget.size_hint_y "kivy.uix.widget.Widget.size_hint_y") 为 .5 这就会把[控件 `Widget`](https://kivy.org/docs/api-kivy.uix.widget.html#kivy.uix.widget.Widget "kivy.uix.widget.Widget") 调整为[布局 `layout`](https://kivy.org/docs/api-kivy.uix.layout.html#module-kivy.uix.layout "kivy.uix.layout") 的50% [宽度 `width`](https://kivy.org/docs/api-kivy.uix.widget.html#kivy.uix.widget.Widget.width "kivy.uix.widget.Widget.width")/[高度 `height`](https://kivy.org/docs/api-kivy.uix.widget.html#kivy.uix.widget.Widget.height "kivy.uix.widget.Widget.height")。 161 | 162 | ![../_images/size_hint[b_].jpg](https://kivy.org/docs/_images/size_hint[b_].jpg) 163 | 164 | 165 | 这时候效果如上图所示,虽然我们已经同时指定了 [`size_hint_x`](https://kivy.org/docs/api-kivy.uix.widget.html#kivy.uix.widget.Widget.size_hint_x "kivy.uix.widget.Widget.size_hint_x") 和 [`size_hint_y`](https://kivy.org/docs/api-kivy.uix.widget.html#kivy.uix.widget.Widget.size_hint_y "kivy.uix.widget.Widget.size_hint_y") 为 .5,但似乎只有对 [`size_hint_x`](https://kivy.org/docs/api-kivy.uix.widget.html#kivy.uix.widget.Widget.size_hint_x "kivy.uix.widget.Widget.size_hint_x") 的修改起作用了。这是因为在[盒式布局 `boxlayout`](https://kivy.org/docs/api-kivy.uix.boxlayout.html#module-kivy.uix.boxlayout "kivy.uix.boxlayout")中,当[`orientation`](https://kivy.org/docs/api-kivy.uix.boxlayout.html#kivy.uix.boxlayout.BoxLayout.orientation "kivy.uix.boxlayout.BoxLayout.orientation")被设置为竖直方向(vertical) 的时候,[`size_hint_y`](https://kivy.org/docs/api-kivy.uix.widget.html#kivy.uix.widget.Widget.size_hint_y "kivy.uix.widget.Widget.size_hint_y") 由布局来控制,而如果[`orientation`](https://kivy.org/docs/api-kivy.uix.boxlayout.html#kivy.uix.boxlayout.BoxLayout.orientation "kivy.uix.boxlayout.BoxLayout.orientation") 被设置为水平方向(horizontal)的时候, [`size_hint_x`](https://kivy.org/docs/api-kivy.uix.widget.html#kivy.uix.widget.Widget.size_hint_x "kivy.uix.widget.Widget.size_hint_x") 由布局来控制,所以这些情况手动设定就无效了。 这些受控维度的尺寸,是根据[子控件 `children`](https://kivy.org/docs/api-kivy.uix.widget.html#kivy.uix.widget.Widget.children "kivy.uix.widget.Widget.children") 在 [`盒式布局 boxlayout`](https://kivy.org/docs/api-kivy.uix.boxlayout.html#module-kivy.uix.boxlayout "kivy.uix.boxlayout")中的总编号来计算的。在上面的例子中,这个子控件的[`size_hint_y`](https://kivy.org/docs/api-kivy.uix.widget.html#kivy.uix.widget.Widget.size_hint_y "kivy.uix.widget.Widget.size_hint_y") 是受控的(.5/.5 = 1)。所以,这里控件就占据了上层布局的整个高度。 166 | 167 | 接下来咱们再添加一个[按钮 `Button`](https://kivy.org/docs/api-kivy.uix.button.html#kivy.uix.button.Button "kivy.uix.button.Button")到这个 [布局 `layout`](https://kivy.org/docs/api-kivy.uix.layout.html#module-kivy.uix.layout "kivy.uix.layout")看看有什么效果。 168 | 169 | ![../_images/size_hint[bb].jpg](https://kivy.org/docs/_images/size_hint[bb].jpg) 170 | 171 | [盒式布局 `boxlayout`](https://kivy.org/docs/api-kivy.uix.boxlayout.html#module-kivy.uix.boxlayout "kivy.uix.boxlayout") 默认对其所有的[子控件 `children`](https://kivy.org/docs/api-kivy.uix.widget.html#kivy.uix.widget.Widget.children "kivy.uix.widget.Widget.children")分配了等大的空间。在咱们这个例子里面,比例是50-50,因为有两个[子控件 `children`](https://kivy.org/docs/api-kivy.uix.widget.html#kivy.uix.widget.Widget.children "kivy.uix.widget.Widget.children")。那么接下来咱们就对其中的一个子控件设置一下 size_hint,然后看看效果怎么样。 172 | 173 | ![../_images/size_hint[oB].jpg](https://kivy.org/docs/_images/size_hint[oB].jpg) 174 | 175 | 从上图可以看出,如果一个子控件有了一个指定的 [`size_hint`](https://kivy.org/docs/api-kivy.uix.widget.html#kivy.uix.widget.Widget.size_hint "kivy.uix.widget.Widget.size_hint"),这就会决定该[控件 `Widget`](https://kivy.org/docs/api-kivy.uix.widget.html#kivy.uix.widget.Widget "kivy.uix.widget.Widget")使用[盒式布局 `boxlayout`](https://kivy.org/docs/api-kivy.uix.boxlayout.html#module-kivy.uix.boxlayout "kivy.uix.boxlayout")提供的空间中的多大比例,来作为自己的[尺寸 `size`](https://kivy.org/docs/api-kivy.uix.widget.html#kivy.uix.widget.Widget.size "kivy.uix.widget.Widget.size") 。在我们这个例子中,第一个[按钮 `Button`](https://kivy.org/docs/api-kivy.uix.button.html#kivy.uix.button.Button "kivy.uix.button.Button") 的[`size_hint_x`](https://kivy.org/docs/api-kivy.uix.widget.html#kivy.uix.widget.Widget.size_hint_x "kivy.uix.widget.Widget.size_hint_x")设置为了 .5。那么这个控件分配到的空间计算方法如下: 176 | 177 | ```Python 178 | first child's size_hint divided by 179 | first child's size_hint + second child's size_hint + ...n(no of children) 180 | 181 | .5/(.5+1) = .333... 182 | ``` 183 | 184 | 185 | 盒式布局 BoxLayout 的剩余[宽度 `width`](https://kivy.org/docs/api-kivy.uix.widget.html#kivy.uix.widget.Widget.width "kivy.uix.widget.Widget.width")会分配给另外的一个[子控件 `children`](https://kivy.org/docs/api-kivy.uix.widget.html#kivy.uix.widget.Widget.children "kivy.uix.widget.Widget.children")。在我们这个例子中,这就意味着第二个[按钮 `Button`](https://kivy.org/docs/api-kivy.uix.button.html#kivy.uix.button.Button "kivy.uix.button.Button") 会占据整个[布局 `layout`](https://kivy.org/docs/api-kivy.uix.layout.html#module-kivy.uix.layout "kivy.uix.layout")的 66.66% [宽度 `width`](https://kivy.org/docs/api-kivy.uix.widget.html#kivy.uix.widget.Widget.width "kivy.uix.widget.Widget.width") 。 186 | 187 | 修改 [`size_hint`](https://kivy.org/docs/api-kivy.uix.widget.html#kivy.uix.widget.Widget.size_hint "kivy.uix.widget.Widget.size_hint") 探索一下来多适应一下吧。 188 | 189 | 190 | 如果你想要控制一个[控件 `Widget`](https://kivy.org/docs/api-kivy.uix.widget.html#kivy.uix.widget.Widget "kivy.uix.widget.Widget")的绝对[尺寸 `size`](https://kivy.org/docs/api-kivy.uix.widget.html#kivy.uix.widget.Widget.size "kivy.uix.widget.Widget.size") ,可以把[`size_hint_x`](https://kivy.org/docs/api-kivy.uix.widget.html#kivy.uix.widget.Widget.size_hint_x "kivy.uix.widget.Widget.size_hint_x")/[`size_hint_y`](https://kivy.org/docs/api-kivy.uix.widget.html#kivy.uix.widget.Widget.size_hint_y "kivy.uix.widget.Widget.size_hint_y")当中的一个或者两个都设置成 None,这样的话该控件的[宽度 `width`](https://kivy.org/docs/api-kivy.uix.widget.html#kivy.uix.widget.Widget.width "kivy.uix.widget.Widget.width") 和[高度 `height`](https://kivy.org/docs/api-kivy.uix.widget.html#kivy.uix.widget.Widget.height "kivy.uix.widget.Widget.height")的属性值就会生效了。 191 | 192 | [`pos_hint`](https://kivy.org/docs/api-kivy.uix.widget.html#kivy.uix.widget.Widget.pos_hint "kivy.uix.widget.Widget.pos_hint") 是一个词典 dict,默认值是空。相比于[`size_hint`](https://kivy.org/docs/api-kivy.uix.widget.html#kivy.uix.widget.Widget.size_hint "kivy.uix.widget.Widget.size_hint"),布局对[`pos_hint`](https://kivy.org/docs/api-kivy.uix.widget.html#kivy.uix.widget.Widget.pos_hint "kivy.uix.widget.Widget.pos_hint")的处理方式有些不同,不过大体上你还是可以对[`pos`](https://kivy.org/docs/api-kivy.uix.widget.html#kivy.uix.widget.Widget.pos "kivy.uix.widget.Widget.pos") 的各种属性设定某个值来设定[控件 `Widget`](https://kivy.org/docs/api-kivy.uix.widget.html#kivy.uix.widget.Widget "kivy.uix.widget.Widget")在[父控件 `parent`](https://kivy.org/docs/api-kivy.uix.widget.html#kivy.uix.widget.Widget.parent "kivy.uix.widget.Widget.parent")中的相对位置(可以设定的属性包括:[`x`](https://kivy.org/docs/api-kivy.uix.widget.html#kivy.uix.widget.Widget.x "kivy.uix.widget.Widget.x"), [`y`](https://kivy.org/docs/api-kivy.uix.widget.html#kivy.uix.widget.Widget.y "kivy.uix.widget.Widget.y"), [`right`](https://kivy.org/docs/api-kivy.uix.widget.html#kivy.uix.widget.Widget.right "kivy.uix.widget.Widget.right"), [`top`](https://kivy.org/docs/api-kivy.uix.widget.html#kivy.uix.widget.Widget.top "kivy.uix.widget.Widget.top"), [`center_x`](https://kivy.org/docs/api-kivy.uix.widget.html#kivy.uix.widget.Widget.center_x "kivy.uix.widget.Widget.center_x"), [`center_y`](https://kivy.org/docs/api-kivy.uix.widget.html#kivy.uix.widget.Widget.center_y "kivy.uix.widget.Widget.center_y"))。 193 | 194 | 195 | 咱们用下面 kivycatalog 中的代码来可视化地理解一下[`pos_hint`](https://kivy.org/docs/api-kivy.uix.widget.html#kivy.uix.widget.Widget.pos_hint "kivy.uix.widget.Widget.pos_hint"): 196 | 197 | 198 | ```Python 199 | FloatLayout: 200 | Button: 201 | text: "We Will" 202 | pos: 100, 100 203 | size_hint: .2, .4 204 | Button: 205 | text: "Wee Wiill" 206 | pos: 200, 200 207 | size_hint: .4, .2 208 | 209 | Button: 210 | text: "ROCK YOU!!" 211 | pos_hint: {'x': .3, 'y': .6} 212 | size_hint: .5, .2 213 | ``` 214 | 215 | 216 | 这份代码的输出效果如下图所示: 217 | 218 | ![../_images/pos_hint.jpg](https://kivy.org/docs/_images/pos_hint.jpg) 219 | 220 | 说了半天[`size_hint`](https://kivy.org/docs/api-kivy.uix.widget.html#kivy.uix.widget.Widget.size_hint "kivy.uix.widget.Widget.size_hint"),你不妨自己试试探索一下 [`pos_hint`](https://kivy.org/docs/api-kivy.uix.widget.html#kivy.uix.widget.Widget.pos_hint "kivy.uix.widget.Widget.pos_hint"),来理解一下这个属性对控件位置的效果。 221 | 222 | 223 | 224 | 225 | 226 | ## 给布局添加背景 227 | 228 | 关于布局,有一个问题经常被问道: 229 | 230 | “怎么给一个布局添加背景图片/颜色/视频/等等......” 231 | 232 | 本来默认的各种布局都是没有视觉呈现的:因为布局不像控件,布局是默认不含有绘图指令的。不过呢,还是你可以给一个布局实例添上绘图指令,也就可以添加一个彩色背景了: 233 | 234 | 在 Python 中的实现方法: 235 | 236 | ```Python 237 | from kivy.graphics import Color, Rectangle 238 | 239 | with layout_instance.canvas.before: 240 | Color(0, 1, 0, 1) # green; colors range from 0-1 instead of 0-255 241 | self.rect = Rectangle(size=layout_instance.size, 242 | pos=layout_instance.pos) 243 | ``` 244 | 245 | 然而很不幸,这样只能在布局的初始化位置以布局的初始尺寸绘制一个矩形。所以还要对布局的尺寸和位置变化进行监听,然后对矩形的尺寸位置进行更新,这样才能保证这个矩形一直绘制在布局的内部。可以用如下方式实现: 246 | 247 | 248 | ```Python 249 | with layout_instance.canvas.before: 250 | Color(0, 1, 0, 1) # green; colors range from 0-1 instead of 0-255 251 | self.rect = Rectangle(size=layout_instance.size, 252 | pos=layout_instance.pos) 253 | 254 | def update_rect(instance, value): 255 | instance.rect.pos = instance.pos 256 | instance.rect.size = instance.size 257 | 258 | # listen to size and position changes 259 | layout_instance.bind(pos=update_rect, size=update_rect) 260 | ``` 261 | 262 | 在 kv 文件中: 263 | 264 | ```Python 265 | FloatLayout: 266 | canvas.before: 267 | Color: 268 | rgba: 0, 1, 0, 1 269 | Rectangle: 270 | # self here refers to the widget i.e BoxLayout 271 | pos: self.pos 272 | size: self.size 273 | ``` 274 | 275 | 上面的 Kv 文件中的生命,就建立了一个隐含的绑定:上面 Kv 代码中的最后两行保证了矩形的[位置 `pos`](https://kivy.org/docs/api-kivy.uix.widget.html#kivy.uix.widget.Widget.pos "kivy.uix.widget.Widget.pos")和[尺寸 `size`](https://kivy.org/docs/api-kivy.uix.widget.html#kivy.uix.widget.Widget.size "kivy.uix.widget.Widget.size")会在[浮动布局 `floatlayout`](https://kivy.org/docs/api-kivy.uix.floatlayout.html#module-kivy.uix.floatlayout "kivy.uix.floatlayout")的[位置 `pos`](https://kivy.org/docs/api-kivy.uix.widget.html#kivy.uix.widget.Widget.pos "kivy.uix.widget.Widget.pos")发生变化的时候进行更新。 276 | 277 | 接下来咱们把上面的代码片段放进 Kivy 应用里面。 278 | 279 | 纯 Python 方法: 280 | 281 | ```Python 282 | from kivy.app import App 283 | from kivy.graphics import Color, Rectangle 284 | from kivy.uix.floatlayout import FloatLayout 285 | from kivy.uix.button import Button 286 | 287 | class RootWidget(FloatLayout): 288 | 289 | def __init__(self, **kwargs): 290 | # make sure we aren't overriding any important functionality 291 | super(RootWidget, self).__init__(**kwargs) 292 | 293 | # let's add a Widget to this layout 294 | self.add_widget( 295 | Button( 296 | text="Hello World", 297 | size_hint=(.5, .5), 298 | pos_hint={'center_x': .5, 'center_y': .5})) 299 | 300 | class MainApp(App): 301 | 302 | def build(self): 303 | self.root = root = RootWidget() 304 | root.bind(size=self._update_rect, pos=self._update_rect) 305 | 306 | with root.canvas.before: 307 | Color(0, 1, 0, 1) # green; colors range from 0-1 not 0-255 308 | self.rect = Rectangle(size=root.size, pos=root.pos) 309 | return root 310 | 311 | def _update_rect(self, instance, value): 312 | self.rect.pos = instance.pos 313 | self.rect.size = instance.size 314 | 315 | if __name__ == '__main__': 316 | MainApp().run() 317 | ``` 318 | 319 | 使用 Kv 语言: 320 | 321 | ```Python 322 | from kivy.app import App 323 | from kivy.lang import Builder 324 | 325 | 326 | root = Builder.load_string(''' 327 | FloatLayout: 328 | canvas.before: 329 | Color: 330 | rgba: 0, 1, 0, 1 331 | Rectangle: 332 | # self here refers to the widget i.e FloatLayout 333 | pos: self.pos 334 | size: self.size 335 | Button: 336 | text: 'Hello World!!' 337 | size_hint: .5, .5 338 | pos_hint: {'center_x':.5, 'center_y': .5} 339 | ''') 340 | 341 | class MainApp(App): 342 | 343 | def build(self): 344 | return root 345 | 346 | if __name__ == '__main__': 347 | MainApp().run() 348 | ``` 349 | 350 | 上面这两个应用的效果都如下图所示: 351 | ![../_images/layout_background.png](https://kivy.org/docs/_images/layout_background.png) 352 | 353 | ### 给**自定义布局规则/类**增加背景色 354 | 355 | 上面那一段中咱们对布局实例增加背景的方法,如果用到很多歌布局里面,那就很快变得特别麻烦了。要解决这种需求,就可以基于布局类 Layout 创建一个自定义的布局子类,给自定义的这个类增加一个背景。 356 | 357 | 358 | 使用 Python: 359 | 360 | ```Python 361 | from kivy.app import App 362 | from kivy.graphics import Color, Rectangle 363 | from kivy.uix.boxlayout import BoxLayout 364 | from kivy.uix.floatlayout import FloatLayout 365 | from kivy.uix.image import AsyncImage 366 | 367 | class RootWidget(BoxLayout): 368 | pass 369 | 370 | class CustomLayout(FloatLayout): 371 | 372 | def __init__(self, **kwargs): 373 | # make sure we aren't overriding any important functionality 374 | super(CustomLayout, self).__init__(**kwargs) 375 | 376 | with self.canvas.before: 377 | Color(0, 1, 0, 1) # green; colors range from 0-1 instead of 0-255 378 | self.rect = Rectangle(size=self.size, pos=self.pos) 379 | 380 | self.bind(size=self._update_rect, pos=self._update_rect) 381 | 382 | def _update_rect(self, instance, value): 383 | self.rect.pos = instance.pos 384 | self.rect.size = instance.size 385 | 386 | class MainApp(App): 387 | 388 | def build(self): 389 | root = RootWidget() 390 | c = CustomLayout() 391 | root.add_widget(c) 392 | c.add_widget( 393 | AsyncImage( 394 | source="http://www.everythingzoomer.com/wp-content/uploads/2013/01/Monday-joke-289x277.jpg", 395 | size_hint= (1, .5), 396 | pos_hint={'center_x':.5, 'center_y':.5})) 397 | root.add_widget(AsyncImage(source='http://www.stuffistumbledupon.com/wp-content/uploads/2012/05/Have-you-seen-this-dog-because-its-awesome-meme-puppy-doggy.jpg')) 398 | c = CustomLayout() 399 | c.add_widget( 400 | AsyncImage( 401 | source="http://www.stuffistumbledupon.com/wp-content/uploads/2012/04/Get-a-Girlfriend-Meme-empty-wallet.jpg", 402 | size_hint= (1, .5), 403 | pos_hint={'center_x':.5, 'center_y':.5})) 404 | root.add_widget(c) 405 | return root 406 | 407 | if __name__ == '__main__': 408 | MainApp().run() 409 | ``` 410 | 411 | 使用 Kv 语言: 412 | 413 | ```Python 414 | from kivy.app import App 415 | from kivy.uix.floatlayout import FloatLayout 416 | from kivy.uix.boxlayout import BoxLayout 417 | from kivy.lang import Builder 418 | 419 | 420 | Builder.load_string(''' 421 | <CustomLayout> 422 | canvas.before: 423 | Color: 424 | rgba: 0, 1, 0, 1 425 | Rectangle: 426 | pos: self.pos 427 | size: self.size 428 | 429 | <RootWidget> 430 | CustomLayout: 431 | AsyncImage: 432 | source: 'http://www.everythingzoomer.com/wp-content/uploads/2013/01/Monday-joke-289x277.jpg' 433 | size_hint: 1, .5 434 | pos_hint: {'center_x':.5, 'center_y': .5} 435 | AsyncImage: 436 | source: 'http://www.stuffistumbledupon.com/wp-content/uploads/2012/05/Have-you-seen-this-dog-because-its-awesome-meme-puppy-doggy.jpg' 437 | CustomLayout 438 | AsyncImage: 439 | source: 'http://www.stuffistumbledupon.com/wp-content/uploads/2012/04/Get-a-Girlfriend-Meme-empty-wallet.jpg' 440 | size_hint: 1, .5 441 | pos_hint: {'center_x':.5, 'center_y': .5} 442 | ''') 443 | 444 | class RootWidget(BoxLayout): 445 | pass 446 | 447 | class CustomLayout(FloatLayout): 448 | pass 449 | 450 | class MainApp(App): 451 | 452 | def build(self): 453 | return RootWidget() 454 | 455 | if __name__ == '__main__': 456 | MainApp().run() 457 | ``` 458 | 459 | 上面这两个应用的效果都如下图所示: 460 | 461 | ![../_images/custom_layout_background.png](https://kivy.org/docs/_images/custom_layout_background.png) 462 | 463 | 在自定义布局类中定义了背景之后,就是要确保在自定义布局的各个实例中使用到这个新特性。 464 | 465 | 466 | 首先,要在**全局上**增加一个图形或者颜色给内置的 Kivy 布局的背景,这就需要将所用布局的默认 Kv 规则进行覆盖。 467 | 468 | 就拿网格布局 GridLayout 举例吧: 469 | 470 | ```Python 471 | <GridLayout> 472 | canvas.before: 473 | Color: 474 | rgba: 0, 1, 0, 1 475 | BorderImage: 476 | source: '../examples/widgets/sequenced_images/data/images/button_white.png' 477 | pos: self.pos 478 | size: self.size 479 | ``` 480 | 481 | 接下来把这段代码放到一个 Kivy 应用里面: 482 | 483 | ```Python 484 | from kivy.app import App 485 | from kivy.uix.floatlayout import FloatLayout 486 | from kivy.lang import Builder 487 | 488 | 489 | Builder.load_string(''' 490 | <GridLayout> 491 | canvas.before: 492 | BorderImage: 493 | # BorderImage behaves like the CSS BorderImage 494 | border: 10, 10, 10, 10 495 | source: '../examples/widgets/sequenced_images/data/images/button_white.png' 496 | pos: self.pos 497 | size: self.size 498 | 499 | <RootWidget> 500 | GridLayout: 501 | size_hint: .9, .9 502 | pos_hint: {'center_x': .5, 'center_y': .5} 503 | rows:1 504 | Label: 505 | text: "I don't suffer from insanity, I enjoy every minute of it" 506 | text_size: self.width-20, self.height-20 507 | valign: 'top' 508 | Label: 509 | text: "When I was born I was so surprised; I didn't speak for a year and a half." 510 | text_size: self.width-20, self.height-20 511 | valign: 'middle' 512 | halign: 'center' 513 | Label: 514 | text: "A consultant is someone who takes a subject you understand and makes it sound confusing" 515 | text_size: self.width-20, self.height-20 516 | valign: 'bottom' 517 | halign: 'justify' 518 | ''') 519 | 520 | class RootWidget(FloatLayout): 521 | pass 522 | 523 | 524 | class MainApp(App): 525 | 526 | def build(self): 527 | return RootWidget() 528 | 529 | if __name__ == '__main__': 530 | MainApp().run() 531 | ``` 532 | 533 | 效果大概如下图所示: 534 | 535 | ![../_images/global_background.png](https://kivy.org/docs/_images/global_background.png) 536 | 537 | 我们已经对网格布局 GridLayout 类的规则进行了覆盖,所以接下来在应用中使用这个类就都会显示那幅图片了。 538 | 539 | **动画背景**怎么弄呢? 540 | 541 | 就像在矩形Rectangle/ 边界图像BorderImage /椭圆Ellipse/等里面添加设置绘图指令一样,可以用一个特定的纹理属性 texture : 542 | 543 | ```Python 544 | Rectangle: 545 | texture: reference to a texture 546 | ``` 547 | 548 | 549 | 可以用下面的代码实现一个动画背景: 550 | 551 | ```Python 552 | from kivy.app import App 553 | from kivy.uix.floatlayout import FloatLayout 554 | from kivy.uix.gridlayout import GridLayout 555 | from kivy.uix.image import Image 556 | from kivy.properties import ObjectProperty 557 | from kivy.lang import Builder 558 | 559 | 560 | Builder.load_string(''' 561 | <CustomLayout> 562 | canvas.before: 563 | BorderImage: 564 | # BorderImage behaves like the CSS BorderImage 565 | border: 10, 10, 10, 10 566 | texture: self.background_image.texture 567 | pos: self.pos 568 | size: self.size 569 | 570 | <RootWidget> 571 | CustomLayout: 572 | size_hint: .9, .9 573 | pos_hint: {'center_x': .5, 'center_y': .5} 574 | rows:1 575 | Label: 576 | text: "I don't suffer from insanity, I enjoy every minute of it" 577 | text_size: self.width-20, self.height-20 578 | valign: 'top' 579 | Label: 580 | text: "When I was born I was so surprised; I didn't speak for a year and a half." 581 | text_size: self.width-20, self.height-20 582 | valign: 'middle' 583 | halign: 'center' 584 | Label: 585 | text: "A consultant is someone who takes a subject you understand and makes it sound confusing" 586 | text_size: self.width-20, self.height-20 587 | valign: 'bottom' 588 | halign: 'justify' 589 | ''') 590 | 591 | 592 | class CustomLayout(GridLayout): 593 | 594 | background_image = ObjectProperty( 595 | Image( 596 | source='../examples/widgets/sequenced_images/data/images/button_white_animated.zip', 597 | anim_delay=.1)) 598 | 599 | 600 | class RootWidget(FloatLayout): 601 | pass 602 | 603 | 604 | class MainApp(App): 605 | 606 | def build(self): 607 | return RootWidget() 608 | 609 | if __name__ == '__main__': 610 | MainApp().run() 611 | ``` 612 | 613 | 614 | 要理解这里到底发生了什么,得从第 13 行开始看: 615 | 616 | ```Python 617 | texture: self.background_image.texture 618 | ``` 619 | 620 | 这里是指定让边界图像 BorderImage 的纹理属性在背景图像 background_image 的纹理属性发生更新的时候进行同步更新。背景图像 background_image 属性的定义是在第 40 行: 621 | 622 | ```Python 623 | background_image = ObjectProperty(... 624 | ``` 625 | 626 | 627 | 这一句代码是将背景图像 background_image 设置成一个[对象属性 `ObjectProperty`](https://kivy.org/docs/api-kivy.properties.html#kivy.properties.ObjectProperty "kivy.properties.ObjectProperty"),这样就可以在其中添加一个[图形控件 `Image`](https://kivy.org/docs/api-kivy.uix.image.html#kivy.uix.image.Image "kivy.uix.image.Image")。图像控件有一个纹理属性(texture property);在前面的 self.background_image.texture 这句代码中,就是建立了一个名为 texture 的到这个属性的引用。[图形控件 `Image`](https://kivy.org/docs/api-kivy.uix.image.html#kivy.uix.image.Image "kivy.uix.image.Image") 支持动画(animation):随着动画的改变,图像的纹理会同步更新,在这个过程中,边界图像 BorderImage 指令的 texture 纹理属性也会同步更新。 628 | 629 | (译者注:texture of BorderImage instruction,这里我对 instruction 的翻译应该是不太对的,不过我还没理清楚该怎么表述。) 630 | 631 | 也可以直接传递自定义数据到纹理属性 texture。更多细节可以参考[纹理 `Texture` 的文档](https://kivy.org/docs/api-kivy.graphics.texture.html#kivy.graphics.texture.Texture "kivy.graphics.texture.Texture")。 632 | 633 | 634 | 635 | 636 | ## 网状布局 637 | 638 | 嗯,看看这个过程如何扩展是很有趣的。 639 | 640 | 641 | ## 尺寸和位置度量 642 | 643 | Kivy 的默认长度单位是像素 pixel,所有的尺寸和位置都用这个单位来表达。你也可以用其他单位来衡量,在跨平台多种设备的时候,这有助于实现更好的连续性体验(这些设备会把尺寸自动转换到像素)。 644 | 645 | 可用单位包括 [`pt`](https://kivy.org/docs/api-kivy.metrics.html#kivy.metrics.pt "kivy.metrics.pt"), [`mm`](https://kivy.org/docs/api-kivy.metrics.html#kivy.metrics.mm "kivy.metrics.mm"),[`cm`](https://kivy.org/docs/api-kivy.metrics.html#kivy.metrics.cm "kivy.metrics.cm"), [`inch`](https://kivy.org/docs/api-kivy.metrics.html#kivy.metrics.inch "kivy.metrics.inch"), [`dp`](https://kivy.org/docs/api-kivy.metrics.html#kivy.metrics.dp "kivy.metrics.dp") and [`sp`](https://kivy.org/docs/api-kivy.metrics.html#kivy.metrics.sp "kivy.metrics.sp")。可以在[度量文档 `metrics`](https://kivy.org/docs/api-kivy.metrics.html#module-kivy.metrics "kivy.metrics") 中了解更多相关内容。 646 | 647 | 你还可以探索一下[屏幕模块 `screen`](https://kivy.org/docs/api-kivy.modules.screen.html#module-kivy.modules.screen "kivy.modules.screen")的用法,这个可以模拟出不同设备的屏幕,供测试应用。 648 | 649 | 650 | ## 使用屏幕管理器进行屏幕分割 651 | 652 | 如果你的应用程序要包含多个程序,那可能就需要从一个[屏幕 `Screen`](https://kivy.org/docs/api-kivy.uix.screenmanager.html#kivy.uix.screenmanager.Screen "kivy.uix.screenmanager.Screen")到另一个[屏幕 `Screen`](https://kivy.org/docs/api-kivy.uix.screenmanager.html#kivy.uix.screenmanager.Screen "kivy.uix.screenmanager.Screen")提供一个导航的通道。幸运的是,正好有一个[屏幕管理器类`ScreenManager`](https://kivy.org/docs/api-kivy.uix.screenmanager.html#kivy.uix.screenmanager.ScreenManager "kivy.uix.screenmanager.ScreenManager"),这个类允许你来定义分开的各个屏幕,设置屏幕管理器的[`TransitionBase`](https://kivy.org/docs/api-kivy.uix.screenmanager.html#kivy.uix.screenmanager.TransitionBase "kivy.uix.screenmanager.TransitionBase")就可以实现从一个屏幕到另一个屏幕的跳转导航。 653 | 654 | 655 | 656 | --------------------------------------------------------------------------------