免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: elution
打印 上一主题 下一主题

[转]GTK+与MFC不完全对比 [复制链接]

论坛徽章:
0
1 [报告]
发表于 2006-12-11 05:29 |显示全部楼层
我也不喜欢MFC,但还是有一点不同的意见,做什么东西都不要太主观。


原帖由 elution 于 2006-12-10 10:33 发表
今天看到一篇关于GTK+和MFC对比的文章,学GTK+编程的来看看

MFC已经江河日下,日渐式微,而GTK+可谓欣欣向荣,如日中天。这里无意于落井下石,痛打落水狗,贬MFC而尊GTK+。自己即在使用MFC也在使用 GTK+,不会偏袒其中之任何一方。这个对比完全出于个人对两者的理解,说它是不完全对比,一方面只是一时兴起想做个笔记而已,另外一方面我对两者的理解也是有限的。


MFC的日渐式微和GTK+的如日中天没有可比性,
没见过GTK+在Windows平台的"如日中天",
而且两种情况都是针对特定群体。

1.         两者都是基于面向对象设计的。尽管MFC是用C++写的,而GTK+是用C写的,但思想都是面向对象的。GTK+使用glib的对象机制,由于用C写的,其实现相对有点繁琐。


令人觉得麻烦的是 GTK+ 写的东西长度怎么那么长...

2.         两者都是基于消息驱动的。这是GUI系统的共性,消息可以是硬件上报的,如鼠标事件、键盘事件和触摸屏等等,也可以是程序产生,如一个窗口给另外一个窗口发送了一个消息。但两者并不完全相同,GTK+通过select挂在多个文件描述符上,可以同时等待多个事件源,比如socket、子进程退出和内核事件等等,而MFC只能通过GetMessage挂到消息队列上。


两种方式各有优缺点,从效率来说,我比较偏向 MessageQueue 方式。

3.         两者都不是线程安全的,即只有一个线程可以操作GUI资源。主要是出于性能的考虑,这个问题不大,因大多数应用程序都是单线程的。而且它们都提供一些机制,让其它线程可以在必要时操作GUI资源。在GTK+中可以通过idle函数来实现,在MFC中可以通过PostMessage来实现(附带说明一下: Win32原生的GUI API是线程安全的)。


GTK+ 在 v1.2 后的版本在特定情况下是可以做到线程安全的,gdk_threads_enter/gdk_threads_leave
MFC 是不建议你在不明白相应条件下使用多线程,而建议从工作者线程(听着怎么那么别扭) PostMessage 到主线程去处理。

4.         GTK+整合了一系列的基础函数库,功能强大,而MFC孤军做战,势单力薄。Glib是GTK+的基本库,里面实现了常见的容器和算法,可谓应有尽有,同时隔离了平台相关的功能。Pango是GTK+用于文字渲染的函数库,它负责控制不同文字的layout布局,而把字模的绘制交给freetype等字体函数库处理。MFC虽然实现了一些容器,但数量不多也不好用,除了对原生GUI API的包装外,没提供多少其它功能,与Microsoft Foundation Class Library这个名称一点都不相称。


当你真正用 pango 去处理实际的东西时你会发觉他除了所谓的功能强大外就是效率低下。
不要一味的否定 MFC, 它是没有必要再去实现或包装一些 Win32 API 已经有的东西。

5.         GTK+是跨平台的,而MFC则不是。GTK+在设计时就考虑了可移植性,它按分层模型来组织整个系统,Glib封装了依赖于OS平台的函数,提供一套抽象的接口,在不同的平台有不同的实现。GDK封装了依赖于输入/输出设备的功能,如键盘事件的获取和显示缓冲的输出,同时实现了基本的绘图功能。GTK +几乎可以在所有PC平台下运行,而MFC从来都没有考虑过可移植性,它是与Win32 GUI绑定在一起的。


GTK+ 不能几乎可以在所有PC平台下运行,它运行的最好的也就是在 X Window 下而已。
MFC 不可能考虑跨操作系统,最多就是 X86/PowerPC/MIPS 等。

6.         GTK+小巧,而MFC笨重。GTK+编译出来的可执行文件约3M左右,而MFC本身虽然不大,但它各种版本加在一起就可观了。MFC有ansi版本、有unicode版、有debug版、有release版、还有一些组合,如果你因此而晕倒了,那是很正常的。


你看看 GTK+ 依赖的库就不会说 GTK+ 小巧,而 MFC 依赖的库同样 GTK+ for Win32 都需要。

7.         GTK+的使用简单,MFC的使用繁琐。GTK+的使用比较简单,即使在没有工具的帮助下,要写一个GTK+的应用程序也不难,实际上绝大多数GTK+ 应用程序都是一行代码一行代码的敲出来的。而MFC的使用则太麻烦了,很难想象没有VC的向导的帮助,写一个基于MFC的应用程序。即有了VC的向导,仍有大量的程序员说MFC很难用。


"GTK+的使用简单,MFC的使用繁琐" 不敢苟同
即使没有任何向导,我可以只用 gvim+gcc+msdn 写 MFC 的程序,你信不信,事实上也有很多人这么做。
VC 的傻瓜向导和 Glade 的界面编辑一样,要知道原来基础的东西才能事半功倍,否则就一样是误认子弟。

