九天雁翎的博客
如果你想在软件业获得成功,就使用你知道的最强大的语言,用它解决你知道的最难的问题,并且等待竞争对手的经理做出自甘平庸的选择。 -- Paul Graham

一周Qt使用小结

 


     初创公司,没有像大公司那样的技术积累,很多东西需要自己从头干起,其中较大的一块就是工具。想起刚刚参加工作半年的那会儿,老板为了说服我写工具,说让我进工具组是培养我,写了一个数据校验工具后,我就死活再也不肯开发工具了,硬要继续写服务端程序。现在真是轮回,这次我是发现,我们实在是太需要工具了,于是决定自己写工具来提高公司的游戏开发效率。

     于是,首先用本周时间,开发了一个用于编辑游戏layout的工具,使用的UI库是Qt。这个虽然是在公司有在MacOS下使用工具的需求下做出的选择,但是还是不得不说,对比3年前学习和使用MFC的经历,总体来说是心情愉快了很多。

     Qt的学习断断续续,虽然我的博客中有个Qt的分类,但是在之前其实了解的还是比较浅的,除了大概翻看过《C++ GUI Qt 4编程》(第二版)一书,用Qt结合OpenGL做了一些小的动画demo,基本没有开发过啥实际的东西。说起来这还是第一次在工作中使用到Qt,中间多少还是走了一些弯路,也碰到过一些问题,这里大概总结一下,想到哪就说到哪了。

  • 很难避免要说的是与MFC的比较,但是我前面说了,我们公司用MacOS的人较多,跨平台是硬指标,MFC无法选择。至于其他类似的跨平台库wx等的选择,见以前的文章。就中国目前的国情,已经自己较低的水平,为了避免口水站,这部分就省略了。
  • 就使用体验来说,Qt的确比MFC的设计好了很多,因为Qt原来就是个靠卖库生存的公司,库和API的设计就是公司的核心竞争力,要是设计的不好,公司就没法生存了。所以感觉API的设计上的确是花了很多功夫的。(参考这个文章)signal/slot系统的存在的确让设计灵活了很多,开发的过程中甚至都能让思维更加一致和清楚,因为你在设计和使用某个类时,完全可以暂时不考虑其他类。(这是理想情况)设计时假如有模块化的思想,signal/slot可以很方便的用于模块间的解耦。
  • Qt更加完全的面向对象,这点很多人都提到过,不过其实,我感觉有的时候这个面向对象甚至有些稍微过头。
  • 随着学习的语言和各类框架,库越来越多,越来越杂,慢慢感觉到其实光是学习某个东西都是了解的非常浅,只有切实的使用这个东西开发达到一定规模的工程时,才能慢慢的有所领悟,然后才能进一步的掌握。其实断断续续学Qt很久了,但是直到这一周(即使仅仅是一周时间,2千行多一点的代码规模)的密集开发,才感觉慢慢了解了一些东西。
  • Qt的designer工具:基于一贯的习惯,不是太喜欢类似的工具(从MFC时代来的经验),而是愿意手工编码,首先是感觉手工编码时自己对代码更加了解,防止生成一对垃圾代码,不好懂,也难修改。其次是感觉手工编码比用鼠标去拖拽效率还能更高一些-_-!(这个是纯个人意见...........)对于大量重复的操作,要么抽象一下,要么借助神器vi........都不是啥问题。
  • 帮助文档:MSDN是我见过最牛的,不过Qt的assist也不差了。
  • Model/View的引入使得Table和list控件使用更加的方便,这个有人不同意,甚至形容其为“脱裤子放屁....”,我觉得是还没有理解到底该怎么使用。我刚开始的时候,使用Qt预定义的QStandardItemModel与QTreeView的组合,发现的确相当费劲,好端端的平白无故加入了Model的操作,还要关心Model与View之间的交互,而自己的真实数据又感觉直接保存在QStandardItemModel的对象中使用非常不方便,还是需要额外再保存一份,然后每次来回同步着调用,此时真是感觉Qt的Model/View设计的真废。(对,当时我就是感觉Qt本身设计的废,本身这种MVC的变种模式使用应该是要更方便才对)后来第二次开发另一个东西的时候,直接用QTableWidget,相当于是自己的数据+Widget的组合,用着是比较自然了,但是感觉还不是足够的方便。然后查阅了一下资料,对其进行了重构,通过自己定义的Model来实现Qt中的Model/View,此时才感觉到使用的方便,这种使用方式,就和iPhone中的委托很像了,数据可以仅仅保留自己的一份,然后通过使用这些数据来实现自定义Model中的接口,任何时候我的修改都是直接针对于我自己的数据的,完全不用关心view层的事情,(最多是通知刷新)不仅仅是只保留了一份数据,而且在操作上带来的极大的方便。
  • Qt的XML接口实在算不上是方便的,假如排除有些类可以直接作为某些XML接口的参数的因素,很多其他的xml库使用都要更加方便。(比如tinyxml和rapidxml)当然,其实对于简单数据,个人更喜欢json。
  • 一方面是为了学习,另一方面是为了减少类型转换,我大量的使用了Qt的容器和String类,感觉与std的设计大同小异,但是算法库稍微弱一点。
  • 绘图时QImage+QPainter的组合非常方便,虽然我是做一个游戏的layout编辑工具,但是完全不需要使用到opengl。(目前没有考虑到半透明的情况)
  • QDockWidget控件在Windows下的效果非常棒,但是MacOS下效果一般,不够美观,边框的拖动响应也不是太好,特别是调节大小的鼠标提示很难出来。
  • 有意思的现象是Windows下的字体比Mac下略小,所以假如是固定坐标的对话框(没有用layout),最好是在Mac下设计,不然的话有可能在Mac下显示不全。
  • Qt程序的发布,Windows下编译Release版本后,拷贝需要的Qt Dll即可,Mac下对编译好的app使用macdeployqt命令(甚至可以通过参数-dmg 打成dmg包)
  • 自定义Model的data()函数,当role == Qt::EditRole时,显示的是此格在被编辑时的内容。《C++ GUI Qt4编程》一书未描述,文档中也没有详细描述,因为刚开始编辑时总是会出现一点击编辑总是空的情况,自己猜的,不过还真正确。



