# 6. 快速入门

# 6.1 开始使用 AWTK Designer

AWTK Designer(下文简称 Designer)是专门用来制作 AWTK 应用程序 UI 界面的实用工具。只要通过拖拽和点击就可以完成复杂的界面设计。同时也提供代码编辑器,可以完成逻辑代码的编写。

本文 awtk-demo-hello-designer (opens new window) 为例(又称:HelloDesigner-Demo),介绍如何使用 Designer 开发 AWTK 应用程序。在开发 AWTK 应用程序前,首先需要了解 Designer 的基本用法,比如:如何使用 Designer 新建项目。

# 6.1.1 新建项目

首先启动 Designer,会弹出"新建项目"对话框,如下图所示:

图6.1 新建项目
图6.1 新建项目

选择常规项目,并对项目进行一些设置,其中几个常用的选项如下:

  • 项目名称与路径可根据实际情况设置。
  • 启动页面名称为程序运行时展示的最初窗体的名称,默认为 home_page。
  • 默认语言与国家/地区与翻译相关,在后续介绍翻译功能时讲解,默认为中国中文(zh_CN)。
  • AWTK 路径默认为安装 AWStudio 时内置 AWTK SDK,用户也可以按需修改。

其他参数一般采用默认设置,有需要可以更改,最后点击"创建"按钮即可。如果在后续的操作中想对这些项目参数进行修改,可以点击左下角的"设置"按钮,再点击"项目设置"进行修改。

图6.2 项目设置
图6.2 项目设置

# 6.1.2 新建窗体

此处创建名为 basic 窗体文件,步骤如下:

  • 在 Designer 左上角的"编辑"界面中,点击"新建窗体"图标,会弹出"新建窗体"窗口。
  • 在窗体类型中选择"Window",并输入窗体文件名称为"basic",点击"创建"按钮,即可新建窗体。
图6.3 新建窗体
图6.3 新建窗体

# 6.1.3 打包资源

使用 Designer 完成界面设计后,在"工具栏"的"项目"页面中点击"打包"按钮,即可打包生成资源。

图6.4 打包项目资源
图6.4 打包项目资源

# 6.1.4 编译运行

# 1. 搭建编译环境

在编译程序之前,需要搭建好 Windows 编译环境,搭建环境的详情步骤请参考 AWTK在线帮助文档 (opens new window) 中的《AWTK开发实践》。如果已经搭建好编译环境,可以忽略本节内容。

# 2. 编译和模拟运行应用程序

完成界面设计和代码编辑后,可以用 Designer 编译并模拟运行应用程序,步骤如下:

  • 在"工具栏"的"项目"页面中点击"编译"按钮,弹出程序编译的命令行窗口,如果编译成功,会提示"scons:done building targets",如果编译失败的话也会有错误提醒。
  • 编译成功后,可以点击"编译"按钮旁的"模拟运行"按钮进行模拟。
图6.5 编译和模拟运行
图6.5 编译和模拟运行
图6.6 编译成功
图6.6 编译成功

# 6.2 HelloDesigner-Demo项目

本章简单介绍 HelloDesigner-Demo 项目的具体功能,并以该项目为例说明 AWTK 应用程序的目录结构,帮助读者更好的理解下文中的界面设计和代码编辑。

# 6.2.1 功能详解

HelloDesigner-Demo 的运行效果如下图所示,读者可以在 AWStudio 中下载该示例,或者前往仓库下载源码:awtk-demo-hello-designer (opens new window),下载完成后可以使用 Designer 打开该项目,并编译运行。

图6.7 HelloDesigner-Demo运行效果
图6.7 HelloDesigner-Demo运行效果

使用 Designer 打开 HelloDesigner-Demo 的步骤如下:

  • 在"工具栏"的"项目"页面中点击"打开项目"按钮;
  • 在弹出的"选择项目文件"窗口中,选择项目目录下的"project.json"文件打开。
图6.8 打开项目
图6.8 打开项目
图6.9 选择HelloDesigner-Demo项目打开
图6.9 选择HelloDesigner-Demo项目打开

HelloDesigner-Demo 中包含的界面和各个界面的实现功能如下所示:

主界面功能:

  • 点击右上角的中英互译按钮可实现界面显示文本的中英文切换;
  • 点击中间 4 个按钮可打开对应的窗口;

