IT技术博客大学习 共学习 共进步

界面程序开发的一些总结

Vimer 2010-04-16 09:20:18 浏览 3,044 次

    一直纠结于究竟该用什么标题:总结其实说不上的,毕竟自己经验也不怎么丰富,充其量也就是一小结;换用感悟之类的也不大合适,这会让人以为我故作老成、经验丰富,诱骗大家,知根知底的朋友们当然很容易就揭穿我了。想来想去,虽然以后还有很长的路要走,但就暂且用“总结”来回顾一下自己做界面开发的一些经验和心得吧。

    第一语言是C++,所以当初选择学习MFC似乎是理所当然的了。这是我最开始上网找资料以决定学什么时认定的道理,那时以为这是当然的嘛,可在过去这么长时间后,回头想想,甚是为自己的盲目而汗颜。我不是说MFC不好,在我看来,MFC是十分强大而优秀的,因此才会成为VC开发人员的首选。它的框架之庞大复杂,虽然使得其功能强大,而且拓展性强,但对于初学者来说实在太过晦涩,其架构和模版在简单明了的windows程序基础上加入了大量设计模式和其他常见的界面开发理念,如所见即所得和文档/视图模型,而这些东西,对于初学者来说是很难理解的。初学者固然可以通过模版向导来生成一个程序框架,也可以在窗口设计器里用鼠标拖拽出你的窗体,但除此之外呢?在相当长一段时间里,我只知道该怎么用MFC,但不知道为什么,经常性的觉得它的模版的架构是莫名其妙。

    因为经常性的要用到,所以我经常为给程序加入某个功能而到处查资料,实现后却也只是一知半解,即使在我浏览过几遍精通MFC等书,依然无法为我答疑解惑,即使是最权威的《mfc windows程序设计》一书也是如此。我一度怀疑自己的学习方法,后来知道,问题的根本不是学习方法,而是学习顺序。提到的这些书,都是工具书,也仅仅是工具书而已,对于经验丰富的老鸟,它们能够提供查询等价值,但对于初学者它们只能告诉你可以这样做或者应该这样做,而无法告诉你为什么要这样做。但我相信,每一个有学习欲望的人,都是渴望了解为什么的,这也是为了能继续前进而必须要解决的。

    要学习一套类库最好的方法是看文档和代码,但很可惜MFC是不开源的,它的封装太成功了,完美到让每一个使用它的人难以深入到底层,也就不能洞悉一切,只能盲目的在模版的框架下机械的是用一些类和API。

    窗口之间是如何通信的?系统消息如何发送与接收?还有鼠标键盘的各种操作,自定义消息的处理,这些是初学者学要掌握而在MFC框架下很难看到的细节,当你需要使用这些东西时,你会发现不论使用多少次,这些东西永远都是这么陌生。是的,当然会感到陌生了,因为MFC的关系,我们离这些东西的实现太远了。

    后来我冷落了MFC一段时间,在我看来,它就是一个怪物,实在难以驾奴。我的突破来自一本书,是关于windows程序设计的,但不是讲MFC的,我在翻看mfc windows程序设计一书的序时,看到作者提到了这本书,叫《Programming Windows》,于是我去看了,然后顿悟了。我觉得每一个学习窗口程序开发的人都要看一看这本书,而且要精读,不管你使用的是什么语言,都可以拿来参考。

    当我初学MFC时遇到问题上网寻找解决方法,总是会找到一些很奇怪的方法,这些方法一眼看去就不是MFC框架里的东西,很显然要底层的多,有各种系统的API,还有大量的全局函数,甚至还有不少内核级函数,比如检测鼠标键盘状态,发送系统消息,设置系统热键,获取消息队列等,这些东西从哪里来的?现在我知道,都可以从《Programming Windows》中找到解答,而且是告诉你为什么。

    于是后来抛开了MFC的那套模版的类库,仅仅基于windows API来写自己的窗口,处理消息,这样的效果的显著的,如果连这样过程式的窗口处理都理解不了无法驾奴的话,你怎么去掌握并精通MFC那一套庞大复杂的经过精心封装的类库呢?

    到这里我才感觉界面开发的学习总算是到了一个阶段。你能够认识到,所谓的窗口程序,看上去很复杂,但在我看来只有两样东西,那就是窗口和消息队列。这种认识类似于行家去繁就简的能力,初学者看来是一团乱麻,真正了解的人却知道,所有的东西都是虚的,是为了实现一个功能而包装成这样或那样,但真正的基础,确实再简单明了不过了。后来看过一些其他的开发库,比如Qt,CEGUI等,无论各个库是如何宣传的,比如Qt的信号和槽,CEGUI的事件注册和回调函数等,在这种认识基础上都是统一的,或者说这些界面开发库设计的出发点都是差不多的,窗口的背后是一个消息队列。

    我觉得如果如果能够有这样的认识,那就算是进入到第一个阶段了,这时的你能够理解窗口程序的真正意义,窗体和消息队列成为了你的工具,你发现自己能够随心所欲的操纵窗口做任何事情。这个阶段的你能完成的功能有两个典型例子,一个是基于窗口的多窗体通信,另一个是基于系统消息队列的钩子程序。

    是的,到这里我们已经可以完成看起来比较复杂,功能上也足够强大的窗口程序了,但人的需求是无限的,这时我们就会觉得自己的窗口太单调,不够漂亮……

    经过在第一阶段的痛苦磨炼,我们总算是打下了比较坚固的基础,可以快速的开发各种常见的窗口程序,各种控件的应用比较熟练,也能利用消息机制完成各种需要的功能。但一个完整的窗口程序不仅仅是由一堆简单的控件堆砌而成,在很多场合下,控件的事件响应函数需要调用具体的、功能性的代码。打个比方,尽管你可以使用如CPicture这些MFC提供的控件为你的窗口添加一些图片,但老实说,你并不知道这个控件中到底是怎么添加图片的,我发现,大多数情况下我们都是在窗口的属性编辑器里添加自己需要的属性,很少自己手动的添加一些功能性的代码。这个阶段我们的程序的一个明显的特点就是没有属于自己的控件,我们从来不会用面向对象的方式来开发自己的控件。

    因为这样,我们可以做的事情很少。例如,窗口程序中,最常见的就是添加各种图片元素,复杂一些的如flash,此外还有一些其他的多媒体元素,如让窗口播放视频,显示OpenGL等的3D实时渲染结果,自定义绘制各种图表等。如果不能做到这些,我觉得就算不上真正懂了界面开发的技术,因为提到的所有这些,都关系到界面开发中最重要的技术之一,那就是GDI。GDI是每一个窗口程序都不可或缺的技术和元素,没有它,你的窗口不免功能单调、有形无神。

    我曾在这些问题前徘徊了很久,尽管有这样或那样的教程,但大多杂乱无章,而且网上的资料看多了你就会发现几乎所有的教程追根朔源都引自有限的几个版本,就是这几个版本,也只是机械的调用API,你拿来后经常会出错,往往是因为这些作者也没有弄透彻。

    学到了这里,去理解GDI的技术,就是迫在眉睫的需要了,如果不突破GDI的封锁,3D渲染输出、图表绘制、游戏开发这些复杂功能我们永远也理解不了,我们也永远不会知道各种不同格式图片之间的区别,例如bmp图片是用的或运算,而png图片用的是与运算,尽管两种文件存储的都是像素数据,但png就可以不遮挡背景实现部分透明的显示,而bmp不可以。

    我的突破源于一次阅读光线跟踪算法的代码,这次经历让我认识到自己欠缺的是什么,那是观念上的缺失而不是技术上的。以前我总是想,一个控件是怎么放入那些image的,又是怎么显示一帧一帧的视频的,此外还有2D和3D的渲染图像……而后来我突然意识到,不管有多少种多媒体元素,归根结底,在窗口中这些就是一个一个的像素而已,甚至连窗口也只是像素。没错,所有呈现的最后结果都是像素!这个观点就是认识GDI的基础,以这个为出发点来看的话,以前疑惑的问题就变得简单了,从此也不必再受限于别人提供的控件了,只要不嫌麻烦,一切都可以自己动手,读取图像数据、建立一个绘图区、设置绘图区像素格式、载入像素数据,一切OK了,几乎一切控件的实现大致就这么个过程,无论它看起来多么复杂。

    说起来我对于像素的如此执著,应该源于对3D渲染技术和游戏开发的热情,在这个学习的过程中,很多脱离了具体代码和技术的认识方法的建立,让我们能有自己的视角来处理问题,这可以让很多问题简化。

    与第一个阶段相比,我们的认识其实更深了一层,以前看到的窗口,在现在看来只是一堆像素的堆砌,所以只要我们会操作这小小的象素,就可以让我们的窗口去做更多更有趣的事情的事情了,比如游戏……只要你想得到!

    然后最痛苦的时候来了,尽管已经了解并掌握了几乎所有必需的知识,对于一个任务,我们能从功能上比较完美的实现,但这个时候,我们已经站上一个高度,追求完美的品质告诉我们一定要把界面做得尽量美观,让人过目难忘或者心情舒适。但开发过程中我们发现这是一个很痛苦的过程,一切并不像想象中的那么简单,自己做出来的界面经常会让自己反胃!我写过小游戏,写过播放器,但自己几乎不会去用它们,为什么?就是因为做出来的界面让自己实在难以提起兴趣,它们跟那些软件相比,差得太远。

    我们很快就发现这个阶段遇到的困难,跟以前不一样。以前的难题可以通过经验和知识来克服,这次却不行了。我们之所以感到痛苦而不是困惑,就是因为问题不是出在专业技能上,这是审美的问题,这是大多数程序员缺乏、甚至是匮乏的素质。在程序员的世界里,大家都很容易陷入代码的泥淖而不自觉,这对于后台开发人员无所谓,但对于一名前台开发人员,一名从事界面开发的专业人来说,审美素质是很重要的,当这些人沉浸到代码和功能中时,那就是一场灾难!在界面的开发过程中,我们必须拿出大量时间来思考关于美学的东西,尽管这会中断你的工作,对于敲代码的程序员来说这很困难的,因为一旦开始了Programming,直到遇到难题为止,高效的节奏总是让人难以停下来。但适当的时候我们还是应该停下来,到了一定阶段,只有思考才可以让自己继续提高。

    忘了从什么时候开始,在写界面的代码之前我总是喜欢先设计一下。当然我并不是那么专业的美工,我只是拿个画图工具把界面勾画一下,这里用什么控件,那里用什么控件,颜色该如何搭配……我们应该通过这个步骤,尽量把自己的美学融入设计之中,这样才能减少开发过程中的困惑和中断。

    经历了那么多次失败的打击后,我明白了一个道理:在界面开发这个过程中,美工的工作跟程序员相比要重要的多。一个控件在代码层面上(不包括后台数据)的处理工作主要包括几个状态:Normal,MouseHover,Press。归根结底就是对基本事件的响应,说起来是十分明了的事情。而响应的效果,就需要美工来设计了。这一点在游戏的开发过程中体现到了极致:一款游戏在界面方面(包括游戏菜单和游戏画面)的成败,理所当然依赖于美工多过程序员。

    其实界面的工作就是忽悠用户,因为用户要看的是效果,而不会去关心实现的细节。而大多数看上去很复杂的效果,其实可以用一些很简单的基本控件堆砌而成,反倒是一些看上去很简单的功能,在实现上却要耗费程序员很大心力,而用户是永远不会理解这些的。

    在这个阶段我体会到的是:所有的东西都是窗口!更加高深的境界我体会不到,但提过的那几点认识是我认为界面开发人员一定要经历和体会的。当然不同的人会有不同的想法,但没有类似这种认知和方法论的原则,将会很难深入。比如,在深切体会到“一切都是窗口”这一点后你想到了什么?以前说过大多数人,尤其是初学者在一个界面的工程中很少会有自己的控件。对于我,以前的工作只能是在控件库的类继承图上往下走,即只能从最底层的子类往下继承,结果往往是为了一个功能而不得不加入其他一大堆垃圾,而现在呢?感觉我看到了这棵类继承图上的电梯,我可以在这棵树上任意往来,现在我更多的是回到起点,从最上面的基类出发,构建一个完全是我自己的控件,能够完成需要的功能,并且不会加入多余的东西,我喜欢这种畅快淋漓和掌握一切的感觉。

建议继续学习

  1. web应用应该考虑的一些问题 (阅读 7,122)
  2. 2011年手机产品设计趋势(1):精致实用的界面 (阅读 5,384)
  3. 总结的一些PHP开发中的tips (阅读 5,241)
  4. 产品经理3年沉淀和总结 (阅读 4,580)
  5. 我来CSDN的这一年 (阅读 4,402)
  6. 写在 0x20 岁之前 (阅读 3,580)
  7. 2009年年终盘点 (阅读 3,502)
  8. Zakas解答Baranovskiy的JavaScript小测试 (阅读 3,220)
  9. 无线产品团队总结 (阅读 3,042)
  10. 2010年过去了,我写篇日志留点印记 (阅读 2,482)