问题

MFC、WTL、WPF、wxWidgets、Qt、GTK 各有什么特点?

回答


以下是MFC、WTL、WPF、wxWidgets、Qt、GTK等框架的详细特点分析:



1. MFC(Microsoft Foundation Classes)
核心特性:
基于Windows API的封装:MFC是微软为Windows开发的C++类库,封装了Windows API,简化了Windows应用程序的开发。
面向对象设计:通过类(如`CWnd`、`CFrameWnd`)封装了窗口、控件、消息处理等底层功能。
文档/视图架构:支持经典的MFC架构(文档视图),适合复杂的文档编辑类应用。
与Windows深度集成:充分利用Windows API的特性(如GDI、OLE、COM),适合Windows平台的底层开发。
适用场景:
传统Windows桌面应用开发(如Office、Windows资源管理器)。
需要与Windows API深度集成的系统级应用。
缺点:
过时:微软已推荐使用更现代的WPF或C++/CLI替代方案。
学习曲线高:需要理解Windows API和MFC类层次结构。
跨平台能力差:仅限Windows平台。



2. WTL(Windows Template Library)
核心特性:
轻量级替代方案:WTL是微软推出的轻量级Windows GUI库,基于C++模板,不依赖MFC的复杂类层次。
高性能:直接调用Windows API,避免MFC的冗余封装,适合对性能要求高的应用。
现代设计:支持C++11/14特性,提供更简洁的接口(如`CWindow`类)。
跨平台潜力:通过移植技术可支持其他平台(如Linux),但主要面向Windows。
适用场景:
需要高效、轻量的Windows GUI应用(如游戏、工具软件)。
与MFC兼容但需要更底层控制的场景。
缺点:
社区和文档较少:相比MFC,WTL的开发者和资源较少。
功能较基础:缺少MFC的高级功能(如文档/视图架构)。



3. WPF(Windows Presentation Foundation)
核心特性:
基于XAML的UI开发:使用XAML定义界面,支持数据绑定、样式、动画等现代UI特性。
跨平台潜力:通过.NET Core等技术,可扩展到跨平台(如Linux、macOS)。
与.NET集成:深度整合.NET Framework,支持C、VB.NET等语言。
现代化特性:支持矢量图形(如`Canvas`)、多线程、3D图形(通过DirectX)。
适用场景:
现代Windows桌面应用(如Office 2013+)。
需要复杂UI交互和数据绑定的应用。
缺点:
仅限Windows:尽管有跨平台尝试,但主要针对Windows平台。
性能瓶颈:XAML的解析和渲染可能不如原生代码高效。



4. wxWidgets
核心特性:
跨平台GUI库:支持Windows、Linux、macOS、iOS、Android等平台,使用C++和C语言。
本地化UI:通过封装本地控件(如Windows的`Button`、Linux的`Gtk`),实现与操作系统一致的界面。
轻量级:代码量较少,适合小型项目。
开源且免费:遵循LGPL许可证,支持商业用途。
适用场景:
需要跨平台的桌面应用(如文本编辑器、工具软件)。
需要与本地系统集成的UI开发。
缺点:
功能较基础:缺乏高级UI组件(如图表、3D图形)。
文档和社区支持有限:相比Qt,开发者资源较少。



5. Qt
核心特性:
跨平台框架:支持Windows、Linux、macOS、嵌入式系统、移动平台(Android、iOS)等。
全面功能:内置GUI、网络、数据库、多线程、图形渲染(QPainter)、3D(Qt3D)等。
信号与槽机制:强大的事件处理模型,简化了UI交互。

开源且免费:商业用途需购买商业许可证,但有开源版本(LGPL)。
跨平台编译:支持多种编译器(GCC、MSVC、Clang)。
适用场景:
复杂的跨平台应用(如工业软件、游戏、嵌入式系统)。
需要高性能和丰富功能的开发。
缺点:
学习曲线陡峭:需要掌握C++和Qt的复杂类库。
许可证问题:商业使用需购买许可证,可能增加成本。



