AWTK开发UI简单入门C语言篇

AWTK 开发 UI 简单入门 – C 语言篇

一,前序

  在上一篇教程中(AWTK 的 Window 开发环境安装教程),我们已经配置好 AWTK 的开发环境了,今天我们使用 C 语言写一个简单的小例子,让大家更加容易理解 AWTK 的工作原理。
  在 windows 平台上面开发,马上想到的开发工具就是 vs 了,作为宇宙最强的 IDE,在开发上的便捷性和易用性都是没得说的,虽然我们也可以使用 vscode 作为开发工具,但是为了让大家更加简单的理解 AWTK 这一个 GUI 的用法,所有我决定采用 vs 作为开发工具,并且不会采用 scons 来生成项目,尽量简单化一点,让大家看的明白。(毕竟在 windows 上开发,应该大部分人都会用 vs 这个 IDE 的吧)
  本章节中,采用的代码为 ZLG 提供的 HelloWorld-Demo 项目为原型来介绍如果做一个简单的 GUI,其界面为下图:
在这里插入图片描述

备注:

  1. 虽然本文采用 ZLG 提供的 HelloWorld-Demo 项目为原型来介绍,但UI 界面只是大致一样,同时为了更好的让读者了解,所以其代码会修改过,其目的是尽可能的使用最简单的代码和逻辑带读者入门。
  2. 附上 ZLG 提供 HelloWorld-Demo 项目的 github 地址:https://github.com/zlgopen/awtk-examples
  3. 附上本人修改后的 HelloWorld-Demo 项目的 github 地址:https://github.com/WNsACE/CSDN_AWTK_DEMO

二,建立项目

  本章节采用 vs2017 作为 IDE,所以下面的截图都是 vs2017 的界面,其他版本的 vs,其实都差不多。
  在例子中出现的 “D:\OpenLibraries\awtk\awtk” 为 AWTK 源码的路径,需要根据具体情况来对应修改 电脑上面的 AWTK 源码路径。

1.创建空项目

  使用 vs2017 创建一个新的 c++ 空项目,并修改名字为HelloWorld-Demo,如下图:
在这里插入图片描述

2.配置项目
  1. 把平台改为x64,如下图:
    在这里插入图片描述

备注:因为 AWTK 默认编译为 64 位的类库。

  1. 给项目新建两个 .c 文件,分别名为 app_main.c 和 window_main.c。

备注:这两个 .c 文件是空文件,没有任何东西的。

  1. 给项目加入 AWTK 相关的头文件,如下图:
    在这里插入图片描述

头文件路径为:

  1. D:\OpenLibraries\awtk\awtk\src
  2. D:\OpenLibraries\awtk\awtk\src\ext_widgets;
  1. 给项目加入对应的宏,如下图:
    在这里插入图片描述

这里主要是加入的宏分别是: WIN32 。

  1. 给项目加入 AWTK 相关类库,如下图:
    在这里插入图片描述在这里插入图片描述

类库路径:D:\OpenLibraries\awtk\awtk\lib;
类库名字:assets.lib;awtk.lib;base.lib;glad.lib;gpinyin.lib;linebreak.lib;nanovg.lib;SDL2.lib;tkc.lib;widgets.lib;winmm.lib;imm32.lib;version.lib;
备注:这里先不解释各个类库的作用,留到后面再讲,而这里的类库只是加入最基础的只是可以让本demo跑起来的最少类库。

  1. 其中 AWTK 的类库为:
    assets.lib,awtk.lib,base.lib,glad.lib,gpinyin.lib,linebreak.lib,nanovg.lib,SDL2.lib,tkc.lib,widgets.lib。
  2. 系统类库为:winmm.lib,imm32.lib,version.lib。
3.部署资源

  由于本项目中只用到很少的资源,只需要把 AWTK 的少量资源拷贝过来就可以了,本文暂时不介绍如何配置资源和生成资源。
  在这个 demo 中主要是资源分别是字体资源和风格资源,风格资源是必须要的(每一个 AWTK 的项目都必须要有一个 default 风格),而字体资源的话,如果项目中需要显示文字的话,则需要增加字体资源,否则可以不需要,接下来把 AWTK 源码中的资源直接拷贝过来。

  1. 把在程序目录下创建 res 的文件夹,如下图。
    在这里插入图片描述