Basic 界面功能:

  • 在编辑器中输入文本可同步更新到上方的静态文本控件中;
  • 定时增加水平进度条的值;
  • 点击 dec/inc 按钮,可减少/增加水平进度条的值;
  • 水平进度条的值改变后会同步更新到 dec/inc 按钮之间的静态文本控件上;
  • 调整垂直滑动条的值可以改变垂直进度条的值;
  • 点击 close 按钮可关闭 Basic 窗口。

Background Change 界面功能:

  • 点击中间 6 个背景切换按钮可切换对应的背景颜色或背景图片;
  • 点击 close 按钮可关闭 Background Change 窗口。

List View 界面功能:

  • 点击包含图标的列表项目时,将列表项的显示文本更新到静态文本控件中;
  • 点击 Clone Self 列表项可在列表视图尾部添加一个列表项;
  • 点击 Remove Self 列表项可从列表视图中移除该列表项;
  • 点击 close 按钮可关闭 List View 窗口。

Animate Widget 界面功能:

  • 各种控件动画;
  • 点击 close 按钮可关闭 Animate Widget 窗口。

# 6.2.2 项目目录

HelloDesigner-Demo 项目各目录功能如下所示,其中大部分在使用 Designer 新建项目时就会自动生成:

文件名 作用
bin 存放编译后的可执行文件与动态库
design 存放 Designer工程的原始资源文件
lib 存放编译的静态库(使用静态编译)
res 存放运行时的资源文件(Designer 打包资源输出目录)
scripts 存放工具脚本
src 存放 C 源代码
project.json Designer 工程配置文件
SConstruct SCons 编译脚本文件

# 6.3 HelloDesigner-Demo 界面设计

开发 AWTK 应用程序的第一个步骤通常是进行界面设计,本章介绍如何使用 Designer 来制作 HelloDesigner-Demo 项目中的五个界面:主界面、Basic 界面、Background Change 界面、List View 界面和 Animation Widget 界面。

# 6.3.1 主界面设计

HelloDesigner-Demo 程序运行时的主界面如下图所示,界面功能详见上文第二节,下面介绍如何使用 Designer 设计该界面。

图6.10 主界面
图6.10 主界面

1. 创建按钮控件

以控件按钮为例,在 Designer 左侧的"控件列表"中,选中"按钮",将其拖拽进窗体中,便能创建按钮控件,如下图所示,此处创建 5 个按钮控件。

图6.11 创建按钮控件
图6.11 创建按钮控件

2. 修改控件名称

创建好控件后,可以给控件修改合适的名称,以便后续写逻辑代码时,可以通过名称找到对应的控件,步骤如下:

  • 在"窗体编辑器"中选中要修改名称的按钮控件;
  • 在 Designer 右侧"控件编辑器"的"名称"列表中修改"name"属性,或者双击对象浏览器的对应控件修改名称;
  • 此处分别修改 5 个按钮控件的名称为"basic_btn"、"background_btn"、"listview_btn"、"animator_btn"和"language_btn",如图所示。
图6.12 修改控件名称
图6.12 修改控件名称

3. 调整控件布局

以“Basic”按钮为例,可拖拽和拉伸控件来调整控件的布局,也可以选中控件后,在“控件编辑器”中的“布局”列表中设置 x、y 坐标和 w、h 宽高来调整布局。此处采用百分比来设置控件布局,最终布局效果如图所示。

图6.13 调整控件布局
图6.13 调整控件布局

4. 设置按钮的显示文字

为了更加直观地表示按钮的功能,可在按钮中添加文字显示,步骤如下:

  • 在"窗体编辑器"中选中要修改显示文本的按钮控件;
  • 在"控件编辑器"的值列表中,修改"text"属性,即可设置按钮的显示文字,或者直接双击按钮控件进行修改;
  • 此处将项目右上角的中英互译按钮(language_btn)的显示文本删除,其余4个按钮控件的显示文本分别设置为“Basic”、“Background Change”、“List View”和“Animate Widget”,如图所示。
图6.14 设置显示文字
图6.14 设置显示文字

5. 修改显示字体的大小

创建好控件后,Designer 会提供控件默认样式,如需修改样式,可在“控件编辑器”的“样式”列表中修改相应的样式属性。以“Basic”按钮的字体样式为例,修改“font_size”属性值为 22(默认值为 18),可增大显示字体的大小,如图所示,其它按钮控件同理。

图6.15 修改控件显示字体大小
图6.15 修改控件显示字体大小

6. 设置按钮在其他状态下的样式

控件一般都会有多种状态,前面字体大小设置我们只设置了“normal”状态下的,为避免不同状态下字体大小不一致,因此其他状态下也要进行修改。如图所示,展开“state”属性的下拉框,可选择不同的控件状态。此处将“over”和“pressed”状态下的字体大小也设置 22。

