以GuiLiteSamples中的HelloSlide 为例,剖析一下GuiLite的设计思路和刷新机制;

首先是main.cpp; 可以分成3部分:

1、根据fb mode拿到对应的phy_fb, 后续的绘制都在这个fb上执行;

2、init _std_io(), 初始化输入设备,这里创建一个线程专门用于输入事件的poll, 检测到对应事件后, 直接调用c_slide_group的on_touch方法;

void sendTouch2HelloSlide(int x, int y, bool is_down)
{
is_down ? s_root.on_touch(x, y, TOUCH_DOWN) : s_root.on_touch(x, y, TOUCH_UP);
}

这个s_root就是在layout UI的时候我们创建的一个static的c_slide_group;

//////////////////////// layout UI ////////////////////////
c_page s_page1, s_page2, s_page3, s_page4, s_page5;
static c_slide_group s_root;
static WND_TREE s_root_children[] =
{
{ NULL,0,0,0,0,0,0 }
};

3、startHelloSlide(phy_fb, screen_width, screen_height, color_bytes);//never return;

摘取关键的代码片段进行剖析:

在UIcode.cpp中,有UI初始化的code

void create_ui(void* phy_fb, int screen_width, int screen_height, int color_bytes)
{
load_resource();
s_display = new c_display(phy_fb, screen_width, screen_height, UI_WIDTH, UI_HEIGHT, color_bytes, (1 + 5)/*1 root + 5 pages*/);
c_surface* surface = s_display->alloc_surface(Z_ORDER_LEVEL_1);
surface->set_active(true); s_root.set_surface(surface);
s_root.connect(NULL, ID_ROOT, 0, 0, 0, UI_WIDTH, UI_HEIGHT, s_root_children); s_root.add_slide(&s_page1, ID_PAGE1, 0, 0, UI_WIDTH, UI_HEIGHT, NULL);
s_root.add_slide(&s_page2, ID_PAGE2, 0, 0, UI_WIDTH, UI_HEIGHT, NULL);
s_root.add_slide(&s_page3, ID_PAGE3, 0, 0, UI_WIDTH, UI_HEIGHT, NULL);
s_root.add_slide(&s_page4, ID_PAGE4, 0, 0, UI_WIDTH, UI_HEIGHT, NULL);
s_root.add_slide(&s_page5, ID_PAGE5, 0, 0, UI_WIDTH, UI_HEIGHT, NULL);
s_root.set_active_slide(0);
s_root.show_window(); while(1)
{
thread_sleep(1000000);
}
} //////////////////////// interface for all platform ////////////////////////
void startHelloSlide(void* phy_fb, int width, int height, int color_bytes)
{
create_ui(phy_fb, width, height, color_bytes);
}

上面只是在比较浅显的层面看了一下,现在要深入进入,看看slide的操作是如何传递的,以及重绘是如何发生的:

首先是s_root.on_touch() 方法;我们在GuiLite.h 中找到对应的类和方法的实现如下:

class c_slide_group : public c_wnd {
public:
...
inline virtual void on_touch(int x, int y, TOUCH_ACTION action);
protected:
c_wnd* m_slides[MAX_PAGES];
int m_active_slide_index;
c_gesture* m_gesture;
};

对应的实现是一个虚函数,虚函数的语义是子类可以重载这个函数,我们先看下在这一层的实现:

inline c_slide_group::c_slide_group()
{
m_gesture = new c_gesture(this);
for (int i = 0; i < MAX_PAGES; i++)
{
m_slides[i] = 0;
}
m_active_slide_index = 0;
}
inline void c_slide_group::on_touch(int x, int y, TOUCH_ACTION action)
{
x -= m_wnd_rect.m_left;
y -= m_wnd_rect.m_top;
if (m_gesture->handle_swipe(x, y, action))
{
if (m_slides[m_active_slide_index])
{
m_slides[m_active_slide_index]->on_touch(x, y, action);
}
}
}

这里看到的是,最后调了c_wnd类的on_touch方法;实现如下:

virtual void on_touch(int x, int y, TOUCH_ACTION action)
{
c_wnd* model_wnd = 0;
c_wnd* tmp_child = m_top_child;
while (tmp_child)
{
if ((tmp_child->m_attr & ATTR_PRIORITY) && (tmp_child->m_attr & ATTR_VISIBLE))
{
model_wnd = tmp_child;
break;
}
tmp_child = tmp_child->m_next_sibling;
}
if (model_wnd)
{
return model_wnd->on_touch(x, y, action);
}
x -= m_wnd_rect.m_left;
y -= m_wnd_rect.m_top;
c_wnd* child = m_top_child;
while (child)
{
if (child->is_focus_wnd())
{
c_rect rect;
child->get_wnd_rect(rect);
if (true == rect.PtInRect(x, y))
{
return child->on_touch(x, y, action);
}
}
child = child->m_next_sibling;
}
}