6. GTK(GIMP Toolkit)
核心特性:
跨平台GUI库:主要面向Linux,但也支持Windows、macOS、Android等平台。
基于C语言:主要使用C语言开发,但也支持C++(通过` gtkmm`)。
本地化UI:通过封装本地控件(如Linux的`Gtk`),实现与系统一致的界面。
开源且免费:遵循GPL许可证,适合开源项目。
适用场景:
Linux桌面应用(如GIMP、GNOME桌面环境)。
需要轻量级且与Linux集成的UI开发。
缺点:
功能较基础:相比Qt,缺少高级功能(如3D图形、数据库)。
社区活跃度较低:相比Qt和wxWidgets,开发者资源较少。



对比总结
| 框架 | 语言 | 平台支持 | UI复杂度 | 性能 | 学习曲线 | 开源性 | 适用场景 |
|||||||||
| MFC | C++ | Windows | 高 | 高 | 高 | 无 | 传统Windows桌面应用 |
| WTL | C++ | Windows | 中 | 高 | 中 | 无 | 高性能Windows GUI应用 |
| WPF | C | Windows | 高 | 中 | 中 | 无 | 现代Windows桌面应用 |
| wxWidgets | C++ | 多平台 | 中 | 中 | 中 | 是 | 跨平台桌面应用 |
| Qt | C++ | 多平台 | 高 | 高 | 高 | 是 | 复杂跨平台应用、嵌入式系统 |
| GTK | C/C++ | 多平台 | 中 | 中 | 中 | 是 | Linux桌面应用、轻量级UI |



选择建议
Windows原生开发:MFC(传统)、WTL(高性能)、WPF(现代UI)。
跨平台需求:wxWidgets(轻量)、Qt(全面)、GTK(Linux专用)。
高性能需求:WTL、Qt。
现代UI开发:WPF(Windows)、Qt(跨平台)。
开源项目:wxWidgets、GTK、Qt。

根据项目需求(如平台、性能、复杂度)选择合适的框架,同时考虑社区支持和长期维护性。

网友意见

user avatar

谢邀(终于用上这个高大上的词汇了,真的有点小激动呢)

WTL都算不上什么Framework,就是利用泛型特性对Win API做了层封装,设计思路也没摆脱MFC的影响,实际上用泛型做UI Framework也只能算是一次行为艺术,这个思路下继续发展就会变得没法用了,比如 代码过于复杂,编译太慢,出错不好调试等问题难以解决。

而且封装得也不完全,还是随处可见 HWND HDC之类的东西。

用途主要是写一些很小的程序,或者作为其他UI框架的后端实现部分,比如我写过一个小框架用来做安装卸载程序,非常小,其中创建管理窗口部分是用WTL的。

MFC是更高级点的Win API封装,比WTL封装彻底,很难见到HWND HDC了,也提供了不少实用工具类,比如高级控件,泛型容器,IO访问,网络协议等。除此之外,还提供了一些基本框架,比如 Document/View,这就是个MVC的简化版本,只有MV,但是对于数据的管理,消息的传递等又没有什么约束,导致Doc/View被用得乱七八糟。尤其是对事件处理的模型,消息映射是功能简陋,而且容易出错的方式,唯一优点是性能好。 从VC++ 1.X就有MFC了,那时整个UI界的设计思想都比较落后(除了Apple),MFC又背负了沉重的兼容性包袱,比如vc++ 1.52的MFC程序到了vc2003稍加修改都可以编译,导致MFC后期没有什么发展,就是沿着老的思路完善了些细节,添加了些组件,但是根本性的设计问题没有改进。

GTK,这个吃了语言的亏,用C写面向对象实在是痛苦,虽然在思想上比MFC要先进了些,但是写出来的代码比MFC要罗嗦很多了。相比MFC,多了Layout的概念,事件处理上有了Signal/slot,虽然用起来很麻烦。

wxWidgets,这个基本就是个跨平台的MFC,对各个平台的差异做了抽象,实际上后端大多还是用平台原生的API实现,好多控件都是直接用系统原生的。有wxWidgets for GTK+的版本,后端就是GTK+,wxWidgets就是一层壳。这也是wxWidgets的优点,它编译出来的程序发行包比较小,性能也不错。

