量产工具一一业务系统(六)

目录

前言

一、代码流程框架

1.业务系统程序流程图

2.业务系统主页面流程图

3.main.c

4.main_page.c

二、处理配置文件

1.配置文件示例

2.处理配置文件

3.config.h

4.config.c 

三、生成产品界面

1.计算每个按钮的范围

2.main_page.c

四、处理输入事件

1.main_page.c

五、上机测试

六、改进代码

1.common.h

2.freetype.c

3.disp_manager.c

4.main_page.c

5.上机测试


前言

前面我们实现了显示系统框架,输入系统框架,文字系统框架,UI系统框架和页面系统框架,链接:

  • 量产工具一一显示系统(一)-CSDN博客
  • 量产工具一一输入系统(二)-CSDN博客
  • 量产工具一一文字系统(三)-CSDN博客
  • 量产工具一一UI系统(四)-CSDN博客
  • 量产工具一一页面系统(五)-CSDN博客

接下来我们来实现业务系统框架,也就是把前面所实现的系统框架全部整合到一起实现功能。

一、代码流程框架

1.业务系统程序流程图

2.业务系统主页面流程图

3.main.c

#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <linux/fb.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <sys/ioctl.h>
#include <stdlib.h>#include <disp_manager.h>
#include <font_manager.h>
#include <input_manager.h>
#include <page_manager.h>int main(int argc, char **argv)
{int error;if (argc != 2){printf("Usage: %s <font_file>\n", argv[0]);return -1;}/* 初始化显示系统 */		DisplaySystemRegister(); SelectDefaultDisplay("fb");InitDefaultDisplay();/* 初始化输入系统 */		InputSystemRegister(); InputDeviceInit();/* 初始化文字系统 */		FontSystemRegister(); error = SelectAndInitFont("freetype", argv[1]);if (error){printf("SelectAndInitFont err\n");return -1;}/* 初始化页面系统 */		PageSystemRegister(); /* 运行业务系统的主页面 */Page("main")->Run(NULL);return 0;	
}

4.main_page.c

在主页面流程函数下我们需要:

  • 1.读取配置文件
  • 2.根据配置文件生成按钮和界面
  • 3.在while循环里读取输入事件
  • 4.根据输入时间找到对应按钮
  • 5.找到后调用出发按钮函数
static void MainPageRun(void *pParams)
{int error;InputEvent tInputEvent;PButton ptButton;PDispBuff ptDispBuff = GetDisplayBuffer();/* 读取配置文件 */error = ParseConfigFile();if (error)return ;/* 根据配置文件生成按钮、界面 */GenerateButtons();while (1){/* 读取输入事件 */error = GetInputEvent(&tInputEvent);if (error)continue;/* 根据输入事件找到按钮 */ptButton = GetButtonByInputEvent(&tInputEvent);if (!ptButton)continue;/* 调用按钮的OnPressed函数 */ptButton->OnPressed(ptButton, ptDispBuff, &tInputEvent);}
}

在下面我们再一一实现上面所用到的函数。

二、处理配置文件

对于我们要制作的页面,里面有很多按钮,那么我们怎么知道每个按钮里面都存放着什么呢?

这时我们就需要配置文件,以后我们想要打开哪个按钮,调整测试模块时,可以直接修改配置文件即可,就不需要重新修改,编译程序就可以带来非常大的灵活性。

1.配置文件示例

2.处理配置文件

创建一个ItemCfg 结构体,用于表示配置文件中的一个条目,以便于处理配置文件

3.config.h

#ifndef _CONFIG_H
#define _CONFIG_H#include <common.h>#define ITEMCFG_MAX_NUM 30
#define CFG_FILE  "/etc/test_gui/gui.conf"typedef struct ItemCfg {int index;char name[100];int bCanBeTouched;char command[100];
}ItemCfg, *PItemCfg;int ParseConfigFile(void);
int GetItemCfgCount(void);
PItemCfg GetItemCfgByIndex(int index);
PItemCfg GetItemCfgByName(char *name);#endif

4.config.c 

处理配置文件主要分为下面几个步骤

  • 1.打开配置文件
  • 2.循环读取文件中每一行
  • 3.读取每一行数据
  • 4.吃掉开头的空格或者TAB
  • 5.忽略注释
  • 6.处理数据