看到这里,基本上接触到GUI的核心概念了,也就是VieeTree。所谓ViewTree是指,GUI的所有View都是以Tree的数据结构来组织的。我们重点关注c_wnd这个类,看看里面到底有何玄机:首先我们看下一个c_wnd是如何添加到Tree的,首先是,connect方法:

virtual int connect(c_wnd *parent, unsigned short resource_id, const char* str,
short x, short y, short width, short height, WND_TREE* p_child_tree = 0)
{
if (0 == resource_id)
{
ASSERT(false);
return -1;
}
m_id = resource_id;
set_str(str);
m_parent = parent;
m_status = STATUS_NORMAL;
if (parent)
{
m_z_order = parent->m_z_order;
m_surface = parent->m_surface;
}
if (0 == m_surface)
{
ASSERT(false);
return -2;
}
/* (cs.x = x * 1024 / 768) for 1027*768=>800*600 quickly*/
m_wnd_rect.m_left = x;
m_wnd_rect.m_top = y;
m_wnd_rect.m_right = (x + width - 1);
m_wnd_rect.m_bottom = (y + height - 1);
c_rect rect;
get_screen_rect(rect);
ASSERT(m_surface->is_valid(rect));
pre_create_wnd();
if (0 != parent)
{
parent->add_child_2_tail(this);
}
if (load_child_wnd(p_child_tree) >= 0)
{
load_cmd_msg();
on_init_children();
}
return 0;
}

先看接口,再看实现,首先,一个node添加到Tree上,一定是要首先指定其parent节点的,这个毫无疑问;

如果parent不是NULL,说明很可能,这个节点还有兄弟节点,那么这个时候就要调用parent的add_child_2_tail方法把this这个节点add进去,具体如下:

void add_child_2_tail(c_wnd *child)
{
if (0 == child)return;
if (child == get_wnd_ptr(child->m_id))return;
if (0 == m_top_child)
{
m_top_child = child;
child->m_prev_sibling = 0;
child->m_next_sibling = 0;
}
else
{
c_wnd* last_child = get_last_child();
if (0 == last_child)
{
ASSERT(false);
}
last_child->m_next_sibling = child;
child->m_prev_sibling = last_child;
child->m_next_sibling = 0;
}
}

添加过程叙述如下:

先判空,再判等,这两种情况都无需进行添加操作;然后再判断m_top_child是否为空,m_top_child是当前节点的第一个插入的子节点,所以叫top child, 后面简称长子;若长子为空,则本次插入的child就是长子,否则这次插入的就是兄弟节点,而且要找到当前年龄最小的节点,在其之后进行插入;

这里分析完后,回到刚才的connect函数,继续看后面load_child_wnd的操作:

typedef struct struct_wnd_tree
{
c_wnd* p_wnd;
unsigned int resource_id;
const char* str;
short x;
short y;
short width;
short height;
struct struct_wnd_tree* p_child_tree;
}WND_TREE;
int load_child_wnd(WND_TREE *p_child_tree)
{
if (0 == p_child_tree)
{
return 0;
}
int sum = 0;
WND_TREE* p_cur = p_child_tree;
while (p_cur->p_wnd)
{
if (0 != p_cur->p_wnd->m_id)
{//This wnd has been used! Do not share!
ASSERT(false);
return -1;
}
else
{
p_cur->p_wnd->connect(this, p_cur->resource_id, p_cur->str,
p_cur->x, p_cur->y, p_cur->width, p_cur->height, p_cur->p_child_tree);
}
p_cur++;
sum++;
}
return sum;
}

注意,如果这个添加的子树不为空的话,这里会产生递归的操作,也就是说在connect中,又产生了connect。

再次回到之前对c_slide_group类的on_touch方法的回顾,可以看到这个类自带c_gestrure; 通过这个

m_gesture->handle_swipe(x, y, action)

处理swipe的操作,这里会影响m_active_slide_index, 以及gestrue处理后还会让c_slide_group继续在更新后的m_active_slide_index处理swipe的事件;

可以猜到,画面的刷新就是在这里完成的,具体类和时序,我们下一章继续分析;