备注:为了让代码结构好看一点,所以讲上面创建的 app_main.c 和 window_main.c 放到 src 文件夹中。

  1. 把 D:\OpenLibraries\awtk\awtk\demos 目录下的 assets 文件夹拷贝到刚刚创建的 res 的文件夹中,如下图:
    在这里插入图片描述
  2. 把 res 文件夹下多余用不到的文件删除。(这一步其实不做也是无所谓的,只不过为了让后面大家更好理解而已)

需要删除的文件分别是:( ./表示 HelloWorld-Demo 项目路径)

  1. ./res/assets/dark (文件夹)
  2. ./res/assets/README.md (文件)
  3. ./res/assets/default/inc (文件夹)
  4. ./res/assets/default/raw/data (文件夹)
  5. ./res/assets/default/raw/images (文件夹)
  6. ./res/assets/default/raw/scripts (文件夹)
  7. ./res/assets/default/raw/strings (文件夹)
  8. ./res/assets/default/raw/ui (文件夹)
  9. ./res/assets/default/raw/xml (文件夹)
  10. ./res/assets/default/raw/fonts/ap.ttf (文件)
  11. ./res/assets/default/raw/fonts/default_full.ttf (文件)
  12. ./res/assets/default/raw/fonts/README.md (文件)
  13. ./res/assets/default/raw/fonts/text.txt (文件)

注意:在 ./res/assets/default/raw/styles文件夹下,除了 default.bin 和 default.xml 两个文件以外全部删除。

三,编写项目

1. 打开 app_main.c 文件,并写入下面的代码:
#include "awtk.h"

extern ret_t application_init(void);

int main(void)
{
	int lcd_w = 800;
	int lcd_h = 480;

	/* 
	* 初始化 AWTK
	* 参数 APP_DESKTOP 为设置 window 的桌面模式 
	* 参数 "res" 为设置资源目录路径为程序工作目录下"res"
	*/
	tk_init(lcd_w, lcd_h, APP_DESKTOP, NULL, "res");

	/* 预加载名为 default.tff 的字体资源 */
	assets_manager_preload(assets_manager(), ASSET_TYPE_FONT, "default");
	/* 预加载名为 default.bin 的风格资源 */
	assets_manager_preload(assets_manager(), ASSET_TYPE_STYLE, "default");

	/* 初始化资源 */
	tk_init_assets();

	/* 打开主屏幕 */
	application_init();

	/* 进入awtk事件循环 */
	tk_run();

	return 0;
}

2. 打开 window_main.c 文件,并写入下面的代码:
#include "awtk.h"
#include "awtk.h"
extern ret_t application_init(void);

widget_t* label_4_btn = NULL;	//递增数值label控件指针
widget_t* label_4_edit = NULL;	//显示文本框label控件指针

/**
 * Label文本的数值 + offset
 */
static ret_t label_add(widget_t* label, int32_t offset)
{
	if (label)
	{
		int32_t val = 0;
		if (wstr_to_int(&(label->text), &val) == RET_OK)
		{
			char text[32];
			val += offset;
			val = tk_max(-200, tk_min(val, 200));
			tk_snprintf(text, sizeof(text), "%d", val);
			widget_set_text_utf8(label, text);

			return RET_OK;
		}
	}

	return RET_FAIL;
}

/**
 * 递增按钮事件
 */
static ret_t on_inc_click(void* ctx, event_t* e)
{
	label_add(label_4_btn, 1);

	return RET_OK;
}

/**
 * 递减按钮事件
 */
static ret_t on_dec_click(void* ctx, event_t* e)
{
	label_add(label_4_btn, -1);

	return RET_OK;
}

/**
 * 正在编辑事件
 */
static ret_t on_changing(void* ctx, event_t* evt)
{
	widget_t* target = WIDGET(evt->target);
	widget_set_text(label_4_edit, target->text.str);

	return RET_OK;
}

/**
 * 初始化
 */