图6.16 切换控件状态
图6.16 切换控件状态

7. 设置按钮的翻译文本

主界面需实现中英互译功能,因此需要将按钮的显示文本设置为可翻译的,步骤如下:

  • 在"窗体编辑器"中选中要设置的按钮控件;
  • 在"控件编辑器"的"值"列表中,点击"text"属性右侧的"设为翻译的"按钮即可,此处以主界面上的"Basic"按钮为例,如下图所示,其余按钮同理。
图6.17 设置按钮显示文本为可翻译的
图6.17 设置按钮显示文本为可翻译的

8. 添加中英互译文本

将按钮控件的显示文本设置为翻译的后,还需要添加中英文翻译文本,添加步骤如下:

  • 点击“工具栏”的“项目”页面中的“翻译”按钮,打开“多国语言编辑器”;
  • 点击“多国语言编辑器”右下角的“添加一种语言”按钮,弹出“添加语言”对话框,选择“语言”为“Chinese”,“国家/地区”为“China”,点击确定按钮;
  • 添加成功后在“多国语言编辑器”中可看见新增列“Chinese_China”,在该列中添加原始文本对应的中文,如图所示,英文同理,选择"English"与"United States"即可。
图6.18 添加翻译文本
图6.18 添加翻译文本

在第一节新建项目时提到的默认地区与语言会在程序初始化时根据翻译文本对有需要翻译的文本进行翻译。

9. 裁剪字库

Designer 支持对字库进行裁剪,去掉应用程序中不需要的字符,特别是在嵌入式平台,可以减少资源占用。本项目使用到中文字符有:“基础背景切换列表控件动画”,在裁剪字库时需保留这些字符,步骤如下:

  • 在 Designer 左下角的“资源浏览器”中点击“字体”按钮,切换至字体资源界面;
  • 点击字体资源界面右上角的“裁剪设置”按钮,打开“项目设置”对话框;
  • 在“保留的字符”编辑框中添加需要保留的中文字符,点击确定按钮;
  • 回到字体资源界面,点击 default 字体右侧的“裁剪字体”按钮,即可裁剪字体,可见字体资源大小从原本的991.96KB,减小为 28.68KB,如图所示。
图6.19 裁剪字体资源
图6.19 裁剪字体资源

10. 添加图片资源

点击 Designer 左侧“资源浏览器”中的“+”按钮,在弹出的对话框中选中所需图片,点击“打开”,即可添加图片资源,如图所示。

此处添加图片“awtk_logo.png”、“language_en.png”和“language_zh.png”,这三张图片可在示例程序 awtk-demo-hello-designer-master/design/default/image/xx 目录下找到。

图6.20 添加图片资源
图6.20 添加图片资源

11. 添加图片控件

将图片添加进工程后,创建图片控件,在“控件编辑器”的“值”列表中,点击“image”属性下拉框,选中上一小节中添加的 awtk_logo.png 图片,即可将图片显示到界面中,如图所示。

图6.21 创建图片控件显示logo
图6.21 创建图片控件显示logo

12. 创建按钮控件的样式

中英互译按钮(language_btn)在不同的语言环境下需要显示对应的图标,此处为按钮控件创建样式“en”和“zh”,分别在中文和英文语言环境下使用,步骤如下:

  • 点击"窗体编辑器"下方的"样式"按钮;
  • 打开"样式"窗口后点击右下方的"+"弹出"新建样式"窗口;
  • 设置控件类型为"button",样式名称为"en",点击确定按钮,创建样式;
  • 将“en”样式中“state”属性切换到“normal”,点击“icon”属性下拉框,选择添加的 language_en.png 图片,如图所示;
  • 按照上述步骤再添加按钮的“zh”样式,“icon”属性选择 language_zh.png 图片。
图6.22 创建按钮控件"en"样式
图6.22 创建按钮控件"en"样式

此处添加的样式默认添加在 design/default/style 文件夹中,并且样式文件与窗口同名。

# 6.3.2 Basic 界面设计

点击主界面的"Basic"按钮,可以进入 Basic 界面,如下图所示,界面功能详见第二节,可以参考第一节的内容新建 Basic 界面的窗体,下面介绍如何使用 Designer 设计该界面。

图6.23 Basic界面
图6.23 Basic界面

1. 添加窗口动画

