目录
- 应用程序
- 创建应用程序
- 应用程序配置
- 使用 on_start 和 on_stop 进行性能分析
- 自定义布局
- 暂停模式
- 异步应用
- 与其他协程交互Kivy应用
AppApp.async_run()App.build()App.build_config()App.build_settings()App.close_settings()App.configApp.create_settings()App.destroy_settings()App.directoryApp.display_settings()App.get_application_config()App.get_application_icon()App.get_application_name()App.get_running_app()App.iconApp.kv_directoryApp.kv_fileApp.load_config()App.load_kv()App.nameApp.on_config_change()App.on_pause()App.on_resume()App.on_start()App.on_stop()App.open_settings()App.optionsApp.pause()App.rootApp.root_windowApp.run()App.settings_clsApp.stop()App.titleApp.use_kivy_settingsApp.user_data_dir
async_runTouchApp()runTouchApp()stopTouchApp()
应用程序¶
App 类是创建 Kivy 应用程序的基础。可以将其视为进入 Kivy 运行循环的主要入口点。在大多数情况下,您会继承此类并创建自己的应用。您创建特定应用类的实例,然后,当准备好启动应用程序的生命周期时,调用该实例的 App.run() 方法。
创建应用程序¶
使用 build() 方法覆盖的方式¶
要在你的应用类中重写 build() 方法,并返回你构建的控件树,即可用控件树初始化你的应用。
以下是一个极简应用的示例,它仅显示一个按钮:
'''
Application example using build() + return
==========================================
An application can be built if you return a widget on build(), or if you set
self.root.
'''
import kivy
kivy.require('1.0.7')
from kivy.app import App
from kivy.uix.button import Button
class TestApp(App):
def build(self):
# return a Button() as a root widget
return Button(text='hello world')
if __name__ == '__main__':
TestApp().run()
该文件也可以在示例文件夹中找到:kivy/examples/application/app_with_build.py。
这里没有构建任何控件树(或者如果你愿意,可以说只有根节点的树)。
使用kv文件的方法¶
您也可以使用 Kivy 语言 来创建应用程序。.kv 文件可以同时包含规则和根部件定义。以下是与 kv 文件中 Button 示例相同的例子。
'test.kv' 文件的内容:
#:kivy 1.0
Button:
text: 'Hello from test.kv'
'main.py' 文件的内容:
'''
Application built from a .kv file
==================================
This shows how to implicitly use a .kv file for your application. You
should see a full screen button labelled "Hello from test.kv".
After Kivy instantiates a subclass of App, it implicitly searches for a .kv
file. The file test.kv is selected because the name of the subclass of App is
TestApp, which implies that kivy should try to load "test.kv". That file
contains a root Widget.
'''
import kivy
kivy.require('1.0.7')
from kivy.app import App
class TestApp(App):
pass
if __name__ == '__main__':
TestApp().run()
参见 kivy/examples/application/app_with_kv.py。
main.py 与 test.kv 之间的关系在 App.load_kv() 中有说明。
应用程序配置¶
使用配置文件¶
你的应用程序可能需要自己的配置文件。如果你使用 config 参数(一个 ConfigParser 实例)将节键值对添加到 App.build_config() 方法中,App 类会自动处理 'ini' 文件。
class TestApp(App):
def build_config(self, config):
config.setdefaults('section1', {
'key1': 'value1',
'key2': '42'
})
一旦你向配置中添加了一个部分,磁盘上就会创建一个文件(其位置参见 get_application_config),并根据你的类名命名。“TestApp”将生成一个名为“test.ini”的配置文件,内容如下:
[section1]
key1 = value1
key2 = 42
"test.ini" 将在运行时自动加载,您可以在 App.build() 方法中访问配置::
class TestApp(App):
def build_config(self, config):
config.setdefaults('section1', {
'key1': 'value1',
'key2': '42'
})
def build(self):
config = self.config
return Label(text='key1 is %s and key2 is %d' % (
config.get('section1', 'key1'),
config.getint('section1', 'key2')))
创建一个设置面板¶
你的应用程序可以提供一个设置面板,让用户配置一些配置项。以下是在KinectViewer示例(位于examples目录中)中实现的一个示例:
您可以通过扩展 App.build_settings() 方法来添加自己的设置面板。请参阅 Settings 了解如何创建面板,因为您首先需要一份 JSON 文件或数据。
让我们以之前带有自定义配置的TestApp代码片段为例。我们可以创建一个如下的JSON:
[
{ "type": "title",
"title": "Test application" },
{ "type": "options",
"title": "My first key",
"desc": "Description of my first key",
"section": "section1",
"key": "key1",
"options": ["value1", "value2", "another value"] },
{ "type": "numeric",
"title": "My second key",
"desc": "Description of my second key",
"section": "section1",
"key": "key2" }
]
然后,我们可以使用这个JSON创建一个面板,自动生成所有选项,并将它们链接到我们的:attr:App.config ConfigParser实例::
class TestApp(App):
# ...
def build_settings(self, settings):
jsondata = """... put the json data here ..."""
settings.add_json_panel('Test application',
self.config, data=jsondata)
就这样!现在你可以按 F1(默认按键)来切换设置面板,或者在安卓设备上按“设置”键。如果你想手动处理,也可以直接调用 App.open_settings() 和 App.close_settings() 方法。面板中的任何更改都会自动保存到配置文件中。
你也可以使用 App.build_settings() 来修改设置面板的属性。例如,默认面板有一个侧边栏,用于在 json 面板之间切换,其宽度默认为 200dp。如果你希望它更窄,可以添加以下代码:
settings.interface.menu.width = dp(100)
在你的 build_settings() 方法中。
您可能想知道用户何时更改了配置值,以便调整或重新加载您的界面。此时,您可以重载 on_config_change() 方法::
class TestApp(App):
# ...
def on_config_change(self, config, section, key, value):
if config is self.config:
token = (section, key)
if token == ('section1', 'key1'):
print('Our key1 has been changed to', value)
elif token == ('section1', 'key2'):
print('Our key2 has been changed to', value)
Kivy配置面板默认添加到设置实例中。如果您不希望包含此面板,可以按如下方式声明您的应用程序:
class TestApp(App):
use_kivy_settings = False
# ...
这仅移除Kivy面板,但并不会阻止设置实例出现。如果您希望完全阻止设置实例出现,可以这样做:
class TestApp(App):
def open_settings(self, *largs):
pass
在 1.0.7 版本加入.
使用 on_start 和 on_stop 进行性能分析¶
在Python代码中进行分析以发现优化位置通常非常有用。标准库分析器(http://docs.python.org/2/library/profile.html)提供了多种代码分析选项。对于分析整个程序,使用profile作为模块或profile的run方法的自然方式不适用于Kivy。然而,可以使用:meth:`App.on_start`和:meth:`App.on_stop`方法来实现::
import cProfile
class MyApp(App):
def on_start(self):
self.profile = cProfile.Profile()
self.profile.enable()
def on_stop(self):
self.profile.disable()
self.profile.dump_stats('myapp.profile')
当你退出应用时,这将创建一个名为 myapp.profile 的文件。
自定义布局¶
您可以通过设置 App.settings_cls 来选择不同的设置控件布局。默认情况下,这是一个 Settings 类,它提供了图示的侧边栏布局,但您可以将其设置为 kivy.uix.settings 中提供的任何其他布局,或者创建自己的布局。更多信息请参阅 kivy.uix.settings 模块文档。
您可以通过重写 App.display_settings() 来自定义设置面板的显示方式,该方法在屏幕显示设置面板之前被调用。默认情况下,它只是将面板绘制在窗口顶部,但您可以修改它,例如,将设置显示在 Popup 中,或者如果您正在使用 ScreenManager,则将其添加到应用的屏幕管理器中。如果这样做,您还应该修改 App.close_settings() 以适当退出面板。例如,要让设置面板在弹出窗口中显示,您可以这样做:
def display_settings(self, settings):
try:
p = self.settings_popup
except AttributeError:
self.settings_popup = Popup(content=settings,
title='Settings',
size_hint=(0.8, 0.8))
p = self.settings_popup
if p.content is not settings:
p.content = settings
p.open()
def close_settings(self, *args):
try:
p = self.settings_popup
p.dismiss()
except AttributeError:
pass # Settings popup doesn't exist
最后,如果你想替换当前的设置面板组件,可以通过 App.destroy_settings() 移除对它的内部引用。如果你修改了 App.display_settings(),则需小心检测设置面板是否已被替换。
暂停模式¶
在 1.1.0 版本加入.
在平板和手机上,用户可以随时切换到另一个应用程序。默认情况下,您的应用程序将关闭,并触发 App.on_stop() 事件。
如果您支持暂停模式,当切换到其他应用程序时,您的应用程序将无限期等待,直到用户切换回您的应用程序。在Android设备上存在一个OpenGL问题:当您的应用恢复时,不保证OpenGL ES上下文会被恢复。Kivy中尚未实现恢复所有OpenGL数据的机制。
当前已实现的暂停机制是:
Kivy 每帧都会检查操作系统是否因用户切换到其他应用、手机关机或任何其他原因而激活了暂停模式。
App.on_pause()被调用:如果返回 False 或
App.on_pause()没有返回语句,则会调用App.on_stop()。如果返回 True 或未定义
App.on_pause(),应用程序将休眠,直到操作系统恢复我们的应用。当应用恢复时,会调用
App.on_resume()方法。如果我们的应用内存已被操作系统回收,那么将不会调用任何东西。
以下是一个关于如何使用`on_pause()`的简单示例:
class TestApp(App):
def on_pause(self):
# Here you can save data if needed
return True
def on_resume(self):
# Here you can check if any data needs replacing (usually nothing)
pass
警告
on_pause 和 on_stop 都必须保存重要数据,因为在调用 on_pause 之后,on_resume 可能根本不会被调用。
异步应用¶
除了正常运行应用外,Kivy 还可以在异步事件循环中运行,例如标准库中的 asyncio 包或 trio 包(强烈推荐)所提供的循环。
背景¶
通常,当Kivy应用运行时,它会阻塞运行它的线程,直到应用退出。在内部,每个时钟迭代中,它会执行所有应用回调、处理图形和输入,并通过睡眠剩余时间来实现空闲。
为了能够异步运行,Kivy应用不能休眠,而是必须将运行上下文控制权释放给运行Kivy应用的异步事件循环。我们在空闲时通过调用所使用的异步包的相应函数来实现这一点,而不是进行休眠。
异步配置¶
要异步运行Kivy应用,必须将:func:`async_runTouchApp`或:meth:`App.async_run`协程调度到所用异步库的事件循环中运行。
环境变量 KIVY_EVENTLOOP 或 async_runTouchApp() 和 App.async_run() 中的 async_lib 参数,用于设置当应用通过 async_runTouchApp() 和 App.async_run() 运行时,Kivy 内部使用的异步库。它可以设置为 "asyncio"``(当使用标准库 `asyncio` 时)或 ``"trio"``(当使用 trio 库时)。如果未设置环境变量且未提供 ``async_lib,则默认使用标准库 asyncio。
:也可以直接调用 init_async_lib() 来设置要使用的异步库,但只能在应用通过 async_runTouchApp() 或 App.async_run() 开始运行之前调用。
要以异步方式运行应用,需将 async_runTouchApp() 或 App.async_run() 调度到给定库的异步事件循环中运行,如下方示例所示。此时,Kivy 被视为该库在其事件循环中运行的另一个协程。在内部,Kivy 将使用指定的异步库 API,因此 KIVY_EVENTLOOP 或 async_lib 必须与运行 Kivy 的异步库相匹配。
更全面的基础和更高级的示例,请参阅 examples/async 目录下的演示应用。
Asyncio 示例 ~~~~~~~~~~~~~
import asyncio
from kivy.app import async_runTouchApp
from kivy.uix.label import Label
loop = asyncio.get_event_loop()
loop.run_until_complete(
async_runTouchApp(Label(text='Hello, World!'), async_lib='asyncio'))
loop.close()
Trio 示例 ~~~~~~~~~~
import trio
from kivy.app import async_runTouchApp
from kivy.uix.label import Label
from functools import partial
# use functools.partial() to pass keyword arguments:
async_runTouchApp_func = partial(async_runTouchApp, async_lib='trio')
trio.run(async_runTouchApp_func, Label(text='Hello, World!'))
与其他协程交互Kivy应用¶
在与同一异步事件循环中运行的其他协程交互时,与任何kivy对象进行交互都是完全安全的。这是因为它们都在同一线程中运行,并且其他协程仅在Kivy空闲时执行。
同样地,Kivy 回调可以安全地与同一事件循环中运行的其他协程中的对象进行交互。常规的单线程规则适用于这两种情况。
在 2.0.0 版本加入.
- class kivy.app.App(**kwargs)[源代码]¶
-
Application 类,更多信息请参阅模块文档。
- 事件:
- on_start:
当应用程序正在启动时触发(在调用
runTouchApp()之前)。- on_stop:
当应用程序停止时触发。
- on_pause:
当应用程序被操作系统暂停时触发。
- on_resume:
当应用被操作系统从暂停状态恢复时触发。请注意:无法保证此事件会在 on_pause 事件被调用之后触发。
在 1.7.0 版本发生变更: 新增参数 kv_file。
在 1.8.0 版本发生变更: 参数 kv_file 和 kv_directory 现在是 App 的属性。
- async async_run(async_lib=None)[源代码]¶
与
run()相同,但这是一个协程,可以在正在运行的异步事件循环中调度。参见
kivy.app获取示例用法。在 2.0.0 版本加入.
- build()[源代码]¶
初始化应用程序;此方法仅会被调用一次。如果此方法返回一个控件(树),它将被用作根控件并添加到窗口中。
- 返回:
如果没有self.root存在,则为None或一个根
Widget实例。
- build_config(config)[源代码]¶
在 1.0.7 版本加入.
此方法在应用程序初始化之前被调用,用于构建你的
ConfigParser对象。你可以在此处为配置设置任何默认的节/键/值。如果设置了任何内容,配置将自动保存在由get_application_config()返回的文件中。- 参数:
- config:
ConfigParser 使用此方法可添加默认的节/键/值项。
- config:
- build_settings(settings)[源代码]¶
在 1.0.7 版本加入.
当用户(或您)想要显示应用程序设置时,会调用此方法。它在设置面板首次打开时被调用一次,之后面板会被缓存。如果缓存的设置面板被
destroy_settings()移除,则可能会再次调用此方法。您可以使用此方法添加设置面板并自定义设置部件,例如通过更改侧边栏宽度。有关完整详情,请参阅模块文档。
- 参数:
- settings:
Settings 用于添加面板的Settings实例。
- settings:
- config¶
返回应用程序配置的
ConfigParser实例。您可以在build()方法中使用它来查询一些配置令牌。
- create_settings()[源代码]¶
创建设置面板。此方法通常在应用生命周期内仅调用一次,结果会在内部缓存,但如果缓存的面板被
destroy_settings()移除,则可能会再次调用。默认情况下,它会根据
settings_cls构建一个设置面板,调用build_settings(),如果use_kivy_settings为 True,则添加一个 Kivy 面板,并绑定到 on_close/on_config_change 事件。如果你想自定义设置方式,而不使用Kivy面板或关闭/配置变更事件,那么这就是你需要重载的方法。
在 1.8.0 版本加入.
- destroy_settings()[源代码]¶
在 1.8.0 版本加入.
如果当前存在设置面板,则取消引用它。这意味着当下次运行
App.open_settings()时,将创建并显示一个新的面板。这不会影响面板的任何内容,但允许您(例如)在响应屏幕尺寸变化而更改设置控件后刷新设置面板布局。如果你修改了
open_settings()或display_settings(),应小心正确地检测之前的设置控件是否已被销毁。
- property directory¶
在 1.0.7 版本加入.
返回应用程序所在的目录。
- display_settings(settings)[源代码]¶
在 1.8.0 版本加入.
显示设置面板。默认情况下,面板直接绘制在窗口顶部。您可以通过重写此方法来定义其他行为,例如将其添加到ScreenManager或Popup中。
如果显示成功,应返回True,否则返回False。
- 参数:
- settings:
Settings 您可以修改此对象以调整设置显示。
- settings:
- get_application_config(defaultpath='%(appdir)s/%(appname)s.ini')[源代码]¶
返回应用程序配置的文件名。根据平台的不同,应用程序文件将存储在不同的位置:
在 iOS 上:<appdir>/Documents/.<appname>.ini
在Android上:<user_data_dir>/.<appname>.ini
否则:<appdir>/<appname>.ini
在桌面平台分发您的应用程序时,请注意,如果应用程序旨在系统范围内安装,用户可能对应用程序目录没有写权限。若您希望存储用户设置,应重载此方法并更改默认行为,将配置文件保存至用户目录。:
class TestApp(App): def get_application_config(self): return super(TestApp, self).get_application_config( '~/.%(appname)s.ini')
一些注意事项:
在 1.0.7 版本加入.
在 1.4.0 版本发生变更: 为iOS和Android平台定制了默认路径。为桌面操作系统添加了默认路径参数(不适用于iOS和Android)。
在 1.11.0 版本发生变更: 将Android版本改为使用:attr:~App.user_data_dir,并在iOS配置文件名中添加了缺失的点。
- icon¶
应用程序的图标。图标可以位于主文件所在的同一目录中。您可以按如下方式设置::
class MyApp(App): def build(self): self.icon = 'myicon.png'
在 1.0.5 版本加入.
在 1.8.0 版本发生变更: icon 现在是一个
StringProperty。请勿再像之前文档中所述的那样在类中设置图标。备注
在Kivy 1.8.0之前的版本中,你需要按如下方式设置::
class MyApp(App): icon = 'customicon.png'
推荐使用256x256或1024x1024;对于GNU/Linux和Mac OSX,使用32x32;对于Windows 7或更早版本,使用32x32。对于Windows 8,使用<=256x256,256x256确实有效(至少在Windows 8上),但会被缩放,效果不如32x32图标好。
- kv_directory¶
应用程序kv文件存储目录的路径,默认为None
在 1.8.0 版本加入.
如果设置了kv_directory,它将用于获取初始的kv文件。默认情况下,该文件假定位于当前App定义文件所在的同一目录中。
- kv_file¶
要加载的 Kv 文件的文件名,默认为 None。
在 1.8.0 版本加入.
如果设置了kv_file,它将在应用程序启动时被加载。默认kv文件的加载将被阻止。
- load_config()[源代码]¶
(内部)此函数用于返回包含应用程序配置的ConfigParser。它执行三项操作:
创建ConfigParser的实例
通过调用
build_config()加载默认配置,然后如果存在,则加载应用程序配置文件,否则创建一个。
- 返回:
ConfigParser实例
- load_kv(filename=None)[源代码]¶
该方法在应用首次运行时被调用,前提是该应用之前尚未构建任何控件树。随后,此方法会在包含应用类的文件所在目录中查找匹配的 kv 文件。
例如,假设你有一个名为 main.py 的文件,内容如下:
class ShowcaseApp(App): pass
该方法将在包含main.py的目录中查找名为`showcase.kv`的文件。kv文件的名称必须为类名的小写形式,如果类名以'App'结尾,则需去掉该后缀。
您可以在kv文件中定义规则和根部件::
<ClassName>: # this is a rule ... ClassName: # this is a root widget ...
必须只有一个根部件。关于如何创建 kv 文件的更多信息,请参阅 Kivy 语言 文档。如果您的 kv 文件包含一个根部件,它将被用作 self.root,即应用程序的根部件。
- property name¶
在 1.0.7 版本加入.
根据类名返回应用程序的名称。
- on_config_change(config, section, key, value)[源代码]¶
当设置页面更改了配置令牌时,会触发此事件处理器。
在 1.10.1 版本发生变更: 添加了相应的
on_config_change事件。
- on_pause()[源代码]¶
当请求进入暂停模式时调用的事件处理器。如果您的应用可以进入暂停模式,应返回True;否则返回False,您的应用将被停止。
您无法控制应用程序何时进入此模式。这由操作系统决定,主要用于移动设备(Android/iOS)以及窗口大小调整场景。
默认返回值为True。
在 1.1.0 版本加入.
在 1.10.0 版本发生变更: 默认返回值现在是True。
- on_resume()[源代码]¶
当您的应用程序从暂停模式恢复时调用的事件处理器。
在 1.1.0 版本加入.
警告
恢复时,OpenGL上下文可能已被损坏或释放。此时,您可以重建部分OpenGL状态,例如FBO内容。
- open_settings(*largs)[源代码]¶
打开应用程序设置面板。该面板将在首次使用时创建,若之前缓存的设置面板已被
destroy_settings()移除,则会重新创建。设置面板将通过display_settings()方法显示,默认情况下,该方法会将设置面板添加到与您的应用程序关联的窗口中。如果您希望以不同方式显示设置面板,应重写该方法。- 返回:
如果设置已被打开,则为True。
- options¶
传递给App的__init__方法的选项。
- pause(*largs)[源代码]¶
暂停应用程序。
在Android上,将操作系统状态设置为暂停时,Kivy应用状态会随之变化。此功能在其他操作系统上不可用。.. versionadded:: 2.2.0
- settings_cls¶
在 1.8.0 版本加入.
用于构建设置面板的类,以及传递给
build_config()的实例。您应使用Settings或提供的具有不同布局的子类之一(SettingsWithSidebar、SettingsWithSpinner、SettingsWithTabbedPanel、SettingsWithNoMenu)。您也可以创建自己的 Settings 子类。有关更多信息,请参阅Settings的文档。settings_cls是一个ObjectProperty,默认值为SettingsWithSpinner,它通过一个下拉选择器来显示设置面板并在它们之间切换。如果你设置一个字符串,将使用Factory来解析该类。
- stop(*largs)[源代码]¶
停止应用程序。
如果使用此方法,整个应用将通过调用
stopTouchApp()停止。在 Android 上除外,会将 Android 状态设置为停止,Kivy 状态随后跟随。
- title¶
您的应用程序标题。您可以按如下方式设置:
class MyApp(App): def build(self): self.title = 'Hello world'
在 1.0.5 版本加入.
在 1.8.0 版本发生变更: title 现在是一个
StringProperty。请勿像之前文档中所述的那样在类中设置标题。备注
对于Kivy < 1.8.0版本,您可以按照以下方式设置::
class MyApp(App): title = 'Custom title'
如果您想动态更改标题,可以这样做:
from kivy.base import EventLoop EventLoop.window.title = 'New title'
- use_kivy_settings = True¶
在 1.0.7 版本加入.
如果为True,应用程序设置也将包含Kivy设置。如果您不希望用户从您的设置界面更改任何Kivy设置,请将其改为False。
- property user_data_dir¶
在 1.7.0 版本加入.
返回用户文件系统中应用程序可用于存储附加数据的目录路径。
不同平台对于用户数据(如偏好设置、存档游戏和设置)的存储位置有不同的约定。此函数实现了这些约定。当属性被调用时,会创建<app_name>目录,除非该目录已存在。
在 iOS 上,返回的是 `~/Documents/<app_name>`(位于应用的沙盒内)。
在Windows上,返回`%APPDATA%/<app_name>`。
在 OS X 上,返回 ~/Library/Application Support/<app_name>。
在Linux上,返回`$XDG_CONFIG_HOME/<app_name>`。
在Android平台上,返回的是 Context.GetFilesDir。
在 1.11.0 版本发生变更: 在Android上,此函数此前返回`/sdcard/<app_name>`。自Android API 26起,该文件夹默认变为只读,因此user_data_dir已被移至可写位置。
- async kivy.app.async_runTouchApp(widget=None, embedded=False, async_lib=None)[源代码]¶
与
runTouchApp()相同,但它是一个协程,可以在现有的异步事件循环中运行。async_lib是要使用的异步库。有关详细信息及示例用法,请参阅kivy.app。在 2.0.0 版本加入.
- kivy.app.runTouchApp(widget=None, embedded=False)[源代码]¶
静态主函数,用于启动应用程序循环。你可以通过以下参数访问一些魔法功能:
参见
kivy.app获取示例用法。- 参数:
- <empty>
为了使事件分发正常工作,至少需要一个输入监听器。否则,应用程序将退出。(MTWindow 充当输入监听器)
- widget
如果你只传入一个widget,系统将创建一个MTWindow,并将你的widget作为根widget添加到该窗口中。
- embedded
不进行事件分发。这将由你来完成。
- widget + embedded
不进行事件分发。这将是你的工作,但我们会尝试获取窗口(必须由你事先创建)并将控件添加到其中。这对于将Kivy嵌入其他工具包(如Qt,参见kivy-designed)非常有用。