以上这些就是上世纪90年代的UI Framework技术水平了,至今它们也依然没有太多进步。

下面来谈谈21世纪的技术。

Qt,虽然它也是上世纪90年代出现的,但是它在21世纪有了长足的进步。应该说它的起点就比较高,一开始就定位跨平台,而且不满足于简单封装系统API,而是要自己创造出一套完整的API和框架,甚至要代替系统API,所以不仅仅是做UI,而是涉及到了APP开发所用到的所有东西,包括网络,数据库,多媒体,脚本引擎等。signal/slot是Qt发明的,这是事件通知模型里C++语言的最佳实现了,甚至我都觉得这该写进C++标准,估计C++委员会的老顽固们是从不写GUI的。

早期的QT也是没有DirectUI的概念的,每一个QWidget都对应一个原生窗口,从Qt4.4开始,只有顶层QWidget才是原生窗口,而Child Widget是Alien Widget,只是个抽象的图层不对应原生窗口,这就实现了DirectUI的概念,很多图形效果也就变得可能了,比如窗口层叠透明效果。

在4.8后实现了QPA(Qt Platform Abstraction),这就使移植Qt变得很容易,目前Qt是支持平台最多的框架没有之一。

由于早期授权的问题,Qt对于开源社区不是很友好,导致推广不太顺利,直到它改成了LGPL方式,如果Qt能早点想开了,恐怕就没有wxWidgets的生存空间了。

Qt的缺点也是有的,就是太大,不过可以自己剪裁,我可以把QT库剪裁到发行包压缩后2.5MB。

WPF,微软在Win Form的思路上走到死胡同后,终于痛下决心用正确的方法开发UI库了。21世纪的UI一定是定义出来的,绝对不能是代码写出来的,所以有了XAML这个强大的定义工具,不但可以定义UI布局,还包括图形动画效果,消息响应方式等。配合C#这种优秀的语言,更是如虎添翼。但是问题也很明显,就是过于庞大,不仅开发时要用到庞大的IDE和设计工具,发行的安装包也十分巨大,所以目前还是很少有人拿他写通用软件客户端的,大多是做企业项目时写专用客户端。

大概4-5年前吧疼讯曾经用WPF写了个QQ,但是只实现了基本功能就已经比C++客户端大好多了,而且运行缓慢,主要是太吃内存,而且那时WPF的优化还不充分。

最后我想补充下真正的UI库之王,cocoa。

Apple的成功有很多原因,其中之一就是cocoa,cocoa理念十分先进,而且出来得早,我都怀疑Qt和WPF有不少思想都是借鉴cocoa的。

定义式的UI,用xib就可以定义UI的绝大部分细节,而且提供所见即所得的可视化设计工具。

严格的MVC,而且定义非常清晰,分工明确。

signal/slot,虽然不叫这个名字,但思想就是,而且真的是拖动鼠标就能connect。

提供了ARC,闭包和反射,给UI开发带来巨大的便利性,当然这得益于Objective-C这个语言。

再补充下 Borland的OWL和VCL。

我是从Borland C++3.0和Delphi 1.0开始用的,那时的Borland看来很有前途的,可惜后来一系列决策失误导致现在这个公司几乎消失了,同学们不要再往这个坑里跳了。

OWL曾经和MFC是竞争对手,设计思想也差不多,个人感觉OWL的API设计更优雅一点,但是在市场上OWL被MFC彻底击败。

Delphi是神作,它在RAD(快速应用开发)领域长时间没有对手,直到BS架构取代CS架构。Delphi的特点就是简单、开发快,单纯就写个基本可用的应用来说,可能至今都没有比他更快的,但是缺点就是丑,基本大多数Delphi应用都是一大堆控件堆积在一起,很不美观,另外由于Pascal语言的限制无法和现有大量的C/C++代码融合。虽然后来有C++ Builder,但是Builder里简单和快的优点也消失了。Borland的C++编译器越做越差,导致后来开源项目都不太愿意兼容这个编译器了。

VCL准确地说不是UI库,而是一套组件接口规范,类似COM ActiveX。delphi和C++builder都是基于这个规范构建了基础库。