#include <config.h>
#include <stdio.h>
#include <string.h>static ItemCfg g_tItemCfgs[ITEMCFG_MAX_NUM];
static int g_iItemCfgCount = 0;int ParseConfigFile(void)
{FILE *fp;char buf[100];char *p = buf;/* 1. 打开配置文件 */fp = fopen(CFG_FILE, "r");if (!fp){printf("can not open cfg file %s\n", CFG_FILE);return -1;}/* 循环读取文件的每一行 */while (fgets(buf, 100, fp)) {/* 2.1 读取每一行数据 */buf[99] = '\0';		/* 2.2 吃掉开头的空格或TAB */p = buf;while (*p == ' ' || *p =='\t')p++;/* 2.3 忽略注释 */if (*p == '#')continue;/* 2.4 处理 */g_tItemCfgs[g_iItemCfgCount].command[0] = '\0';g_tItemCfgs[g_iItemCfgCount].index = g_iItemCfgCount;sscanf(p, "%s %d %s", g_tItemCfgs[g_iItemCfgCount].name, &g_tItemCfgs[g_iItemCfgCount].bCanBeTouched, \g_tItemCfgs[g_iItemCfgCount].command);g_iItemCfgCount++;		}return 0;
}/* 定义一个函数,用于获取配置文件中条目的数量 */
int GetItemCfgCount(void)
{return g_iItemCfgCount;
}/* 定义一个函数,用于根据索引获取配置文件中的条目 */
PItemCfg GetItemCfgByIndex(int index)
{if (index < g_iItemCfgCount)return &g_tItemCfgs[index];elsereturn NULL;
}/* 定义一个函数,用于根据名称获取配置文件中的条目 */
PItemCfg GetItemCfgByName(char *name)
{int i;for (i = 0; i < g_iItemCfgCount; i++){if (strcmp(name, g_tItemCfgs[i].name) == 0)return &g_tItemCfgs[i];}return NULL;
}

三、生成产品界面

想要显示如下界面,我们可以通过上面配置文件知道有哪些按钮,接下来我们需要确定每个按钮的大小和位置,需要计算出来。

1.计算每个按钮的范围

2.main_page.c

#include <config.h>
#include <stdio.h>
#include <ui.h>
#include <page_manager.h>
#include <math.h>
#include <string.h>#define X_GAP 5
#define Y_GAP 5static Button g_tButtons[ITEMCFG_MAX_NUM];static void GenerateButtons(void)
{int width, height;int n_per_line;int row, rows;int col;int n;PDispBuff pDispBuff;int xres, yres;int start_x, start_y;int pre_start_x, pre_start_y;PButton pButton;int i = 0;/* 算出单个按钮的width/height */g_tButtonCnt = n = GetItemCfgCount();pDispBuff = GetDisplayBuffer();xres = pDispBuff->iXres;yres = pDispBuff->iYres;width = sqrt(1.0/0.618 *xres * yres / n);n_per_line = xres / width + 1;width  = xres / n_per_line;height = 0.618 * width;	/* 居中显示:  计算每个按钮的region  */start_x = (xres - width * n_per_line) / 2;rows    = n / n_per_line;if (rows * n_per_line < n)rows++;start_y = (yres - rows*height)/2;/* 计算每个按钮的region */for (row = 0; (row < rows) && (i < n); row++){pre_start_y = start_y + row * height;pre_start_x = start_x - width;for (col = 0; (col < n_per_line) && (i < n); col++){pButton = &g_tButtons[i];pButton->tRegion.iLeftUpX = pre_start_x + width;pButton->tRegion.iLeftUpY = pre_start_y;pButton->tRegion.iWidth   = width - X_GAP;pButton->tRegion.iHeigh   = height - Y_GAP;pre_start_x = pButton->tRegion.iLeftUpX;/* InitButton */InitButton(pButton, GetItemCfgByIndex(i)->name, NULL, NULL, MainPageOnPressed);i++;}}/* OnDraw */for (i = 0; i < n; i++)g_tButtons[i].OnDraw(&g_tButtons[i], pDispBuff);
}

四、处理输入事件

我们得到的输入事件,可能来自触摸屏,也可能是其他APP发来的网络数据

对于触摸屏事件,根据iX、iY找到按钮 

