Try Toga
Toga 是一个跨平台的Python GUI库, 支持Android和iOS,有一些简单的控件。它不像kivy那么复杂,kivy要求我们去学习 一种新的脚本语言来写界面,如果都需要学一门新的语言,那为什么我不用web的方式来开发界面呢? 所以我一直没有想去深入了解kivy。
Toga hello
所有的GUI程序大抵是相似的:
- 一个App对象
- 一个主窗口
- 一些菜单和工具栏按钮(command)
- 一些widget
- 一些container/box
- box和widget可以通过某些style来改变布局和样式
import toga
from toga.style.pack import COLUMN, Pack
def button_handler(widget):
print("button handler")
for i in range(0, 10):
print("hello", i)
yield 1
print("done", i)
def action0(widget):
print("action 0")
def action1(widget):
print("action 1")
def action2(widget):
print("action 2")
def action3(widget):
print("action 3")
def action5(widget):
print("action 5")
def action6(widget):
print("action 6")
class Tutorial2App(toga.App):
def startup(self):
brutus_icon = "icons/brutus"
cricket_icon = "icons/cricket-72.png"
data = [("root%s" % i, "value %s" % i) for i in range(1, 100)]
left_container = toga.Table(headings=["Hello", "World"], data=data)
right_content = toga.Box(style=Pack(direction=COLUMN, padding_top=50))
for b in range(0, 10):
right_content.add(
toga.Button(
"Hello world %s" % b,
on_press=button_handler,
style=Pack(width=200, padding=20),
)
)
right_container = toga.ScrollContainer(horizontal=False)
right_container.content = right_content
split = toga.SplitContainer()
# The content of the split container can be specified as a simple list:
# split.content = [left_container, right_container]
# but you can also specify "weight" with each content item, which will
# set an initial size of the columns to make a "heavy" column wider than
# a narrower one. In this example, the right container will be twice
# as wide as the left one.
split.content = [(left_container, 1), (right_container, 2)]
# Create a "Things" menu group to contain some of the commands.
# No explicit ordering is provided on the group, so it will appear
# after application-level menus, but *before* the Command group.
# Items in the Things group are not explicitly ordered either, so they
# will default to alphabetical ordering within the group.
things = toga.Group("Things")
cmd0 = toga.Command(
action0,
text="Action 0",
tooltip="Perform action 0",
icon=brutus_icon,
group=things,
)
cmd1 = toga.Command(
action1,
text="Action 1",
tooltip="Perform action 1",
icon=brutus_icon,
group=things,
)
cmd2 = toga.Command(
action2,
text="Action 2",
tooltip="Perform action 2",
icon=toga.Icon.DEFAULT_ICON,
group=things,
)
# Commands without an explicit group end up in the "Commands" group.
# The items have an explicit ordering that overrides the default
# alphabetical ordering
cmd3 = toga.Command(
action3,
text="Action 3",
tooltip="Perform action 3",
shortcut=toga.Key.MOD_1 + "k",
icon=cricket_icon,
order=3,
)
# Define a submenu inside the Commands group.
# The submenu group has an order that places it in the parent menu.
# The items have an explicit ordering that overrides the default
# alphabetical ordering.
sub_menu = toga.Group("Sub Menu", parent=toga.Group.COMMANDS, order=2)
cmd5 = toga.Command(
action5,
text="Action 5",
tooltip="Perform action 5",
order=2,
group=sub_menu,
)
cmd6 = toga.Command(
action6,
text="Action 6",
tooltip="Perform action 6",
order=1,
group=sub_menu,
)
def action4(widget):
print("CALLING Action 4")
cmd3.enabled = not cmd3.enabled
cmd4 = toga.Command(
action4,
text="Action 4",
tooltip="Perform action 4",
icon=brutus_icon,
order=1,
)
# The order in which commands are added to the app or the toolbar won't
# alter anything. Ordering is defined by the command definitions.
self.commands.add(cmd1, cmd0, cmd6, cmd4, cmd5, cmd3)
self.main_window = toga.MainWindow()
# Command 2 has not been *explicitly* added to the app. Adding it to
# a toolbar implicitly adds it to the app.
self.main_window.toolbar.add(cmd1, cmd3, cmd2, cmd4)
self.main_window.content = split
self.main_window.show()
def main():
return Tutorial2App("Tutorial 2", "org.beeware.toga.tutorial")
if __name__ == "__main__":
main().main_loop()
Togo Android
跨平台到安卓上Android最难搞的还是打包,外加一些上网问题。Togo使用briefcase 进行打包。
安装
pip install briefcase
创建一个新的工程
briefcase new
如果只是想测试下,可以加--no-input
,其实就是所有的都默认。
不出意外的话,就会有一些工程没法下载,咱们可以自己手动建
C:\Users\<your-user-name>\AppData\Local\BeeWare\briefcase\Cache\templates
然后在其中手动clone两个工程
git clone github:beeware/briefcase-android-gradle-template.git
git clone github:beeware/briefcase-template
之后就能顺利完成创建新工程了。
打包工程
briefcase package android -p apk
以上命令是在所有都设置好的时候才生效,现在我们来设置。
Android SDK
首先我建议安装Android studio, 然后在 Tools
=> SDK Manager
中,下载SDK,注意必须要勾选 SDK Tools
中的 Android SDK Command-line Tools
然后修改环境变量,将 ANDROID_HOME
设置为SDK所在目录,默认为 C:\Users\<your-user-name>\AppData\Local\Android\Sdk
JDK
briefcase目前要求JDK17,可以在微软的网站上下载,
下载完随便解压到一个地方,然后修改环境变量,将 JAVA_HOME
指向解压的目录即可
Gradle
Gradle可以从这里下载, 但是默认不是从这里下载的,由于我在下载完成前,脚本已经从官方成功下载的这个文件,所以没研究如何手动安装gradle,也许这里可以
但是gradle的镜像还是要设置的,将这个 init.gradle 文件放到 C:\Users\<your-user-name>\.gradle
中即可
签名
经过以上配置,应该能成功生成apk文件,但是如果这个时候将apk文件下载到手机中,
会提示 packageInfo is null
,表示没有签名。briefcase官方文档中关于
keytool的描述根本就没法找到,经过研究,我采用下面的方式。
打开Android Studio,如下动图,创建一个jks文件,并在其中创建一个key,请记住 Alias
和 Password
使用APK Tool签名,
先要将签名按Android Studio生成的jks来设置,如下图所示
最后回到主页来,对生成的apk进行签名,签名无误后即可下载到手机中安装
结束语
我想我可以教小朋友们写自己的手机app了。
如果要处理带c扩展的库的话,还有很多问题,暂时还没有尝试,参见这里