UI库是个很大的话题,够写好几本书来探讨的,我这里就是随便写点自己的感受。

单纯讨论每个库的优劣是没有意义的,而是要放到具体的应用场景里来看,每个库都有自己擅长的场景。

如果仅在Windows下,追求程序小巧,用WTL,不足的地方自己实现去吧,但是视觉效果就呵呵了。

如果可以大一点,还要好看点,那就Qt。

如果完全不在乎大小,只要视觉效果华丽,就用WPF,如果把开发工具价格也考虑进来,那么土豪才会选WPF呢。

MFC就是个鸡肋了,除非你现有的工程师不会用别的,或者有历史遗留代码要保持兼容。

如果要求跨平台,那么就用Qt,wxWidgets和GTK+跟现在的Qt比起来没有什么优势了。

如果是iOS Android,那么最好用原生UI库,除非你写游戏。

user avatar

感觉我说了太多 Qt 的事情了,今天只说一下 MFC ,到底过时在哪里,都在说 "MFC 就是 xxx" 类似的话,我来补充点细节,增加点感性认识,到底 MFC 过时在哪里?想要用好 MFC 可以怎么办?

虽然 MFC 也有 DIALOG 的设计器,似乎可以拖一下控件,做个 hello world, 计算器之类的好像也很简单,但是稍微复杂那么一点就麻烦了,比如布局,MFC 里的控件只能设置绝对坐标和大小,那么如果你的窗口扩大或者缩小了,想自动改变内部特定控件的大小和位置怎么办?比如 C# 里随便设置一下各个控件的 docking 和 anchor 就能:

就能让某些控件随窗口变大而移动,某些控件随窗口变大而变大,而某些控件不变,这在任何 GUI 库里都是最基础的功能,都可以在设计器里点两下就做到的事情,MFC 却需要重载 WM_SIZE, WM_SIZING 消息来自己写代码每次手工计算所有控件的新坐标和大小,想写的通用点,还得上千行的代码,枚举所有子控件,根据额外信息重新计算位置大小,虽然 2015 的 MFC 里加了一个半成品的布局信息,但是基本没用,你在 MFC 的设计器里拖控件,都是写死坐标和大小的。

你也别说 c# 比 MFC 新,c# 的 docking 和 anchor 都是抄的 MFC 同期的 delphi 的布局方式,delphi 里叫做 align 和 anchors,c# 改都没改就换了个名字拿过去了。可以说布局是 GUI 库最基本的一个功能了,连 tkinter 都支持,MFC 却没有,而且持续十多年不思进取不增加。

再举个界面设计的常见操作,设置窗口的最小尺寸,其他编辑器里就是填写个窗口属性了事,MFC 里怎么做?要到 MainFrame 那里用 ClassWizard 找到 WM_GETMINMAXINFO 消息,为其生成一个函数,并编写:

       void CMainFrame::OnGetMinMaxInfo(MINMAXINFO* lpMMI) {     CRect rc(0, 0, 400, 300);     CalcWindowRect(rc);     lpMMI->ptMinTrackSize.x = rc.Width();     lpMMI->ptMinTrackSize.y = rc.Height(); }      

是不是一脸懵逼?这 MINMAXINFO 是干嘛的?OnGetMinMaxInfo 到底什么时候被调用?CalcWindowRect 又是啥意思?看到这里你还想用么?

最后再举一个界面设计里最常见的例子,spliter bar,就是可以拖动改变左右两边控件/容器大小的分隔栏,比如资源管理器左边的文件树和右边的内容中间那根可以左右拖动控制改变左右两边控件尺寸比例的分隔栏就是 spliter bar,其他 GUI 库里就是设计器里拖出来点点点就创建好的东西,MFC 却不行,设计器里根本没有 spliter bar,需要在 OnCreateClient 函数里自己手工创建 CSplitterWnd,并且为左右两边分别创建两个 view,还要重载 WM_SIZE 消息,每次手工算位置,通知左右两个 view 更新大小,还有各种坑,其他 GUI 库一分钟做完的事情,你 MFC 里可能要搞一小时(算上编码和调试填坑时间)。