对于网络数据,我们限定为这样的格式:

  • “name ok”、“name err”、“name 70%”
  • 根据name找到按钮

对于按钮,我们要提供自己的OnPressed函数,不适用UI系统默认的函数

1.main_page.c

#include <config.h>
#include <stdio.h>
#include <ui.h>
#include <page_manager.h>
#include <math.h>
#include <string.h>#define X_GAP 5
#define Y_GAP 5static Button g_tButtons[ITEMCFG_MAX_NUM];
static int g_tButtonCnt;static int MainPageOnPressed(struct Button *ptButton, PDispBuff ptDispBuff, PInputEvent ptInputEvent)
{unsigned int dwColor = BUTTON_DEFAULT_COLOR;char name[100];char status[100];char *strButton;strButton = ptButton->name;/* 1. 对于触摸屏事件 */if (ptInputEvent->iType == INPUT_TYPE_TOUCH){/* 1.1 分辨能否被点击 */if (GetItemCfgByName(ptButton->name)->bCanBeTouched == 0)return -1;/* 1.2 修改颜色 */ptButton->status = !ptButton->status;if (ptButton->status)dwColor = BUTTON_PRESSED_COLOR;}else if (ptInputEvent->iType == INPUT_TYPE_NET){/* 2. 对于网络事件 *//* 根据传入的字符串修改颜色 : wifi ok, wifi err, burn 70 */sscanf(ptInputEvent->str, "%s %s", name, status);if (strcmp(status, "ok") == 0)dwColor = BUTTON_PRESSED_COLOR;else if (strcmp(status, "err") == 0)dwColor = BUTTON_DEFAULT_COLOR;else if (status[0] >= '0' && status[0] <= '9'){			dwColor = BUTTON_PERCENT_COLOR;strButton = status;			}elsereturn -1;}else{return -1;}/* 绘制底色 */DrawRegion(&ptButton->tRegion, dwColor);/* 居中写文字 */DrawTextInRegionCentral(strButton, &ptButton->tRegion, BUTTON_TEXT_COLOR);/* flush to lcd/web */FlushDisplayRegion(&ptButton->tRegion, ptDispBuff);return 0;
}static void GenerateButtons(void)
{int width, height;int n_per_line;int row, rows;int col;int n;PDispBuff pDispBuff;int xres, yres;int start_x, start_y;int pre_start_x, pre_start_y;PButton pButton;int i = 0;/* 算出单个按钮的width/height */g_tButtonCnt = n = GetItemCfgCount();pDispBuff = GetDisplayBuffer();xres = pDispBuff->iXres;yres = pDispBuff->iYres;width = sqrt(1.0/0.618 *xres * yres / n);n_per_line = xres / width + 1;width  = xres / n_per_line;height = 0.618 * width;	/* 居中显示:  计算每个按钮的region  */start_x = (xres - width * n_per_line) / 2;rows    = n / n_per_line;if (rows * n_per_line < n)rows++;start_y = (yres - rows*height)/2;/* 计算每个按钮的region */for (row = 0; (row < rows) && (i < n); row++){pre_start_y = start_y + row * height;pre_start_x = start_x - width;for (col = 0; (col < n_per_line) && (i < n); col++){pButton = &g_tButtons[i];pButton->tRegion.iLeftUpX = pre_start_x + width;pButton->tRegion.iLeftUpY = pre_start_y;pButton->tRegion.iWidth   = width - X_GAP;pButton->tRegion.iHeigh   = height - Y_GAP;pre_start_x = pButton->tRegion.iLeftUpX;/* InitButton */InitButton(pButton, GetItemCfgByIndex(i)->name, NULL, NULL, MainPageOnPressed);i++;}}/* OnDraw */for (i = 0; i < n; i++)g_tButtons[i].OnDraw(&g_tButtons[i], pDispBuff);
}static int isTouchPointInRegion(int iX, int iY, PRegion ptRegion)
{if (iX < ptRegion->iLeftUpX || iX >= ptRegion->iLeftUpX + ptRegion->iWidth)return 0;if (iY < ptRegion->iLeftUpY || iY >= ptRegion->iLeftUpY + ptRegion->iHeigh)return 0;return 1;
}static PButton GetButtonByName(char *name)
{int i;for (i = 0; i < g_tButtonCnt; i++){if (strcmp(name, g_tButtons[i].name) == 0)return &g_tButtons[i];}return NULL;
}static PButton GetButtonByInputEvent(PInputEvent ptInputEvent)
{int i;char name[100];if (ptInputEvent->iType == INPUT_TYPE_TOUCH){for (i = 0; i < g_tButtonCnt; i++){if (isTouchPointInRegion(ptInputEvent->iX, ptInputEvent->iY, &g_tButtons[i].tRegion))return &g_tButtons[i];}}else if (ptInputEvent->iType == INPUT_TYPE_NET){sscanf(ptInputEvent->str, "%s", name);return GetButtonByName(name);}else{return NULL;}return NULL;
}static void MainPageRun(void *pParams)
{int error;InputEvent tInputEvent;PButton ptButton;PDispBuff ptDispBuff = GetDisplayBuffer();/* 读取配置文件 */error = ParseConfigFile();if (error)return ;/* 根据配置文件生成按钮、界面 */GenerateButtons();while (1){/* 读取输入事件 */error = GetInputEvent(&tInputEvent);if (error)continue;/* 根据输入事件找到按钮 */ptButton = GetButtonByInputEvent(&tInputEvent);if (!ptButton)continue;/* 调用按钮的OnPressed函数 */ptButton->OnPressed(ptButton, ptDispBuff, &tInputEvent);}
}static PageAction g_tMainPage = {.name = "main",.Run  = MainPageRun,
};void MainPageRegister(void)
{PageRegister(&g_tMainPage);
}

