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

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

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

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

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

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

界面程序开发的一些总结(二)

经过在第一阶段的痛苦磨炼,我们总算是打下了比较坚固的基础,可以快速的开发各种常见的窗口程序,各种控件的应用比较熟练,也能利用消息机制完成各种需要的...

阅读全文

界面程序开发的一些总结(一)

一直纠结于究竟该用什么标题:总结其实说不上的,毕竟自己经验也不怎么丰富,充其量也就是一小结;换用感悟之类的也不大合适,这会让人以为我故作老成、经验...

阅读全文

29则回应给“界面程序开发的一些总结(三)”

  1. Grissiom说道:

    非常好的一系列文章~在 GReader 上全分享了~;)

    不过对于最后的一点还是有点不明白,所有东西都是窗口和“自由的继承和扩展”有什么联系呢?一个 PushButton(我用 PyQt4) 为什么会是一个窗口呢?望指教。

    [回复]

    ian 回复:

    额,我只是对windows和MFC使用多一点,至于QT只是略有研究,但是就MFC来说,所有的窗口控件类都是从CWnd继承来的,本质上都是窗口。至于QT,控件都是从QWidget继承来的吧,虽然框架有些不一样,但这一点确实相同的。就我看来,这些控件背后都维护着一个消息队列和渲染函数,这是所有窗口控件的共同点。
    这文章只是我的一点总结而已,甚至都没有具体的知识点,其中肯定有很多说的不恰当甚至谬误的地方,希望大家指出来,共同学习。

    [回复]

    Grissiom 回复:

    MFC 我倒是一点都没有接触了…… QT 其实也了解的不深哈~大家一起探讨探讨~;)

    其实我觉得,如果说“窗口”的话会给不熟悉 MFC 的人一个误解,因为平时所熟知的“窗口”是显示在桌面上的那个带着边框,有标题栏的“程序窗口”(不知我说明白了没……)。但是像按钮之类的小玩意肯定是不会带他自己的边框和标题栏了。如果如你所说,窗口控件都是从 “CWnd” 继承来,到有叫做“窗口”的理由,因为他们毕竟都是继承“窗口(Wnd==window)”的……当然,这只是命名规则而已……

    不过我感觉至少在 Qt 里面,并不是每一个控件都维护一个消息队列的。他只是把自己的事件注册到主循环里然后主循环负责分发各个事件。如果不刻意使用多线程的话整个程序还是单线程的。其实 Qt 研究的不是很深入,不知说得对不对,望指教……

    [回复]

    ian 回复:

    其实关于这个“窗口”的概念,是需要澄清一下的,在windows开发人员看来,无论是Grissiom所说的有标题的程序主窗口,还是按钮、菜单,都叫做window,当然这只是对于开发人员来说的程序上的概念
    至于那个消息队列嘛,我在MFC里看不出有多大区别。就Windows系统而言,从整个操作系统来看,内部有一个系统消息队列,这个消息队列包含所有的交互事件,比如鼠标点击、窗口拖动、消息发送,然后系统会把这个消息队列里的消息取出来一个一个的发送到目标,比如我们的程序主窗口。在这之后,主窗口又会将消息发送给对应的子窗口(也就是这个消息的目标),比如我们点击按钮,系统发送一个消息给主窗口,主窗口再传给子控件,这么一层一层传下去,所以这么来看,无论是窗口,还是控件、菜单,其实都没有区别,而且程序都必然要开启子线程来处理这些窗口消息的,绝对不是简单的单线程而已。

    [回复]

    Grissiom 回复:

    Qt(PyQt) 是单线程的,刚试了一下。方法如下:建一个 PushButton,把他的 clicked 信号关联到一个死循环里。程序起来后点那个按钮,可以看出来程序死在那里了~ MFC 不了解,不过感觉也可以用同样的方法试试~

    [回复]

    ian 回复:

    感谢Grissiom不懈的专研,这里我的理解确实有些偏差,仅就消息的处理而言,确实是单线程的。看了点QT的资料,发现消息的处理是这样的,当调用QApplication::exec()时,就进入了事件循环. 该循环可以简化的描述为如下的代码:
    while ( !app_exit_loop ) {
    while( !postedEvents ) { processPostedEvents() }
    while( !qwsEvnts ) { qwsProcessEvents(); }
    while( !postedEvents ) { processPostedEvents() }
    }
    所有的消息都在这个循环里处理,而处理的过程就是调用各个控件的回调函数,就这么来看,的确是单线程的,而且控件没有单独的维护消息队列。但是有一点,QT里事件循环是异步的,也就是说,当你点击一个按钮后,系统先把这个事件放到消息队列后就返回了,然后会在上面这个循环里面处理这个消息。这个异步处理我是这么理解的:点击按钮,QT会开启一个线程将消息注册到消息队列中去,然后线程关闭返回,这样本质上还是多线程的。不知道这样理解对不对。

    [回复]

    Grissiom 回复:

    上面没按钮了,就在这里回复了哈~;)

    嗯,果然,即使是程序死掉,在那个按钮身上点几次他就会几次进入死循环。看来事件没有被丢掉…… 又查了查资料,发现 windows 可能还真是多线程的:
    http://www.limodev.cn/blog/archives/1500

    不过其实并不是所有的 GUI 实现都需要多线程。我怀疑 Xwindow 下的 Qt 就是单进程的。X 负责把事件用队列传给他。这应该算是进程间通信,操作系统负责保留那个队列。感觉多线程毕竟有点麻烦……

    [回复]

  2. kexbar说道:

    同意!就我看来,本质上来说,所谓“窗口”就是联系软件与人的操作的!一个按钮,你所看到的每个界面上的项目,除了文字和图片,甚至都可以是一个“窗口”。

    用过VIM,你看到的基本就一个窗口,用过VS或其他IDE,他们就已经为你设计了多个开发时可能要用的”窗口“。

    [回复]

    Dante 回复:

    哈哈,kexbar 领悟能力好强,对vim和vs从如此视角比较我的确是第一次听说,很受启发~~
    其实细心的话会发现,这个系列的文章是另一个作者ian写的呢,呵呵,算是无心插柳啦~~

    [回复]

    ian 回复:

    确实如此,窗口和字符界面的区别也就在于开了更多的线程(消息队列、文档、视图)来满足交互性,了解了窗口背后的机制,就能随心所欲的操纵,实现更加复杂的功能

    [回复]

    依云 回复:

    gVim 也不只一个窗口的,在 GTK 下,连工具提示和弹出菜单都是角色(role)不同的窗口呢!

    [回复]

    Dante 回复:

    哈哈,这一点我都忘记了呢,这几个月都是在XShell下全屏Vim,居然都忘记gvim下也有菜单……杯具啊……

    [回复]

  3. Grissiom说道:

    对了,要是有邮件回复提醒就好了~ 就不用还得记着回来看回复了~;)

    [回复]

    Dante 回复:

    呀,不对呀,应该每个回复的用户都会有邮件提醒的呀~~

    [回复]

    Grissiom 回复:

    咦?我没有啊…… spam 里也没有…… 杯具……

    [回复]

    Dante 回复:

    杯具……我还一直信誓旦旦的以为有呢……

    [回复]

    Dante 回复:

    哇咔咔,OK啦,看看收到邮件不?

    [回复]

    依云 回复:

    我也从来没有收到过,所以一直是用 RSS 看评论的….

    [回复]

    Dante 回复:

    ……,原来依云兄都是这样看更新呀……,奇怪了,得好好查查……

    [回复]

    Dante 回复:

    之前的WP Thread Comment设置有问题~~
    现在已经能够自动邮件回复啦

    哈哈,依云兄可以不用再那么麻烦啦~~

    [回复]

  4. mhsy2003说道:

    哎,我的界面编程经历跟你差不多,很熟悉的一个过程,找到队伍了。

    [回复]

    ian 回复:

    哈哈,那感情好啊,大家以后可以一起学习啊

    [回复]

    mhsy2003 回复:

    我理解那个循环很快,当初是先学过opengl,我一开始就猜跟opengl一样的循环监测事件,更新,绘制,双缓存消灭闪屏。

    不知道你看过侯捷的深入浅出MFC没有,如果没看过我建议你去看下它的前六章,很不错的。我MFC编的不多,C#编的比较多,但是整个界面的东东差不多,最后我还是回归到本质自己绘制自己做鼠标监测,有点类似OPENGL里面当初做碰撞检测,鼠标拾取。

    另外,FLTK你研究过没,它的很简单,一切都是用点线面画的,很本质,事件就是通过回调函数。

    [回复]

    mhsy2003 回复:

    好像qt的美工可以用css?
    以前很希望微软能做用css来分离控件的样式。
    后来微软做了WPF,我又不想用,WPF是用Direcx直接绘制界面的,用XAML来描述界面,C#做事件处理,本质上升级版的ASP。。。甚至DHTML。微软的东西一直没变,只是一直在升级 换名字。所以我也没想用。

    [回复]

  5. 依云说道:

    已经收到邮件提醒了!
    上边没有“留言”可以点了,就写在最下面了。

    [回复]

    Dante 回复:

    哈哈,终于OK啦~~

    [回复]

    Grissiom 回复:

    嗯~ OK 了~多谢~;)

    [回复]

  6. egmkang说道:

    Windows里面,所有能看得见的东西都是窗口,最大的是窗口,控件也是窗口.”Windows程序设计”里面那些纯API写出来的程序,控件都是用CreateWindow弄出来的.
    窗口,都有一个窗口过程,来响应自己的消息;而主线程,有一个消息循环,从系统那里拿到属于应用的消息,然后分发,并且处理执行窗口过程.
    不知道我的理解对不对??

    [回复]

  7. abc881858说道:

    我只领悟到动画都是图片, MFC我只要去写消息处理, 然后弱弱的问, 我到了哪个境界?

    [回复]

发表评论