大家好,我要介绍的所有知识点都是WINCE/windows触摸屏DUI开源框架constvar(点击下载代码)开发过程中遇到的比较有讨论价值的问题。
本文要讨论的是可视化界面编辑工具与控件实现方式的一些关系。
可视化界面编辑工具是DIRECTUI界面框架不可少的工具,它应当是整个框架的比较重要的一部分。VS中的可视化开发工具很强大,比如用MFC拖出来的界面,接近所见即所得,而且消息事件方法属性的增删改查都很便利,接口也很统一,可以说已经做得非常好了。说实话,平常如果做工具软件对界面没要求的那种,哥不想用任何的DUI框架,直接上MFC是最快最好用的。
但是MFC的问题在于定制控件外观和形态非常麻烦,自绘什么的代价非常大并且极不灵活,而且很容易导致代码重复,MFC的自绘工程大一点到处都是各种控件GDI绘画,而且控件形态死板,适应变化能力差,这些都与MFC控件的实现方式有关,就是所有的控件都是以继承为主要的实现方式。可以参见CSDN上的类的继承树,像CtreeCtrl,CComboBox, CListCtrl 这些看上去”外观复杂”的控件都是从CWND派生的,CWND之所以重要,是因为他是所有控件的基类,从CWnd派生也就意味着是一个新的控件。 如果从CWND派生一个控件, 即使这个控件组合了再多的其它的CWnd派生的控件对象,它本身也还是一个控件,而不仅仅是一个组合。
这里引出的问题就是一个“新控件”有它自己的属性和默认形态,所以它在界面编辑工具上必须有一个对应的功能来创建该类控件。 所以打开MFC的控件工具箱,上面所述的那些控件都能看到有自己对应的创建工具,并且这些控件拖到界面都有自己的形态。但这种一一对应关系,导致界面编辑工作会需要把新增加控件添加到自己的“工具箱”,也就是新控件要在界面编辑上对应一种实现。这样的话,界面编辑工具就会不断的需要被修改。
举个简单的例子, 比如在MFC,我实现了一个自定义按钮控件从CButton派生,但是它上面还叠加了一个CEDIT控件用来显示按钮的某种状态,就这样一个看似简单的自定义控件, MFC的工具箱就拖不出来了,只有靠动态创建了或者是分别新建一个按钮和CEDIT,因为MFC的工具箱没有对我们自定义控件进行实现。 这样问题就来了,如果是强制要求使用者动态创建那就意味着这个可视化工具对这些新控件无法支持编辑,也就是”不可视”了, 如果是用后面的方法,控件又不是一个整体了,这就表示必须要在代码中对这个多个小部件进行逻辑关联,并且新控件的新属性也没法在界面编辑时设置, 这也就违背了与其它现有控件的一致性,也就是实现了就能用,不实现就只手动,这就是坑啊。
MFC哥是动不了它了,但是自已写的框架还是可以动的,就把这个新控件它添加到“工具箱”,实现它就可以了。没错是可以,但基于继承实现的控件库,为了适应多变的界面需求最终必定会变成很奇葩很臃肿,常期会因为一些小形态变化去创建一个新控件类别来描述这些差异,因为基类用的地方很多了,不敢动了,动会引起之前的实现不稳定。 或者复制一个类,稍作改动,来实现一个控件相类似的形态。这些方法确实非常猥琐,并最终让代码极其难看与令人生厌。就算维护的人忍耐力强,但是界面编辑工具怎么办呢?加一个控件就修改一下?不加又会导致到处是坑。
以上虽以MFC为例,但是DIRECTUI也是一样。一但以继承为实现新控件的方式,都会有这样的问题。
Constvar为了避免这个问题,采取了以组合为控件(或叫复杂控件)的实现方式。首先,对极其有限的几个基本控件在界面编辑工具上进行实现,3-5种都足够了。 其它的控件都有这几种基本控件拼成,当然,这样的话,复杂控件也就是任意新控件都必须有自己对应的逻辑,来把这些小部件组合起来。比如一个CListCtrl, 在这里可能就是一系列的btn, static组成的。在代码中CListCtrl也不再派生于CWND,它不需要派生于任何类,它只要组合这些小部件并控件它们就可以了。这样的好处就是,加什么控件,界面编辑工具都不需要再重新去实现一个对应的功能了。并且用这些小部件组合的应变能力很强。 缺点也就是这些部件都是独立的个体,是独立的基本控件,有自己的属性,它们在界面编辑时无法表现成一个新控件, 也就是界面编辑器只能拖出一个界面外观, 它的灵魂还得用代码控制。但这相对于第一种来说已经简单并强大很多。
总的来说,如果能控制控件在有限集以内不再新增,并且全部把它们界面工具上加以实现,继承这种实现还是有一点点优势的,但实际上可操作性极差,基本不可能。 所以常期会导致这种界面编辑工具的烂尾。
组合解决了这一点,但是在所见即所得方面略输一二,并且在新控件的各种属性初始化只能体现到代码或都辅助代码中或者是附加其它的工作中,说白了就是界面编辑工作根本没有那玩意儿,要设置那些属性得想别的附加办法。