上面三个界面设计中最基础的概念:布局,控件细节配置(如最小尺寸),splitter bar,在 MFC 里都是空缺的,可以看出你想用它开发一个稍微复杂一点点的界面都是非常麻烦和琐碎的事情。

同期的 delphi/c++ builder 简直是甩 MFC 十条街,再一个是 MFC 的封装太浅了,基本就是 Win32 API 对 C++ 做了一层映射,加了一些宏而已,其他 GUI 库,包括 wxwidgets 你都不需要和 Win32 API 打交道,但你要写 MFC 不了解 Win32 API 是不可能的,比如 ClassWizard 里:

你读不懂那一片 WM_ 的 Win32 消息是干嘛的,不了解 Win32 消息分发的机制,你基本别想写 MFC,而就算你用 wxWidgets 根本不需要去处理这么琐碎的事情,再一个是子控件管理,同期的界面库对窗口上的子控件都是直接封装成类的,并且按对象来组织。

MFC 里却和 Win32 程序一样,靠 ID 来管理,比如有一个静态文字 static text/label 之类的东西,你想改一下上面的字,MFC 里你先要找到这个 static text 的 id,然后用 ID 来获取类指针,然后再操作,比如:

       // TODO: Add your control notification handler code here CStatic *st = (CStatic*)this->GetDlgItem(IDC_STATIC1); st->SetWindowText(_T("hahahah"));      

这基本就是 Win32 API 里的 GetDlgItem 和 SetWindowText:

根据 ID 获取控件 HWND,只是把第一个参数给省略了。这个封装真的是 low 到家,围绕 ID 来组织控件这种 Win32 最原始的东西都要暴露出来,同期没有任何一个界面库需要直接操作控件 ID 的,不管同期的 Delphi 还是 wxWidgets 都是直接把每个子控件当作一个对象的,直接按对象来组织围绕对象开发即可。

封装太浅,很多东西又空缺,导致程序写大了一地碎鸡毛,还有人在多个窗口间靠 SendMessage 传指针来通信的,后期出点问题修都修不完。

那么 MFC 程序想写复杂了该怎么办呢?首先要靠编码规范来规避很多坑,比如多窗口间通信,就要约定只能纵向通信,拒绝横向通信,因为父亲控件控制子控件的生命周期,向下调用没问题,而子控件在生命周期内也有指向父控件的 parent 指针,那么上下级之间纵向通信是没问题的,父亲知道儿子什么时候被销毁,儿子也知道父亲永远在那里。但是要避免横向相互持有指针,那么兄弟控件通信可以绕道父节点或者 CMainFrame 那里去走一圈,避免直接兄弟之间直接指针调用方法,可以减少很多问题。

其次是自己要封装很厚的库,用来弥补 MFC 的不足,那么勉强一用,唯一的问题就是界面太丑了,不过有很多解决方案,比如用 skin++ 这类外挂库,两行代码,直接 hook 控件 redraw 的消息自己绘制:

几行代码就可以换肤,这样对中型项目基本是足够了,想要做的更好点,基本就要自己绘制上 dui 了,中小团队很难玩得转,很多公司会选择购买一些成品的 dui 库结合 MFC 使用,比如迅雷的 bolt ,我当年一个项目买过 uipower 的 DirectUI 库,用了一段时间后还是被逼着走上了自己写 dui 的老路。

大部分成熟的 MFC 项目,到最后都会撸自己的 dui 代码,仅使用 MFC 一些基础功能,比如消息,CFrameWnd,CString 之类的,里面就是自己绘制,程序开头载入一个界面布局的 xml 文件,根据 xml 文件描述的内容载入对应资源自动生成 dui 的子控件,然后重新解释鼠标消息,对于像 TextEdit ,RichText 之类复杂的控件,还是会用 MFC 原有的封装一层盖上去,浮在你的 dui 界面上面。

最终费劲千辛万苦,你终于可以用 MFC 做一个类似 360 这样稍微丰富多彩点的消费级界面了:

或者做出各种复杂度高的行业软件界面了,那么恭喜你,你在 MFC 里花了三年的时间,做出来的东西,终于摸到了只有半年经验的 Qt 程序员的脚后跟了。