使用Qt的时候,还走了一些弯路,一部分也算是自己了解Qt不深入,一部分应该也算是Qt的设计问题。
Model的自定义使用:
insertRows,removeRows需要自己实现,大部分时候仅仅需要:

  beginInsertRows(parent, row + 1, row + count);

  endInsertRows();

  return true;

  beginRemoveRows(parent, row , row + count - 1);

  endRemoveRows();

  return true;

但是还是需要自己实现,不然的话实现是空的,那么是没有删除和添加效果的。相当不理解,那rowCount是干啥用的?其实应该只需要update/refresh一下就好了。或者,emit一下Qt中已经有的rowsInserted或者rowsRemoved signal也就好了,但是在rowsInserted,rowsRemoved信号的文档中明确的表示这两个消息不允许子类调用的,“It can only be emitted by the QAbstractItemModel implementation, and cannot be explicitly emitted in subclass code.”

而insertRow和removeRow是调用insertRows和removeRows来实现的,(文档如此描述)所以我们不需要实现了。不知道哪种逻辑更为正确,插入多行是多次插入呢,(所以插入多行可以通过多次调用插入一行实现)还是插入一行是插入多行的特殊情况呢?(就如同Qt这样反过来实现)
beginMoveRows和endMoveRows系列就更有意思了,因为没有moveRows用于重载..............那么,这些protected的函数什么时候调用呢?

最后找到了layoutChanged信号,发现只需要在改动后emit此信号即可刷新。并且insert和remove都可以实现。原来........Qt设计者眼中的update/refresh名字叫做layoutChanged.........相当晕。

使用QAction作为快捷键的时候,在一个列表空间中创建,发现无论如何都无法出发triggered信号,最后只能在全应用程序的菜单中添加action了事........这个比较困惑,也就是说没有局部快捷键?
对Qt的了解有限,使用一周,为了防止同一个坑掉进去两次,特写下一些东西作为回头查阅的资料,觉得不对的请提出来。

 

分类:  未分类 
标签:  Qt 

Posted By 九天雁翎 at 九天雁翎的博客 on 2011年03月26日

前一篇: 网络协议编写的三层境界 后一篇: OpenGL(ES) 线性插值算法黑边问题探源