效果图
先上一张效果图
使用方法
emWin中图标字体的使用方法其实很简单,因为这种图标是用ttf字库的形式保存的,所以只要硬件平台的RAM空间支持emWin ttf字库的显示,就可以直接用。显示的方法也很简单,直接调用字符串显示函数即可,这里简单说一下使用方法。
获取图标字体
想要显示图标字体,那首先肯定要能获得图标资源,目前我知道的图标字体网站有两个,一个是阿里巴巴矢量图标库,还有一个是Font Awesome。
阿里的图标样式是最丰富的,单色彩色都有,还可以下载png、svg和ai格式,相比之下Font Awesome的优点呢,就是非常方便,接近一千个图标只需要下载一个ttf文件。在这里以阿里的图标库举例。
- 首先,进到阿里巴巴矢量图标库网页,搜索想要使用的图标,然后点击添加入库,这里需要登录账号才能继续操作,外部账号支持github和微博账号;
- 把所有想用的图标全部入库以后,点击页面右上角的购物车图标,会弹出一个对话框,我们选择添加至项目,一般第一次使用会提示没有项目,按照提示新建一个就好;
- 进入到项目以后,可以在页面看到之前入库的图标,每个图标下面都有一串字符,这个是图标对应的unicode编码,这些图标对应的编码需要记住,因为emWin显示的时候就是输入这串编码来显示的,点击:下载至本地,就可以把这些图标的字体文件下载下来;
- 下载完成后,打开压缩包,里面有很多种格式的文件,我们只需要ttf格式的字体文件,这样,图标字体的文件就算拿到了。可以看到,7个图标一共才3KB多,非常小。
程序调用
接下来就是程序上加载和使用图标字体,其实加载方法就和emWin加载普通ttf字库的方法完全相同,只是使用方法稍有区别。
我这里以野火STM32H743 Pro开发板的TTF字体显示例程为基础,模拟器上的使用方法是一样的。下面只会演示如何显示图标字体,至于ttf字体相关的内容请参考野火的emwin教程文档,关于emWin模拟器如何显示ttf字体,可以到这篇帖子了解:如何在VS2019的emwin模拟器中显示中文(出处: 野火电子论坛)
- 首先,在GUIFont_Create.c中只需修改字体文件的存放路径和名称,我这里是放到了SD卡的一个指定目录,如果是模拟器,就直接放到模拟器工程下的文件夹;
/* 图标文件路径 */
static const char FONT_TTF_ADDR[] = { "0:/Font/iconfont.ttf" };
- 然后这个文件里剩下的所有内容都不需要改,我这里再贴一下字体的创建函数,下面还要用到。FONT_TTF_24到120就是创建的不同大小的图标字体,名字可以自己定义;
/* 存储器初始化标志 */
static uint8_t Storage_Init_Flag = 0;
/* 字库属性结构体 */
GUI_TTF_CS cs0, cs1, cs2, cs3, cs4;
/* 字库数据结构体 */
GUI_TTF_DATA ttf_data;
/* 定义emwin字体 */
GUI_FONT FONT_TTF_24;
GUI_FONT FONT_TTF_48;
GUI_FONT FONT_TTF_72;
GUI_FONT FONT_TTF_96;
GUI_FONT FONT_TTF_120;
/* 字库数据缓冲区 */
char *TTFfont_buffer;
GUI_HMEM hFontMem;
/* 字库存储路径 */
static const char FONT_STORAGE_ROOT_DIR[] = "0:";
static const char FONT_TTF_ADDR[] = "0:/Font/iconfont.ttf";
/* 字库存储在文件系统时需要使用的变量 */
static FIL fnew; /* file objects */
static FATFS fs; /* Work area (file system object) for logical drives */
static FRESULT res;
static UINT br; /* File R/W count */
/**
* @brief 获取字体数据
* @note 无
* @param res_name:要读取的文件名
* @retval 无
*/
static void FONT_TTF_GetData(const char *res_name)
{
if (Storage_Init_Flag == 0)
{
/* 挂载sd卡文件系统 */
res = f_mount(&fs,FONT_STORAGE_ROOT_DIR,1);
Storage_Init_Flag = 1;
}
/* 打开文件 */
taskENTER_CRITICAL();
res = f_open(&fnew , res_name, FA_OPEN_EXISTING | FA_READ);
taskEXIT_CRITICAL();
if(res != FR_OK)
{
printf("无法找到字库文件\r\n");
while(1);
}
/* 申请一块动态内存空间 */
hFontMem = GUI_ALLOC_AllocZero(fnew.fsize);
/* 转换动态内存的句柄为指针 */
TTFfont_buffer = GUI_ALLOC_h2p(hFontMem);
/* 读取内容 */
taskENTER_CRITICAL();
res = f_read( &fnew, TTFfont_buffer, fnew.fsize, &br );
taskEXIT_CRITICAL();
if(res != FR_OK)
{
printf("无法读取字库文件\r\n");
while(1);
}
f_close(&fnew);
/* 配置属性 */
ttf_data.pData = TTFfont_buffer;
ttf_data.NumBytes = fnew.fsize;
/* 配置字体参数 */
cs0.pTTF = &ttf_data;
cs0.PixelHeight = 24;
cs0.FaceIndex = 0;
cs1.pTTF = &ttf_data;
cs1.PixelHeight = 48;
cs1.FaceIndex = 0;
cs2.pTTF = &ttf_data;
cs2.PixelHeight = 72;
cs2.FaceIndex = 0;
cs3.pTTF = &ttf_data;
cs3.PixelHeight = 96;
cs3.FaceIndex = 0;
cs4.pTTF = &ttf_data;
cs4.PixelHeight = 120;
cs4.FaceIndex = 0;
}
/**
* @brief 创建TTF字体
* @note 无
* @param 无
* @retval 无
*/
void Create_TTF_Font(void)
{
/* 获取字体数据 */
FONT_TTF_GetData(FONT_TTF_ADDR);
/* 创建TTF字体 */
GUI_TTF_CreateFontAA(&FONT_TTF_24,
&cs0);
GUI_TTF_CreateFontAA(&FONT_TTF_48,
&cs1);
GUI_TTF_CreateFontAA(&FONT_TTF_72,
&cs2);
GUI_TTF_CreateFontAA(&FONT_TTF_96,
&cs3);
GUI_TTF_CreateFontAA(&FONT_TTF_120,
&cs4);
}
- 路径改好之后,新建一个icon_unicode.c文件,把之前在网页上的那些图标对应的编码全部用数组存起来,编码前面的"&#x"要换成"\x",不过实际测试中发现在keil5里"\x"只支持2位16进制数,所以只能把"&#x"改成"\u",就像下面这样。
/* 图标编码数组 */
const char *icon_unicode[] = {
"\ue629", /* 电池 */
"\ue62f", /* 返回 */
"\ue60d", /* 蓝牙 */
"\ue609", /* wifi */
"\uec50", /* USB */
"\ue680", /* SD卡 */
"\ue6bf", /* 文件夹 */
};
注意:此文件的字符编码格式必须是UTF-8-BOM,否则emWin不会有任何显示。keil5中的设置方法请参考野火的emWin教程文档,模拟器上的设置方法请参考如何在VS2019的emwin模拟器中显示中文,这里不做说明。
icon_unicode.c创建好后,添加到keil5工程中,然后在MainTask.c里定义一个枚举,方便调用图标编码。最后,在MainTask函数里调用GUI_DispStringAt就可以显示图标字体了。
extern const char *icon_unicode[];
enum icon_name{
BATTERY = 0U, /* 电池 */
BACK, /* 返回 */
BLE, /* 蓝牙 */
WIFI, /* wifi */
USB, /* USB */
SD_CARD, /* SD卡 */
FOLDER, /* 文件夹 */
};
/**
* @brief GUI主任务
* @note 无
* @param 无
* @retval 无
*/
void MainTask(void)
{
/* 启用UTF-8编码 */
GUI_UC_SetEncodeUTF8();
/* 创建图标字体 */
Create_TTF_Font();
/* 设置背景颜色 */
GUI_SetBkColor(GUI_BLUE);
GUI_Clear();
/* 设置字体模式和颜色 */
GUI_SetTextMode(GUI_TM_TRANS);
GUI_SetColor(GUI_WHITE);
/* 显示图标 */
GUI_SetFont(&FONT_TTF_24);
GUI_DispStringAt(icon_unicode[BATTERY], 24 * 0, 0);
GUI_DispStringAt(icon_unicode[BACK], 24 * 1, 0);
GUI_DispStringAt(icon_unicode[BLE], 24 * 2, 0);
GUI_DispStringAt(icon_unicode[WIFI], 24 * 3, 0);
GUI_DispStringAt(icon_unicode[USB], 24 * 4, 0);
GUI_DispStringAt(icon_unicode[SD_CARD], 24 * 5, 0);
GUI_DispStringAt(icon_unicode[FOLDER], 24 * 6, 0);
GUI_SetFont(&FONT_TTF_48);
GUI_DispStringAt(icon_unicode[BATTERY], 48 * 0, 24);
GUI_DispStringAt(icon_unicode[BACK], 48 * 1, 24);
GUI_DispStringAt(icon_unicode[BLE], 48 * 2, 24);
GUI_DispStringAt(icon_unicode[WIFI], 48 * 3, 24);
GUI_DispStringAt(icon_unicode[USB], 48 * 4, 24);
GUI_DispStringAt(icon_unicode[SD_CARD], 48 * 5, 24);
GUI_DispStringAt(icon_unicode[FOLDER], 48 * 6, 24);
GUI_SetFont(&FONT_TTF_72);
GUI_DispStringAt(icon_unicode[BATTERY], 72 * 0, 24 + 48);
GUI_DispStringAt(icon_unicode[BACK], 72 * 1, 24 + 48);
GUI_DispStringAt(icon_unicode[BLE], 72 * 2, 24 + 48);
GUI_DispStringAt(icon_unicode[WIFI], 72 * 3, 24 + 48);
GUI_DispStringAt(icon_unicode[USB], 72 * 4, 24 + 48);
GUI_DispStringAt(icon_unicode[SD_CARD], 72 * 5, 24 + 48);
GUI_DispStringAt(icon_unicode[FOLDER], 72 * 6, 24 + 48);
GUI_SetFont(&FONT_TTF_96);
GUI_DispStringAt(icon_unicode[BATTERY], 96 * 0, 24 + 48 + 72);
GUI_DispStringAt(icon_unicode[BACK], 96 * 1, 24 + 48 + 72);
GUI_DispStringAt(icon_unicode[BLE], 96 * 2, 24 + 48 + 72);
GUI_DispStringAt(icon_unicode[WIFI], 96 * 3, 24 + 48 + 72);
GUI_DispStringAt(icon_unicode[USB], 96 * 4, 24 + 48 + 72);
GUI_DispStringAt(icon_unicode[SD_CARD], 96 * 5, 24 + 48 + 72);
GUI_DispStringAt(icon_unicode[FOLDER], 96 * 6, 24 + 48 + 72);
GUI_SetFont(&FONT_TTF_120);
GUI_DispStringAt(icon_unicode[BATTERY], 120 * 0, 24 + 48 + 72 + 96);
GUI_DispStringAt(icon_unicode[BACK], 120 * 1, 24 + 48 + 72 + 96);
GUI_DispStringAt(icon_unicode[BLE], 120 * 2, 24 + 48 + 72 + 96);
GUI_DispStringAt(icon_unicode[WIFI], 120 * 3, 24 + 48 + 72 + 96);
GUI_DispStringAt(icon_unicode[USB], 120 * 4, 24 + 48 + 72 + 96);
GUI_DispStringAt(icon_unicode[SD_CARD], 120 * 5, 24 + 48 + 72 + 96);
GUI_DispStringAt(icon_unicode[FOLDER], 120 * 6, 24 + 48 + 72 + 96);
while(1)
{
GUI_Delay(10);
}
}