以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的事件;

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

最新文章

  1. 使用Junit对Spring进行单元测试实战小结
  2. nyoj 613 免费馅饼 广搜
  3. csharp: NHibernate and Entity Framework (EF) (object-relational mapper)
  4. Dedecms最新版本存储型XSS
  5. JavaScript中Eval()函数的使用
  6. [改善Java代码]多线程使用Vector或HashTable
  7. MVC的发展
  8. sublime3快捷键汇总
  9. 调度器(scheduler)
  10. 【java】Date与String之间的转换及Calendar类:java.text.SimpleDateFormat、public Date parse(String source) throws ParseException和public final String format(Date date)
  11. ECharts将折线变平滑和去掉点的属性
  12. PO、POJO、BO、DTO、VO之间的区别(转)
  13. Linux下的Hadoop安装(本地模式)
  14. 著名的Log4j是怎么来的?
  15. 显卡安装一直循环在登录界面——解决之-T450安装显卡驱动和cuda7.5发现的一些问题
  16. 【IT笔试面试题整理】二叉搜索树转换为双向链表
  17. Oracle EBS INV 释放保留
  18. &#127538;Eclipse通过jdbc连接数据库制作简单登陆界面【新手必看】
  19. Eclipse Oxygen创建maven web项目(二)
  20. 【剑道】步法(Ashi Sabaki)

热门文章

  1. DrCush_0813_风湿性疾病, 药物和新冠指南
  2. GPIO 和轮询控制 LED 的状态
  3. AI 能多强「GitHub 热点速览」
  4. 数据结构和算法day1(Java)
  5. 论文学习 Dilated Inception U-Net (DIU-Net) for Brain Tumor Segmentation 1
  6. Oracle 11g 单机服务器ASM部署
  7. 四种语言刷算法之47. 全排列 II
  8. Linux——CentOS7无法ping通外网问题
  9. Fun Day
  10. 微信小程序tabBar图标显示失败问题