💭 写在前面:我们假定读者已经安装好了 3.8 版本后的 Python,并且安装好了依赖项,在 Windows 上构建 BeeWare 应用程序需要 Git,你可以可以从 git-scm.org 网站下载。安装完毕后重新启动 cmd,然后就可以准备建立虚拟环境了。
0x00 建立虚拟环境(基于 Windows)
首先,我们需要创建一个 "沙盒" 用于教程的演示,在虚拟环境中安装软件包,我们电脑上的其他 Python 项目将不会被影响。如此一来,即使玩坏了也不会污染环境,直接把 "沙盒" 丢了就行。
💬 具体操作:在 Windows cmd 下输入
md beeware-tutorial
cd beeware-tutorial
py -m venv beeware-venv
beeware-venv\Scripts\activate.bat
输入完这些后,你的提示符前会出现 (beeware-env)
前缀:
这表示你已经在 BeeWare 的虚拟环境中了,在学习本教程时,请确保你的虚拟环境被激活!
下次运行时,直接运行 activate 指令来重新激活环境即可:
beeware-venv\Scripts\activate.bat # 环境激活
0x01 安装 BeeWare 工具
" 工欲善其事必先利其器 "
在 BeeWare 之旅开始前,我们需要先安装 "小蜜蜂的公文包" —— Briefcase!
Briefcase 是 BeeWare 的一个工具,可以用来打包你的应用程序,以便分发给最终用户。
当然,它也可以用来启动一个新的项目,就像核武器手提箱一样无所不能!
请确保你已在创建的 beeware-tutorial 目录中,并已激活 (beeware-env)
虚拟环境。
💬 操作:在 beeware-tutorial 目录下输入
python -m pip install briefcase
稍等片刻……
当出现 Successfully installed 字样时,则表示已安装成功!
" 恭喜你,你已经拥有了小蜜蜂的万能手提箱 —— Briefcase 了 "
我们前面说过,Briefcase 可以用来打包你的应用程序,分发给最终用户。
还可以用来引导一个新的项目,下面我们就来教大家如何使用公文包启动一个新的项目!
0x02 利用 Briecase 启动新项目
" 任何伟大,都是从一个小小的 Hello,World 开始的,这里我们也不例外!"
我们使用 Briefcase 的 new 命令来创建一个名为 Hello World 的应用程序!
💬 操作:在 beeware-tutorial 目录下输入
briefcase new
公文包会让我们给新的应用程序添加 "亿点点" 细节 (details) :
第一次你可以按照我们的例子输入,"默认值" 直接输入回车即可。
-
正式名 - Formal Name:默认值
Hello World
-
应用程序名 - App Name:默认值
helloworld
-
捆绑 - Bundle:如果你有自己的域名,请按相反的顺序输入域名。举个例子,如果你拥有 foxny.com 域名,请输入 com.foxny。如果你没有自己的域名,就老老实实用默认捆绑 com.example。
-
项目名称 - Project Name:默认值
Hello World
. -
描述 - Description:默认值(或者你也可以写一段比较有意义的描述)
-
作者 - Author:写下你的名字
-
作者邮箱 - Author’s email - 输入你自己的电子邮件地址,这将用于配置文件、帮助文本,以及向应用商店提交应用时需要电子邮件的任何地方。
-
URL:你的应用程序的登陆页面的URL。同样,如果你拥有自己的域名,在该域名上输入一个URL(包括
https://
)。否则,就接受默认的 URL(https://example.com/helloworld
)。这个 URL 不需要实际存在(目前),只有当你把你的应用程序发布到应用商店时才会用到。 -
许可证 - License:接受默认的许可证(BSD)。不过这不会影响到教程的任何操作--所以如果你对许可证的选择有特别强烈的感受,可以自由选择其他许可证
-
GUI 框架 - GUI framework:选择 Toga (BeeWare 自己的 GUI 工具包,后续介绍)
然后 Briefcase 会生成一个项目框架供你使用,如果你按照我们给的示例写细节,你的文件系统应该是这样的:
beeware-tutorial/
beeware-venv/
...
helloworld/
CHANGELOG
LICENSE
README.rst
pyproject.toml
src/
helloworld/
resources/
helloworld.icns
helloworld.ico
helloworld.png
__init__.py
__main__.py
app.py
tests/
__init__.py
helloworld.py
test_app.py
这个框架实际上是一个功能齐全的应用程序,不需要添加任何其他东西。其中:
- src 文件夹内包含了应用程序的所有代码,
- test 文件夹包含了一个初始的测试套件。
- pyproject.toml 文件则描述了如何对应用程序进行打包发布。
如果你在编辑器中打开 pyproject.toml,你会看到你刚刚提供给 Briefcase 的配置细节。
现在我们有了一个存根应用程序 (stub application),可以用 Briefcase 来运行这个应用程序了。
0x03 在开发者模式下运行应用程序
cd 至 helloworld 项目目录,告诉 briefcase 在 Developer 模式 (或 dev 模式) 下启动该项目:
cd helloworld # cd至项目目录
briefcase dev # 启动项目
[helloworld] Installing requirements...
...
[helloworld] Starting in dev mode...
然后我们只需稍等片刻,GUI 窗口就打开了:
恭喜你,你刚刚用 Python 写了一个独立的本地应用程序!
我们现在有了一个工作的应用程序,在开发者模式下运行。现在我们可以添加一些我们自己的逻辑,使我们的应用程序做一些更有趣的事情。下面我们将为我们的应用程序添加一个更有用的用户界面。
0x04 默认生成了什么?
在 src/helloworld 目录中你能看到三个文件,分别是 __init__.py,__main__.py 和 app.py
- __init__.py:将 helloworld 目录标记为一个可导入的 Python 模块。它是一个空文件;它存在的事实告诉 Python 解释器,helloworld 目录定义了一个模块。
- __main__.py:将 helloworld 模块标记为一种特殊的模块 - 一个可执行模块 (executable module)。如果你试图用 python -m helloworld 来运行 helloworld 模块,__main__.py 文件就是 Python 开始执行的地方。
- app.py 中包含了创建应用程序窗口的逻辑。
其中 __main__.py 的内容相对简单,只有短短的 3 行代码:
from helloworld.app import main
if __name__ == '__main__':
main().main_loop()
不难理解,它从 helloworld 应用程序导入 main 方法,如果它作为入口点执行,则调用 main() 方法,并启动应用程序的主循环,主循环是 GUI 应用程序侦听用户输入 (如鼠标点击和键盘按下) 的方式。
0x05 分析默认生成的 app.py
app.py 中包含了创建应用程序窗口的逻辑:
import toga
from toga.style import Pack
from toga.style.pack import COLUMN, ROW
class HelloWorld(toga.App):
def startup(self):
main_box = toga.Box()
self.main_window = toga.MainWindow(title=self.formal_name)
self.main_window.content = main_box
self.main_window.show()
def main():
return HelloWorld()
是不是一脸茫然?不用担心,我们逐行解析它们!
🔑 详细解析:
① 首先我们导入 toga widget 工具包,以及一些与主题风格相关的实用类和常量。
import toga
from toga.style import Pack
from toga.style.pack import COLUMN, ROW
② 然后我们定义了一个 class 类:
class HelloWorld(toga.App):
每个 Toga 应用程序都有一个 toga.App 实例,代表应用程序的运行实体。应用程序最终可能会管理多个窗口 (multiple windows),但对于简单的应用程序,只会有一个主窗口 (main window) 。
③ 下面,我们定义了一个 startup() 启动方法:
def startup(self):
main_box = toga.Box()
startup 方法做的第一件事是定义一个主盒 (main box)。Toga 的布局方案的行为类似于 HTML,通过构建单盒 (single box) 的集合来建立一个应用程序,每个都包含其它的盒子,或一些部件 (actual widgets) 。然后,你将样式应用于这些盒子,以定义它们将如何使用可用的窗口空间。
在该应用程序中,我们只定义了单盒 (single box),没有放进去任何东西:
self.main_window = toga.MainWindow(title=self.formal_name)
这将创建一个 toga.MainWindow 的实例,它的标题将与应用程序的名称相符。在 Toga 中,主窗口是一种特殊的窗口,它是一个与应用程序的生命周期紧密相连的窗口。当主窗口销毁,应用程序就退出了。主窗口也是拥有应用程序菜单的窗口(如果你在像Windows这样的平台上,菜单栏是窗口的一部分)。
然后添加我们的 空盒 (empty box) 作为主窗口的内容,并指示应用程序显示我们的窗口:
self.main_window.content = main_box
self.main_window.show()
最后,我们定义了 main() 方法,它是创建我们应用程序的实例:
def main():
return HelloWorld()
这个 main() 方法是由 __main__.py 导入和调用的,它创建并返回一个我们的 HelloWorld 应用程序的实例。这是最简单的 Toga 应用程序,让我们把一些我们自己的内容放到应用程序中,并让应用程序做一些有趣的事情!
0x06 添加一些我们自己的内容
我们可以尝试修改 src/helloworld/app.py 中的 HelloWorld 类:
class HelloWorld(toga.App):
## 启动函数
def startup(self):
## 创建一个垂直排列的 Box 容器
main_box = toga.Box(style=Pack(direction=COLUMN))
## 通过 toga.Label 创建一个标签
name_label = toga.Label (
"Input your name: ", # 提示用户输出名字
style=Pack(padding=(0, 5))
)
## 通过 toga.TextInput 创建一个编辑框
self.name_input = toga.TextInput(style=Pack(flex=1))
## 创建水平排列的 Box 容器,将标签和编辑框组合在一起
name_box = toga.Box (
style = Pack(direction = ROW, padding = 5)
)
name_box.add(name_label) # 添加标签
name_box.add(self.name_input) # 添加编辑框
## 通过 toga.Button 创建按钮
button = toga.Button (
"Click here to say hello", # 按钮内容
on_press = self.say_hello, #按钮1_被单击 -> 触发 say_hello 函数
style = Pack(padding = 5) # 设置按钮风格
)
## 将组件添加到主框中 [*]
main_box.add(name_box) # 添加 - 刚才创建的水平排列的 Box 容器
main_box.add(button) # 添加 -刚才创建的按钮
## 创建主窗口
self.main_window = toga.MainWindow(title=self.formal_name)
self.main_window.content = main_box # 将主框设置为窗口内容
self.main_window.show() # 显示窗口
def say_hello(self, widget):
print(f"Hello, {self.name_input.value}")
print("hello world!\n");
📌 [ 笔者 ] 王亦优
📃 [ 更新 ] 2022.3.
❌ [ 勘误 ] /* 暂无 */
📜 [ 声明 ] 由于作者水平有限,本文有错误和不准确之处在所难免,
本人也很想知道这些错误,恳望读者批评指正!
📜 参考资料 C++reference[EB/OL]. []. http://www.cplusplus.com/reference/. Microsoft. MSDN(Microsoft Developer Network)[EB/OL]. []. . 百度百科[EB/OL]. []. https://baike.baidu.com/. Write once. Deploy everywhere.— BeeWare |