关于UI回调Invoker的实现(一)
打算写一个DirectUI库,在写其中底层窗口的回调构造的时候遇到一个问题。
Invoker是一个模板,因为closure的关系,它必须保存一个类对象的指针,和回调函数的地址。而函数调用的时候,就可以用一个通用的接口invoke就行了。
接口的声明如下:
class IOperation
{
public:
virtual ~IOperation() {};
virtual void Invoke(IUIWnd* wnd, const EventArg& arg) = 0;
};
回调函数调用的时候,调用Invoke(...),传入(谁)那个窗口调用的,和调用的可能需要的数据。因为回调函数可能有不同的参数,为了方便,我把所有的回调都封装成参数相同的函数。数据都被封装到EventArg结构里面,这里我们不讨论EventArg。
Invoker类继承了IOperation这个接口,声明如下:
template<class TObj>
class Invoker : public IOperation
{
public:
typedef void (TObj::*TFunc)(IUIWnd*, const EventArg&);
struct closure
{
TObj* _Obj;
TFunc _Func;
}; Invoker(TObj* obj, TFunc func)
{
_closure._Obj = obj;
_closure._Func = func;
} Invoker(const Invoker& ci)
{
_closure._Obj = ci._closure._Obj;
_closure._Func = ci._closure._Func;
} bool Equel(TObj* obj, TFunc func)
{
if (_closure._Obj == obj && _closure._Func == func)
{
return true;
}
return false;
} virtual void Invoke(IUIWnd* wnd, const EventArg& arg)
{
(_closure._Obj->*_closure._Func)(wnd, arg);
} private:
closure _closure;
};
里面有个closure,这个就不多讲了,博客园某博主翻译过一篇,写得很好:点击这里查看。感谢博主@Jans的翻译。
从invoker类可以很明了的看到,怎么去构造一个Invoker(再重复一遍,回调函数是一个类的成员函数,因此,在类外调用的时候,需要一个类成员的对象(或对象指针),和成员函数的地址。)
假设现在有一个button,有一个操作是要相应按下的操作。
virtual IOperation* SetPressFunc( IOperation* oper ) = 0;
我的思路是,先构造一个Invoker<TObj> invoker(obj, func), 然后把invoker的指针赋给button中响应按下操作的IOperation指针。
假设有个button对象:btnOK, 于是就用 btnOK->SetPressFunc(invoker); 的确工作了。还算不错。
但是有个小问题:btnOK必须是已经初始化完成了的,也就是说,已经 new 出来了。说实话,我可不想让库的使用者自己去调用 new Button()。竟然库是我写的,我必须用库管理好这些窗口(控件)。我会在程序初始化,读窗口配置文件的时候,为程序员用户,new好这些窗口;在程序结束的时候,释放掉。
然后这也引出了一个问题:窗口都是库来初始化的,程序员用户想让按钮A被点击的时候,相应自己写的回调函数。作为用户,我都不知道A的对象在哪,叫什么名字,这怎么把对调绑定到这个按钮上?真这样了,用户肯定要骂我。程序员骂人都是很透彻的,代码里面fuck不少,你懂的。我需要写一个让你定义的窗口指针,关联到你想关联的窗口对象上。
现在整理一下,如果我是用户,我当前所有的资源。
1、界面配置文件是我用UI编辑器写的,每个窗口(控件)都有一个唯一(准确地说,是父窗口下唯一的)标识吧,比方说,枚举ID(MFC就是这么干的),或者名字。
2、类对象,和要回调成员函数的地址。用于生成一个invoker;
OK,就这么多,够了。
我写了一个关联的函数 InitControl:
template<class TWnd, class TObj>
void InitControl(TObj* obj, TWnd*& out, const std::wstring& id)
{
InitControl(obj, out, obj->getMainWnd(), id);
}
又是模板 = =%。。好吧,其实这个模板函数里面调用的InitControl,还是个模板。这些程序员用户不用管,我现在只是说明原理。如果写完了,开源之后,你们再去研究代码。
别骂我,你想想啊,你的一个类,肯定是一个界面吧,一个程序可能有各种界面吧。我不能为每个类对象去写一个InitControl吧。嘿嘿。要付出代价的。
InitControl参数说明:第一个,类对象指针;第二个,需要关联的窗口指针;第三个参数,要关联的窗口的id,字符串表示哈。
比方说,我CUIXXX类下面,有一个button,声明是IUIButton* btnTest;界面配置文件里面,我想关联的对象的id是btnTest;
我关联的时候,就 InitControl (this, btnTest, L"btnTest"); 然后btnTest就跟我想关联的按钮关联上了。
现在我想让它顺便把按下的响应函数也加上去。好吧,我要改InitControl了。
template<class TWnd, class TObj>
void InitControl(TObj* obj, TWnd*& out, const std::wstring& id,IOperation* oper)
{
InitControl(obj, out, obj->getMainWnd(), id);
//....
}
很显然,这样是不行的。
IOperation只是记录了一个类对象和类成员函数的地址,以及调用所执行的操作。
一个窗口有鼠标左键单击事件,可能有鼠标右键单击事件,以及其它事件:例如,editbox可能有TextChange事件,Combobox有ItemChange事件,就单个IOperation是无法记录这么多事件的,因此,我们需要引入一个中间的传递机制。
把问题留在这里。下一篇我们再讲。
=====>THE END<=====
关于UI回调Invoker的实现(一)的更多相关文章
- 关于UI回调Invoker的实现(二)
上篇我说到,光有一个IOperation*的指针,是无法记录这么多事件的.由于无法确定要把回调绑定到哪个事件上,因此,我们需要引入一个中间的传递机制. 没有看到前面的请先查阅上一篇 关于UI回调Inv ...
- 一个强大的UI node 抽象
基于cocos2d -x的一个强大的 界面对象的基类 ---@type uinode ui 对象的抽象 --@usage -- 界面打开的执行流程 -- 带*的是可选重写的函数,不带*的为必须实现的 ...
- [Android]使用MVP解决技术债务(翻译)
以下内容为原创,欢迎转载,转载请注明 来自天天博客:http://www.cnblogs.com/tiantianbyconan/p/5892671.html 使用MVP解决技术债务 原文:https ...
- iOS开发项目之MVC与MVVM
MVC MVC,Model-View-Controller,我们从这个古老而经典的设计模式入手.采用 MVC 这个架构的最大的优点在于其概念简单,易于理解,几乎任何一个程序员都会有所了解,几乎每一所计 ...
- 猿题库 iOS 客户端架构设计
原文: http://mp.weixin.qq.com/s?__biz=MjM5NTIyNTUyMQ==&mid=444322139&idx=1&sn=c7bef4d439f4 ...
- 猿题库 iOS 客户端架构设计-唐巧
序 猿题库是一个拥有数千万用户的创业公司,从20013年题库项目起步到2015年,团队保持了极高的生产效率,使我们的产品完成了五个大版本和数十个小版本的高速迭代. 在如此快速的开发过程中,如何保证代码 ...
- [iOS] 响应式编程开发-ReactiveCocoa(二)
RAC实现图片下载功能 在实现异步RAC下载图片的过程中,需要注意以下几点: • 通过 NSURLConnection 对象的 +(RACSignal *)rac_sendAsynchronousRe ...
- 用好lua+unity,让性能飞起来——luajit集成篇/平台相关篇
luajit集成篇 大家都知道luajit比原生lua快,快在jit这三个字上. 但实际情况是,luajit的行为十分复杂.尤其jit并不是一个简单的把代码翻译成机器码的机制,背后有很多会影响性能的因 ...
- Android ANR的产生与分析
ANR即Application Not Responding应用无响应,一般在ANR的时候会弹出一个应用无响应对话框.也许有些开发者在使用某些手机开发中不在弹出应用无响应弹出框,特别是国产手机An ...
随机推荐
- 云捕Redis实战
本文由作者余宝虹授权网易云社区发布. Redis是一个支持丰富数据结构的分布式key-value系统,Redis在云捕系统的地位相当重要,碰到的问题也比较多,最近才解决了一个遗留的老大难问题.由于15 ...
- WordPress插件Social Warfare<=3.5.2 无需登录RCE漏洞
该漏洞只存在于Social Warfare插进的3.5.0.3.5.1和3.5.2版本中,其他版本不存在. 2019年3月21日插件作者紧急发布了3.5.3版本以修复高危的RCE漏洞,在<=3. ...
- 1、认识Struts2
先上百度百科的权威说明:一定注意我下面做标记的话: 框架就是一个半成品,就是可以帮我们完成一些业务 1. 什么是Struts2的框架 * Struts2是Struts1的下一代产品,是在 struts ...
- linux命令之文件备份与压缩命令
1.tar:打包备份 该命令是将多个命令打包到一起,并且可以实现解压打包.打包是将多个文件或者目录变成一个总的文件,压缩则是将一个大的文件通过压缩算法变成一个小文件. 参数 说明 z(常用) 通过gz ...
- php中的XML DOM(10)
1.PHP DOM (1) Php中的DOM跟javascript不一样,属性不用另外增加一个节点 2.主要类 DOMDocument :文档类 DOMNodeList :节点列表类 DOMNode ...
- 关于布尔值bool值
1.空或0布尔值为false,非0或非空为true 2.多个判断连在一起判断优先级:(括号)>not >and >or and: print(27 and 1>4) - ...
- 【ocp-12c】最新Oracle OCP-071考试题库(37题)
19.choose the best answer View the Exhibit and examine the structure of the PROMOTIONS table. Evalua ...
- 使用wblockCloneObjects从后台读取dwg文件复制实体到当前数据库
AcDbDatabase *pNewDb=new AcDbDatabase(Adesk::kFalse); if (pNewDb == NULL) { return; } Acad::ErrorSta ...
- [转]NSProxy实现AOP方便为ios应用实现异常处理策略
[转载自:http://blog.csdn.net/yanghua_kobe/article/details/8395535] 前段时间关注过objc实现的AOP,在GitHub找到了其中的两个库:A ...
- OO第二单元の小结
第二单元(线程与电梯问题)总结博客 三次作业的设计策略 第一次:本次作业只有一部电梯,而且不用捎带.因此,我一共设计了两个线程:一个负责管理输入,一个负责电梯运行.同时,我将调度队列设置为单例模式,里 ...