• 28368阅读
  • 7回复

[翻译]再论 Gtkmm 与 Qt [复制链接]

上一主题 下一主题
离线chwoozy
 

只看楼主 倒序阅读 楼主  发表于: 2006-06-29
Translated by ChenChunhui

原帖的链接是:http://www.telegraph-road.org/writings/gtkmm_vs_qt.html
最后附有html格式的文档

(Andi Peredri 为此文提供了 俄文翻译 )

再论 Gtkmm 与 Qt

(让我们期望这是最后一次了).
  在这篇访谈里,Murray Cumming,当前的gtkmm(以前被称为 Gtk--)的维护者,谈到了他认为我是为什么离开了gtkmm的,和他心目中gtkmm相对于Qt的优势。因为我不同意他那番话中说的很多东西,我觉得我应该回复一下了。

为什么我离开

Murray : (...)我猜想Guillaume从未真正地掌握gtkmm的代码基础,并抓住机会从令他沮丧的事情中逃离出来。(...)


  我解释了为什么我离开gtkmm,而且“抓住机会从令他沮丧的事情中逃离出来” 绝对不是原因之一。不过你确实几乎说对了一件事。我确实从未真正地掌握gtkmm的内在特性,因为这是Karl的领域,我比起Karl来说能花在gtkmm上的空闲时间实在是太少了,并且对这些时间中干的其中大多数事情都是不感兴趣的。我的目标是获得一个可以用于Rosegarden的工具包。所以我在gtkmm上的主要活动是为小部件打包。

gtkmm 与 Inti

Murray : (...)我认为Guillaume无论如何都确信,由于RedHat的支持, Inti会成功而gtkmm会逐渐消亡。


  呃,是的,我相信Inti会成功,而显然我是错的。我相信的原因大概是我认为, 当一个开发者可以专职为一个项目工作的时候,那个项目就能进展得很快。但是这并没有发生,因为Havoc最终还是把它大部分的时间花到了GTK+ 2上。

Murray : (...)绝大多数gtkmm的用户和开发者都强烈反对Inti的设计决定


  据我所知, “绝大多数”在这里是指6人左右,或者根据我在档案里读到的线索。这6人里最重要的一人显然就是Karl,他的观点我至今都还反对。我不需要一个“黑客工具箱”,我需要一个能运转的且易用的的工具箱。

社区开发

Murray : (...)Inti消亡了,因为它从未涉及到任何一个开发者社区(...)
(...)基本上,QT并不是公开开发的,所以在没有受益于任何真正的批评的情况下犯了一些错误。(...)另外也许更重要的是,如果你在使用gtkmm的时候遇到了什么问题你可以提交一个补丁或与其它开发者进行讨论。


  在我看来,我认为更确切的说Inti消亡的原因是它的维护者的停止维护。对于Qt来说,确实它不是公开开发的, 你猜怎么样: 它很棒.

  你似乎在暗示公开开发意味着品质。这是一个旧的自由软件的神话。一群自认为知道自己在讨论什么东西的人们(我确实曾经是当中的一员)于空闲时间相互收发的电子邮件并不能保证什么东西。但是由一群技能熟练的人组成的一个天天为难题而工作的、接收用户反馈的、能当面讨论问题的小团队很有可能达成某些好事。

  让我们面对事实吧:好的程序员并不是泛滥成灾,即使是在自由软件世界。尽管区别就是很多人并没有意识到他们的真实技术水平。所以让很多人来参与困难问题的决定没有什么好处,只会让事情变得更糟。

  所有的gtkmm 的设计决定都是公开详尽地讨论的,就这样仍有一些决定是错误的(像内存管理问题),这主要是因为参与讨论的人里面没有一个真正在使用gtkmm来开发实现的应用程序。我们全都太拘泥于创建一个“真正的C++ API”,而不是制作一个便于使用的东西。我在上面给出链接的Karl的帖子对于这个来说是一个极好的例子。一个由Matthew Thomas 制作、在许多网站上被充分讨论的网页日志条目,切中肯綮。它讲述的是用户界面设计,但是里面绝大多数也可以用于API的设计。无论是对用户还是开发者,界面的设计要面对相同的问题:平衡标准、美学和务实。

  之所以说Qt好是因为奇趣科技(Trolltech)的开发者是很厉害的,并且他们确实听取了他们客户的意见(我知道这些第一手情况因为我是他们中的一员)。不仅如此,他们的客户在创造大型的、真实世界中的应用程序。他们的客户并不关心“信守C++精神”,他们关心的是解决实在的问题和落实应该做的事情。Qt的开发者并不试图预言什么是一个好的API以及什么不是,他们有大约2000多位客户让他们的选择选择面临实践的检验。

  我并没有说Qt的API是完美的,它确实是有些瑕疵的。我是说它工作得非常好,我说这话的理由是我在过去两年在两个不同的项目(Rosegarden和为雇主的内部开发)上天天都在使用它。你在开发一个更好的东西的时候会比较艰难,而我并不相信gtkmm正朝着那个方向发展,感觉它的发展方向恰恰相反。

  最后,你可以向Qt的开发者们提交一个补丁并与他们讨论问题,因为客户支持是他们工作的一部分。我知道这些第一手情况因为我自己就干过这样的事情,KDE的开发者们也是这样的。

