|
EFL - 1.7.1
Void指针
void *则为“无类型指针”,可以指向任何数据类型
void指针不能复引用,因为void指针只知道,指向变量/对象的起始地址
–*vp//错误
void指针不能参与指针运算,除非进行转换
有时候由于重载等的干扰,导致需要转换成void *,来进行取地址
–例如,(void *)obj.member,就可以取到member的地址;直接&(obj.member)取到的实际上是obj的开始地址
EFL 用了大量的void指针
信息隐藏
–别人看到的是void指针,无法知道我们其指向的地址保存的是什么东西
风险
–允许把任何类型的参数都传入以void*指针类型为参数的函数
void*指针在EFL的应用举例
1.保存一个指向任何类型的对象的指针(key-value)
- <font size="4">void evas_object_data_set(
- Evas_Object *obj, //
- const char *key, //
- const void *data //
- )</font>
复制代码 2.获取这个对象
- <font size="4">void evas_object_data_get(
- const Evas_Object *obj,
- const char *key
- )</font>
复制代码- <font size="4">复制代码
- typedef struct appdata{
- Evas_Object* win;
- Evas_Object* layout;
- Evas_Object* conform;
- Evas_Object* nf;
- Evas_Object* base_ly;
- Evas_Object* genlist;
- Elm_Object_Item *nf_it;
- } appdata_s;</font>
复制代码 在某个文件某个函数中我只知道appdata_s的nf这个对象,但是我想通知genlist这个对象去
运行某个东西或者其他的,怎么办呢?先set好,之后就可以:
- <font size="4">Evas_Object *genlist = evas_object_data_get(cv_data->navi, "main_list");</font>
复制代码 Const
const int* p;
– 其实等价于const int (*p); 和 int const (*p);
– 即,*p是常量。p指向的数据不能修改。但是,p本身的值可以修改(P可以指向其他的地址)
int* const p;
– 这个指针是常量,不能修改,但是可以修改指针指向的值
构造函数和析构函数
C++
– 该类对象被创建时,编译系统对象分配内存空间,并自动调用该构造函数->由构造函数完成成员的初始化工作
– 如果用new运算符动态地建立了一个对象,当用delete运算符释放该对象时,先调用该对象的析构函数
C里面没有new, C++才有new。
– C里面是malloc和free,但是这个不能建立类的对象,因为不能调用构造函数和析构函数
C的面向对象编程,我们自己编写函数代替构造函数和析构函数
– Tizen:xxxx_add() 和 xxxx_del()
Overriding & overloading
overriding:
– 父类与子类,相同的名称和参数
overloading:
– 同一个类,不同的参数个数或者参数类型,返回值可以改变。
C实现继承
使用结构struct来实现
要继承的基类必须作为子类的成员放在子类结构的第一位
- <font size="4">typedef struct son
- {
- father base;//基类
- int version;
- }</font>
复制代码 为什么呢?
因为我们要强制类型转换,呵呵呵
Widget:smart_class
譬如有个void指针data指向上面的数据结构
那么我们可以用强制类型转换:
- <font size="4">Evas_Smart_Class *sc = (Evas_Smart_Class *)data; //能获取a,b,c,d
- Elm_Widget_Smart_Class *wsc = (Elm_Widget_Smart_Class *) data; //获取更多的,e,f,g,h,i,j,
- Eml_MyWidget_class *mwsc = (Eml_MyWidget_class *)data; //获取更多的 , k,l,m,n,o,p</font>
复制代码- <font size="4">typedef struct _Elm_Genlist_Smart_Class
- {
- Elm_Layout_Smart_Class base;//基类
- int version;
- } Elm_Genlist_Smart_Class;</font>
复制代码
1.继承Layout类
2.实现scrollable接口
3.滑动的时候,动态产生和销毁items[节省内存,减低消耗]
Immediate mode Rendering
原始的canvas绘制,简单
即时绘画
Graphics Library不知道自己都画了些什么
– 当需要重画的时候,需要再重新需要由application层再从零开始重新画(工作重复,繁琐)
Retained mode Rendering
状态机
Graphic Library带有一个完善的model来保存需要显示的信息。
– 譬如:Tizen上面的所有widget实例都对应一个Evas_object来保存widget的相关信息
Application只需要创建widget,widget的显示以及update,统一由Graphic Library来维护
如何区别
Graphics Library是否有独立的model保存需要画的Object信息。
– Tizen有Evas ---->retained mode
需要更新时,谁来处理优化工作。
– Tizen---->由Evas来统一优化处理
Evas(Evas 是Retained mode Rendering )
Evas介绍
Evas是一个canvas display library
Evas不是widget,也不是widget toolkit,但是是widget的基础
在Evas的世界里,canvas是结构化的,在canvas上面是严格结构化的Evas_Object
在Evas的世界里,你可以把Evas当做是一个状态机
Evas_object To Widget
每个在手机屏幕上面存在的widget实例都存在一个相对应的Evas_object实例
– 一对一关系,用来记录和跟踪widget实例的状态属性等
– Evas_object随着widget实例的构建而构建,随着析构而消逝(回收)
– Evas_object不是widget的一部分
Evas_object组成树状结构
对于Widget来说,每个Evas_object都是widget
可能是Button,可能是layout,可能是entry,可能是genlist等等
类结构
类是两个结构体的组合
– 一个是实例结构体,另一个是类结构体
类结构体初始化函数一般被调用一次,而实例结构体的初始化函数的调用次数等于对象实例化的次数。
– 所有实例共享的数据,可保存在类结构体中(函数),而所有对象私有的数据,则保存在实例结构体中
后面我们会看到:
obj->smart.smart = s; 设置smart class (s为3中函数的参数)
application
而evas_object_smart_data_set 是设置object_data->data, 就是说明我们从object->object_data就可以找到data了
o = (Evas_Object_Smart *)(obj->object_data);
o->data = data; //看清楚了,是object_data里面的void* 指针成员 data指向widget的data
这意味着Evas_object都bind着一个widget层的data,而这个data
就是widget user设计的。
Widget类的实例化
l Smart Class 初始化介绍
上面说到每个widget类一般都有个Smart Class结构
l Smart Data 初始化介绍
上面说到每个widget类一般都有个Smart Data结构
Smart class构造函数
调用
- obj = elm_widget_add( <b>_elm_layout_widget_smart_class_new() </b>, parent);
复制代码 注意了,这里的_elm_layout_widget_smart_class_new()的确是个函数,
在evas.h搜宏
EVAS_SMART_SUBCLASS_NEW
可以找到这个函数
smart = evas_smart_class_new(sc);
别看这里那么多代码,其实就仅仅是准备了smart class ,没错,千辛万苦就仅仅是准备了smart class作为返回值
Smart class的统一宏定义
在Evas.h中统一定义了一个宏,方便创建新Widget 的Smart Class:
EVAS_SMART_SUBCLASS_NEW
主要作用:
– 定义初始化子类的Smart Class的new 和 set函
New函数会通过set函数先获取到该控件所有父类的smart class并且继承过来,然后new一个smart class
Set函数用于设置一个smart class(嵌套调用来获取父类的smart class)
主要作用:
定义两个函数( prefix##_ 为前缀,如layout就会替换为:_elm_layout_widget):
static void prefix##_smart_set(api_type * api)
static Evas_Smart *prefix##_smart_class_new(void)
调用函数:prefix##_smart_set_user(api)
如Elm_layout.c的
static void _elm_layout_smart_set_user(Elm_Layout_Smart_Class *sc)
注:这个宏实在太隐晦,而是使用了prefix##这样的东东实在让人无迹可寻。
当时我为了找一个函数:
_elm_layout_widget_smart_class_new()
的实现我还在tizen论坛发问了。没有人回答我。
最后实在是没撤了,慢慢来找,一步一步推断,发现,竟然被定义在EVAS_SMART_SUBCLASS_NEW这个宏里面
#define EVAS_SMART_SUBCLASS_NEW(smart_name, prefix, api_type, parent_type, parent_func, cb_desc) \
static const parent_type * prefix##_parent_sc = NULL; \
static void prefix##_smart_set_user(api_type * api); \
static void prefix##_smart_set(api_type * api) \
{ \
Evas_Smart_Class *sc; \
if (!(sc = (Evas_Smart_Class *)api)) \
return; \
if (!prefix##_parent_sc) \
prefix##_parent_sc = parent_func(); \
evas_smart_class_inherit(sc, prefix##_parent_sc); \
prefix##_smart_set_user(api); \
} \
static Evas_Smart *prefix##_smart_class_new(void) \
{ \
static Evas_Smart *smart = NULL; \
static api_type api; \
if (!smart) \
{ \
Evas_Smart_Class *sc = (Evas_Smart_Class *)&api; \
memset(&api, 0, sizeof(api_type)); \
sc->version = EVAS_SMART_CLASS_VERSION; \
sc->name = smart_name; \
sc->callbacks = cb_desc; \
prefix##_smart_set(&api); \
smart = evas_smart_class_new(sc); \
} \
return smart; \
}
Smart class申请
当一个新类型的widget要加入的时候,会在Evas.h这个文件申请一个静态变量。
static api_type api; ////api_type为widget的类型
静态变量生存期为整个源程序,是始终存在的。
这就保证了所有同类型的widget的smart class都是同一个smart class
构造总览
2.3.
初始化Smart Class
4
后面我们会看到是通过evas_object_smart_add() 函数再调用其他函数最后生成并初始化一个Smart Data
最后生成Evas_Object
Widget的初始化:class
obj = elm_widget_add(_elm_layout_widget_smart_class_new(), parent);
3.是参数调用
Widget的初始化:smart class准备
SC: smart class
这里是smart class的构造过程,在函数prefix##_smart_class_new内先定义一个临时变量,用这个临时变量完成了以下3. 5.,
然后再以这个临时变量为参数生成Evas_Smart
smart = evas_smart_class_new(临时变量);
最后把生成的smart return回去作为参数值
obj = elm_widget_add(prefix##_smart_class_new() , parent);
1. prefix##_smart_class_new 是构造函数_add的参数调用
2.没错,就是定义在了Evas.h 用宏的方式
3.继承父类:其实就是把子类中的父类func pointer赋值为父类的默认值
5.调用子类的prefix##_smart_set_user(api); 根据子类需求,改变子类的的函数指针值赋予新函数
Evas is a clean display canvas API for several target display systems that can draw
anti-aliased text, smooth super and sub-sampled scaled images, alpha-blend objects
and much more.
Smart Class inheritance
每个父类都提供一个_smart_class_get来给它的子类获取该父类的类方法
该_smart_class_get函数会调用自己的smart_class_set函数
子类在生成的时候,一定会调用父类的_smart_class_get函数
通过不断的嵌套调用从而实现了继承
Smart_set函数中
prefix##_parent_sc = parent_func();
evas_smart_class_inherit(sc, prefix##_parent_sc);
prefix##_smart_set_user(api);
这三个个语句是实现class继承的关键。
Prefix##_parent_sc 这个是是有统一宏定义的参数决定,都是每个widget的:XXX_smart_class_get函数
而XXX_smart_class_get函数又会调用它自己的smart_set函数。
然后smart_set函数又调用smart_get函数,一直到widget基类的_elm_widget_smart_set函数停止
prefix##_smart_set_user(api);这个函数是设置该类除了父类的之外自己的smart class
自己set()->父亲get class->父亲set-》。。。。。。
譬如:
Entry是layout的孩子,engry会先跑自己的_elm_entry_smart_set函数,在跑parent fun:layout的class get
elm_layout_smart_class_get()
_elm_layout_smart_set(&_sc);
elm_container_smart_class_get
_elm_container_smart_set(&_sc);
elm_widget_smart_class_get(void);
_elm_widget_smart_set(&_sc);
题外话:
#define ELM_WIDGET_SMART_CLASS_INIT_NAME_VERSION(name) \
ELM_WIDGET_SMART_CLASS_INIT(EVAS_SMART_CLASS_INIT_NAME_VERSION(name))
这个宏其实就是申请一个结构变量空间
#define ELM_WIDGET_SMART_CLASS_INIT(smart_class_init) \
{smart_class_init, ELM_WIDGET_SMART_CLASS_VERSION, NULL, NULL, NULL, NULL, \
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}
#define EVAS_SMART_CLASS_INIT_NAME_VERSION(name) {name, EVAS_SMART_CLASS_VERSION, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}
Init Widget(class && data)
1:elm_layout_add(Evas_Object *parent)
在app添加widget的时候调用elm_layout_add(),该函数作用是:
设置Smart class,Smart data,interface
2:
obj = elm_widget_add(_elm_layout_widget_smart_class_new(), parent);
3. evas_object_smart_add(e, smart);
2.3.4.5:
elm_layout_add()通过widget一直调用,最终会调用到Evas_object_smart.c的
evas_object_new ()来alloc一个Evas_Object对象
直接修改obj的属性,bj->smart.smart = s; 设置smart class (s为3中函数的参数)
Evas_object_smart_init()再初始化这个对象
6:还会通过:
_evas_smart_class_ifaces_private_data_alloc()
来处理interfaces以及interface的parivate data的空间申请(如果不实现接口则没有)
7.该函数最终会通过获取该子类的add方法来调用evas_object_smart_data_set() :
通过下面语句调用
if (s->smart_class->add) s->smart_class->add(obj);
在Elm_XXXX.c 或者 Elm_widget_XXXX.c 获取XXX_Smart_Data
调用XX_smart_add()
到这一步,实例化终于成功了。
Smart data的申请1
_smart_add()函数
上一张PPT我们看到,当smart class准备好了之后,会通过
7.
if (s->smart_class->add)
s->smart_class->add(obj);
来调用_smart_add函数哦,没错,这个就是准备smart data的。
_smart_add()
如何申请Smart data? 请看下一页
Smart data的申请2
每个Widget都有自己的_smart_add()函数
都会使用宏: EVAS_SMART_DATA_ALLOC
_smart_add()函数的作用:
① 如果smart data没有申请的话就申请,并设置一些属性。
② 调用父类的_smart_add()函数,这样嵌套调用就可以设置属于父类data的属性了哦。
③ 用面向对象的思想看待,这个其实就是Smart Data的构造函数
static void
_elm_genlist_smart_add(Evas_Object *obj)
{
EVAS_SMART_DATA_ALLOC(obj, Elm_Genlist_Smart_Data);
ELM_WIDGET_CLASS(_elm_genlist_parent_sc)->base.add(obj);
}
* @remarks When writing a subclassable smart object, the @c .add() function
* needs to check if the smart private data is already allocated
* by some child object or not. This macro makes it easier to do it.
#define EVAS_SMART_DATA_ALLOC(o, priv_type) \
priv_type * priv; \
priv = evas_object_smart_data_get(o); \
if (!priv) { \
priv = (priv_type *)calloc(1, sizeof(priv_type)); \
if (!priv) return; \
evas_object_smart_data_set(o, priv); \
}
EVAS_SMART_DATA_ALLOC介绍
l 这是一个宏
l 所有widget都会用到这个宏来申请smart data的空间(实例化)
l 首先检查这个widget的smart data有没有申请,如果没有申请,就alloc申请空间。
l 这个宏在子类smart_add()函数中配合使用,一般是使用这个宏之后再调用父类的smart_add()函数,总之就是设置smart data的。
记得么,上文说过,如果smart data已经申请了,那么不会再申请了
#define EVAS_SMART_DATA_ALLOC(o, priv_type) \
priv_type * priv; \
priv = evas_object_smart_data_get(o); \
if (!priv) { \
priv = (priv_type *)calloc(1, sizeof(priv_type)); \
if (!priv) return; \
evas_object_smart_data_set(o, priv); \
}
Smart Class的析构(1)
每个控件都会有_smart_del函数
– 通过该函数清理自己的ex data,最后调用父类的_smart_del函数
Evas_object的析构只会在叶子控件进行:
– 调用evas_object_del(Evas_Object *obj)
Smart Class的析构(2)
evas_object_del(Evas_Object *obj)清理evas_object 的时候,会delete smart class。
疑问:为什么在一开始就可以直接delete smart class。
– 答:上文说到,其实相同的控件不会独立申请空间去存储smart class ,都是引用同一个smart class。Delete的时候,只不过是去掉了对该smart class的引用。
– 那么真正删除smart class是什么时候呢?请看下文。
Smart class的引用计数
Smart class有一个int变量专门管理引用计数
int usage;
控件构建的时候
s->usage++;
控件析构的时候
s->usage--;
if ((s->usage <= 0) && (s->delete_me)) evas_smart_free(s);
控件构建时:
elm_widget_add(Evas_Smart *smart, Evas_Object *parent)
evas_object_smart_add(Evas *e, Evas_Smart *s)
evas_object_smart_use(s);
{
s->usage++;
}
控件析构时:
evas_object_del(Evas_Object *obj)
evas_object_smart_del(Evas_Object *obj)
evas_object_smart_unuse(Evas_Smart *s)
{
s->usage--;
if ((s->usage <= 0) && (s->delete_me)) evas_smart_free(s);
}
Smart Data 的析构
每个控件都会有_smart_del函数
– 通过该函数清理自己的ex data,最后调用父类的_smart_del函数
– 最后会调用到widget基类的smart_del函数
– Widget清理完相关数据后最后会
free(sd);
evas_object_smart_data_set(obj, NULL);
调用父类的del函数
ELM_WIDGET_CLASS(xxxx_parent_sc)->base.del(obj);
如:
ELM_WIDGET_CLASS(_elm_layout_parent_sc)->base.del(obj);
什么是EO?
一个lib库名称
一个方便快捷,帮助C的对象化编程工具
– EO其实就是为了减轻程序猿工作量(重复而且boring)
– C + EO能够模拟对象化语言,可以作为C ++ ,objective-c的替代方案
EO是EFL的对象化系统基础
Eo是对Gobject的翻版
Gobject介绍
GObject System以Gtype为基础而实现的一套单根继承的C语言的面向对象的框架。
GObject对象系统是一个建立在GLIB基础上的,用C语言完成的,具有跨平台特色的、灵活的、可扩展的、非常容易映射到其它语言的面向对象的框架。如果你是一个C语言的执着的追随者,你没有理由不研究一下它。- IBM.com
GLib中最有特色的是它的对象系统--GObject System,它是以Gtype为基础而实现的一套单根继承的C语言的面向对象的框架。
-IBM.com
Gobject模拟封装。
– 类是两个结构体的组合,一个是实例结构体,另一个是类结构体。
GType 是GLib 运行时类型认证和管理系统。
– Gtype提供了注册和管理所有基本数据类型、用户定义对象和界面类型的技术实现
Gobject实现多态
– 为每个子类在内存中保存了一份包含成员函数指针的表(虚方法表vtable)
等等(太多东西了,不说了)
EO-EFL的“GObject”
为什么要重新发明轮子?
– 引入Gobject需要导入Glib, bla~ bla~ bla~
C具有良好的兼容性
EO会加入Tizen中
就目前的C++编译器来说,并没有标准的ABI可以在所有的C++编译器运行(除了Windows,Windows上有COM可以处理),以A这个C++编译器所编译出来的库,并不一定能被以B C++编译器所编译的程序调用。如果需要这样的兼容性,C++的方法必须要输出为C的函数,这样就无法享受C++带来的好处了。这主要是因为不同的C++编译器使用了不同的名称特殊处理(Name mangling)以确保输出符号的独一性。(这是必要的,举例来说,不同的类可能会有一样名称的成员函数、被覆载许多次的函数名称,或者出现在多个名字空间但同名的函数,但在输出为目标文件时,这些代码都是独立的,如果名称都一样,会被视为同一份代码,因此需要对名称作特殊处理。)对照C来看,C不支持任何形式的覆载或名称特殊处理,C库的作者永远只能使用明确的前置名以确保输出名称的全域独一性。
EO
继承(多继承)
接口
多态(overriding)
Callbacks
Mixins,reference counting,Weak references等等
本文来自于ThomasLiao的博客巴士!
|
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有账号?立即注册
×
|