ret_t application_init(void)
{
	widget_t* win = window_create(NULL, 0, 0, 0, 0);

	/* 创建文本框*/
	label_4_edit = label_create(win, 160, 96, 480, 40);
	widget_set_text(label_4_edit, L"hello world");
	widget_set_name(label_4_edit, "label_4_edit");

	/* 创建编辑框 */
	widget_t* edit = edit_create(win, 160, 196, 480, 40);
	edit_set_input_type(edit, INPUT_TEXT);
	widget_set_text(edit, L"hello world");
	widget_on(edit, EVT_VALUE_CHANGING, on_changing, NULL);

	/* 创建递减按钮 */
	widget_t* dec_btn = button_create(win, 160, 288, 160, 40);
	widget_set_text(dec_btn, L"dec");
	widget_on(dec_btn, EVT_CLICK, on_dec_click, NULL);

	/* 创建label显示递增数值 */
	label_4_btn = label_create(win, 320, 288, 160, 40);
	widget_set_text(label_4_btn, L"88");
	widget_set_name(label_4_btn, "label_4_btn");

	/* 创建递增按钮 */
	widget_t* inc_btn = button_create(win, 480, 288, 160, 40);
	widget_set_text(inc_btn, L"inc");
	widget_on(inc_btn, EVT_CLICK, on_inc_click, NULL);

	return RET_OK;
}

四,分析代码

  其实把上面代码拷贝到文件中,点击编译和运行就可以看到本文一开始的 UI 效果图。
  但是大部分人都想知道为啥,其实每一行的代码都是代表着什么意思呢?所以这一环节就是配合着上面的代码注释来解释关键性代码的作用。

1. app_main.c 文件的 tk_init 函数
/**
 * @method tk_init
 * 初始化TK。
 * @alias init
 * @annotation ["static", "scriptable"]
 * @param {wh_t} w LCD宽度。
 * @param {wh_t} h LCD高度。
 * @param {app_type_t} app_type 应用程序的类型。
 * @param {const char*} app_name 应用程序的名称(必须为常量字符串)。
 * @param {const char*} app_root 应用程序的根目录,用于定位资源文件(必须为常量字符串)。
 *
 * @return {ret_t} 返回RET_OK表示成功,否则表示失败。
 */
ret_t tk_init(wh_t w, wh_t h, app_type_t app_type, const char* app_name, const char* app_root);

   看到上面的注释,我想大家都应该明白了,每个 AWTK 的程序都必须最先调用这个函数,包括嵌入式平台也是,这个函数会初始化平台信息,创建主循环,初始化各种控件创建信息等。
   如果在嵌入式平台中,LCD 的屏幕宽高就是这里的 LCD 宽高。

2. app_main.c 文件的 assets_manager_preload 函数
/**
 * @method assets_manager_preload
 * 从文件系统中加载指定的资源,并缓存到内存中。在定义了宏WITH\_FS\_RES时才生效。
 * @param {assets_manager_t*} am asset manager对象。
 * @param {asset_type_t} type 资源的类型。
 * @param {char*} name 资源的名称。
 *
 * @return {ret_t} 返回RET_OK表示成功,否则表示失败。
 */
ret_t assets_manager_preload(assets_manager_t* am, asset_type_t type, const char* name);

   这个函数是先把资源加载到资源列表中,主要是加载默认字体和默认风格,然后等待 tk_init_assets 函数的调用,把默认的字体和风格挂载到对应的地方。

3. app_main.c 文件的 tk_init_assets 函数
/**
 * @method tk_init_assets
 * 初始化资源。
 * @annotation ["private"]
 *
 * @return {ret_t} 返回RET_OK表示成功,否则表示失败。
 */
ret_t tk_init_assets(void);

   这个函数主要是把默认字体和默认风格挂载到 AWTK 的 主题上面和字体管理上面,如果没有这两步的话,程序可能会空白一片,没有任何东西显示出来。

4. app_main.c 文件的 tk_run 函数
/**
 * @method tk_run
 * 进入TK事件主循环。
 * @alias run
 * @annotation ["static", "scriptable"]
 *
 * @return {ret_t} 返回RET_OK表示成功,否则表示失败。
 */
ret_t tk_run(void);

   这个函数内部是一个 UI 的主循环,不断地绘制和触发以及接受各种事件,AWTK 所有的函数触发都是发生在 tk_run 函数中。

5. window_main.c 文件的 window_create 函数
/**
 * @method window_create
 * 创建window对象
 * @annotation ["constructor", "scriptable"]
 * @param {widget_t*} parent 父控件
 * @param {xy_t} x x坐标
 * @param {xy_t} y y坐标
 * @param {wh_t} w 宽度
 * @param {wh_t} h 高度
 *
 * @return {widget_t*} 对象。
 */
widget_t* window_create(widget_t* parent, xy_t x, xy_t y, wh_t w, wh_t h);

   这个函数是用来创建一个可视化的窗口,这个可视化的窗口风格类型为 window_t,目前 AWTK 创建的窗口都是全屏的,所以不需要写入 x,y,w,h,同时因为窗口在创建的时候会默认加入 window_manager(窗口管理器)中,所以也不需要写父控件。