Qt对C++的“扩展”

Murray : (...)这里面主要的问题是它对C++语言的修改以及对自己非标准的字符串类的使用。如我们所证实,这是不必要的。


  QString是毫无疑问非常必要的,因为std::string不能处理Unicode。gtkmm自己也有Glib::ustring,我看到你把它的接口制作得与 std::string相似,这样我还是认为这是个坏主意,因为不管它有多标准,它既不方便也不强大。QString提供了非常有用的特性诸如arg()、sprintf()、section()、simplifyWhiteSpace()、toInt()和它的“兄妹”, setNum(),当然还有在日常开发中价值无法衡量的正则表达式的支持。

  现在我们来谈谈长期以来颇具争议的对C++语言的修改。你也许会说这并没有必要。这是事实,尽管你还没有非常充分地证明,因为gtkmm没有提供Qt的“扩展”做到的所有特性。

信号与槽

  我明确地想知道槽和信号是用什么符号表示的。在gtkmm里,它们是模版函数,是你传递给你的连接调用的东西。在Qt里它们是非常旧的const char*s。震惊!恐怖!QObject::connectconst char* 作为槽与信号的参数类型!这也就是我的第一反应。后来我认识到了两件事:
•    我不介意。它可能会在审美观上伤害我,但是它并不妨碍开发。
•    它是动态的。你可以自己产生这些字符串并在运行时再决定把连接和被连接的东西。
  上面的第二点对于我来说是最重要的。它为我当时正在开发的内部应用程序节省了数周的开发时间。这个应用程序在启动的时候就根据一个XML描述文件生成了它自己的用户界面,而在这个文件里面我可以像下面这样写上我自己的代码:
  1.      <connect source="widgetname" dest="someclass"
  2.           signal="buttonPressed()" slot="receivedButtonPress()" />
  
  需要运用的代码在半天之内就编写完毕了。如今,我认为这可以用于Qt设计师。试试用libSigC来做相同的事,看看这样会多“简单”。

  另外一个这种动态性带来的特性就是松耦合。这就是说,在你调用connect函数的时候你不需要完整的类型以及源对象和目标对象的类型定义。你只需要知道它们是QObjects类。所以,假如连接是在代码中的别处实现,而不是在源对象或者目标对象的方法中,这种情况(如我在上面所描述的)下,执行它的函数不需要用“#include”语句来包含源对象和目标对象的定义。代码可以是这样:
  1.      void do_connect(QObject *source, QObject *destination)
  2.      {
  3.          QObject::connect(source, SIGNAL(buttonClicked()),
  4.                           destination, SLOT(gotButtonClicked()));
  5.      }
  
  不错,你失去了编译时的类型检查(但是你仍然可以在运行时进行检查——如果connect()函数执行失败你会得到一个警告信息),假如源对象或目标对象在定义中没有一个正确的信号或槽,在这种情况下你不会遇到一个编译错误,但是在实践中这仍旧让你能干得更快。

  这种设计(两个对象之间的连接是靠第三方来完成的)是很普遍的。一旦你意识到了信号不只是为了事件处理另外还可以在保持松耦合的情况下在对象间进行通信,你就会很频繁地去使用它。