在窗口打开或关闭时,需要播放一些动画过度效果,例如 Basic 窗口打开时向左平移,关闭时向右平移,在 Designer 中可设置窗口动画实现,步骤如下:

  • 在“对象浏览器”中选中“basic”窗口;
  • 在“控件编辑器”的“窗口过渡动画”列表中,点击“open_anim_hint”右侧的编辑框,弹出“设置窗口动画”对话框;
  • “设置窗口动画”对话框中有多种动画类型可以选择,此处选择“左右平移”,设置动画持续时间设置为 500 ms,动画趋势使用默认的“cubic_out”,勾选“应用到关闭动画”,点击确定按钮,如图所示。
图6.24 添加窗口过渡动画
图6.24 添加窗口过渡动画

2. 添加软键盘

编辑框控件在输入状态下,默认会弹出软键盘,如需使用软键盘,需要先添加软键盘资源,步骤如下:

  • 在“工具栏”中切换至“编辑”页面,点击“新建窗体”按钮;
  • 在弹出的“新建窗体”对话框的“窗体类型”中选择“Keyboard”,再点击创建按钮即可,如图所示。
图6.25 添加软键盘
图6.25 添加软键盘

3. 设置进度条控件垂直显示

进度条控件和滑动条控件默认为水平显示,以进度条控件为例,在“窗体编辑器”中选中进度条控件,然后在“控件编辑器”的“杂项”列表中,勾选“vertical”属性,再对控件布局进行调整,即可将进度条控件修改为垂直显示,如图所示,滑动条同理。

图6.26 设置进度条垂直显示
图6.26 设置进度条垂直显示

4. 设置进度条显示文本进度

进度条可设置显示文本,在“窗体编辑器”中选中对应的进度条控件,然后在杂项列表中勾选“show_text”属性,可让进度条以文本形式显示进度,如图所示。

图6.27 设置进度条显示文本进度
图6.27 设置进度条显示文本进度

本界面其余控件按上一节进行设置或者使用默认设置即可,所有用到的控件有:图片、按钮、单行编辑、静态文本、滑动条和进度条。

# 6.3.3 Background Change 界面设计

点击主界面的“Background Change”按钮,可进入 Background Change 界面,如图所示,界面功能详见第二节,下面介绍如何使用 Designer 设计该界面。

图6.28 Background Change界面
图6.28 Background Change界面

1. 设置容器的网格布局

创建通用容器控件(view)后,可设置容器的子控件布局,步骤如下:

  • 在"窗体编辑器"中选中要设置的容器;
  • 点击“控件编辑器”的“布局”列表中“children_layout”属性的编辑框;
  • 在弹出的“设置子控件的排版”对话框中可设置排版类型,此处选择“网格类型”,水平间距、垂直间距和子控件间的间距均设置为 15,行数和列数分别设置为 3 和 2,其余保持默认设置,点击确定按钮,如图所示。
图6.29 设置容器的子控件布局
图6.29 设置容器的子控件布局

2. 向容器中添加子控件

向容器添加子控件有以下两种方式,此处将按钮控件添加到通用容器控件(Veiw)中:

  • 在“窗体编辑器”中,将按钮控件拖拽到通用容器控件(Veiw)上方时,通过按空格键将其放入容器内部,如图左侧所示;
  • 在“对象浏览器”中,直接将按钮控件拖拽到通用容器控件(Veiw)上方,松开鼠标即可,如图右侧所示;
图6.30 向容器中添加子控件
图6.30 向容器中添加子控件

3. 创建窗口样式设置不同的背景

Background Change 界面要实现背景切换的功能,需要创建窗口样式设置不同的背景,此处以创建蓝色背景的窗口样式为例,步骤如下:

  • 参考本节的第一小节,为 window 控件添加新的样式;
  • 控件类型为“window”,样式名称为“blue”,点击确定按钮,创建样式;
  • 设置“bg_blue”样式中的“bg_color”属性为蓝色,若要设置样式的背景图片,则可以在样式的“bg_image”属性右侧的下拉框中选择对应的图片,如图所示。其余背景颜色和图片的设置方法类似,这里不再累赘。
图6.31 创建窗口样式设置不同的背景
图6.31 创建窗口样式设置不同的背景

# 6.3.4 List View 界面设计

点击主界面的“List View”按钮,可进入 List View 界面,如图所示,界面功能详见第二节,下面介绍如何使用 Designer 设计该界面。

1. 创建列表视图

列表视图(list_view)是一个包含滚动视图(scroll_view)和手机版滚动条(scroll_bar_m)的控件,其中的滚动视图可以放置多于屏幕可存放控件容量的容器,在运行时可通过滑动查看不在屏幕中的控件。