注意:在AWTK 中,必须要有一个可视化的窗口,否则画面不会刷新。

6. window_main.c 文件的 xxxxx_create 函数
/**
 * 创建xxxxx控件对象
 * @param {widget_t*} parent 父控件
 * @param {xy_t} x x坐标
 * @param {xy_t} y y坐标
 * @param {wh_t} w 宽度
 * @param {wh_t} h 高度
 *
 * @return {widget_t*} 对象。
 */
widget_t* xxxxx_create(widget_t* parent, xy_t x, xy_t y, wh_t w, wh_t h);

   这里 xxxxx_create 函数是泛指所有的控件创建函数,AWTK 大部分的控件创建函数都是这样子写,只是控件名字会代替上面的 xxxxx 就是该控件的创建函数。
   AWTK 采用树的结构,最顶级是窗口管理器(window_manager)单例,其子集为窗口对象,窗口对象的子集为各个控件,其中每个控件都可以作为其他控件的父集,从而构成一颗 AWTK 控件大树,如下图:
在这里插入图片描述

备注:

  1. 当父集被删除后,其子集也会被删除。
  2. AWTK 的坐标系是左上角为(0,0),从左上角到右下角,x 和 y 的值越来越大。
  3. 在 awtk\src\widgets 和 awtk\src\ext_widgets 文件夹下放在各种各样的控件,有兴趣的朋友可以去看一下。
7. window_main.c 文件的 widget_set_text 函数
/**
 * @method widget_set_text
 * 设置控件的文本。
 * 只是对widget\_set\_prop的包装,文本的意义由子类控件决定。
 * @param {widget_t*} widget 控件对象。
 * @param {const wchar_t*}  text 文本。
 *
 * @return {ret_t} 返回RET_OK表示成功,否则表示失败。
 */
ret_t widget_set_text(widget_t* widget, const wchar_t* text);

   该函数主要是用来设置控件的文本,因为每一个控件都会有自己的文本,但是只有部分控件会自动显示其文本,显示文本的常见控件有:button,label,edit,check_button等。

备注:widget_set_text 函数和 widget_set_text_utf8 函数一样的函数,只不过是传入的字符串类型不一样而已。

8. window_main.c 文件的 widget_set_name 函数
/**
 * @method widget_set_name
 * 设置控件的名称。
 * @annotation ["scriptable"]
 * @param {widget_t*} widget 控件对象。
 * @param {char*} name 名称。
 *
 * @return {ret_t} 返回RET_OK表示成功,否则表示失败。
 */
ret_t widget_set_name(widget_t* widget, const char* name);

   该函数主要是设置控件的名字,主要是配合查找控件的方法使用,如果不需要查找控件的话,控件的名字有没有都无所谓。

9. window_main.c 文件的 widget_on 函数
/*回调事件处理函数原型*/
typedef ret_t (*event_func_t)(void* ctx, event_t* e);

/**
 * @method widget_on
 * 注册指定事件的处理函数。
 * @annotation ["scriptable:custom"]
 * @param {widget_t*} widget 控件对象。
 * @param {event_type_t} type 事件类型。
 * @param {event_func_t} on_event 事件处理函数。
 * @param {void*} ctx 事件处理函数上下文。
 * 
 * @return {int32_t} 返回id,用于widget_off。
 */
int32_t widget_on(widget_t* widget, uint32_t type, event_func_t on_event, void* ctx);

   该函数主要是设置事件回调函数,widget_on 函数是一个很重要的函数,后面会经常使用的来设置各种事件的触发回调函数,例如常见的事件类型有:鼠标点击事件(EVT_CLICK),键盘按下事件(EVT_KEY_DOWN),长按按钮事件(EVT_LONG_PRESS)等等,具体可以查 awtk\src\tkc\event.h 中的事件枚举。
   例如当用户注册了鼠标点击事件的回调函数后,如下代码把 on_dec_click 函数注册为 dec 按钮的点击回调函数,当鼠标点击这个 dec 按钮后,就会触发 on_dec_click 函数,同时会把 widget_on 函数的第四个参数(下面的代码的第四个参数是设置 NULL)作为 on_dec_click 函数的第一个参数传入到 on_dec_click 函数中。

/* 创建递减按钮 */
widget_t* dec_btn = button_create(win, 160, 288, 160, 40);
widget_set_text(dec_btn, L"dec");
widget_on(dec_btn, EVT_CLICK, on_dec_click, NULL);