即使是由源对象或目标对象来进行连接,你仍然会成功,你可以这样:
  1.        void MyWidget::do_connect(QObject *destination)
  2.        {
  3.          connect(this, SLOT(itemClicked(int)),
  4.                  destination, SLOT(gotItemClicked(int)));
  5.        }
    
  你不需要依靠目标对象的你可以自由修改的定义。大发展又再一次出现了。为什么你认为所有新创造出来的语言,如Java或C#,拥有这种灵活性?它只是让你工作得更快。我不记得在我使用Qt的这两年里曾经被什么槽/信号相关的程序缺陷给严重烦扰过。我曾想过这种类型检测的缺失将回来并找你的麻烦,但事实并不是这样。警告信息对于有效地追踪问题已经足够了。
  更多有关这个主题的信息可以在Qt文档上找到。

元对象编译器和被添加的关键字

  这是对Qt质疑得最多的地方。这些你必须在你的自定义类的定义和代码里使用的“槽”、“信号”、“发射”等关键字不是C++里的,并且你完全可以不用它们。是的,这是真的。不过事实是你用它们更好。它们使你的代码看起来清晰且便于阅读。

  奇趣科技(Trolltech)已经给出了关于为什么Qt不为信号和槽使用模板的一个非常好的解释,这个解释我想我已经给你指出来过了。还有, 通过自己的经验, 我已经验证了他们的每个观点, 我相信, 所有其他Qt用户也一样。

  不过有讽刺意味的是他们中的一个观点是语法问题。既然你一直都在制作GTK+和Co.的“C语言中的面向对象的” API,你应该比大多数人更清楚这是对的。然而你和那些认为面向对象不过是“语法之糖”的人在做一样的事。呃,就像类一样,信号和槽是定义明确的概念,因此在语言级(如果是那样的话可以说)上实现它们是有意义的,比让用户单独去对付它们好。

  这样看来你对槽/信号问题的解决方法就是全部在现行C++的框架下实现它们,就像其它人在用纯C语言来实现类一样。我的解决方法就是硬着头皮和让“槽”与“信号”成为官方C++的关键字:-)。程序是用C++库还是用机器语言编写的并不重要。真正重要的是你使用添加上的东西来向编程语言表达你的设计。

  使用元对象编译器这件事,在我看来并不是什么问题。如果你要写一个自己的makefile,你只需要加上一行就可以了。另外,KDE的automake宏或Qt的qmake语句也可以为你处理这个问题。在实践中元对象编译器并不会妨碍你。

Murray : (...)因而用gtkmm来与其它的C++ API进行结合更简单。(...)

  你看到了用Qt与其它的C++ API进行结合时的问题了吗?在Rosegarden里我们很乐意使用STL(并且用得很多),除了STL本身的一些复杂的部分引起的外问题完全没有其它问题:-)。例如std::vector<QString>如预期般工作。