GuiLite 学习笔记(一) Mainloop与ViewTree的更多相关文章

  1. DBus学习笔记

    摘要:DBus作为一个轻量级的IPC被越来越多的平台接受,在MeeGo中DBus也是主要的进程间通信方式,这个笔记将从基本概念开始记录笔者学习DBus的过程 [1] DBus学习笔记一:DBus学习的 ...

  2. RabbitMQ学习笔记(六) RPC

    什么RPC? 这一段是从度娘摘抄的. RPC(Remote Procedure Call Protocol)——远程过程调用协议,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的 ...

  3. Java学习笔记 -- Java定时调度工具Timer类

    1 关于 (时间宝贵的小姐姐请跳过) 本教程是基于Java定时任务调度工具详解之Timer篇的学习笔记. 什么是定时任务调度 基于给定的时间点,给定的时间间隔或者给定的执行次数自动执行的任务. 在Ja ...

  4. 【cocos2d-x 3.x 学习笔记】对象内存管理

    内存管理 内存管理一直是一个不易处理的问题.开发人员必须考虑分配回收的方式和时机,针对堆和栈做不同的优化处理,等等.内存管理的核心是动态分配的对象必须保证在使用完成后有效地释放内存,即管理对象的生命周 ...

  5. Cocos2d-x学习笔记(十四)CCAutoreleasePool具体解释

    原创文章,转载请注明出处:http://blog.csdn.net/sfh366958228/article/details/38964637 前言 之前学了那么多的内容.差点儿全部的控件都要涉及内存 ...

  6. ‎Cocos2d-x 学习笔记(3.1) Scene 场景与场景切换

    1. Scene 简介 游戏中我们看到/看不到的所有元素都是展示在场景之Scene上. 我们可以把场景比作放在地上的没盖纸箱,层Layer是纸箱里堆放的玻璃,Sprite等元素画在玻璃Layer上,这 ...

  7. js学习笔记:webpack基础入门(一)

    之前听说过webpack,今天想正式的接触一下,先跟着webpack的官方用户指南走: 在这里有: 如何安装webpack 如何使用webpack 如何使用loader 如何使用webpack的开发者 ...

  8. PHP-自定义模板-学习笔记

    1.  开始 这几天,看了李炎恢老师的<PHP第二季度视频>中的“章节7:创建TPL自定义模板”,做一个学习笔记,通过绘制架构图.UML类图和思维导图,来对加深理解. 2.  整体架构图 ...

  9. PHP-会员登录与注册例子解析-学习笔记

    1.开始 最近开始学习李炎恢老师的<PHP第二季度视频>中的“章节5:使用OOP注册会员”,做一个学习笔记,通过绘制基本页面流程和UML类图,来对加深理解. 2.基本页面流程 3.通过UM ...

  10. 2014年暑假c#学习笔记目录

    2014年暑假c#学习笔记 一.C#编程基础 1. c#编程基础之枚举 2. c#编程基础之函数可变参数 3. c#编程基础之字符串基础 4. c#编程基础之字符串函数 5.c#编程基础之ref.ou ...

随机推荐

  1. 代码随想录算法训练营day02 | leetcode 977/209/59

    leetcode 977   分析1.0:   要求对平方后的int排序,而给定数组中元素可正可负,一开始有思维误区,觉得最小值一定在0左右徘徊,但数据可能并不包含0:遂继续思考,发现元素分布有三种情 ...

  2. Word 设置页眉、页脚、页码

    页眉:在 Word 文档中,每个页面的顶部区域为页眉.常用于显示文档的附加信息,可以插入时间.图形.公司微标.文档标题.文件名或作者姓名等. 页脚:页脚与页眉的作用相同,都可以作为显示文档的附加信息, ...

  3. vue前端实现将页面显示内容生成pdf文件的几种方法,html2canvas、dom-to-image、jspdf(带分页)基本使用以及介绍

    实际开发需求:vue项目中,根据数据结构生成echarts图表组件,生成带有样式的图表以后,点击下载按钮,把图表以pdf格式的文件下载到本地 实现思路:将vue界面的echarts组件生成图片,然后使 ...

  4. 如何免费获取高清动图并将其插入到Markdown中

    一.发现问题 我在做excel笔记的时候,想要动态展示操作excel的过程,由于我平时的笔记都是使用markdown记录,所以要在md文件中插入动图. 二.解决问题 细化问题 1.如何将动图插入到md ...

  5. 【调试】ftrace(一)基本使用方法

    简介 Ftrace是Linux Kernel的官方tracing系统,支持Function trace.静态tracepoint.动态Tracepoint的跟踪,还提供各种Tracer,用于统计最大i ...

  6. Visual Studio 2022 不支持 .NET Framework 老版本 项目解决办法

    Visual Studio 2022 不支持 .NET Framework老版本 (4.5) 项目解决办法 新电脑安装的是Visual Studio 2022,打开老项目的时候发现没有.net fra ...

  7. uni-app (uView) select下拉框添加模糊搜索

    先看效果: 因为uniapp内置的下拉查询是没有输入模糊搜索的,有的列表选项过多时还是需要这个搜索功能,所以只能自己筛选 (前台.后台两种方法). 下面是代码: <template> &l ...

  8. s-hr实现单点登录,看我这份笔记就够了!!!

    https://pan.kingdee.com/s/MTA5ODk4NyxjNzk1来自:云之家企业云盘

  9. quasar+vue、Input组件绑定两个值

    项目中关于一个只读input绑定两个值,例如input显示取值范围,通过查看vue及quasar文档找出解决方法,如下代码: <q-input v-bind:value="`${det ...

  10. 2022-05-31内部群每日三题-清辉PMP

    1.由于项目执行期间的范围变更,项目经理确定供应商必须对一个已在使用的产品模块进行更改.项目经理首先做什么? A.准备一份变更请求,以更新供应商的合同条款 B.检查采购管理计划和合同条款 C.将该信息 ...