--

类似的话题

  • 回答
    以下是MFC、WTL、WPF、wxWidgets、Qt、GTK等框架的详细特点分析: 1. MFC(Microsoft Foundation Classes) 核心特性: 基于Windows API的封装:MFC是微软为Windows开发的C++类库,封装了Windows API,简化了Wind.............
  • 回答
    在 MFC 中使用 `LoadLibrary` 动态加载 DLL 本身并没有一个严格的、直接的函数调用层面的数字限制。也就是说,你不会因为调用了 `LoadLibrary` N+1 次就触发一个内置的错误码或限制。然而,在实际应用中,间接的限制和考量非常多,这些因素会影响你可以“安全地”加载多少个 .............
  • 回答
    MFC(Microsoft Foundation Classes)这东西,说它“过时”吧,好像也不是那么绝对,但要说它像当年那样风光无限,那肯定是真的没落了。用一个不那么专业的比方,就像一个曾经的影帝,现在偶尔还会拍几部戏,但你不会指望他还能像年轻时那样扛起一部大制作的票房。咱们得从几个方面来聊聊这.............
  • 回答
    形象地理解 MFC 编程框架:你是一位经验丰富的“建筑师”想象一下,你要建造一座宏伟的“Windows 应用程序”大厦。MFC(Microsoft Foundation Classes)框架就像是为你提供的一套预制好的、经过精心设计和优化的建筑材料、施工工具和专业指导手册的综合服务商。你的任务是利用.............
  • 回答
    你好!很高兴能和你聊聊Windows MFC代码移植到Linux这个话题。对于编程新手来说,从零开始接触一个全新的平台和一套框架确实会有些挑战,但这绝对不是一项不可能完成的任务。关键在于你有明确的学习路径和坚持不懈的努力。MFC是什么?为什么移植会有难度?首先,我们得明白MFC (Microsoft.............
  • 回答
    目前在 Windows 桌面应用程序开发领域,MFC、Qt 和 C (通常指 WinForms、WPF 和 MAUI) 都是非常成熟且强大的选择。它们各有优劣,适合不同的项目需求和开发团队背景。下面将为您详细分析这三者,帮助您做出更明智的选择。 1. MFC (Microsoft Foundatio.............
  • 回答
    是的,很多人认为 MFC(Microsoft Foundation Classes)在现代 C++ 开发中确实已经相对过时,尤其是在开发新的、跨平台、现代化 UI 应用方面。MFC 是一个相对古老的框架,它基于 COM 模型,并且与 Windows API 紧密耦合。虽然它在很多遗留 Windows.............
  • 回答
    说实话,我能理解你此刻的心情,就像班里大家都在讨论最新的游戏,而你手里却拿着一本古老的游戏攻略,那种格格不入的感觉肯定不好受。大家热火朝天的在MFC的世界里探索,而你却要从零开始,面对一个完全不同的框架——Qt。这种“异类”感,就像是在一个熟悉的朋友聚会上,突然发现自己是唯一一个没听说过某个流行梗的.............
  • 回答
    我理解你想了解一个开源的6000行UI框架与Qt、MFC相比的优劣,并且希望得到详细且人性化的解答。但要直接回答“能否打败Qt、MFC”这个问题,其实非常复杂,甚至可以说没有一个简单的是或否。这涉及到很多层面的考量,而且“打败”这个词本身就带有很强的竞争意味,而开源项目往往更侧重于满足特定需求和社区.............
  • 回答
    在Visual Studio中调试C代码时,我们确实可以“追踪”进微软提供的.NET Framework或.NET Core的源码,这和调试MFC程序时追踪进Windows API的源码有着异曲同工之妙。这对于理解框架内部的工作机制、定位潜在的框架级问题非常有帮助。要实现这一功能,关键在于Visua.............

本站所有内容均为互联网搜索引擎提供的公开搜索信息,本站不存储任何数据与内容,任何内容与数据均与本站无关,如有需要请联系相关搜索引擎包括但不限于百度google,bing,sogou

© 2025 tinynews.org All Rights Reserved. 百科问答小站 版权所有