五、上机测试

上电开发板,挂载 Ubuntu 的 NFS 目录,编译测试:

六、改进代码

在上面我们可以发现按钮文字大小不一,没有严格居中,太小看不清,要解决这个问题,我们可以根据配置文件的各项确定最长的名字,确定字符大小,从而让每个按钮中文字大小一样。

解决方法:

  • common.h 中新构造结构体描述笛卡尔取值范围。
  • freetype.c 文件中添加 FreetypeGetStringRegionCar 函数,在font_manager.h中进行函数声明。
  • 在 disp_manager.c 文件的 DrawTextInRegionCentral 函数。
  • main_page.c 文件中添加 GetFontSizeForAllButton 函数,另外我们可以改进配置文件中的command,在 OnPressed 函数中,用system函数运行command。

1.common.h

#ifndef _COMMON_H
#define _COMMON_H#ifndef NULL
#define NULL (void *)0
#endiftypedef struct Region {int iLeftUpX;int iLeftUpY;int iWidth;int iHeigh;
}Region, *PRegion;typedef struct RegionCartesian {int iLeftUpX;int iLeftUpY;int iWidth;int iHeigh;
}RegionCartesian, *PRegionCartesian;#endif

2.freetype.c

static int FreetypeGetStringRegionCar(char *str, PRegionCartesian ptRegionCar)
{int i;int error;FT_BBox bbox;FT_BBox glyph_bbox;FT_Vector pen;FT_Glyph  glyph;FT_GlyphSlot slot = g_tFace->glyph;/* 初始化 */bbox.xMin = bbox.yMin = 32000;bbox.xMax = bbox.yMax = -32000;/* 指定原点为(0, 0) */pen.x = 0;pen.y = 0;/* 计算每个字符的bounding box *//* 先translate, 再load char, 就可以得到它的外框了 */for (i = 0; i < strlen(str); i++){/* 转换:transformation */FT_Set_Transform(g_tFace, 0, &pen);/* 加载位图: load glyph image into the slot (erase previous one) */error = FT_Load_Char(g_tFace, str[i], FT_LOAD_RENDER);if (error){printf("FT_Load_Char error\n");return -1;}/* 取出glyph */error = FT_Get_Glyph(g_tFace->glyph, &glyph);if (error){printf("FT_Get_Glyph error!\n");return -1;}/* 从glyph得到外框: bbox */FT_Glyph_Get_CBox(glyph, FT_GLYPH_BBOX_TRUNCATE, &glyph_bbox);/* 更新外框 */if ( glyph_bbox.xMin < bbox.xMin )bbox.xMin = glyph_bbox.xMin;if ( glyph_bbox.yMin < bbox.yMin )bbox.yMin = glyph_bbox.yMin;if ( glyph_bbox.xMax > bbox.xMax )bbox.xMax = glyph_bbox.xMax;if ( glyph_bbox.yMax > bbox.yMax )bbox.yMax = glyph_bbox.yMax;/* 计算下一个字符的原点: increment pen position */pen.x += slot->advance.x;pen.y += slot->advance.y;}/* return string bbox *///*abbox = bbox;ptRegionCar->iLeftUpX = bbox.xMin;ptRegionCar->iLeftUpY = bbox.yMax;ptRegionCar->iWidth     = bbox.xMax - bbox.xMin + 1;ptRegionCar->iHeigh     = bbox.yMax - bbox.yMin + 1;return 0;	
}

