说明:
本文章旨在总结备份、方便以后查询,由于是个人总结,如有不对,欢迎指正;另外,内容大部分来自网络、书籍、和各类手册,如若侵权请告知,马上删帖致歉。
QQ 群 号:513683159 【相互学习】
内容来源:
官方的手册(免费获取)Pxx=该手册的对应页码xx
github-awtk
<<<学习篇7:创建简单工程(方式一:基于awtk_c_demo工程) 学习篇9:button(按键控件)
工程结构
.
├── awtk //1️⃣awtk工程目录
└── awtk-simplest //1️⃣新建工程目录名:awtk-simplest
├── assets_c_gen.py //2️⃣被assets_gen.sh,生成assets.inc
├── assets_gen.py //2️⃣被assets_gen.sh,生成资源文件
├── assets_gen.sh //2️⃣生成资源脚本文件
├── res //2️⃣资源目录
│ └── assets //3️⃣资源子目录
│ └── default //4️⃣资源默认目录
│ └── raw //5️⃣原始资源文件目录
│ ├── fonts //6️⃣字体文件目录
│ │ └── default.ttf
│ ├── images //6️⃣图片文件目录
│ ├── strings //6️⃣多国语言文件目录
│ │ ├── en_US.bin
│ │ └── zh_CN.bin
│ ├── styles //6️⃣样式文件目录
│ │ └── default.xml
│ └── ui //6️⃣UI文件目录
├── SConstruct //2️⃣scons脚本文件
├── scripts //2️⃣脚本文件目录
│ ├── app_helper.py //3️⃣被awtk-simplest/SConstruct调用
│ ├── awtk_locator.py //3️⃣被app_helper.py调用
│ └── __init__.py //3️⃣被调用
└── src //2️⃣源文件目录
├── app_main.c //3️⃣指定main函数入口
├── label.c //3️⃣实现业务逻辑
└── SConscript //3️⃣被awtk-simplest/SConstruct调用
执行过程
一、生成资源
在 ~/awtk/awtk-simplest$ 执行指令:sh assets_gen.sh
AWTK_DIR=../awtk //此处一定要写上正确的awtk工程相对路径
for i in res //res为资源目录
do
python assets_gen.py $AWTK_DIR/bin $i/assets/default/raw $i/assets/default/inc
python assets_c_gen.py $i/assets
done
运行该脚本会调用同文件夹下的assets_c_gen.py
、assets_gen.py
脚本文件,在res目录下生成assets.inc
文件,res/assets/default目录生成inc目录
(将raw目录下的资源转化为data/res文件).
PS:
①可知必须要基于awtk工程才可运行。
②生成资源的三个脚本文件是在 HelloWorld.Xml-Demo项目 中复制所得,具体内容较长置于文末。
③执行完生成:res/assets/default/inc目录包含对应的文件
和res/assets.inc
文件
④res/assets/default/raw目录 下文件复制自 awtk_c_demo工程,下面会讲解default.xml
。
⑤UI文件作用:是使用xml描述界面结构,若直接使用函数创建则可省略。(此处省略,HelloWorld.Xml-Demo项目使用)
⑥样式文件作用:描述界面外观。
二、编译源文件
在 ~/awtk/awtk-simplest$ 执行指令:scons
awtk-simplest/SConstruct文件
import os #导入标准库os
import scripts.app_helper as app #导入scripts文件夹下的app_helper.py文件并取别名为app
helper = app.Helper(ARGUMENTS);
helper.call(DefaultEnvironment)
SConscriptFiles = ['src/SConscript'] #指定源文件路径
helper.SConscript(SConscriptFiles)
运行该脚本,会执行script目录:app_helper.py
、awtk_locator.py
、__init__.py
和src目录下的SConscript
。
awtk-simplest/src/SConstruct文件
import os #导入标准库os
import sys #导入标准库sys
env=DefaultEnvironment().Clone() #环境
BIN_DIR=os.environ['BIN_DIR']; #文件目录:bin
src_files = Glob('*.c') #获取该文件夹下的所有.c文件
env.Program(os.path.join(BIN_DIR, 'demo_label'), src_files);#生成demo_label可执行文件
该SConscript
脚本会对app_main.c
和label.c
进行编译,生成可执行文件demo_label
.
PS:
①执行完生成:awtk-simplest/bin目录
包含对应文件和lib目录
②script目录下app_helper.py
、awtk_locator.py
、__init__.py
三个脚本文件为 awtk_c_demo工程 中复制而来,源文件内容较长置于文末。
三、运行demo_label
在 ~/awtk/awtk-simplest/bin$ 执行指令:./demo_label
实验效果如下:
源码分析
awtk-simplest/src/app_main.c文件
#include "awtk.h" //该头文件包含所需其他头文件
#include "../res/assets.inc" //包含assets.inc文件
extern ret_t application_init(void); //申明外部变量
int main(void) {
int lcd_w = 320; //指定窗口宽度
int lcd_h = 480; //指定窗口高度
char res_root[MAX_PATH + 1];
char app_root[MAX_PATH + 1];
path_app_root(app_root);
memset(res_root, 0x00, sizeof(res_root));
path_build(res_root, MAX_PATH, app_root, "res", NULL); //设置资源根目录为res,与上面assets.inc文件的上级目录相同
tk_init(lcd_w, lcd_h, APP_SIMULATOR, NULL, res_root);
/* 初始化资源 */
assets_init();
/* 初始化扩展控件 */
tk_ext_widgets_init();
/* 打开主屏幕 */
application_init();
/* 进入awtk事件循环 */
tk_run();
return 0;
}
该文件为main函数入口,通常无需修改,可直接套用到项目中。
主要完成:①设置屏幕大小、②资源初始化、③AWTK框架加载等。
awtk-simplest/src/label.c
#include "awtk.h"
ret_t application_init() {
widget_t* win = window_create(NULL, 0, 0, 0, 0); //创建window对象
widget_t* label = label_create(win, 0, 0, 0, 0); //创建label对象
widget_use_style(label, "big_green"); //为控件对象:label指定style(样式)
widget_set_text(label, L"hello awtk!"); //为控件对象:label设置文本:hello awtk
widget_set_self_layout_params(label, "center", "middle", "50%", "30");//设置控件自己的布局(缺省布局器)参数(过时,请用widget_set_self_layout)。
widget_layout(win); //布局当前控件及子控件
return RET_OK;
}
该文件为真正业务逻辑的实现。
若不懂函数功能,awtk提供了API手册,可通过Github下载,文件名为:AWTK-API.chm
,通过索引可快速找到对应函数,了解函数功能和参数意义。
default.xml
...
<label>
<style name="default">
<normal text_color="black" />
</style>
<style name="green">
<normal text_color="green" />
</style>
<style name="left">
<normal text_color="red" text_align_h="left" border_color="#a0a0a0" margin="4" />
</style>
<style name="center">
<normal text_color="green" text_align_h="center" border_color="#a0a0a0"/>
</style>
<style name="center_top">
<normal text_color="green" text_align_v="top" text_align_h="center" border_color="#a0a0a0"/>
</style>
<style name="center_bottom">
<normal text_color="green" text_align_v="bottom" text_align_h="center" border_color="#a0a0a0"/>
</style>
<style name="right">
<normal text_color="blue" text_align_h="right" border_color="#a0a0a0" margin="4"/>
</style>
<style name="center_ap">
<normal text_color="green" text_align_h="center" border_color="#a0a0a0" font_name="ap" font_size="12"/>
</style>
<style name="big_green">
<normal text_color="green" font_size="24" text_align_h="center" border_color="#a0a0a0"/>
</style>
</label>
...
该文件设置了样式,可发现widget_use_style(label, "big_green");
即调用了
执行后文件目录
.
├── assets_c_gen.py
├── assets_gen.py
├── assets_gen.sh
├── bin
│ ├── demo_label
│ ├── libawtk.so
│ └── uses_sdk.json
├── lib
├── res
│ ├── assets
│ │ └── default
│ │ ├── inc
│ │ │ ├── fonts
│ │ │ │ └── default.res
│ │ │ ├── images
│ │ │ ├── strings
│ │ │ ├── styles
│ │ │ │ └── default.data
│ │ │ └── ui
│ │ └── raw
│ │ ├── fonts
│ │ │ └── default.ttf
│ │ ├── images
│ │ ├── strings
│ │ │ ├── en_US.bin
│ │ │ └── zh_CN.bin
│ │ ├── styles
│ │ │ ├── default.bin
│ │ │ └── default.xml
│ │ └── ui
│ └── assets.inc
├── SConstruct
├── scripts
│ ├── app_helper.py
│ ├── app_helper.pyc
│ ├── awtk_locator.py
│ ├── awtk_locator.pyc
│ ├── __init__.py
│ └── __init__.pyc
└── src
├── app_main.c
├── app_main.o
├── label.c
├── label.o
└── SConscript
其他源码
assets_gen.py
#!/usr/bin/python
import os
import sys
import glob
import shutil
import platform
import copy
def joinPath(root, subdir):
return os.path.normpath(os.path.join(root, subdir))
def removeDir(path):
if os.path.isdir(path):
print('rmdir:' + path);
shutil.rmtree(path)
def toExePath(root, name):
if platform.system() == 'Windows':
return joinPath(root, name + '.exe')
else:
return joinPath(root, name)
def forceMakeDirs(dst_dir):
removeDir(dst_dir)
os.makedirs(dst_dir)
# tool.exe src_file dst_file option
def generate(tools_dir, tool_name, src_dir, src_sub_dir, src_suffix, dst_dir, dst_sub_dir, dst_suffix, option, is_override):
tool_path = toExePath(tools_dir, tool_name)
src_dir = joinPath(src_dir, src_sub_dir)
dst_dir = joinPath(dst_dir, dst_sub_dir)
if not os.path.exists(tool_path) :
print(tool_path + ' not exist')
return
if not os.path.exists(src_dir) :
print(src_dir + ' not exist')
return
# Generate
if isinstance(src_suffix, list) :
for f in glob.glob(joinPath(src_dir, '*.*')):
raw=copy.copy(f);
if dst_suffix == '':
inc=''
else :
inc=copy.copy(f);
inc=inc.replace(src_dir, dst_dir)
for suffix in src_suffix :
inc=inc.replace(suffix, dst_suffix)
if is_override:
if os.path.exists(inc):
os.remove(inc)
print(tool_path + ' ' + joinPath(src_dir, raw) + ' ' + joinPath(dst_dir, inc) + ' ' + option)
os.system(tool_path + ' ' + joinPath(src_dir, raw) + ' ' + joinPath(dst_dir, inc) + ' ' + option)
else :
for f in glob.glob(joinPath(src_dir, '*' + src_suffix)):
raw=copy.copy(f);
if dst_suffix == '':
inc=''
else :
inc=copy.copy(f);
inc=inc.replace(src_dir, dst_dir)
inc=inc.replace(src_suffix, dst_suffix)
if is_override:
if os.path.exists(inc):
os.remove(inc)
print(tool_path + ' ' + joinPath(src_dir, raw) + ' ' + joinPath(dst_dir, inc) + ' ' + option)
os.system(tool_path + ' ' + joinPath(src_dir, raw) + ' ' + joinPath(dst_dir, inc) + ' ' + option)
# tool.exe src_file text_file dst_file font_size
def genBmpFont(tools_dir, tool_name, src_dir, src_suffix, dst_dir, dst_suffix, sub_dir, font_size, is_remake_dir):
tool_path = toExePath(tools_dir, tool_name)
src_dir = joinPath(src_dir, sub_dir)
dst_dir = joinPath(dst_dir, sub_dir)
if not os.path.exists(tool_path) :
print(tool_path + ' not exist')
return
if not os.path.exists(src_dir) :
print(src_dir + ' not exist')
return
# Delete History
if is_remake_dir :
removeDir(dst_dir)
os.makedirs(dst_dir);
# Generate
text_file = joinPath(src_dir, 'text.txt')
for f in glob.glob(joinPath(src_dir, '*' + src_suffix)):
raw=copy.copy(f);
inc=copy.copy(f);
inc=inc.replace(src_dir, dst_dir)
if font_size == 18 :
inc=inc.replace(src_suffix, dst_suffix)
else :
inc=inc.replace(src_suffix, '_' + str(font_size) + dst_suffix)
if raw.find('.mini' + src_suffix) == -1 :
print(tool_path + ' ' + joinPath(src_dir, raw) + ' ' + text_file + ' ' + joinPath(dst_dir, inc) + ' ' + str(font_size))
os.system(tool_path + ' ' + joinPath(src_dir, raw) + ' ' + text_file + ' ' + joinPath(dst_dir, inc) + ' ' + str(font_size))
def genTheme(tools_dir, src_dir, dst_dir):
forceMakeDirs(joinPath(dst_dir, 'styles'))
generate(tools_dir, 'themegen', src_dir, 'styles', '.xml', dst_dir, 'styles', '.data', '', 0)
generate(tools_dir, 'themegen', src_dir, 'styles', '.xml', src_dir, 'styles', '.bin', 'bin', 0)
def genString(tools_dir, src_dir, dst_dir):
forceMakeDirs(joinPath(dst_dir, 'strings'))
generate(tools_dir, 'strgen', src_dir, 'strings', '.xml', dst_dir, 'strings', '', '', 0)
generate(tools_dir, 'strgen', src_dir, 'strings', '.xml', src_dir, 'strings', '', 'bin', 0)
def genFont(tools_dir, src_dir, dst_dir):
forceMakeDirs(joinPath(dst_dir, 'fonts'))
generate(tools_dir, 'resgen', src_dir, 'fonts', '.ttf', dst_dir, 'fonts', '.res', '', 0)
# genBmpFont(tools_dir, 'fontgen', src_dir, '.ttf', dst_dir, '.data', 'fonts', 10, 0)
# genBmpFont(tools_dir, 'fontgen', src_dir, '.ttf', dst_dir, '.data', 'fonts', 18, 0)
# genBmpFont(tools_dir, 'fontgen', src_dir, '.ttf', dst_dir, '.data', 'fonts', 28, 0)
# genBmpFont(tools_dir, 'fontgen', src_dir, '.ttf', dst_dir, '.data', 'fonts', 32, 0)
# genBmpFont(tools_dir, 'fontgen', src_dir, '.ttf', dst_dir, '.data', 'fonts', 48, 0)
# genBmpFont(tools_dir, 'fontgen', src_dir, '.ttf', dst_dir, '.data', 'fonts', 64, 0)
# genBmpFont(tools_dir, 'fontgen', src_dir, '.ttf', dst_dir, '.data', 'fonts', 128, 0)
def genImage(tools_dir, src_dir, dst_dir, dpi):
IMAGEGEN_OPTIONS = '\"bgra|bgr565\"'
suffix = ['.png', '.jpg', '.bmp']
forceMakeDirs(joinPath(dst_dir, 'images'))
generate(tools_dir, 'resgen', src_dir, 'images/xx', suffix, dst_dir, 'images', '.res', '', 0)
generate(tools_dir, 'resgen', src_dir, 'images/' + dpi, suffix, dst_dir, 'images', '.res', '', 1)
#generate(tools_dir, 'imagegen', src_dir, 'images/' + dpi, suffix, dst_dir, 'images', '.data', IMAGEGEN_OPTIONS, 0)
def genData(tools_dir, src_dir, dst_dir):
if os.path.exists(joinPath(src_dir, 'data')):
forceMakeDirs(joinPath(dst_dir, 'data'))
generate(tools_dir, 'resgen', src_dir, 'data', '.bin', dst_dir, 'data', '.res', '', 0)
def genUI(tools_dir, src_dir, dst_dir):
forceMakeDirs(joinPath(dst_dir, 'ui'))
generate(tools_dir, 'xml_to_ui', src_dir, 'ui', '.xml', dst_dir, 'ui', '.data', '', 0)
generate(tools_dir, 'xml_to_ui', src_dir, 'ui', '.xml', src_dir, 'ui', '.bin', 'bin', 0)
def check_python_version():
major_version = sys.version_info[0]
if major_version > 2:
# print("The python version is %d.%d. But python2.x is required.(Version 2.7 is well tested!)" %(major_version, sys.version_info[1]))
return True
return False
def run():
if len(sys.argv) <= 3 :
print('Usage: assets_gen.py tools_dir src_dir dst_dir')
exit()
tools_dir = os.path.abspath(sys.argv[1])
src_dir = os.path.abspath(sys.argv[2])
dst_dir = os.path.abspath(sys.argv[3])
if len(sys.argv) > 4 :
opt = sys.argv[4]
else:
opt = ''
if not os.path.exists(tools_dir) :
print('tools dir not exist')
exit()
if not os.path.exists(src_dir) :
print('src dir not exist')
exit()
# Start Generate
if opt == '' or opt == '-style':
genTheme(tools_dir, src_dir, dst_dir)
if opt == '' or opt == '-string':
genString(tools_dir, src_dir, dst_dir)
if opt == '' or opt == '-font':
genFont(tools_dir, src_dir, dst_dir)
if opt == '' or opt == '-image':
if (len(sys.argv) > 5):
dpi = sys.argv[5]
else:
dpi = 'x1'
genImage(tools_dir, src_dir, dst_dir, dpi)
if opt == '' or opt == '-ui':
genUI(tools_dir, src_dir, dst_dir)
if opt == '' or opt == '-data':
genData(tools_dir, src_dir, dst_dir)
run()
assets_c_gen.py
#!/usr/bin/python
import os
import sys
import glob
import shutil
import copy
def joinPath(root, subdir):
return os.path.normpath(os.path.join(root, subdir))
def writeToFile(file_name, str):
fd = os.open(file_name, os.O_RDWR|os.O_CREAT|os.O_TRUNC)
if check_python_version() :
os.write(fd, bytes(str, 'utf-8'))
else:
os.write(fd, str)
os.close(fd)
def genIncludes(files, dir_name):
str1 = ""
for f in files:
incf = copy.copy(f);
incf=incf.replace(dir_name, "assets/default/inc");
incf=incf.replace('\\', '/');
str1 += '#include "'+incf+'"\n'
return str1
def GetFileBaseName(file_name, root_dir_name, subdir_name, suffix):
name = file_name.replace(root_dir_name, '');
name = name.replace('\\', '/');
name = name.replace('/' + subdir_name + '/', '');
name = name.replace(suffix, '');
return name;
def genAssetsManagerAdd(assets_inc_dir, filter, dir_name, name, suffix):
files=glob.glob(joinPath(assets_inc_dir, filter))
result = ''
for f in files:
basename = GetFileBaseName(copy.copy(f), assets_inc_dir, dir_name, suffix)
if dir_name == "data":
result += ' assets_manager_add(rm, ' + name + basename + '_bin' +');\n'
else:
result += ' assets_manager_add(rm, ' + name + basename + ');\n'
return result
def gen_assets_c(assets_dir, assets_c_path):
assets_inc_dir = joinPath(assets_dir, 'default/inc')
if not os.path.exists(assets_inc_dir) :
print('assets inc dir not exist')
exit()
result = '#include "awtk.h"\n'
result += '#include "base/assets_manager.h"\n'
result += '#ifndef WITH_FS_RES\n'
files=glob.glob(joinPath(assets_inc_dir, 'strings/*.data')) \
+ glob.glob(joinPath(assets_inc_dir, 'styles/*.data')) \
+ glob.glob(joinPath(assets_inc_dir, 'ui/*.data')) \
+ glob.glob(joinPath(assets_inc_dir, 'data/*.res'))
result += genIncludes(files, assets_inc_dir);
result += "#ifdef WITH_STB_IMAGE\n"
files=glob.glob(joinPath(assets_inc_dir, 'images/*.res'))
result += genIncludes(files, assets_inc_dir)
result += "#else\n"
files=glob.glob(joinPath(assets_inc_dir, 'images/*.data'))
result += genIncludes(files, assets_inc_dir)
result += '#endif/*WITH_STB_IMAGE*/\n'
result += "#if defined(WITH_STB_FONT) || defined(WITH_FT_FONT)\n"
files=glob.glob(joinPath(assets_inc_dir, 'fonts/*.res'))
result += genIncludes(files, assets_inc_dir)
result += "#else/*WITH_STB_FONT or WITH_FT_FONT*/\n"
files=glob.glob(joinPath(assets_inc_dir, 'fonts/*.data'))
result += genIncludes(files, assets_inc_dir)
result += '#endif/*WITH_STB_FONT or WITH_FT_FONT*/\n'
result += '#endif/*WITH_FS_RES*/\n'
result += '\n';
result += 'ret_t assets_init(void) {\n'
result += ' assets_manager_t* rm = assets_manager();\n\n'
result += ''
result += '#ifdef WITH_FS_RES\n'
result += ' assets_manager_preload(rm, ASSET_TYPE_FONT, "default");\n'
result += ' assets_manager_preload(rm, ASSET_TYPE_STYLE, "default");\n'
result += '#else\n'
result += genAssetsManagerAdd(assets_inc_dir, 'fonts/*.res', 'fonts', 'font_', '.res')
result += genAssetsManagerAdd(assets_inc_dir, 'images/*.res', 'images', 'image_', '.res')
result += genAssetsManagerAdd(assets_inc_dir, 'styles/*.data', 'styles', 'style_', '.data')
result += genAssetsManagerAdd(assets_inc_dir, 'ui/*.data', 'ui', 'ui_', '.data')
result += genAssetsManagerAdd(assets_inc_dir, 'strings/*.data', 'strings', 'strings_', '.data')
result += genAssetsManagerAdd(assets_inc_dir, 'data/*.res', 'data', 'data_', '.res')
result += '#endif\n'
result += '\n'
result += ' tk_init_assets();\n'
result += ' return RET_OK;\n'
result += '}\n'
writeToFile(assets_c_path, result);
def check_python_version():
major_version = sys.version_info[0]
if major_version > 2:
# print("The python version is %d.%d. But python2.x is required.(Version 2.7 is well tested!)" %(major_version, sys.version_info[1]))
return True
return False
def run():
if len(sys.argv) <= 1 :
print('Usage: assets_c_gen.py assets_dir')
exit()
assets_dir = os.path.abspath(sys.argv[1])
assets_c_path = joinPath(assets_dir, '../assets.inc')
gen_assets_c(assets_dir, assets_c_path)
run()
app_helper.py
import awtk_locator as locator
def Helper(ARGUMENTS):
locator.init(ARGUMENTS)
from app_helper_base import AppHelperBase
return AppHelperBase(ARGUMENTS)
awtk_locator.py
import os
import sys
AWTK_ROOT = ''
def getAwtkRoot():
return AWTK_ROOT
def getAwtkSDKPath():
env = os.environ
if 'AWTK_SDK_PATH' in env:
return env['AWTK_SDK_PATH']
else:
return ''
def getAwtkOrAwtkLinuxFbRoot(is_linux_fb):
if is_linux_fb:
return locateAWTK('awtk-linux-fb')
else:
return locateAWTK('awtk')
def locateAWTK(awtk):
awtk_root = ''
if not os.path.exists(awtk_root):
dirnames = ['../'+awtk, '../../'+awtk, '../../../'+awtk]
for dirname in dirnames:
if os.path.exists(dirname):
awtk_root = dirname
break
if not os.path.exists(awtk_root):
awtk_sdk_path = getAwtkSDKPath();
if os.path.exists(awtk_sdk_path):
awtk_root = awtk_sdk_path + '/' + awtk
return os.path.abspath(awtk_root)
def init(ARGUMENTS = None):
global AWTK_ROOT
global LINUX_FB
if ARGUMENTS:
AWTK_ROOT = ARGUMENTS.get('AWTK_ROOT', '')
LINUX_FB = ARGUMENTS.get('LINUX_FB', '')
else:
LINUX_FB = ''
if not os.path.exists(AWTK_ROOT):
AWTK_ROOT = getAwtkOrAwtkLinuxFbRoot(LINUX_FB != '')
elif os.path.exists(LINUX_FB):
print(' do not set LINUX_FB and AWTK_ROOT !!!')
sys.exit()
if LINUX_FB:
AWTK_SCRIPTS_ROOT = os.path.join(AWTK_ROOT, '../awtk/scripts')
else:
AWTK_SCRIPTS_ROOT = os.path.join(AWTK_ROOT, 'scripts')
sys.path.insert(0, AWTK_SCRIPTS_ROOT)
print('AWTK_ROOT: ' + AWTK_ROOT)
print('AWTK_SCRIPTS_ROOT: ' + AWTK_SCRIPTS_ROOT)
init.py
import os
import sys
APP_SCRIPTS_ROOT = os.path.abspath(os.path.dirname(__file__))
print('APP_SCRIPTS_ROOT:' + APP_SCRIPTS_ROOT)
sys.path.insert(0, APP_SCRIPTS_ROOT)