Murray : (...)我相信如果你喜欢C++,你就会喜欢gtkmm,如果你在学习C++,gtkmm就是一个更好的榜样。(...)

  我不能确定gtkmm对于C++初学者是一个“更好的榜样”,但是你说“如果你喜欢C++你就会喜欢gtkmm”,以及你仍然没有理解为什么Qt更好,是问题的核心。我并不喜欢C++。我并不关心C++。我关心的是编写出一个能做有用事情的应用程序。所以我并不介意使用一个会向C++里添加非标准关键字的类库,只要它对编程有帮助。但是你关心C++,所以你就不能做到这点。你在乎这点却无视它的缺陷,并且你没有意识到由于对它的“坚定信仰”,你使生活变得更困难而不更简单。另外,这就恰好是使用Gnome的C语言的程序员如何高高兴兴地去掌握GTK+的对象系统,而他们没有意识到可以用C++和Qt快得多地办到相同的事,并且彻底地确信他们所做的事是“简单”的,因为他们喜欢C语言且不需要去学习另一门语言。

  标准并不是神圣的东西。理论上你最好遵循它们,但是在实践中并不一直是这样的情况,很简单,因为它们是由可能会犯错误的人类所设计出来的。工具和语言不应该被喜欢,它们应该被恰当地使用。否则,当一个更好的选择出现在你面前,你会忽略它,因为你不想放弃你自己喜欢的那一个。

Qt vs. gtkmm

  在谈到这点的时候,我愿意对你在你的“GUADEC talk”里提出的观点发表不同意见。

数据容器

  你说:QT有很多与现在的标准库重复的地方,比如容器和类型信息。

事实确实如此。但是:
•    自从Qt3以来,Qt的容器是与STL兼容的(例如你可以把STL的运算法则应用在它们上)。
•    一些Qt的容器确实比它们的STL上的等价物简单。例如,QPtrCollection::setAutoDelete()是很有用的。
•    你也可以忽略Qt的RTTI,并使用C++的标准RTTI。我们是这样做的,KDE也是这样做的。

内存管理

  啊,又是老生常谈了。第一,你说Qt需要指针,这是错的。你可以为控件使用普通的变量(看这个例子),并且当你在使用指针的时候你可以自行删除它们。你可以这样做,而一般你不会想要这样做的。

  假设你创建了一个包含许多控制和标记的相当复杂的对话类。你显然需要追踪其控制,因为你需要了解它们的状态,于是你让它们保持为数据成员。但是标记和布局控件怎么办?为它们保持一个引用有什么用呢?难道这样:
  1.        new QLabel("Some label here", vbox);
    
  然后忘记它不是更简单吗(因为你知道Qt会为你删除指针)?就我而言,确实,这样更简单。当你可以让电脑为你去做内存管理时亲自做内存管理并没有什么值得自豪的。它总会比你做得更好。

  这样你就是在声称把做枯燥乏味以及容易出错的事情的可能性留给用户是一件好事,因为这是符合“正统C++的选择”。我认为这些“正统C++的选择”应该被任何一个好的C++类库隐藏起来。难道std::string和所有的STL容器会因为它们分配内存而找你的麻烦?它们不会。在最好的情况下你可以使用你自己的内存分配算符,因为有时候你可能会需要实现一些非常特殊的要求,但是这不适用于控件。所以为什么 Qt就不能有一点不一样的地方呢?

容器控件

  在你的谈话中你说Qt的容器类和布局类是分开的,这正和gtkmm在容器类上的选择是相反的。我对你的观点理解得不是很清楚。Qt拥有如QVBox一样的控件,这正好像gtkmm拥有VBox,这两个控件的的行为几乎一样(你只需把控件添加到上面就行了,在Qt中这意味着以QVBOX为父控件添加一个新的控件,并不需要外加一个“add”语句)。另外,Qt拥有可以让你能进行更好调整的布局管理的(如QGridLayout,它同比它的“简化”但和它类似的QGrid相比,提供更多的选项)类。你当然可以在必要的情况下创建一个自己的布局类。

  所以这样Qt明显地提供了与gtkmm一样的特性,甚至还有gtkmm没有的特性。因此我不理解你的观点。

学习和使用