3.disp_manager.c

void DrawTextInRegionCentral(char *name, PRegion ptRegion, unsigned int dwColor)
{FontBitMap tFontBitMap;RegionCartesian tRegionCar;int iOriginX, iOriginY;int i = 0;int error;/* 计算字符串的外框 */GetStringRegionCar(name, &tRegionCar);/* 算出第一个字符的origin */iOriginX = ptRegion->iLeftUpX + (ptRegion->iWidth - tRegionCar.iWidth)/2 - tRegionCar.iLeftUpX;iOriginY = ptRegion->iLeftUpY + (ptRegion->iHeigh - tRegionCar.iHeigh)/2 + tRegionCar.iLeftUpY;/* 逐个绘制 */while (name[i]){/* get bitmap */tFontBitMap.iCurOriginX = iOriginX;tFontBitMap.iCurOriginY = iOriginY;error = GetFontBitMap(name[i], &tFontBitMap);if (error){printf("SelectAndInitFont err\n");return;}/* draw on buffer */		DrawFontBitMap(&tFontBitMap, dwColor);		iOriginX = tFontBitMap.iNextOriginX;iOriginY = tFontBitMap.iNextOriginY;	i++;}}

4.main_page.c

#include <config.h>
#include <stdio.h>
#include <ui.h>
#include <page_manager.h>
#include <math.h>
#include <string.h>
#include <stdlib.h>#define X_GAP 5
#define Y_GAP 5static Button g_tButtons[ITEMCFG_MAX_NUM];
static int g_tButtonCnt;static int MainPageOnPressed(struct Button *ptButton, PDispBuff ptDispBuff, PInputEvent ptInputEvent)
{unsigned int dwColor = BUTTON_DEFAULT_COLOR;char name[100];char status[100];char *strButton;char *command_status[3] = {"err", "ok", "percent"};int command_status_index = 0;char command[1000];PItemCfg ptItemCfg;strButton = ptButton->name;/* 1. 对于触摸屏事件 */if ((ptInputEvent->iType == INPUT_TYPE_TOUCH) && (ptInputEvent->iPressure)){/* 1.1 分辨能否被点击 */if (GetItemCfgByName(ptButton->name)->bCanBeTouched == 0)return -1;/* 1.2 修改颜色 */ptButton->status = !ptButton->status;if (ptButton->status){dwColor = BUTTON_PRESSED_COLOR;command_status_index = 1;}}else if (ptInputEvent->iType == INPUT_TYPE_NET){/* 2. 对于网络事件 *//* 根据传入的字符串修改颜色 : wifi ok, wifi err, burn 70 */sscanf(ptInputEvent->str, "%s %s", name, status);if (strcmp(status, "ok") == 0){command_status_index = 1;dwColor = BUTTON_PRESSED_COLOR;}else if (strcmp(status, "err") == 0){command_status_index = 0;dwColor = BUTTON_DEFAULT_COLOR;}else if (status[0] >= '0' && status[0] <= '9'){			command_status_index = 2;dwColor = BUTTON_PERCENT_COLOR;strButton = status;			}elsereturn -1;}else{return -1;}/* 绘制底色 */DrawRegion(&ptButton->tRegion, dwColor);/* 居中写文字 */DrawTextInRegionCentral(strButton, &ptButton->tRegion, BUTTON_TEXT_COLOR);/* flush to lcd/web */FlushDisplayRegion(&ptButton->tRegion, ptDispBuff);/* 执行command */ptItemCfg = GetItemCfgByName(ptButton->name);if (ptItemCfg->command[0] != '\0'){sprintf(command, "%s %s", ptItemCfg->command, command_status[command_status_index]);system(command);}return 0;
}static int GetFontSizeForAllButton(void)
{int i;int max_len = -1;int max_index = 0;int len;RegionCartesian tRegionCar;float k, kx, ky;/* 1. 找出name最长的Button */for (i = 0; i < g_tButtonCnt; i++){len = strlen(g_tButtons[i].name);if (len > max_len){max_len = len;max_index = i;}}/* 2. 以font_size =100, 算出它的外框 */SetFontSize(100);GetStringRegionCar(g_tButtons[max_index].name, &tRegionCar);/* 3. 把文字的外框缩放为Button的外框 */kx = (float)g_tButtons[max_index].tRegion.iWidth / tRegionCar.iWidth;ky = (float)g_tButtons[max_index].tRegion.iHeigh / tRegionCar.iHeigh;//printf("button width / str width   = %d/%d = %f\n", g_tButtons[max_index].tRegion.iWidth, tRegionCar.iWidth, kx);//printf("button height / str height = %d/%d = %f\n", g_tButtons[max_index].tRegion.iHeigh, tRegionCar.iHeigh, ky);if (kx < ky)k = kx;elsek = ky;//printf("font size = %d\n", (int)(k*100));/* 4. 反算出font size, 只取0.80, 避免文字过于接近边界 */return k * 100 * 0.8;
}static void GenerateButtons(void)
{int width, height;int n_per_line;int row, rows;int col;int n;PDispBuff pDispBuff;int xres, yres;int start_x, start_y;int pre_start_x, pre_start_y;PButton pButton;int i = 0;int iFontSize;/* 算出单个按钮的width/height */g_tButtonCnt = n = GetItemCfgCount();pDispBuff = GetDisplayBuffer();xres = pDispBuff->iXres;yres = pDispBuff->iYres;width = sqrt(1.0/0.618 *xres * yres / n);n_per_line = xres / width + 1;width  = xres / n_per_line;height = 0.618 * width;	/* 居中显示:  计算每个按钮的region  */start_x = (xres - width * n_per_line) / 2;rows    = n / n_per_line;if (rows * n_per_line < n)rows++;start_y = (yres - rows*height)/2;/* 计算每个按钮的region */for (row = 0; (row < rows) && (i < n); row++){pre_start_y = start_y + row * height;pre_start_x = start_x - width;for (col = 0; (col < n_per_line) && (i < n); col++){pButton = &g_tButtons[i];pButton->tRegion.iLeftUpX = pre_start_x + width;pButton->tRegion.iLeftUpY = pre_start_y;pButton->tRegion.iWidth   = width - X_GAP;pButton->tRegion.iHeigh   = height - Y_GAP;pre_start_x = pButton->tRegion.iLeftUpX;/* InitButton */InitButton(pButton, GetItemCfgByIndex(i)->name, NULL, NULL, MainPageOnPressed);i++;}}iFontSize = GetFontSizeForAllButton();//SetFontSize(iFontSize);/* OnDraw */for (i = 0; i < n; i++){g_tButtons[i].iFontSize = iFontSize;g_tButtons[i].OnDraw(&g_tButtons[i], pDispBuff);}
}static int isTouchPointInRegion(int iX, int iY, PRegion ptRegion)
{if (iX < ptRegion->iLeftUpX || iX >= ptRegion->iLeftUpX + ptRegion->iWidth)return 0;if (iY < ptRegion->iLeftUpY || iY >= ptRegion->iLeftUpY + ptRegion->iHeigh)return 0;return 1;
}static PButton GetButtonByName(char *name)
{int i;for (i = 0; i < g_tButtonCnt; i++){if (strcmp(name, g_tButtons[i].name) == 0)return &g_tButtons[i];}return NULL;
}static PButton GetButtonByInputEvent(PInputEvent ptInputEvent)
{int i;char name[100];if (ptInputEvent->iType == INPUT_TYPE_TOUCH){for (i = 0; i < g_tButtonCnt; i++){if (isTouchPointInRegion(ptInputEvent->iX, ptInputEvent->iY, &g_tButtons[i].tRegion))return &g_tButtons[i];}}else if (ptInputEvent->iType == INPUT_TYPE_NET){sscanf(ptInputEvent->str, "%s", name);return GetButtonByName(name);}else{return NULL;}return NULL;
}static void MainPageRun(void *pParams)
{int error;InputEvent tInputEvent;PButton ptButton;PDispBuff ptDispBuff = GetDisplayBuffer();/* 读取配置文件 */error = ParseConfigFile();if (error)return ;/* 根据配置文件生成按钮、界面 */GenerateButtons();while (1){/* 读取输入事件 */error = GetInputEvent(&tInputEvent);if (error)continue;/* 根据输入事件找到按钮 */ptButton = GetButtonByInputEvent(&tInputEvent);if (!ptButton)continue;/* 调用按钮的OnPressed函数 */ptButton->OnPressed(ptButton, ptDispBuff, &tInputEvent);}
}static PageAction g_tMainPage = {.name = "main",.Run  = MainPageRun,
};void MainPageRegister(void)
{PageRegister(&g_tMainPage);
}

