本文将通过实现一个点击切换进度的电量指示灯组件和exampleGUI组件库介绍如何基于TinyPiXOS开发新组件。主要内容包括组件开发规范、自定义组件开发和组件库开发三部分。
组件开发规范
命名规范
采用tp
开头命名组件类,名称具备易读性。
目录规范
- 头文件放置
include/SingleGUI/widgets/
- 源文件放置
src/SingleGUI/widgets/
代码结构(示例)
使用PIMPL
(Pointer to Implementation)设计规范,隐藏实现细节,降低编译依赖性和增强代码稳定性。
使用TP_DEF_VOID_TYPE_VAR
宏声明管理指针;所有成员变量或函数实现细节封装在cpp中。
tpChildWidget
作为所有组件的基类,自定义组件必须继承于tpChildWidget类并包含其头文件。
#include "tpChildWidget.h"
class testLight : public tpChildWidget
{};
示例组件开发
组件介绍:实现一个点击切换进度的电量指示灯。
实现步骤
创建自定义组件类testLight
创建testLight.cpp
和testLight.h
文件
组件类需继承于tpChildWidget
#ifndef __TEST_LIGHT_H
#define __TEST_LIGHT_H#include "tpChildWidget.h"
#include "tpEvent.h"class testLight : public tpChildWidget
{
public:testLight(tpChildWidget *parent);virtual ~testLight();
};#endif
定义电量最大格数和当前显示格数变量
int maxCount_;
int count_;
重写onPaintEvent事件,根据电量格数绘制效果
- 获取绘制画笔
tpCanvas* painter = event->canvas();
- 绘制底色
painter->box(0, 0, width(), height(), _RGB(255, 255, 255));
- 根据最大格数计算每个格子的宽度
int spacing = 3;
int singleWidth = (width() - (maxCount_ + 1) * spacing) / maxCount_;
- 根据当前电量绘制电量格子
for (int i = 0; i < count_; ++i)
{int drawX = spacing + i * (singleWidth + spacing);painter->box(drawX, spacing, drawX + singleWidth, height() - spacing, _RGB(128, 255, 128));
}
重写 onMousePressEvent 捕获鼠标按下事件,获取鼠标点击状态
bool testLight::onMousePressEvent(tpMouseEvent *event)
{tpChildWidget::onMousePressEvent(event);count_++;if (count_ > maxCount_)count_ = 0;return true;
}
组件测试(使用组件)
testLight* light = new testLight(this);
testButton_->setSize(200, 50);
testButton_->move(150, 300);
演示效果
初始化效果
点击组件,增加颜色块
完整源码
头文件:testLight.h
#ifndef __TEST_LIGHT_H
#define __TEST_LIGHT_H#include "tpChildWidget.h"
#include "tpEvent.h"class testLight : public tpChildWidget
{
public:testLight(tpChildWidget *parent);virtual ~testLight();public:virtual bool onMousePressEvent(tpMouseEvent *event) override;virtual bool onPaintEvent(tpObjectPaintEvent *event) override;private:int maxCount_;int count_;
};#endif
源码:testLight.cpp
#include "testLight.h"
#include "tpCanvas.h"testLight::testLight(tpChildWidget *parent): tpChildWidget(parent), maxCount_(4), count_(0)
{
}testLight::~testLight()
{
}bool testLight::onMousePressEvent(tpMouseEvent *event)
{tpChildWidget::onMousePressEvent(event);count_++;if (count_ > maxCount_)count_ = 0;return true;
}bool testLight::onPaintEvent(tpObjectPaintEvent *event)
{tpChildWidget::onPaintEvent(event);tpCanvas *painter = event->canvas();painter->box(0, 0, width(), height(), _RGB(255, 255, 255));int spacing = 3;int singleWidth = (width() - (maxCount_ + 1) * spacing) / maxCount_;for (int i = 0; i < count_; ++i){int drawX = spacing + i * (singleWidth + spacing);painter->box(drawX, spacing, drawX + singleWidth, height() - spacing, _RGB(128, 255, 128));}return true;
}
组件库介绍
当业务需求实现一整套统一样式风格的GUI样式库时,可以使用组件库的形式对相同样式风格的组件进行统一管理,方便后期扩展及维护。未来tinyPiXOS会提供各种样式风格的组件库,并以当前规范进行发布。
本节将创建一个名为exampleGUI的组件库,同时对testLight组件进行改造,将其加入exampleGUI组件库。
目录结构说明
组件库开发需要遵循目录结构规范,将组件库的头文件、源码文件、构建文件等分类放入指定文件夹。并且需要创建FrameworkGlobal.h
放置组件库全局定义,及命名空间声明。目录结构规范如下:
tinyPiXCore/
└─ PiXGUIFramework/├─ exampleGUI/│ ├─ CMakeList.txt│ └─ CMakePresets.json└─ src/├─ include/│ └─ GUIFramework/│ └─ exampleGUI/│ └─ widgets/│ └─ testLight.h└─ src/└─ GUIFramework/└─ exampleGUI/└─ widgets/└─ testLight.cpp
定义框架命名空间
编辑FrameworkGlobal.h
#ifndef _EXAMPLE_GUI_GLOBAL_H
#define _EXAMPLE_GUI_GLOBAL_H#define EXAMPLE_GUI_NAMESPACE_BEGIN namespace exampleGUI {
#define EXAMPLE_GUI_NAMESPACE_END }#endif
重构testLight类
使用PIMPL隐藏设计实现
这里我们将已经开发好的点击切换进度的电量指示灯组件加入exampleGUI组件库。
重构头文件:testLigh.h
#ifndef __TEST_LIGHT_H
#define __TEST_LIGHT_H#include "tpChildWidget.h"
#include "tpEvent.h"
#include "FrameworkGlobal.h"EXAMPLE_GUI_NAMESPACE_BEGINTP_DEF_VOID_TYPE_VAR(ItestLightData);
class testLight : public tpChildWidget
{
public:testLight(tpChildWidget *parent);virtual ~testLight();public:virtual bool onMousePressEvent(tpMouseEvent *event) override;virtual bool onPaintEvent(tpObjectPaintEvent *event) override;private:ItestLightData *data_;
};EXAMPLE_GUI_NAMESPACE_END#endif
重构源代码:testLigh.cpp
#include "testLight.h"
#include "tpCanvas.h"EXAMPLE_GUI_NAMESPACE_BEGINstruct testLightData
{int maxCount_;int count_;testLightData() : maxCount_(0), count_(0){}
};testLight::testLight(tpChildWidget *parent): tpChildWidget(parent)
{testLightData *lightData = new testLightData();lightData->maxCount_ = 4;lightData->count_ = 0;data_ = lightData;
}testLight::~testLight()
{testLightData *lightData = static_cast<testLightData *>(data_);if (lightData){delete lightData;lightData = nullptr;data_ = nullptr;}
}bool testLight::onMousePressEvent(tpMouseEvent *event)
{tpChildWidget::onMousePressEvent(event);testLightData *lightData = static_cast<testLightData *>(data_);lightData->count_++;if (lightData->count_ > lightData->maxCount_)lightData->count_ = 0;return true;
}bool testLight::onPaintEvent(tpObjectPaintEvent *event)
{tpChildWidget::onPaintEvent(event);testLightData *lightData = static_cast<testLightData *>(data_);tpCanvas *painter = event->canvas();painter->box(0, 0, width(), height(), _RGB(255, 255, 255));int spacing = 3;int singleWidth = (width() - (lightData->maxCount_ + 1) * spacing) / lightData->maxCount_;for (int i = 0; i < lightData->count_; ++i){int drawX = spacing + i * (singleWidth + spacing);painter->box(drawX, spacing, drawX + singleWidth, height() - spacing, _RGB(128, 255, 128));}return true;
}EXAMPLE_GUI_NAMESPACE_END
测试使用(使用组件库)
CMakeList引入exampleGUI头文件目录和引入动态库引用
include_directories(/usr/include/tinyPiX/GUIFramework)
target_link_libraries(examplesApp exampleGUI)
为防止多个UI框架头文件重复导致引用异常,请使用UI框架的父级目录引入。
#include"exampleGUI/widgets/testLight.h"
使用方式同上一节自定义组件
注:需添加命名空间引入
exampleGUI::testLight* light = new exampleGUI::testLight(this);
testButton_->setSize(200, 50);
testButton_->move(150, 300);
TinyPiXOS开发者联盟
源码级支持 + 真实项目:TinyPiXOS开发者联盟招募中。
开发资料
关注我们
官网网站
技术资料
视频合集
感谢支持和关注,如果对项目感兴趣,请点赞、收藏和转发!