图6.32 创建列表视图
图6.32 创建列表视图

2. 向列表视图中添加列表项

双击滚动视图控件可以进入滚动视图编辑界面,在该界面放置的控件全部为滚动视图的子控件,往滚动视图中添加多个列表项后,再设置列表项的名称和显示文本,如图所示:

图6.33 向列表视图添加列表项
图6.33 向列表视图添加列表项

3. 向列表项中添加图标

列表项本身也是一个容器,可以参考上一小节的内容向列表项中添加图片控件,然后添加图片资源并显示图标,并且可以将图片的绘制格式修改为图标形式,此处可将“控件编辑器”的“值”列表中的“draw_type”属性设置为“icon”,如图所示。

图6.34 设置图标在图片控件的绘制方式
图6.34 设置图标在图片控件的绘制方式

# 6.3.5 Animation Widget 界面设计

点击主界面的“Animation Widget”按钮,可进入 Animation Widget 界面,如图所示,界面功能详见第二节,下面介绍如何使用Designer设计该界面。

1. 添加控件动画效果

Animation 界面中包含4个图片控件,分别展示了位移、缩放、透明和旋转四种不同的控件动画效果,这里以位移动画为例,介绍 Designer 如何添加控件动画效果,步骤如下:

  • 在“窗体编辑器”中选中图片控件;
  • 在“控件编辑器”的“动画”属性里点击“+”按钮,弹出“设置动画”对话框;
  • 此处选择动画类型为“位移”,设置单词动画持续时间为 1000 ms,并勾选往返播放,往返次数设置为 0,即永久播放,同时设置图片控件在 x 方向上不变,在 y 方向上从 100 移动到 200,如图所示,其他动画效果添加步骤与此类似,这里不再赘述。(旋转动画中角度的单位为弧度)

要注意区分窗口动画和控件动画,窗口动画用于窗口打开关闭时的过度效果,控件动画用于窗口内控件的动作,两者不能混用。

图6.35 添加控件动画
图6.35 添加控件动画

在完成界面设计后,可以点击"工具栏"的"编辑"页面,点击"预览"查看当前的界面设计。

图6.36 预览
图6.36 预览

预览只展示界面设计,不涉及代码相关的预览,每次预览只会展示当前页面的预览结果。

# 6.4 HelloDesigner-Demo 代码编辑

界面设计完成后,需要编写相应的逻辑代码,本章主要讲解如何源代码中使用 AWTK 实现 HelloDesigner-Demo 项目的功能。如果想要了解更多 AWTK 编程方面的知识,请参阅 AWTK开发实践 (opens new window)

# 6.4.1 项目的源代码文件

HelloDesigner-Demo 的源代码文件在项目的src目录下,具体说明见下表

源文件 说明
common 存放导航器源代码,由 Desinger 自动生成
pages 存放页面源代码,使用 Designer 新建窗体时自动生成,文件名与页面名相同
application.c 存放当前项目的初始化源代码,由 Designer 自动生成
main.c 存放当前项目的应用程序入口,由 Designer 自动生成
SConscript Scons编译脚本,由 Designer 自动生成

在 main.c 包含了 awtk/src/awtk_main.inc 文件,该文件中包含了 main 函数以及与 AWTK 框架相关的初始化、事件循环等函数。

代码的编写可以在 Designer 的代码编辑器中完成,也可以使用另外的代码编辑器,例如 vscode 等,但需要注意,在 Designer 保存之后代码才会同步到另外的代码编辑器。

# 6.4.2 应用程序初始化

AWTK 应用程序的初始化函数为 application_init,该函数在 main.c 中声明,并在 application.c 中实现。Designer 创建项目时会自动生成,用户可在该函数中实现项目初始化,并且可以在 application_exit 函数中实现项目的反初始化,比如释放内存等。

# 6.4.3 主界面功能

1. 初始化函数

当用户使用 Designer 新建一个界面时,Designer 会在 pages 文件夹下生成对应的 c 代码文件,并为该文件初始化以下代码内容:

#include "awtk.h"
#include "../common/navigator.h"

/* 初始化窗口的子控件 */
static ret_t visit_init_child(void* ctx, const void* iter) {
  widget_t* win = WIDGET(ctx);
  widget_t* widget = WIDGET(iter);
  const char* name = widget->name;

  /* 初始化指定名称的控件(设置属性或注册事件),请保证控件名称在窗口上唯一 */
  if (name != NULL && *name != '\0') {
  }

  return RET_OK;
}