5.上机测试

上电开发板,挂载 Ubuntu 的 NFS 目录,编译测试:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/43935.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Python实战因果推断】18_线性回归的不合理效果8

目录 Saturated Regression Model Regression as Variance Weighted Average Saturated Regression Model 还记得我在本章开头强调回归和条件平均值之间的相似性吗&#xff1f;我向你展示了使用二元干预进行回归与比较干预组和对照组的平均值是完全一样的。现在&#xff0c;由…

Python | Leetcode Python题解之第225题用队列实现栈

题目&#xff1a; 题解&#xff1a; class MyStack:def __init__(self):"""Initialize your data structure here."""self.queue collections.deque()def push(self, x: int) -> None:"""Push element x onto stack."&…

LabVIEW机器视觉技术在产品质量检测中有哪些应用实例

LabVIEW的机器视觉技术在产品质量检测中有广泛的应用&#xff0c;通过图像采集、处理和分析&#xff0c;实现对产品缺陷的自动检测、尺寸测量和定位校准&#xff0c;提高生产效率和产品质量。 1. 电子元器件质量检测 在电子制造业中&#xff0c;电子元器件的质量检测是确保产品…

【基于深度学习方法的激光雷达点云配准系列之GeoTransformer】——粗配准

【GeoTransformer系列】——粗配准 1.coarse_matching1.1 概要1.2 功能1.3 超参1.4 input1.5 output2 coarse_target2.1 概要2.2 功能2.3 input2.4 output在模型部分有了初步了解之后, 接下来我们对后续的粗配准、精配准等部分依次进行解读. 本篇主要来看粗配准部分, 代码是在G…

