{"id":14967243,"url":"https://github.com/xuantongyao/micropython-xt-gui","last_synced_at":"2025-09-05T03:33:05.013Z","repository":{"id":243923227,"uuid":"813794610","full_name":"XuanTongYao/micropython-xt-gui","owner":"XuanTongYao","description":"基于micropython的轻量级GUI库  供嵌入式使用","archived":false,"fork":false,"pushed_at":"2025-03-13T15:56:23.000Z","size":2773,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-06-07T01:36:24.101Z","etag":null,"topics":["embedded","gui","micropython"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/XuanTongYao.png","metadata":{"files":{"readme":"Readme.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2024-06-11T18:54:55.000Z","updated_at":"2025-03-23T21:32:02.000Z","dependencies_parsed_at":"2024-06-12T03:49:22.529Z","dependency_job_id":"950ec204-02d5-4cef-9011-ef19a5442f49","html_url":"https://github.com/XuanTongYao/micropython-xt-gui","commit_stats":{"total_commits":30,"total_committers":2,"mean_commits":15.0,"dds":"0.033333333333333326","last_synced_commit":"18f390f7d5f70eca189f480f6493649dbb5eff91"},"previous_names":["xuantongyao/micropython-xt-gui"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/XuanTongYao/micropython-xt-gui","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/XuanTongYao%2Fmicropython-xt-gui","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/XuanTongYao%2Fmicropython-xt-gui/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/XuanTongYao%2Fmicropython-xt-gui/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/XuanTongYao%2Fmicropython-xt-gui/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/XuanTongYao","download_url":"https://codeload.github.com/XuanTongYao/micropython-xt-gui/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/XuanTongYao%2Fmicropython-xt-gui/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":273707304,"owners_count":25153724,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-09-05T02:00:09.113Z","response_time":402,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["embedded","gui","micropython"],"created_at":"2024-09-24T13:37:41.492Z","updated_at":"2025-09-05T03:32:59.997Z","avatar_url":"https://github.com/XuanTongYao.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# XT_GUI\n\n这是一个基于 [micropython](https://docs.micropython.org/en/latest/library/index.html) 的 轻量级 GUI 库.\n\n使用 [micropython](https://docs.micropython.org/en/latest/library/index.html) 中的 [framebuf](https://docs.micropython.org/en/latest/library/framebuf.html) 库，构建一个高效帧缓冲，GUI 所有的绘制操作都先在帧缓冲上进行再同步到 GDDRAM，实现双缓冲绘图。\n\n注意：目前只支持 RGB565 屏幕\n\n- [XT\\_GUI](#xt_gui)\n  - [硬件要求](#硬件要求)\n  - [快速上手](#快速上手)\n    - [远程调试(无需安装)](#远程调试无需安装)\n    - [安装](#安装)\n  - [参考文档](#参考文档)\n  - [1. 基础](#1-基础)\n    - [1.1 文字显示](#11-文字显示)\n      - [使用你自己的字体库](#使用你自己的字体库)\n    - [1.2 按键响应](#12-按键响应)\n    - [1.3 显示器驱动](#13-显示器驱动)\n  - [2. 示例代码详细说明](#2-示例代码详细说明)\n  - [3. Q\\\u0026A](#3-qa)\n  - [4. TODO List](#4-todo-list)\n  - [5. 开发者请看](#5-开发者请看)\n    - [5.1 项目文件结构](#51-项目文件结构)\n      - [资源](#资源)\n      - [显示驱动](#显示驱动)\n      - [附件](#附件)\n      - [Demos](#demos)\n      - [GUI](#gui)\n    - [5.2 GUI核心架构](#52-gui核心架构)\n    - [5.3 控件绘制详细说明](#53-控件绘制详细说明)\n    - [5.4 按键响应详细说明](#54-按键响应详细说明)\n    - [5.5 事件触发，函数调用约定](#55-事件触发函数调用约定)\n    - [5.5 定义详细说明](#55-定义详细说明)\n      - [绘制层栈](#绘制层栈)\n      - [已进入控件栈](#已进入控件栈)\n      - [帧缓冲切片](#帧缓冲切片)\n      - [容器绘制区域](#容器绘制区域)\n      - [控件分类](#控件分类)\n\n## 硬件要求\n\n运行 python 解释器后剩余空闲内存大于整个屏幕帧缓冲占用的空间，并至少留有 10KByte。\n\n```python\n# 占用空间简单计算公式\n_1位单色屏 = ceil(width/8)*height\n_RGB565屏 = width*height*2\n```\n\n例如：\n\nSSD1306 分辨率为 128x64，色彩模式 1 位单色。帧缓冲占用空间为 1024 Byte；\n\nST7789 分辨率为 240x240，色彩模式 RGB565。帧缓冲占用空间为 115,200 Byte\n\n## 快速上手\n\n### 远程调试(无需安装)\n\n该方法不会改变主机的文件系统，但运行速度非常慢，而且内存占用大。\n\n1. 准备运行`micropython`的开发板和一个`ST7789`的`LCD`屏幕，并使用 4 线串行接口的方式完成连接\n2. 克隆或下载本仓库到 PC 机本地\n3. 打开`setup_hardware.py`并修改相关引脚配置\n\n   ```python\n   # 请根据自身硬件情况更改引脚和波特率\n   # 初始化显示屏\n   spi0 = SPI(0, baudrate=30_000_000, phase=1, polarity=1, sck=Pin(2), mosi=Pin(3))\n   display_driver = st7789.ST7789(\n      spi0, 240, 240, reset=Pin(0, Pin.OUT), dc=Pin(1, Pin.OUT)\n   )\n   display = st7789.ST7789_API(display_driver)\n   ```\n\n4. 下载官方的 [mpremote](https://docs.micropython.org/en/latest/reference/mpremote.html#mpremote) 工具`pip3 install mpremote`\n5. 挂载代码目录到主机(请确保运行命令时路径处于代码目录，串口不被其他程序占用)`mpremote mount .`\n6. 运行你想运行的 demo`\u003e\u003e\u003e import demos.foo_bar`\n7. 部分 demo 中有些代码需要修改引脚等\n\n### 安装\n\n将以下文件结构全部复制到主机的根目录下:\n\n- demos/\n- driver/\n- gui/\n- resource/\n- setup_hardware.py\n\n根据实际情况还可添加`add_ons/`\n\n根据自身情况修改引脚号等，然后在根目录下运行你想运行的 demo`\u003e\u003e\u003e import demos.foo_bar`\n\n## 参考文档\n\n- [示例](./docs/Demos.md)\n- [所有控件列表](./docs/All%20widgets%20list.md)\n- - [基础控件](./docs/All%20widgets%20list.md)\n- - [高级控件](./docs/All%20widgets%20list.md)\n- - [特殊控件](./docs/All%20widgets%20list.md)\n- [驱动列表](./docs/All%20driver%20list.md)\n- [实用工具](./docs/Utils.md)\n- 核心组件\n- - [物理按键处理](./docs/KeyHandler.md)\n- - [XT_GUI类](./docs/XT_GUI.md)\n\n## 1. 基础\n\n`xt-gui`的核心类为[XT_GUI](./docs/XT_GUI.md)。\n\n`xt-gui`默认按键处理类使用了[asyncio](https://docs.micropython.org/en/latest/library/asyncio.html)，`xt-gui`通常也以异步协程的方式运行，但可以修改为同步方式。\n\n`xt-gui`坐标系将左上角定义为(0,0)，向右下角移动为增加，横轴为x，纵轴为y。\n\n`xt-gui`上显示的所有元素均由控件组成。\n\n### 1.1 文字显示\n\n字体读取与制作使用个人改进的[ufont](https://github.com/XuanTongYao/MicroPython-uFont)库，理论上支持显示UTF-16编码的所有字符，支持不完整的字符集。\n\n`ufont`根据字符的Unicode点位码(序号)从文件中读取未压缩的Bitmap数据，`xt-gui`依据Bitmap数据和文本颜色进行上色转换为RGB565格式的像素数据，再绘制到屏幕上。\n\n![alt text](img/1723683958333.jpg)\n\n#### 使用你自己的字体库\n\n必须在类中实现以下的属性\n\n```python\n# 字体大小\nfont_size:int\n# 获取字符的Bitmap数据并写入到buffer中\ndef fast_get_bitmap(self,char:str,buffer:bytearray)-\u003eNone:\n   pass\n```\n\n### 1.2 按键响应\n\n`xt-gui`默认使用的按键处理类为[KeyHandler](./docs/KeyHandler.md)\n\n使用回调的方式来响应按键触发事件，支持按下、抬起、长按事件，可以指定回调函数的参数。\n\n下面是该类的部分源码，每个`KeyHandler`类实例只能处理单个按键的输入，构造函数需要填入两个值:`key`必须实现`__call__`方法返回一个`int`或`bool`作为当前按键值、`active`定义了按键按下时应该为什么值。`KeyHandler`类使用了[asyncio](https://docs.micropython.org/en/latest/library/asyncio.html)和状态机模式来实现消抖等操作。\n\n如果你想自定义基于`asyncio`的按键处理类，必须实现其`__call__`方法用于启动相应的异步任务。\n\n```python\nclass KeyHandler:\n\n    def __init__(self, key, active=0) -\u003e None:\n        \"\"\"\n        Args:\n            key: 按键对象，可以是Pin或其他，必须实现__call__方法用于获取按键值.\n            active: 按键按下有效值. 默认0表示按下.\n        \"\"\"\n        pass\n\n    def __call__(self):\n        self.__hold_sleep_task = asyncio.create_task(self.__hold_check(HOLD_MS / 1000))\n        self.__scan_loop_task = asyncio.create_task(self.__do_scan_loop())\n```\n\n通常将按键事件的回调函数设置为`XT_GUI`实例的成员函数`key_response(key:int)`，参数设置为[按键键值](./docs/Utils.md)。\n\n```py\nkey_enter = KeyHandler(setup_hardware.BTN_ENTER)\nkey_enter.set_press_func(GUI.key_response, KEY_MOUSE0)\n```\n\n`XT_GUI`类内部维护一个[控件栈](#已进入控件栈)，栈顶为当前进入的控件，当调用`key_response(key:int)`时，`XT_GUI`实例会将键值传递给栈顶控件，栈顶控件根据键值进行响应。\n\n### 1.3 显示器驱动\n\n`xt-gui`使用[DisplayAPI](./docs/Utils.md)类作为屏幕驱动通用接口。\n\n`DisplayAPI`构造时要求传入一个显示器驱动对象，该对象必须实现以下属性:\n\n```py\n# 显示器像素宽高\nwidth: int\nheight: int\n# 显示器颜色模式\ncolor_mode: int\n# 将buffer中的像素数据写入到显示器\n# buffer包含了全屏幕的像素数据，从左上角开始，从左到右，从上到下依次写入\ndef write_gddram(self, buffer:bytearray):\n   pass\n```\n\n## 2. 示例代码详细说明\n\n下面以[buttons示例](./demos/buttons.py)为例，介绍`xt-gui`的使用。\n\n首先来看[配置硬件](./setup_hardware.py)的部分。\n\n根据你的情况，创建一个显示器驱动实例，并根据它来创建`DisplayAPI`实例。\n\n```py\nimport gc\nfrom machine import Pin, SPI\n\ngc.collect()\nfrom driver import st7789\nfrom gui.utils.core import DisplayAPI\nimport machine\n\n# 超频，你可以注释掉这条语句\nmachine.freq(250000000)\n\n# 请根据自身硬件情况更改引脚和波特率等\n# 初始化显示屏\nspi0 = SPI(0, baudrate=30_000_000, phase=1, polarity=1, sck=Pin(2), mosi=Pin(3))\ndisplay_driver = st7789.ST7789(\n    spi0, 240, 240, reset=Pin(0, Pin.OUT), dc=Pin(1, Pin.OUT)\n)\ndisplay_driver.set_fullscreen()# 设置全屏刷新，不适用于其他驱动。\ndisplay = DisplayAPI(display_driver)\n```\n\n手动调用垃圾收集是防止内存碎片的产生，在内存较小的机器上很有用。\n\n然后是初始化按键的部分，这里使用Pin类初始化两个物理按键，然后还使用了FJ08KN摇杆+ADC来模拟按键。请根据你自身情况调整引脚等，如果你没有FJ08KN摇杆请将摇杆部分的代码注释掉。理论上buttons示例中只使用确认/进入按键和下键就能运行。\n\n```py\n# 请根据自身硬件情况更改按键引脚\n\n# 退出按键\nBTN_ESCAPE = Pin(5, Pin.IN)\n# 确认/进入按键\nBTN_ENTER = Pin(6, Pin.IN, Pin.PULL_UP)\n# # 下键\n# BTN_DOWN = Pin(7, Pin.IN, Pin.PULL_UP)\n# # 上键\n# BTN_UP = Pin(8, Pin.IN, Pin.PULL_UP)\n\n# FJ08KN摇杆模拟按键\nfrom driver import fj08kn\nfrom machine import ADC\n\ngc.collect()\n\njoystick = fj08kn.FJ08K(ADC(Pin(29)), ADC(Pin(28)))\nBTN_UP = joystick.get_simulate_key(1)\nBTN_DOWN = joystick.get_simulate_key(3)\n```\n\n硬件全部初始化完成后，就可以[开始使用](./demos/buttons.py)了。\n\n导入必要的库文件。\n\n```py\n# 导入硬件配置文件，也就是上面代码的内容\nimport setup_hardware\n# 字体加载库\nfrom gui import ufont\n# 通用工具\nfrom gui.utils.core import *\n# 物理按键处理类\nfrom gui.key_handler import KeyHandler\n# XT_GUI核心\nfrom gui.xt_gui import XT_GUI\n# 常见的按钮：普通按钮、复选框、单选按钮\nfrom gui.widgets.buttons import XButton, XCheckbox, XRadio\n```\n\n创建XT_GUI实例。`load_into_mem=True`表示将字体文件全部加载到内存中(内存小慎用)，以减少文件读取次数。`loop_focus=True`表示焦点可以循环切换，而不是单向的。\n\n```py\n# 创建XT_GUI实例\nGUI = XT_GUI(\n    setup_hardware.display,\n    ufont.BMFont(\"./resource/fonts/for_demo/16x16_text_demo.bmf\", load_into_mem=True),\n    loop_focus=True,\n)\n```\n\n实例化各种按钮控件，并设置位置大小等参数，给第一个按钮绑定一个回调函数，按下时会执行，然后将其添加到XT_GUI实例中。\n\n```py\n\ndef print_hello():\n    print(\"Hello world!\")\n\nhello_button = XButton((0, 0), text=\"你好\", key_press=print_hello)\nhello_checkbox = XCheckbox((38, 0), (49, 16), 16, text=\"你好\")\nhello_radio = XRadio((87, 0), (49, 16), 16, text=\"你好\")\n\n# 添加控件\nfor widget in [hello_button, hello_checkbox, hello_radio]:\n    GUI.add_widget(widget)\n\n```\n\n设置好按键处理类，并设置按键事件的回调函数。\n\n`set_press_func`用于设置按键按下时的回调函数，第一个参数为回调函数，第二个参数为调用回调应该传入的参数。\n\n`GUI.key_response`是GUI处理按键响应的函数，调用这个函数并传入键值以告知GUI处理。\n\n最后运行异步主循环\n\n```py\nkey_esc = KeyHandler(BTN_ESCAPE)\nkey_esc.set_press_func(GUI.key_response, KEY_ESCAPE)\nkey_enter = KeyHandler(BTN_ENTER)\nkey_enter.set_press_func(GUI.key_response, KEY_MOUSE0)\nkey_next = KeyHandler(BTN_DOWN)\nkey_next.set_press_func(GUI.key_response, KEY_DOWN)\n\n# 启动异步主循环\nGUI.run(key_esc, key_enter, key_next)\n```\n\n效果图\n\n![alt text](img/1723683958322.jpg)\n\n## 3. Q\u0026A\n\n还不知道写什么，遇到任何问题都可以提issue。\n\n## 4. TODO List\n\n- [ ] 完善文档\n- [ ] 更新inputs 控件模块 ps:当前inputs控件全部属于不可用状态\n- [ ] 蜂鸣器播放音乐\n- [ ] MIDI解码\n\n## 5. 开发者请看\n\n### 5.1 项目文件结构\n\n核心模块：\n\n- [资源 ./resource/](./resource/)\n- [GUI ./gui/](./gui/)\n- [显示驱动 ./driver/](./driver/)\n- [附件 ./add_ons/](./add_ons/)\n- [Demos ./demos/](./demos/)\n\n#### 资源\n\n字体，图片，文本等资源全部放在该文件夹内。\n\n#### 显示驱动\n\n有关显示驱动的.py文件全部放在该文件夹内。\n\n#### 附件\n\n不属于GUI组件但某些Demo需要的模块放在该文件夹内。\n\n#### Demos\n\n所有可运行的有关Demo的.py文件全部放在该文件夹内。\n\n#### GUI\n\nGUI核心组件以及实用工具放在该文件夹内。\n\n### 5.2 GUI核心架构\n\n- [XT_GUI](./gui/xt_gui.py)核心主程序\n- - 异步主循环\n- - 维护绘制层栈\n- - 维护已进入控件栈\n- - 传递按键响应参数\n- - 触发绘制并刷新GDDRAM\n- - 绘制文字\n\n- [KeyHandler](./gui/key_handler.py)处理物理按键输入\n- - 物理按键消抖\n- - 按键异步扫描循环\n- - 按键事件(按下，释放，长按)及回调支持\n\n- [BMFont](./gui/ufont.py)点阵字体加载器\n- - 加载不完整字体集的字体文件\n- - 获取字体点阵数据\n- - 缩放字体点阵数据 TODO\n\n- [XWidget](./gui/widgets/base.py)核心控件\n\n- [DisplayAPI](./gui/utils/core.py)屏幕驱动通用接口\n- - GUI核心与显示驱动的中间件\n- - 双缓冲刷新\n- - 负责生成帧缓冲切片\n\n- [Utils](./gui/utils/core.py)通用工具\n- - GUI单例管理\n- - 常用颜色定义\n- - 按键键值定义；按键响应返回值定义\n- - 颜色转换\n- - 图像解码\n\n### 5.3 控件绘制详细说明\n\n本项目的核心组件均使用双缓冲绘图，为了提高性能还采用了延迟绘图的方式。\n\n所谓延迟绘图就是在每个控件中添加一个标志，用来指明是否需要重绘，如果不需要重绘则会直接跳过。同时在每个容器控件中添加一个标志，用来指明是否需要擦除容器绘制区域，防止绘制时出现残影。\n\n绘制只能由GUI实例来触发，对于控件使用递归调用的方式绘制；\n\n绘制过程中不会修改需要重绘的标志，这些标志只会在事件触发过程修改。\n\n下面这段伪代码表示触发绘制并刷新GDDRAM的流程：\n\n```python\nwhile True:\n    绘制层 = 绘制层栈.栈顶()\n    绘制层.传递绘制()\n    刷新帧()\n\n\ndef 传递绘制:\n    if 需要重绘:\n        绘制()\n    if 自身绘制区域无效:\n        return\n\n    已擦除标志 = False\n    for 子控件 in 子控件列表:\n        if 子控件超出容器绘制区域:\n            continue\n        if 子控件 is 容器控件:\n            子控件.传递绘制()\n        elif 子控件.需要重绘:\n            子控件.绘制()\n        \n```\n\n**重绘标志在以下条件下必须被设置：**\n\n- 控件的父控件被更改时；\n- 控件位置、大小、焦点状态等一切能够影响绘制结果的参数被更改时；\n- 收到**擦除容器绘制区域事件**时；\n- 收到**重建容器绘制区域事件**时；\n\n**擦除容器绘制区域在以下条件下必须被执行：**\n\n- 收到**变换事件**时；\n\n### 5.4 按键响应详细说明\n\n[XCtrl](./gui/widgets/base.py)类都拥有一个`_key_input`属性，用于接收[按键键值](./gui/utils/key.py)输入，并返回一个响应结果。\nGUI实例通过调用`_key_input`将按键响应的键值传递给**已进入控件栈**栈顶元素或**基础绘制层**，并获得一个响应结果返回值。\n\n响应结果返回值通常有三种：\n\n1. **ESC**:表示将退出该控件。通常返回给GUI实例。\n2. **ENTER**:表示将进入该控件。通常返回给父控件。\n3. 一个**可控制控件**对象:表示要进入该控件。通常返回给GUI实例。\n\n父控件需要对**ENTER**返回值进行处理，通常是将当前焦点控件返回给GUI实例。\n\n焦点控制:**容器控件**(例如XFrameLayout)通常需要进行焦点控制，除了用于切换焦点的键值，其余键值需要被传递到当前焦点控件，位于焦点的控件会被突出显示(取决于其绘制函数)。显然，仅有**可控制控件**拥有焦点状态。\n\n### 5.5 事件触发，函数调用约定\n\n在控件对象的正常生命周期中，只要用户没有手动调用私有或弱私有方法，它们的事件触发和相关函数调用必须遵循以下约定，同时GUI保证这些约定有效。\n\n---\n\n可以查看[源代码](./gui/widgets/base.py)中`_event_receiver`、`_transfer_event_trigger`、`_rebuild_draw_area_event_handler`相关内容。\n\n事件触发：事件被触发后执行相关操作，并将事件传递到相关控件。\n\n控件拥有事件触发器、事件接收器、事件处理器。\n\n控件内建有以下事件，在特定的条件下被触发，用于实现某些特定功能：\n\n1. 变换事件：控件的位置、大小被更改时；只向最近的父控件分发。\n2. 重建容器绘制区域事件：控件重建容器绘制区域时；只向子控件分发。\n3. 擦除容器绘制区域事件：控件擦除容器绘制区域时；只向子控件分发。\n\n---\n\n函数调用约定：\n\n1. 绘制只会由GUI或父控件递归调用；当其被调用时，始终认为其父控件有效，不需要对父控件进行类型检查。\n2. 重建容器绘制区域只会在父控件有效时调用；当其被调用时，始终认为其父控件有效，不需要对父控件进行类型检查。\n\n### 5.5 定义详细说明\n\n#### 绘制层栈\n\nGUI实例允许存在多个绘制层，常用于实现切换页面的效果(不支持半透明合成和叠加显示)。多个绘制层以栈的形式进行维护，GUI只会绘制栈顶的绘制层。**绘制层栈**中的元素全部为容器控件。栈底元素是是每个GUI实例固定保留的绘制层(**基础绘制层**)，不允许退出(弹栈)，默认为XFrameLayout类型:不带边框的平面布局容器。\n\n创建绘制层/移除绘制层 对应着 压栈/弹栈操作。\n\n#### 已进入控件栈\n\nGUI实例维护一个**已进入控件栈**，用于将按键输入的键值传递给栈顶元素。**已进入控件栈**的元素全部为**可控制控件**。如果**已进入控件栈**为空，则键值传递给**基础绘制层**。\n\n进入控件/退出控件 对应着 压栈/弹栈操作。\n\n#### 帧缓冲切片\n\nGUI依赖于双缓冲绘图刷新，DisplayAPI类保留一个全屏幕的帧缓冲区，以Bitmap的格式保存在内存中。借助[FrameBuffer](https://docs.micropython.org/en/latest/library/framebuf.html)可以从全屏幕帧缓冲区中截取一个允许读写的矩形区域，称为**帧缓冲切片**。**帧缓冲切片**不保存Bitmap格式的像素信息，因此不会占用额外内存。对超出**帧缓冲切片**的区域进行绘制操作将自动忽略，可以实现限定绘制区域的效果。\n\n由于使用了[framebuf](https://docs.micropython.org/en/latest/library/framebuf.html)库，`DisplayAPI`继承自`framebuf.FrameBuffer`，因此`DisplayAPI`对象可以调用`framebuf.FrameBuffer`中的方法，同时内部带有一个帧缓冲区`self.buffer`。\n\n`DisplayAPI`类有一个特殊的方法`framebuf_slice( x, y, w, h)`，用来生成一个帧缓冲区，该帧缓冲区可以指定偏移量，对应显示器全屏帧缓冲区的部分区域。主要用于实现掩码效果，利用`framebuf.FrameBuffer`的特性，超出缓冲区区域的部分会自动跳过绘制，同时不会影响性能，可以很好的将图形绘制到指定区域内(例如：子控件超出父容器区域的画面自动忽略绘制)。因为非`framebuf.GS8`和`framebuf.RGB565`像素格式的帧缓冲区使用单个字节保存了多个像素的数据，为了精确定位到每一个像素，使用了`FrameBufferOffset`类保存了绘制时x坐标应该进行的偏移量。\n\n帧缓冲切片通常由DisplayAPI类生成。\n\n#### 容器绘制区域\n\n容器的子控件当然只允许在容器的区域内绘制。每个容器都拥有自己的**容器绘制区域**，其本质是一个**帧缓冲切片**。\n\n**重建容器绘制区域在以下条件下必须被触发：**\n\n- 控件的父控件被更改时；\n- 控件的位置、大小被更改时；\n- 收到**重建容器绘制区域事件**时；\n\n#### 控件分类\n\n有三种控件：单一控件、可控制控件和容器控件\n\n单一控件：继承自[XWidget](./gui/widgets/base.py)，且不属于可控制控件和容器控件的控件。仅做显示功能。\n\n可控制控件：继承自[XCtrl](./gui/widgets/base.py)，且不属于容器控件的控件。允许响应按键输入。\n\n容器控件：继承自[XLayout](./gui/widgets/base.py)的控件。允许响应按键输入；允许包含子控件；拥有自身的布局方法。\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fxuantongyao%2Fmicropython-xt-gui","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fxuantongyao%2Fmicropython-xt-gui","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fxuantongyao%2Fmicropython-xt-gui/lists"}