8.         GTK+使用signal机制,解开消息源与消息目标之间耦合。而MFC使用消息,将消息源与消息目标硬编码在一起。Signal的好处是,不需要知道目标是谁,谁关心谁就注册,这种出版订阅机制是解耦的最佳方式。而MFC的消息则是必须知道目标是谁,把消息源与消息目标死死的绑在一起。MFC提供了一套文档/视图框架,实现了类似出版订阅的功能,这本是设计者引以自豪的东西,结果因为太复杂不能被人理解,反而为开发人员所诟病。


GTK+ 的 signal 机制只是由于它是因 glib 引起的必然而已,不要把它吹的如何如何。
X Window/Win32 API 等哪个不是用消息队列,存在这么久必然有其道理。
个人更偏向于使用那种随时可以把消息转来转去的消息队列,如 BeOS API,你说它耦合性太强吧,易用就好

9.         GTK+采用layout机制动态计算各子窗口的坐标位置,自适应屏幕大小的变化。而MFC要求子窗口的坐标位置硬编码,结果要适应不同分辨率的屏幕非常困难。GTK+在窗口布局时分为两个阶段,第一个阶段父窗口先询问子窗口的最佳大小,第二个阶段父窗口根据自己的大小计算子窗口的实际大小,子窗口根据实际大小进行调整。


GTK+ 的 layout 你在试试在 table 中去自由控制吧,除非你用后来才实现的 fixed。
理想中: 又能自由控制位置,又能根据最佳大小调整。我只在 BeOS API 中见过。

10.     GTK+采用容器机制来合理分离控件的职责,MFC没有容器这个概念,很难实现递归组合。GTK+中差不多所有控件都是容器,都可以容纳其它任何控件,而MFC只有顶层窗口才是容器,可以容纳其它子控件。容器这个概念对代码重用的影响非常之大,这里举两个例子:其一是带图片的按钮 (BitmapButton),在GTK+中它就是GtkImage和GtkLabel的组合,而在MFC中,图片和文字都要自己绘制。前者的 GtkImage和GtkLabel可以在很多地方重用,而后都的绘制代码和事件处理代码只有自己才能使用。其二是列表框,在GTK+中,它只是一个容器,你可以向里面放编辑器、下拉框和其它任何者你想得到的控件。而在MFC中,即使只是实现一个不同外观的列表框,你都要采用自绘的方式,代码重用非常困难,向列表框中加入其它控件就更麻烦了,要使用一些非同寻常的手段不可。


要是你想,同样可以给 MFC 增加象容器的功能。

11.     GTK+采用容器机制优先使用组合而不是继承,符合现代设计的原则。MFC强制使用继承,使用麻烦而且耦合紧密。GTK+应用程序不需要继承任何窗口。MFC应用程序必须继承对话框或者其它顶层窗口才行,虽然可以采用中介者模式,把控件之间的交互集中在顶层窗口中,不需要继承控件,但仍然很麻烦。


继承不是好办法,但"继承+消息"确是你永远想不到的理想。
MFC 也是可以类似 QT 的 SIGNAL/SLOT 的。
GTK+ 使用 signal 机制,不要说现代,其实就是消息驱动,它也有继承的机制,你写个 GtkWidget 就知道。

论坛徽章:
0
2 [报告]
发表于 2007-04-17 00:38 |显示全部楼层
原帖由 mistletoezju 于 2007-4-16 16:33 发表
继承+消息, 好处在哪


没想到那么久的贴子还被拉了起来。
简单的示例,主要还是看个人喜好...



  1. class MyHandle : public AHandle {
  2. public:
  3.         MyHandle();
  4.         virtual ~MyHandle();

  5.         virtual void MessageReceived(AMessage *msg);
  6.         virtual void Bombing();

  7. private:
  8. ...
  9. }

  10. ...

  11. void
  12. MyHandle::Bombing()
  13. {
  14.         AMessage reply;

  15.         if (SendMessage(fSolider, AMessage('redy'), &reply) != A_OK ||
  16.             reply.HasBool("Yes, sir.") == false) {
  17.                 Tell(fSolider, "What are you doing ?");
  18.         } else if (!fCommandReceived) {
  19.                 Tell(fChief, "Waiting for your command, sir.");
  20.         } else {
  21.                 AHandle::Bombing();
  22.         }
  23. }


  24. void
  25. MyHandle::MessageReceived(AMessage *msg)
  26. {
  27.         AMessage bombMsg;

  28.         switch(msg->what) {
  29.                 case 'bomb':
  30.                         if ((msg->FindMessage("command", &bombMsg) == A_OK ?
  31.                                         (bombMsg.AddBool("fromCaptain", true),
  32.                                                 SendMessage(fSoldier, bombMsg) == A_OK) :
  33.                                         false)) return;
  34.                         AHandle::MessageReceived(msg);
  35.                         break;

  36.                 ...
  37.                 default:
  38.                         AHandle::MessageReceived(msg);
  39.                         break;
  40.         }
  41. }

  42. ...

复制代码

[ 本帖最后由 savageranthony 于 2007-4-17 00:54 编辑 ]
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP