Skip to content

一个现代的,极简的,易于扩展的UI框架,基于MicroPython和FrameBuffer,支持事件驱动

Notifications You must be signed in to change notification settings

maysrp/micropython-AyUI

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

12 Commits
 
 
 
 
 
 
 
 

Repository files navigation

AyUI

一个现代的,极简的,易于扩展的UI框架,基于MicroPython和FrameBuffer,支持事件驱动。

完成度 60%

架构图: Engine -> Activity -> View -> DrawAble

目前的架构下存在未知的内存泄漏,初步怀疑内存泄漏来自于uasyncio,如果担心内存泄漏问题的可以选择直接调用Engine.start方法或者在多核心上使用_thread库

Activity 活动

Activity将会收到以下方法:

  • self.activity.change() 切换当前的Activity
  • self.activity.push() 新增一个Activity,挂起上一个Activity
  • self.activity.pop() 退出当前Activity并删除实例,返回上一个Activity
  • self.activity.create_event() 创建一个事件,由Engine接收
  • self.event.on() 注册事件监听器并绑定当前Activity

以上操作都基于帧,当前帧产生的各种事件都会在下一帧开始前运行,并且Activity重写优先于Event监听,该特性要求后端服务程序尽量不要占用过长时间,当触发Activity变化时,余下的Event将不会再触发。

Activity事件重写一共有三种:onCreateonDestroyonStart,分别对应Activity创建、Activity销毁和Activity启动,其中onCreate事件和onDestroy事件在整个Activity生命周期内只会被调用一次,而onStart事件只要切换到当前Activity就会触发一次。

此外还有两个绘图重写:beforeFrameafterFrame,分别在绘制本帧前执行和绘制本帧后执行,用于配置可能的动画,尽管提供了这两种重写方法,但还是推荐使用支持动画的视图和组件。

Activity上有个至少且必须实现的重写view,改方法重写接受一个元组,包含屏幕的宽和高,要求返回一个视图(View)的实现。理论上你在实现view的时候可以选择渲染所有内容,但是我们还是推荐你使用View -> DrawAble的架构,或者直接使用BasicView实现的无布局渲染序列。

Engine 引擎

Engine 负责Activity的注册和切换,以及Event的监听和路由。 AyUI的所有事情将起源于此,当我们初始化时提供以下参数:

from ayui import Engine

engine = Engine(width,height,framebuf,draw_exec)
  • width: 目标FrameBuffer的宽
  • height: 目标FrameBuffer的高
  • framebuf: FrameBuffer对象
  • draw_exec: 绘图回调,每一帧绘制结束调用

Engine提供一个装饰器供注册Activity使用,而所有的Activity必须先注册才能被使用:

@engine.register_activity("MainActivity")
class MainActivity(Activity):
    def onCreate(self):
        print("MainActivity Create")
        self.activity.push("SecondActivity")
        
    def onStart(self):
        print("MainActivity Start")

当然你也可以这样使用:

class MainActivity(Activity):
    def onCreate(self):
        print("MainActivity Create")
        self.activity.push("SecondActivity")
        
    def onStart(self):
        print("MainActivity Start")

engine.register("MainActivity", MainActivity)

你需要指定哪个Activity最先启动,使用以下方法:

engine.start_activity_from("MainActivity")

启动引擎:

import uasyncio

uasyncio.run(engine.start(target_fps= 20))

目前Engine所有的函数都是公开的,但这并不意味着你可以随意的调用它们,至少目前阶段这样的调用是无法被预见的。

Event 事件

除了Active可以创建事件,在异步Engine上可以调用commit方法来产生事件,如果你的异步符合规范,那么你的代码将会在每帧渲染的间隙得以执行,这意味这事件的产生是线程安全的。

...
@engine.register_activity("MainActivity")
class MainActivity(Activity):
    def onCreate(self):
        print("MainActivity Create")
        self.event.on("click", self.onClick)
        
    def onStart(self):
        print("MainActivity Start")

    def onClick(self, payload):
        print("clink", payload)
...
async def app_main():
    while True:
        engine.commit('click', 'home')
        await uasyncio.sleep_ms(2000)
...
uasyncio.create_task(engine.start(target_fps= 20))
uasyncio.create_task(app_main())
uasyncio.get_event_loop().run_forever()

这应该会每两秒输出 click home

举个例子

生命周期

from machine import Pin,I2C
from driver.SSD1306 import SSD1306_I2C
from ayui import Engine,Activity
import uasyncio

i2c = I2C(0)
oled = SSD1306_I2C(128, 64, i2c)

engine = Engine(oled.width,oled.height,oled,oled.show)

@engine.register_activity("MainActivity")
class MainActivity(Activity):
    def onCreate(self):
        print("MainActivity Create")
        self.activity.push("SecondActivity")
        
    def onStart(self):
        print("MainActivity Start")
        
@engine.register_activity("SecondActivity")
class SecondActivity(Activity):
    def onCreate(self):
        print("SecondActivity Create")
        
    def onStart(self):
        print("SecondActivity Start")
        self.activity.pop()

engine.start_activity_from("MainActivity")

uasyncio.create_task(engine.start(target_fps= 20))
# 你可以在这里创建其他的异步任务以扩展事件等功能
uasyncio.get_event_loop().run_forever()

""" output
[INFO] AyUI: The UI thread starts
MainActivity Create
MainActivity Start
SecondActivity Create
SecondActivity Start
MainActivity Start
"""

绘图实例

实时显示内存占用,这应该会有一个白色的大框包裹一段红色的信息:

from AyUI import Activity
from AyUI.views.basic import BasicView
from AyUI.widgets.memtest import Memtest

@engine.register_activity("MainActivity")
class MainActivity(Activity):
    def view(self, space):
        return BasicView(
            Memtest(tft.rgb(255,0,0)),
            
            space = (space[0]-2,space[1]-2),
            margin= (0,0,0,0),
            padding=(2,2,2,2),
            border = 1,
            border_color = tft.rgb(255,255,255)
        )
    
    def onCreate(self):
        print("MainActivity onCreate")

    def onStart(self):
        print("MainActivity onStart")

About

一个现代的,极简的,易于扩展的UI框架,基于MicroPython和FrameBuffer,支持事件驱动

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • Python 100.0%