RT-Thread GUI - Object

RT-Thread GUI 2019-01-01 1.1k

RT-Thread GUI 物件架構#

在 RTGUI 中,最小的物件為 widget,再來是 window,window 也是一個 widget;而每個 widget 也是一個 object,這是為了仿造 C++ 的物件導向所設計的,相同的概念我們在 RT-Thread 中已經看過許多次了,在 GUI engine 中也是相同的設計,其中在 object 結構中又串在 type 的結構上,type 中定義了兩個函式:constructordestructor,在 C++ 的 class 中,常使用 init 函式來初始化新建的 class,這裡的 constructordestructor 即用來初始化新建立的物件,及在刪除物件時,釋放該釋放的記憶體。[1]


結構#

File: rtgui_object.h

121
122
123
124
125
126
127
128
129
130
131
132
133
/* rtgui base object */
struct rtgui_object
{
/* object type */
const rtgui_type_t *type;

/* the event handler */
rtgui_event_handler_ptr event_handler;

enum rtgui_object_flag flag;

rt_uint32_t id;
};
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
/* rtgui type structure */
struct rtgui_type
{
/* type name */
char *name;

/* parent type link */
const struct rtgui_type *parent;

/* constructor and destructor */
rtgui_constructor_t constructor;
rtgui_destructor_t destructor;

/* size of type */
int size;
};

定義物件類型#

RTGUI 設計了一個巨集函數來定義不同的物件,如下:

76
77
78
79
80
81
82
83
84
#define DEFINE_CLASS_TYPE(type, name, parent, constructor, destructor, size) \
const struct rtgui_type _rtgui_##type = { \
name, \
parent, \
RTGUI_CONSTRUCTOR(constructor), \
RTGUI_DESTRUCTOR(destructor), \
size }; \
const rtgui_type_t *_rtgui_##type##_get_type(void) { return &_rtgui_##type; } \
RTM_EXPORT(_rtgui_##type##_get_type)

## 為連字符,在RT-Thread 理解 RTM_EXPORT裡有提過了,基本上就是填入值進去結構體


建立物件#

File: rtgui_object.c

功能 回傳值 *object_type
建立物件 物件指標 要建立的物件種類
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
/**
* @brief Creates a new object: it calls the corresponding constructors
* (from the constructor of the base class to the constructor of the more
* derived class) and then sets the values of the given properties
*
* @param object_type the type of object to create
* @return the created object
*/
rtgui_object_t *rtgui_object_create(const rtgui_type_t *object_type)
{
rtgui_object_t *new_object;

if (!object_type)
return RT_NULL;

new_object = rtgui_malloc(object_type->size);
if (new_object == RT_NULL) return RT_NULL;

#ifdef RTGUI_OBJECT_TRACE
obj_info.objs_number ++;
obj_info.allocated_size += object_type->size;
if (obj_info.allocated_size > obj_info.max_allocated)
obj_info.max_allocated = obj_info.allocated_size;
#endif

new_object->type = object_type;

rtgui_type_object_construct(object_type, new_object);

return new_object;
}
RTM_EXPORT(rtgui_object_create);

建立物件相當簡單,透過欲建立的物件類型所定意義的 construct 函數來建立,其中 rtgui_type_object_construct 會呼叫正確的建立函式來初始化資料。


功能 回傳值
呼叫正確的 construct 函式來初始化物件 void
*type *object
欲初始化的物件類型 物件本體
54
55
56
57
58
59
60
61
62
void rtgui_type_object_construct(const rtgui_type_t *type, rtgui_object_t *object)
{
/* construct from parent to children */
if (type->parent != RT_NULL)
rtgui_type_object_construct(type->parent, object);

if (type->constructor)
type->constructor(object);
}

如果欲建立的物件類型在某一個物件類型的底下,如 window 之於 widget,則先呼叫在上層的 construct;接著呼叫自己的 construct 來完成建立的動作。


再仔細的看一下 “object” 的 construct 函式,其動作為:填入 vaild 的旗標,並將 id 填入 object 的記憶體指標;以上動作在 _rtgui_object_constructor 完成

功能 回傳值 *object
“object” 建立函式 void 要建立的物件
28
29
30
31
32
33
34
35
static void _rtgui_object_constructor(rtgui_object_t *object)
{
if (!object)
return;

object->flag = RTGUI_OBJECT_FLAG_VALID;
object->id = (rt_uint32_t)object;
}

刪除物件#

功能 回傳值 *object
刪除物件 void 要刪除的物件
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
/**
* @brief Destroys the object.
*
* The object destructors will be called in inherited type order.
*
* @param object the object to destroy
*/
void rtgui_object_destroy(rtgui_object_t *object)
{
if (!object || object->flag & RTGUI_OBJECT_FLAG_STATIC)
return;

#ifdef RTGUI_OBJECT_TRACE
obj_info.objs_number --;
obj_info.allocated_size -= object->type->size;
#endif

/* call destructor */
RT_ASSERT(object->type != RT_NULL);
rtgui_type_destructors_call(object->type, object);

/* release object */
rtgui_free(object);
}
RTM_EXPORT(rtgui_object_destroy);

這裡一樣透過 rtgui_type_destructors_call 來呼叫正確的 destruct 函式,destruct 負責釋放該釋放的記憶體;最後透過 rtgui_free 釋放整個物件。regui_free 則簡單的呼叫 rt_free 釋放記憶體,我們在前幾篇文章有討論過了(mempoolmemheapsmall memslab


功能 回傳值
呼叫正確的 destructor 函式來清除物件 void
*type *object
欲清除的物件類型 物件本體
64
65
66
67
68
69
70
71
72
void rtgui_type_destructors_call(const rtgui_type_t *type, rtgui_object_t *object)
{
/* destruct from children to parent */
if (type->destructor)
type->destructor(object);

if (type->parent)
rtgui_type_destructors_call(type->parent, object);
}

同樣的如果此物件類型是在某個物件類型的底下,先呼叫上層的 destruct;接著呼叫自己的 desturct 完成清除的動作。


最後來看一下 “object” 的刪除函式:填入 none 的旗標,並將物件種類設為 NULL;動作在 _rtgui_object_destructor 完成

功能 回傳值 *object
“object” 的刪除函式 void 欲清除的物件
37
38
39
40
41
42
43
44
45
/* Destroys the object */
static void _rtgui_object_destructor(rtgui_object_t *object)
{
/* Any valid objest should both have valid flag _and_ valid type. Only use
* flag is not enough because the chunk of memory may be reallocted to other
* object and thus the flag will become valid. */
object->flag = RTGUI_OBJECT_FLAG_NONE;
object->type = RT_NULL;
}