websocket推送消息,模拟推送

上一篇文章&#xff1a;什么是webSocket&#xff1f;以及它的一些相关理论知识 背景&#xff1a; MQTT 的发布/订阅模式与 WebSocket 的双向通信特性相结合。 通过将 MQTT 与 WebSocket 结合使用&#xff0c;可以在 Web 应用中实现高效、实时的消息传输&#xff0c;特别适用于…

24/7/10总结

flex布局 父项常见属性 justify-content:设置主轴上的子元素排列方式 flex-wrap:设置子元素是否换行 align-items:设置侧轴上的子元素的排列方式&#xff08;单行&#xff09; 拉伸要把子盒子里的高度给去掉 如果两个align-items都是center并且主轴是y轴就是这种效果…

Java | Leetcode Java题解之第225题用队列实现栈

题目&#xff1a; 题解&#xff1a; class MyStack {Queue<Integer> queue;/** Initialize your data structure here. */public MyStack() {queue new LinkedList<Integer>();}/** Push element x onto stack. */public void push(int x) {int n queue.size();…

操作系统:信号究竟是什么?如何产生?

OS信号 一、信号的概念二、信号的产生1&#xff09;终端按键产生信号1、 前台进程、后台进程2、验证终端按键是否产生信号 2&#xff09;调用系统函数向进程发信号3&#xff09;硬件异常产生信号1、浮点数溢出&#xff0c;CPU产生信号2 浮点数溢出&#xff0c;产生信号原理3. 空…

Mysql-内置函数

一.什么是函数&#xff1f; 函数是指一段可以直接被另外一段程序调用的程序或代码。 mysql内置了很多的函数,我们只需要调用即可。 二.字符串函数 MySQL中内置了很多字符串函数: 三.根据需求完成以下SQL编写 由于业务需求变更,企业员工的工号,统一为5位数,目前不足5位数的全…