五,总结

   本文介绍的是采用 C 语言直接简单 UI demo,希望大家可以看完后可以自己去写一个简单的 demo,因为 AWTK 支持采用 XML 来表述 UI 界面,所以在下一章节会用 XML 来写和本文相同的 UI demo。

  • 18
    点赞
  • 71
    收藏
    觉得还不错? 一键收藏
  • 28
    评论
### 回答1: 《AWTK 开发实践 v0.70.pdf》是一本关于AWTK(AnyWhere ToolKit)开发实践的技术文档。AWTK是一套基于C语言编写的开源图形用户界面(GUI)库,可用于嵌入式系统、物联网设备和桌面应用程序的开发。该文档介绍了使用AWTK进行开发的具体实践方法和技巧。 文档首先简要介绍了AWTK的概念、特点和应用场景。接着详细介绍了AWTK的架构和基本概念,如窗口、控件、布局和事件处理等。然后,文档通过几个实际案例展示了如何使用AWTK进行应用程序的开发。这些案例涵盖了窗口和控件的创建、布局的设计、事件处理的方法、图形资源的使用等方面。 文档还介绍了AWTK的开发工具和环境搭建,包括编译AWTK的步骤、集成开发环境的配置、调试技巧和性能优化等内容。此外,文档还提供了AWTK的相关资源和文档链接,方便开发者进行更深入的学习和研究。 总体而言,《AWTK 开发实践 v0.70.pdf》是一本系统而全面地介绍AWTK开发的实践指南。通过阅读该文档,开发者可以了解AWTK的基本原理和使用方法,并通过实际案例掌握AWTK开发的技巧。无论是对于初学者还是有一定经验的开发者来说,这本文档都是一个宝贵的学习资源,有助于快速、高效地利用AWTK进行开发。 ### 回答2: 《awtk开发实践v0.70.pdf》是一个关于awtk开发实践的文档,它提供了有关使用awtk框架进行应用开发的详细指南和实践经验。 awtk是一款开源的GUI引擎,用于嵌入式系统和物联网设备上的应用开发。它提供了丰富的UI控件库和强大的绘图功能,可以帮助开发者快速构建美观、高效的应用界面。 《awtk开发实践v0.70.pdf》首先介绍了awtk的基本概念和架构,包括界面布局、事件处理、资源管理等。然后,通过实际案例演示了如何使用awtk进行应用开发,涵盖了常见的UI控件使用、布局调整、数据绑定等。 此外,文档还提供了一系列的最佳实践和技巧,帮助开发者更好地利用awtk进行开发。例如,如何优化性能、如何处理触摸事件、如何实现国际化等。 总的来说,《awtk开发实践v0.70.pdf》为开发者提供了全面而详实的awtk开发指南。通过学习和实践这些内容,开发者可以更快地上手awtk框架,高效地构建优秀的应用界面。这对于嵌入式系统和物联网设备的应用开发者来说是非常有价值的资料。 ### 回答3: 《awtk开发实践v0.70.pdf》是指一个关于AWTK(Advanced Widgets Toolkit)开发实践的文档,文档的版本是v0.70。 AWTK是一个开源的GUI开发框架,主要用于嵌入式设备和物联网终端上的图形用户界面(UI)开发。它提供了丰富的UI控件、动画效果和事件处理机制,可以方便地开发出漂亮而功能丰富的界面。 这份文档的目的是帮助开发人员了解AWTK的基本概念和使用方法,以及在实际开发中的实践经验和技巧。文档内容包括AWTK的架构、组件、控件和资源管理等方面的介绍,还有关于界面设计、事件处理、动画效果和多语言支持等方面的详细说明和实例代码。 通过学习这份文档,开发人员可以快速了解AWTK的基本特性和开发流程,掌握AWTK的开发技巧和最佳实践。文档中的示例代码和案例分析可以帮助开发人员理解和解决实际开发中遇到的问题。 此外,文档还进行了版本控制,说明了v0.70版本相对于先前版本的变化和改进,以及在新版本中引入的新功能和修复的Bug。这对于已经使用过AWTK或者希望升级到新版本的开发人员来说非常有价值。 总而言之,《awtk开发实践v0.70.pdf》是为了帮助开发人员了解和应用AWTK框架的一份实践指南,对于想要使用AWTK进行GUI开发开发人员来说是一份很有价值的参考资料。
评论 28
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值