我想gtkmm使你的代码更清晰也理协调。我认为它节省你学习时间并减少让你烦恼的东西。

  我自己的经验直接同这相矛盾。在使用Qt两周以后,我精通它的程度比我曾经用gtkmm的时候对gtkmm的精通程度更胜一筹,约三年来我一直使用这个“该死的”东西:-)。

  在这两年来我也在与那六七个几乎全转向Qt或Swing甚至正宗GTK+的“前gtkmm用户”讨论,他们告诉我的是一样的:gtkmm太复杂了,用起来太笨重了。我相信你已经在gtkmm2里改进了API,但是你无能为力的是要对付你加入的许多另外的库这样的琐事。我也很奇怪为什么Terraform这个几乎是当时唯一使用gtkmm的大型应用程序,不再使用它了。

  那么让我再来谈谈我自己关于Qt的一些非常具普遍性的经验吧:所有这些Qt的非图形界面相关的类,如XML分析程序,线程处理类,日期和时间处理,正则表达式,等等,是非常有用的。Qt的开发者认为它们不实用,所以不想加入它们,但是Qt的主顾对开发者提出加入它们的要求,这是因为主顾们需要它们。没有这些特性的帮助你是编写不出一个时髦的桌面应用程序的。Rosegarden使用gzip压缩的XML作为文件格式。XML是一个显而易见的选择,大部分是因为Qt拥有一个它的分析器。要用gtkmm做相同的事,我们需要与libxml连接。这意味着另外一些拥有不同API和或多或少文档……等等的库需要处理,我们甚至有可能需要封装它,这又会导致更多的代码。

  这实际上正代表了我使用gtkmm开发Rosegarden的无益尝试(见Rosegarden开发历史以获得更多细节)。我一开始试着创建一个可以把音符显示在上面的简单的控件。但是等一下,我必须创建一个没有多少实用价值的音符的位图,并且要做到这点我需要使用GDK和imlib,它们中没有一个在当时是已经被封装的(而且封装者使用了一个与gtkmm的其它部分完全不同的内存管理策略)。于是我首先要向这些封装者里加入材料。接下来我需要Gnome Canvas来把谱线和音符显示到上面去。这又是没有封装的,所以又得封装。这此这般,令人作呕。现在libxml、vfs和其它我们用的工具也是一样的,KDE提供了它们,而它们的Gnome中的等价物还没有被封装(另外我这里使用的“等价物”一词所指得东西比较宽泛)。

  在转向Qt/KDE后大概一个月里,我取得的进展比过去3年还大。一段时间后,Chris和Rich重新加入进来,现在我们仍然进展稳定,因为程序架构并不妨碍,甚至对于相当难的像IPC一样的东西也是这样。DCOP运转得太好了,从甚至不知道该做什么事情的时候起,让Rosegarden对DCOP的消息有反应,仅仅用了我20分钟(我没有撒谎)。大多数的用户界面问题在几小时之内就解决了,这样我们就能集中精力对付实际的问题。刚才我随便写了一些关于Rosegarden的开发的不是很有条理的想法,如果你需要更多的细节你可以去查阅一下。

  关于“节省学习时间”,看看gtkmm的这篇关于内存管理的页面。和QT的内存管理比较一下。

总结

Murray : (...)Guillaume现在使用QT。他声称对他来说拥有一个完美运转的工具比一个完美的API更重要。gtkmm2将很快变得稳定——这样我们就可以在gtkmm2里同时拥有易用性和完美的API了。

  是的,我使用Qt/KDE,并为此感到高兴,因为经过了这么些年Rosegarden开始看起来像一个真正的应用程序,which has always been the point. 这在使用gtkmm的时候是绝对不会发生的。
