一个简单的UI框架思想

嵌牛导读:写了这么久,终于接触到UI了。在我的印象中UI的因果逻辑我完全不懂。在《跟我一起学C++第三季》中接触了一个非常简陋的UI框架,然后结合最近学习wxWidgets的经验,所以想纯靠伪代码写一下UI框架干的事情。

嵌牛鼻子:UI框架

嵌牛提问:UI框架window之间的通信如何进行的

嵌牛正文:

事件驱动

本UI是事件驱动模型。什么是事件驱动模型呢?实际上是比较抽象的。其实就和Reactor模式一样。当我们移动鼠标,或者点击鼠标,键盘输入。就会产生一个事件。我们针对这些事件写好对应的eventHandler。当事件一个一个发生的时候,eventHandler就一个一个调用。所以是没有涉及多线程,因此如果某个eventHandler比较耗时,就会导致我们感觉起来很卡。实际上就是因为其它操作还在排队,并没有被调用。

Application 代表运行的程序,其逻辑很简单。

while(1)

{

    // 当有事件到来的时候被唤醒,

    eventID = getEventID();

    switch(eventID)

    {

    case ButtonClicked:

        eventHandler();

    break;

    case ...

    }

}

Application的实现一般为单例模式,因为运行的程序只有一个。

App单例的实现

WindowBase

我们需要将图形绘制到屏幕上。而屏幕是由一个一个像素点构成的。我们绘图的过程实际上就是向这些像素点填充的一个过程。有点小孩子在方格上填充色彩的感觉。

ScreenBuffer

因此我们就需要抽象出一个二维数组。用来代表图形上的像素。ScreenBuffer,其是WindowBase的嵌套类。

图形的表示

我们在坐标轴上确定一个矩形需要俩个东西。

图形的起始坐标。——Position

图形的宽度和高度。——Size

这样我们就知道了我们的图形是要画在哪个位置。

举个栗子:

比如说我们当前的画布是高25。宽80。由25 * 80个像素点构成我们的画布。

当我们想要画一条线的时候。我们给定起始点(0,4)。

for(int i = 0; i < 80; ++i)

    buffer[4][i] = '-'

这样我们就在buffer中画出了一条线。而buffer常常也被我们称为逻辑屏幕。如果需要其呈现到实际屏幕上,只需要调用相关的接口(暂定为refresh)将buffer中的数据刷新到屏幕上即完成绘图。

便利的接口

我们就可以提供一些便利的接口给派生类。

DrawHLine(startX, startY, length);

DrawVLine(startX, startY, length);

FillReact(startX, startY, width, length);

Write(char)

Write(string)

refresh()

Window

Window类用来抽象窗口。我们看到的一个Button,一个Label,一个子窗口都是窗口。Window是继承自WindowBase的。因为每个Window都需要自己的图形。所有都会有自己的Draw方法。

可能的派生类

Button

Label

继承Window的子类有很多。它们之间的最大区别在于绘制自己的图形方式不同。从而呈现出不同的样子。

Window标识

对于不同的Window或者说控件来说。我们都需要一个标识。标识主要是用来关联eventHandler的。

比如说。

在Exit和About这俩个Button上。我们发生ButtonClicked事件的eventHandler肯定是不同的。但事件类型时一样的。

所以我们的回调函数不仅仅需要确定发生事件的类型,同时还需要确定发生事件的Window。

Window之间的关系

以一个一般的窗口为例。我们总是有一个root窗口。这个窗口代表着这个程序,关闭这个窗口的同时也会导致程序的退出。

root窗口下有很多子窗口。子窗口下又有很多子窗口。关闭一个窗口会导致所有子窗口的关闭。不难明白窗口之间的关系是呈现树状关系。

Window之间的通信

这里直接举了wxWidget上的例子。

可以看到我们总共有5个Window。

TotalWindow

LeftWindow

PlusWindow(实际上是PlusButton,Button类继承自Window)

MinusWindow

RightWindow

当我们点击+号的时候,我们希望右侧的窗口的数值+1。这该怎么通信呢?

我的第一反应是去做一个eventfd。当+点击的时候,就向eventfd写一个char。然后RightPanel注册了一个事件。但是想想就觉的麻烦。

实际上我们可以直接利用树装关系。通过Parent来获得RightPanel。

大致的伪代码思路如下。

LeftPanel::OnPlus()

{

    count++;

    p = getParent();

    p->rPanel->text = count;

    p->rPanel->refresh();

}

Event

事件类。我觉的是最好写的。

eventID用来标识事件的类型。

eventHandler事件的回调函数要准备好。

因为事件触发的时候,大部分时候会重绘Window,所以我们需要让事件保留Window的指针。

总体关系如下:

一个RootWindow可以有无数的childWindow。每个Window可以绑定无数个事件。每个事件只能关联到一个Window。

————————————————

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,185评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,445评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,684评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,564评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,681评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,874评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,025评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,761评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,217评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,545评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,694评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,351评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,988评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,778评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,007评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,427评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,580评论 2 349

推荐阅读更多精彩内容