windows驱动开发基础-环境篇

前言 Windows上无论是用户模式下还是内核模式下&#xff0c;有关驱动的开发都有可能影响系统稳定性&#xff0c;所以我们首先要准备一个专用的测试环境&#xff0c;可以使用VM等虚拟机方便环境修复和还原 测试模式 开启测试模式&#xff1a;cmd 命令 bcdedit /set testsign…

旷野之间2 - 如何训练医疗保健小型语言模型(AI-SLM)

​​​​ 在本文中,我们将研究如何针对疾病症状训练一个小型医疗保健语言模型。为此,我们将从HuggingFace获取数据集(用于训练我们的模型):https://huggingface.co/datasets/QuyenAnhDE/Diseases_Symptoms QuyenAnhDE/Diseases_Symptoms 数据集来自 Hugging Face。图片来源…

6.MkDocs附录

安装插件 在 MkDocs 中&#xff0c;插件通常是通过 pip​ 工具安装的。你可以使用以下步骤来安装和配置 MkDocs 插件。 1.使用 pip​ 命令安装你需要的插件。例如 pip install pymdown-extensions‍ 2.更新 mkdocs.yml​ 文件。 ‍ 3.使用 mkdocs serve​ 命令本地预览你…

CentOS6禁止锁屏

在电源中设置后还是会锁屏, 原因是有屏幕保护程序 电源管理都 “从不” 一些AI的回答 在CentOS 6系统中&#xff0c;如果你想要禁用锁屏功能&#xff0c;可以编辑/etc/kbd/config文件。这个文件通常包含了键盘相关的设置&#xff0c;包括密码策略和屏幕锁定选项。 首先打开终…

支持向量机 (support vector machine,SVM)

支持向量机 &#xff08;support vector machine&#xff0c;SVM&#xff09; flyfish 支持向量机是一种用于分类和回归的机器学习模型。在分类任务中&#xff0c;SVM试图找到一个最佳的分隔超平面&#xff0c;使得不同类别的数据点在空间中被尽可能宽的间隔分开。 超平面方…

三级_网络技术_12_路由设计技术基础

1.R1、R2是一个自治系统中采用RIP路由协议的两个相邻路由器&#xff0c;R1的路由表如下图(a)所示&#xff0c;当R1收到R2发送的如下图(b)的(V.D)报文后&#xff0c;R1更新的4个路由表项中距离值从上到下依次为0、3、3、4 那么&#xff0c;①②③④可能的取值依次为()。 0、4、…

List、Map、Set 接口在Java中的存取元素特点

List、Map、Set 接口在Java中的存取元素特点 1、List 接口2、Map 接口3、Set 接口4、总结 &#x1f496;The Begin&#x1f496;点点关注&#xff0c;收藏不迷路&#x1f496; 在Java中&#xff0c;List、Map和Set是三个最常用的集合接口。它们各自有不同的特点和用途&#xff…

详解Java的内部类

一、基本介绍 一个类的内部又完整的嵌套了另一个类结构。被嵌套的类称为内部类(inner class)嵌套其他类的类称为外部类(outer class)。它是我们类的第五大成员&#xff0c;内部类最大的特点就是可以直接访问私有属性&#xff0c;并且可以体现类与类之间的包含关系。 二、内部类…

Maven的基本使用

引入依赖 1.引入Maven仓库存在的依赖&#xff0c;直接引入&#xff0c;刷新Maven <dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>5.2.12.RELEASE</version> </dependency…

Redis代替Session实现共享

集群的session共享问题 session共享问题&#xff1a;多台tomcat并不共享session存储空间&#xff0c;当请求切换到不同的tomcat服务时导致数据丢失的问题。 session的替代方案&#xff1a; 数据共享内存存储key、value结构 将redis替换session可以解决session共享问题

从天空到地面:无人机航拍推流直播技术在洞庭湖决口封堵中的全方位支援

据新闻报道&#xff0c;受持续强降雨影响&#xff0c;湖南省华容县团洲垸洞庭湖一线堤防发生管涌险情&#xff0c;随后出现决口。截至7月8日20时左右&#xff0c;226米长的洞庭湖一线堤防决口已累计进占208米&#xff0c;目前剩余18米&#xff0c;有望在今晚或9日凌晨实现合龙。…