/* 初始化窗口 */
ret_t home_page_init(widget_t* win, void* ctx) {
  (void)ctx;
  return_value_if_fail(win != NULL, RET_BAD_PARAMS);
  /* 遍历窗口中子控件,visit_init_child 是遍历时的回调函数,每遍历一个控件就会执行一次 */
  widget_foreach(win, visit_init_child, win);

  return RET_OK;
}

2. 为按钮添加事件

在主界面菜单中,只有几个按钮需要绑定事件,它们的作用分别是:打开窗口和切换中英文显示,对于打开窗口关闭窗口这种简单的操作,使用 Designer 就可以完成,此处以"basic_btn"按钮为例进行演示如何添加事件,步骤如下:

  • 在"窗体编辑器"点击"basic_btn"控件;
  • 切换"控件编辑器"为"事件"界面;
  • 点击右上角的"+"按钮,并选择想要添加的事件类型,此处为"click"点击事件;
  • 选择"动作"一栏为"打开窗口",并选择打开窗口的名称为"basic"。
图6.37 设置按钮点击打开指定窗口
图6.37 设置按钮点击打开指定窗口

设置完成后,Designer 会自动在源代码中添加对应的代码,如下所示,其他几个打开窗口的操作与之类似,就不再赘述。

/* 在此处添加了一个回调函数,内容为打开窗口 */
static ret_t on_basic_btn_click(void* ctx, event_t* e) {
  return navigator_to("basic");
}

static ret_t visit_init_child(void* ctx, const void* iter) {
  widget_t* win = WIDGET(ctx);
  widget_t* widget = WIDGET(iter);
  const char* name = widget->name;

  /* 初始化指定名称的控件(设置属性或注册事件),请保证控件名称在窗口上唯一 */
  if (name != NULL && *name != '\0') {
    /* 在此处添加了查找对应名称控件并进行事件注册的操作 */
    if (tk_str_eq(name, "basic_btn")) {
      /* 为控件注册事件的回调函数 */
      widget_on(widget, EVT_CLICK, on_basic_btn_click, win);
    }
  }

  return RET_OK;
}

接下来为"language_btn"按钮添加回调函数用来切换按钮主题与系统语言,步骤如下:

  • 在"窗口编辑器"选择"language_btn"按钮;
  • 切换"控件编辑器"为"事件"页面;
  • 点击右上角的"+"按钮,选择想要添加的事件类型,此处选择"click";
  • 选择"动作"一栏为"执行回调函数"。

完成操作后,Designer 会在源代码文件添加注册回调函数的代码,我们只需要在回调函数中实现切换语言的功能即可:

/* 中英文互译 */
static ret_t change_locale(const char* str) {
  char country[3];
  char language[3];
  strncpy(language, str, 2);
  strncpy(country, str + 3, 2);
  /* 切换语言为language,地区为country */
  locale_info_change(locale_info(), language, country);
  return RET_OK;
}

/* 中英互译按钮的事件回调函数 */
static ret_t on_language_btn_click(void* ctx, event_t* e) {
  // TODO: 在此添加控件事件处理程序代码
  widget_t* language_btn = WIDGET(e->target); /* 获取触发事件的按钮对象 */
  const char* language = locale_info()->language;  /* 获取当前语言环境 */
  if (tk_str_eq(language, "en")) {           /* 切换语言并改变按钮样式 */
    change_locale("zh_CN");
    widget_use_style(language_btn, "en");
  } else {
    change_locale("en_US");
    widget_use_style(language_btn, "zh");
  }
  return RET_OK;
}

static ret_t visit_init_child(void* ctx, const void* iter) {
  widget_t* win = WIDGET(ctx);
  widget_t* widget = WIDGET(iter);
  const char* name = widget->name;

  /* 初始化指定名称的控件(设置属性或注册事件),请保证控件名称在窗口上唯一 */
  if (name != NULL && *name != '\0') {
    if (tk_str_eq(name, "basic_btn")) {
      widget_on(widget, EVT_CLICK, on_basic_btn_click, win);
    } else if (tk_str_eq(name, "language_btn")) {
      /* 此处将窗口对象 win 作为上下文 ctx 传给事件回调函数 */
      widget_on(widget, EVT_CLICK, on_language_btn_click, win);
    }
  }

  return RET_OK;
}

AWTK API 函数具体的参数与作用,可以查阅:AWTK-API 手册 (opens new window)

# 6.4.4 Basic 界面功能

1. 点击按钮关闭当前窗口