和你所说的相反,gtkmm2离可以提供相同级别的特性还有几年的差距。如果它能达到,它也会付出巨大的资源代价,因为你必须把每个库都添加到封装者里。即使拥有gtkmm、gnomemm、bonobomm(它暗示了与所有它们所封装的Gnome的库所连接),你仍然没有得到Qt及kde库的所有特性。看看一个简单控件的层次结构,我数出了4个如下的“对象”:
•    SigC::Object
•    Glib::ObjectBase
•    Glib::Object
•    Gtk::Object

  人们会对它们的内存冲突感到惊讶。

  另外一个问题,即使gtkmm这几年来一直稳定,为什么使用它的应用程序却很少呢?

  我们大约一年前进行过相似的讨论。看起来你的观点还是没有改变:你因为个人喜好的缘故不喜欢Qt,但是你仍旧对为什么使用它就会让你的代码难于编写和维护这点没有一个清晰的论据。我的经验是Qt使编写及维护代码成为一项简单的任务。只要看看由它产生的软件的价值就知道了。如果gtkmm被如此广泛使用,你就会在这方面得分。这是自由软件,所以更好的技术应该流行,是吧?

  你不喜欢Qt,因为它不符合你心目中一个C++类库应该遵循的标准,如此而已。我认为你的想法是错误的,gtkmm正好重复了这类让C++获得“艰深易错的语言”名声的错误:自身不够详尽和把太多的东西留给用户。

  如此我祝你的gtkmm2好运,但我还要继续使用Qt/KDE并在Rosegarden上帮助Rich和Chris。
________________________________________
P.S. : 一个gtkmm常见问题 #2.4的“补丁”
下面是对关于一些项目的回答的修正。
•    gtkmm使用std::string、std::list、std::vector、iterators,等等。Qt使用自定义的容器。

这是对的,但是:
o    QString使用起来在功能和便利性上大大优于std::string,另外它是基于Unicode编码的。实际上你的确不能对用户可见的字符串使用std::string,除非你计划从不使你的软件多国语言化并使它仅仅保持为英文版。
o    容器在大多数情况下是作为一个没有好的STL运行环境的平台的代替品。它们确实拥有几个便利的特性(如对基于指针的容器的“自动删除”),但是通常你的确不会使用它们,除非Qt的API需要这样。它们也是兼容STL的, 这意味着你可以对它们使用STL的运算法则。只要把它们视作另一种容器……
•    在gtkmm里可以使用普通的C++内存管理。Qt需要把所有的控件都视为指针来进行处理,并且控件的删除交由父控件来处理。

这句话彻底错了。你可以把控件视作变量来处理,不过显然这样做在及个别情况下才有意义(如创建一个对话框),另外你也可以在需要的时候自行删除控件。
•    gtkmm的控件的安排更加简单。在Qt中,容器和布局是分开的类,子控件必须被同时添加到它们两者中。

这也是错的:看看QHBox、QVBox、QGroupBoxQGrid。只有在你需要对控件如何放置有更高要求的时候,布局类才是必要的。Qt的布局类同样拥有一个autoAdd标志位,这样可以减轻你向它们或父控件添加控件时的工作量。
Guillaume Laurent
最后修改:2004年7月28日 星期三23:46:07 CEST
gtkmm_vs_qt.rar (16 K) 下载次数:45
[ 此贴被chwoozy在2007-04-02 09:29重新编辑 ]
离线chai2010

只看该作者 1楼 发表于: 2007-02-07
楼主真是好人
离线chwoozy

只看该作者 2楼 发表于: 2007-02-24
谢谢
我最近对这篇文章做了一次更新,希望能有更少的错误和更好的阅读效果
离线XChinux

只看该作者 3楼 发表于: 2007-02-25
感谢楼主的辛勤工作
二笔 openSUSE Vim N9 BB10 XChinux@163.com 网易博客 腾讯微博
承接C++/Qt、Qt UI界面、PHP及预算报销系统开发业务
离线tw801

只看该作者 4楼 发表于: 2008-05-05
很好,坚定了学习QT的决心
离线soul
只看该作者 5楼 发表于: 2008-07-22
支持!感谢楼主分享啊~
离线wd007

只看该作者 6楼 发表于: 2009-01-11
谢谢搂主,辛苦了
欢迎访问我的博客,一起学习提高
http://blog.csdn.net/qter_wd007
离线woniu1983
只看该作者 7楼 发表于: 2009-12-22
太感谢Le····
快速回复
限100 字节
 
上一个 下一个