TinyUI是本人在疫情期間開發的一套可移植的嵌入式UI庫,如果感興趣的人比較多將開源出來。
---------------------------------------------------------------------------------------------------------------------------------
windows模擬器演示程序。
下載地址:https://pan.baidu.com/s/1sLhGqH0GZKEFkALCWVHCAg
提取碼: yooy
---------------------------------------------------------------------------------------------------------------------------------
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使用自定義字庫,矢量字體顯示使得文字細節非常豐富(把本模擬器截圖粘貼到windows自帶畫圖中,放大數倍即可看到字體細節),字體放大後的效果如下;
8. TinyUI可移植目標平臺豐富;
9. TinyUI使用UTF8編碼;
目前模擬器未使用鼠標鉤子,使用鉤子需要轉換座標:),有時鼠標擡起事件會丟失。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中
}