该操作与上一节的打开窗口类似,故只展示 Designer 设置完成的情况,如下图所示,其他窗口的"close"按钮同理。

图6.38 设置按钮按下时关闭窗口
图6.38 设置按钮按下时关闭窗口

2. 点击按钮设置进度条的值

在Basic界面中,实现点击 dec/inc 按钮,可减少/增加水平进度条的值,步骤如下:

  • 为 dec/inc 按钮添加"click"事件;
  • 实现两个按钮的回调函数,代码如下:
/* 以动画的形式改变进度条的值 */
static ret_t progress_bar_animate_delta(widget_t* win, const char* name, int32_t delta) {
  widget_t* progress_bar = widget_lookup(win, name, TRUE); /* 获取进度条控件 */
  /* 获取进度条的值,加上差值,并限制值的范围 */
  int32_t value = (PROGRESS_BAR(progress_bar)->value + delta);
  value = tk_min(100, value);
  value = tk_max(0, value);
  /* 设置控件的值,并以动画的形式变化到指定的值 */
  widget_animate_value_to(progress_bar, value, 500);

  return RET_OK;
}

/* 递减按钮事件回调函数 */
static ret_t on_dec_btn_click(void* ctx, event_t* e) {
  widget_t* win = WIDGET(ctx);
  progress_bar_animate_delta(win, "click_bar", -10);
  return RET_OK;
}

/* 递增按钮事件回调函数 */
static ret_t on_inc_btn_click(void* ctx, event_t* e) {
  widget_t* win = WIDGET(ctx);
  progress_bar_animate_delta(win, "click_bar", 10);
  return RET_OK;
}

3. 响应编辑器的值正在改变事件

在 Basic 界面中,在编辑器(edit)中输入文本可同步显示到上方的静态文本中,实现步骤如下:

  • 为编辑器(edit)添加"value_changing"事件;
  • 实现回调函数,代码如下:
/* 编辑器的值变化事件回调函数 */
static ret_t on_edit_value_changing(void* ctx, event_t* e) {
  /* 获取几个需要用到的控件 */
  widget_t* target = WIDGET(e->target);
  widget_t* win = WIDGET(ctx);
  widget_t* label = widget_lookup(win, "edit_label", TRUE);
  /* 将 edit 中的文本设置为 label 控件显示的文本 */
  widget_set_text(label, target->text.str);

  return RET_OK;
}

在 Basic 界面中拖动滑动条中的滑块,可以立刻改变垂直进度条的值,该功能也是通过响应滑动条的值正在改变事件实现,读者可以举一反三,代码位于 src/pages/basic.c。

4. 响应进度条的值改变事件

Basic 界面中,水平进度条的值改变后会同步显示到 dec/inc 按钮之间的静态文本控件上,实现步骤如下:

  • 为水平进度条添加"value_changed"事件;
  • 实现回调函数,代码如下:
/* 进度条值改变事件 */
static ret_t on_click_bar_value_changed(void* ctx, event_t* e) {
  widget_t* win = WIDGET(ctx);
  widget_t* label = widget_lookup(win, "click_bar_label", TRUE);
  widget_t* bar = WIDGET(e->target);
  char text[32];
  value_t v;

  /* 获取进度条的值,格式化后将其设置为 label 控件显示的文本 */
  value_set_int32(&v, widget_get_value(bar));
  tk_snprintf(text, sizeof(text), "%d%%", value_int32(&v));
  widget_set_text_utf8(label, text);

  return RET_OK;
}

在Basic界面中拖动滑动条中的滑块,在松开鼠标左键后才会改变垂直进度条的值。该功能也是通过响应滑动条的值改变事件实现,读者可以举一反三,源代码位于 src/pages/basic.c。

5. 使用定时器改变进度条的值

在 Basic 界面中,水平进度条的值会随着时间不断变化,该功能可通过 AWTK 中的定时器来实现,步骤如下:

  • 在窗口初始化函数中添加定时器,并设置回调函数为 on_add_bar_value,间隔时间为 1500 ms,代码如下:
ret_t basic_init(widget_t* win, void* ctx) {
  (void)ctx;
  return_value_if_fail(win != NULL, RET_BAD_PARAMS);
  widget_foreach(win, visit_init_child, win);

  /* 添加定时器 */
  widget_add_timer(win, on_add_bar_value, 1500);

  return RET_OK;
}
  • 实现定时器的回调函数 on_add_bar_value,代码如下:
/* 定时器回调函数(定时增加progress_bar的值)*/
static ret_t on_add_bar_value(const timer_info_t* timer) {
  widget_t* win = WIDGET(timer->ctx);
  widget_t* bar = widget_lookup(win, "click_bar", TRUE);
  value_t v;
  int32_t val;

  value_set_int32(&v, widget_get_value(bar));
  val = value_int32(&v);
  if (val >= 100) { /* 限制值范围 */
    progress_bar_set_value(bar, 0);
  }
  /* 调用上文中实现的进度条动画函数 */
  progress_bar_animate_delta(win, "click_bar", 10);

  return RET_REPEAT;
}

# 6.4.5 Background Change 界面功能

1. 点击按钮切换背景颜色或图片

在 Background Change 界面中,实现点击按钮切换对应的背景颜色或图片,在该界面中,用来切换背景或图片的按钮名称都为"style",所以实现一个按钮的回调函数相当于实现所有按钮的回调函数,步骤如下:

  • 为"style"按钮添加"click"事件;
  • 实现回调函数,代码如下:
/**
 * 改变背景按钮事件
 */
static ret_t on_style_click(void* ctx, event_t* e) {
  // TODO: 在此添加控件事件处理程序代码
  char text[64] = "";
  widget_t* win = WIDGET(ctx);
  /* 获取触发事件的按钮 */
  widget_t* target = (widget_t*)e->target;
  /* 获取按钮的文本 */
  widget_get_text_utf8(target, text, ARRAY_SIZE(text));
  /* 根据按钮文本改变窗口样式 */
  widget_use_style(win, text);

  return RET_OK;
}

在本界面中,由于几个按钮的逻辑功能类似,我们可以给几个按钮设置相同的 name,在遍历窗口控件时初始化这些按钮(注册事件回调),在事件回调函数中通过事件对象中的 target 属性获取当前触发事件的按钮控件,并根据控件的特征实现对应的功能。

# 6.4.6 List View 界面功能

1. 点击列表项设置显示文本

与上一节的按钮相似,几个列表项的功能类似,在此处也将几个列表项的名字设为相同,功能为点击该列表项时,设置左侧静态文本中的显示文本,步骤如下:

  • 为"list_item"控件添加"click"事件;
  • 实现回调函数,代码如下:
/* 普通列表项点击事件回调函数 */
static ret_t on_list_item_click(void* ctx, event_t* e) {
  // TODO: 在此添加控件事件处理程序代码
  widget_t* win = WIDGET(ctx);
  /* 获取触发事件的列表项 */
  widget_t* list_item = WIDGET(e->target);
  /* 获取 label 控件 */
  widget_t* label = widget_lookup(win, "list_view_label", TRUE);
  value_t v;
  /* 获取当前列表项的文本并赋给 label 控件 */
  value_set_wstr(&v, widget_get_text(list_item));
  widget_set_text(label, value_wstr(&v));

  return RET_OK;
}

2. 点击Clone Self 添加列表项

在 List View 界面中,点击 Clone Self 列表项,可以在列表视图尾部添加一个相同的列表项,实现步骤如下:

  • 为"clone_self"控件添加"click"事件;
  • 实现回调函数,代码如下:
/* 克隆列表项点击事件回调 */
static ret_t on_clone_self_click(void* ctx, event_t* e) {
  // TODO: 在此添加控件事件处理程序代码
  widget_t* widget = WIDGET(e->target);
  /* 在列表项的父控件中克隆自己 */
  widget_t* clone = widget_clone(widget, widget->parent);
  /* 克隆控件只克隆属性,还需要在此处手动注册"click"事件 */
  widget_on(clone, EVT_CLICK, on_clone_self_click, clone);

  return RET_OK;
}

3. 点击 Remove Self 移除列表项

在 List View 界面中,点击 Remove Self 列表项,可以从列表视图移除该列表项,实现步骤如下:

  • 为"remove_self"控件添加"click"事件;
  • 实现回调函数,代码如下:
/**
 * 列表项移除事件
 */
static ret_t on_remove_self_click(void* ctx, event_t* e) {
  // TODO: 在此添加控件事件处理程序代码
  widget_t* widget = WIDGET(e->target);
  /* 从父控件中移除该列表项 */
  widget_remove_child(widget->parent, widget);
  /* 销毁该列表项 */
  widget_destroy(widget);

  return RET_OK;
}

# 6.4.7 编译运行 HelloDesigner-Demo

完成以上的代码编写后,可以参考第一节的步骤编译并运行 HelloDesigner-Demo 项目。

图6.39 运行HelloDesigner
图6.39 运行HelloDesigner