以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. CSS transform: scale()

    前言 transform属性允许你旋转,缩放,倾斜或平移给定元素.其中scale(x, y)就是实现元素缩放的属性值. scale(x, y)的 x 乘以原本元素的 x:y 乘以原本的元素 y,就可以 ...

  2. IO相关了解

    1.IO的概念 IO简单来讲就是对输入输出设备的简化表达形式 单片机中各种接口,进行数据流的传输 从磁盘中读取数据至内存,又或者从内存中写入磁盘 编程中的IO 此时的IO其应用程序的运行态,即进程-- ...

  3. LeetCode-1609 奇偶树

    来源:力扣(LeetCode)链接:https://leetcode-cn.com/problems/even-odd-tree 题目描述 如果一棵二叉树满足下述几个条件,则可以称为 奇偶树 : 二叉 ...

  4. 安装ElasticSearch7.6.2使用自带JDK

    平时用jdk8,但运行es7无法启动.在elasticsearch7以上的版本中会自带jdk.需要修改elasticsearch-env配置文件,就可以使用自带jdk版本,不影响其他java项目. w ...

  5. spring 事务不生效

    1.方法自身(this)调用问题,导致事务失效 非事务方法seckillVoucher()中调用的自身类的事务方法createVoucherOrder(). 解决办法: ps:要加aspj依赖,同时在 ...

  6. 【MySQL】导出到CSV

    http://www.yiidian.com/mysql/mysql-export-table-to-cvs.html 要将表导出为 CSV 文件,我们将使用SELECT INTO....OUTFIL ...

  7. Java——IO框架

    IO框架 流:内存与存储设备之间传输数据的通道 分类 流向 输入流:从硬盘等外设到内存的流 输出流:从内存到硬盘等外设的流 传输单位 字节流(抽象类InputStream,OutputStream): ...

  8. 创建一个与a.txt文件同目录下的另一个文件b.txt

    File file1 = new("d:\\a\\a.txt"); File file2 = new(file1.getParent(),"b.txt"): F ...

  9. RxJava2.x的理解与总结

    RxJava2.x的理解与总结 RxJava是一个基于观察者设计模式将链式编程和异步结合在一起的开源库. 链式编程 通过查看GitHub开源项目的简介开源知道,RxJava有几个基类. 他们分别适用于 ...

  10. iOS开发-应用评分引导

    导入头文件#import <StoreKit/StoreKit.h>+ (void)yoStoreReview{ if (@available(iOS 10.3, *)) { if ([S ...