TinyUI是本人在疫情期间开发的一套可移植的嵌入式UI库,如果感兴趣的人比较多将开源出来。
---------------------------------------------------------------------------------------------------------------------------------
windows模拟器演示程序。
下载地址:https://pan.baidu.com/s/1b7f0zfAe6KnKGL3vhicc6g
提取码: yp6q
---------------------------------------------------------------------------------------------------------------------------------
TinyUI相关博客:
3. TinyUI-TUIListView多列文本显示最简单的使用
5. TinyUI-按键对接
TinyUI简介:
TinyUI是一套适用于嵌入式平台开发的UI库,具有比较完整的事件驱动系统,该UI库使用方便简单。
目前基于低端嵌入式UI大多使用C语言进行开发或设计界面时需要计算UI组件/控件坐标,无法提高产品开发效率,或大多数嵌入式开发人员自行涉及UI,大多设计都在中断中显示UI或处理业务逻辑。另外一个更重要的问题即是无法自适应不同尺寸的屏幕,每开发新的产品或更换屏幕时都需要大量的修改或重写。
本UI库使用C++(C++ 11或以上版本)进行开发,其大多数UI组件/控件均参考主流平台进行设计,如ListView、GridView、LinearLayout、Spinner、ScrollView、TabView、Dialog等UI组件基本设计与Android一致,并且这些UI组件/控件的使用方法均与Android APP开发一致;其中GridLayout的使用方法与WPF/UWP基本一致。
TinyUI主要特点:
1. 提供LinearLayout和GridLayout等2种UI布局,可自适应不同尺寸屏幕,并且可以布局嵌套;
2. UI组件/控件使用简单,与主流平台设计相似;
3. 对于处理器是否集成LCD控制器均支持,并且如果内存够大还可以支持双缓存,可支持任意大小尺寸屏幕;
4. 对无触摸(但需要有按键),几乎所有可获得焦点的UI组件/控件均可绑定按键,当物理按键按下时UI组件/控件自动响应事件,而无需开发人员进行处理;
5. 所有的UI组件/控件可用功能比较丰富,如: TextView提供多种对齐、跑马方式,以及省略号结尾等;
6. 移植简单,底层驱动只需实现TinyUI定义的4个接口即可,如: LCD、按键、定时器、触摸;
7. TinyUI使用自定义字库(支持矢量字体与非矢量字体);
7.1 矢量字体
矢量字体显示使得文字细节非常丰富(把本模拟器截图粘贴到windows自带画图中,放大数倍即可看到字体细节),字体放大后的效果如下;
7.2 非矢量字体
8. TinyUI可移植目标平台丰富;
9. TinyUI使用UTF8编码;
10. 与硬件外设无关的应用可使用Visual studio并基于模拟器进行开发;
目前模拟器未使用鼠标钩子,使用钩子需要转换坐标:),有时鼠标抬起事件会丢失。TinyUI由本人/个人开发&测试,开发时间不足2个月,因此部分小UI组件/控件还未完成,同时会存在一定的BUG。
------------- TinyUI非常年轻,它的的发展需要大家的支持,您的支持将是我最大的动力。
如下贴出部分演示代码:
AboutWindow.h
class AboutWindow : public TUIWindow, public TUIButtonListener
{
public:
AboutWindow(TUIWindow* parent = nullptr);
virtual ~AboutWindow();
void onShow();
void onClose();
void onClick(TUIButton* view);
private:
TUIGridLayout rootLayout; // 顶层内容视图使用GridLayout
TUIButton backButton; // 返回按钮
};
AboutWindow.cpp
AboutWindow::AboutWindow(TUIWindow* parent)
: TUIWindow(parent)
{
setContentView(&this->rootLayout); // 设置GridLayout为当前窗口的内容视图
this->rootLayout.setRowNumber(3); // 3行
this->rootLayout.setColumnNumber(2); // 3列
this->rootLayout.setRowHeight(0, 30); // 第1行高30
this->rootLayout.setRowHeight(1, 30); // 第2行高30
this->rootLayout.setRowHeight(2, TUILAYOUT_DIM::TUI_MATCH_REMAIN); // 第3行高占满剩余空间
this->rootLayout.setColumnWidth(0, 50); // 第1列宽50
this->rootLayout.setColumnWidth(1, TUILAYOUT_DIM::TUI_MATCH_REMAIN); // 第2列占满剩余空间
this->backButton.setText(L"返回");
this->backButton.setMargin(2, 0, 2, 0); // 设置按钮外边距(顺序: 左->上->右->下)
this->backButton.registerListener(this); // 当前窗口监听backButton点击事件
this->backButton.bindKeycode(TUIVKCode::TUIVK_BACK); // backButton绑定回退键
this->rootLayout.addView(&this->backButton, 0, 0); // backButton放到第0行,第0列
}
显示AboutWindow:
aboutWindow.show();
移植
TinyUI本身并不需要使用者做大量的工作,除非你需要更高级的功能(需要提供一个软中断给TinyUI)。
移植的难易程度取决于你的驱动结构好坏。
注: 我的驱动是C写的
1. 定时器接口移植
UITimer::UITimer(int32_t id)
{
if (0 == id)
{
normal_timer = (timer_t *)device_driver_autowired(DDTYPE_TIMER, DDID_TIMER02);
normal_timer->ops->open(TIMER_MILLISECOND, TIMER_CONTINUOUS);
}
}
UITimer::~UITimer()
{
}
void UITimer::start(uint32_t millisecond)
{
if (nullptr == normal_timer)
{
return;
}
normal_timer->ops->start(millisecond);
}
void UITimer::stop()
{
if (nullptr == normal_timer)
{
return;
}
normal_timer->ops->close();
}
void UITimer::registerCallback(timeoutCallback callback)
{
if (nullptr == normal_timer)
{
return;
}
normal_timer->ops->register_timeout_callback(callback);
}
2. LCD接口移植
UIDisplay::UIDisplay()
{
ili9341 = (lcd_controller_t *)device_driver_autowired(DDTYPE_LCD_CONTROLLER, DDID_LCD_CONTROLLER_ILI9341);
ili9341->ops->open();
}
UIDisplay::~UIDisplay()
{
}
bool UIDisplay::readPoint(int32_t x, int32_t y, color_t* color)
{
uint16_t c = 0;
ili9341->ops->read_point(x, y, &c);
*color = c;
return true;
}
void UIDisplay::drawPoint(int32_t x, int32_t y, int32_t visibleX1, int32_t visibleY1, int32_t visibleX2, int32_t visibleY2, color_t color)
{
ili9341->ops->draw_point(x, y, color);
}
void UIDisplay::drawLine(int32_t x1, int32_t y1, int32_t x2, int32_t y2, int32_t visibleX1, int32_t visibleY1, int32_t visibleX2, int32_t visibleY2, color_t color)
{
ili9341->ops->draw_line(x1, y1, x2, y2, color);
}
void UIDisplay::drawBuffer(int32_t x, int32_t y, uint32_t bufferWidth, uint32_t bufferHeight, int32_t visibleX1, int32_t visibleY1, int32_t visibleX2, int32_t visibleY2, const uint8_t* buffer)
{
ili9341->ops->draw_buffer(x, y, bufferWidth, bufferHeight, buffer);
}
void UIDisplay::clear(int32_t x, int32_t y, uint32_t width, uint32_t height, int32_t visibleX1, int32_t visibleY1, int32_t visibleX2, int32_t visibleY2, color_t color)
{
ili9341->ops->clear(x, y, width, height, color);
}
uint8_t UIDisplay::getBPP()
{
return ili9341->ops->get_bpp();
}
uint32_t UIDisplay::getScreenWidth()
{
return ili9341->ops->get_width();
}
uint32_t UIDisplay::getScreenHeight()
{
return ili9341->ops->get_height();
}
uint8_t* UIDisplay::getFB()
{
//return g_FrameBuffer; // 不支持
return nullptr;
}
void UIDisplay::submit(uint8_t* buffer)
{
//ili9341->ops->draw_buffer(0, 0, 320, 240, g_FrameBuffer); // 不支持
}
3. TinyUI初始化及驱动
void initTinyUI()
{
TUIInit(); // Tiny初始化
UIDisplay *display = new UIDisplay();
TUIRegisterFBInterface(display); // 注册显示接口
UITimer *timer0 = new UITimer(0); // 实例化一个定时器给TinyUI使用
TUIRegisterTimerInterface(0, timer0);
string filePath = "1:font.tui"; // 字库路径
TUIRegisterFontInterface(TUIFontRenderer::instance(), filePath.c_str()); // 注册字体渲染器,TinyUI运行自定义
MyLauncher* myLauncher = new MyLauncher(); // 定义自己的主界面
TUIStartup(myLauncher); // 把自己的主界面注册到TinyUI中
}