MFC和QT等UI框架的特点
UI设计的3大原则:
- 面向对象;
- MVC;
- 消息队列驱动;
直到现在各个UI系统,包括题主所提到的MFC、WPF、Qt,也包括其它,诸如Android SDK、Cocoa的构建仍旧建立在这3大原则的基础上。
要提到MFC,就不得不先提到Windows SDK,后者是随Windows 1.0所提供的操作系统API。Windows 1.0在1985年发售,尽管在此之前已有施乐的Star、苹果的Lisa和Mac OS这样的图形界面操作系统,但Windows 1.0毕竟是第一个大规模发行的图形操作系统,需要直面各样的开发者与普通用户的问题,也算是“第一个吃螃蟹的”。既然是第一个,当然是不成熟的。这种不成熟即有当时技术条件的限制,也有经验上的匮乏,我用一个例子简要说明一下。例如,我需要显示一个窗口,Windows SDK看上去是这样的:
int WinMain() {//1 register a window classWNDCLASS wndclass;wndclass.style = CS_HREDRAW | CS_VREDRAW;wndclass.lpfnWndProc = WndProc;wndclass.cbClsExtra = 0;wndclass.cbWndExtra = 0;wndclass.hInstance = NULL;wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);wndclass.lpszMenuName = NULL;wndclass.lpszClassName = "MainWndClass";RegisterClass(&wndclass);//2 create a winowHWND hwnd = CreateWindow("MainWndClass","Window Title",WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,NULL,NULL,hInstance,NULL);//3 message loopMSG msg;while (GetMessage(&msg, NULL, 0, 0)) {TranslateMessage(&msg);DispatchMessage(&msg);}return 0;
}
对,你没有看错,那个叫CreateWindow的函数的有11个参数!按照面向对象的观念与简洁性的做法,它不应该是这样的吗(一个Gtk的例子):
GtkWidget *window = gtk_window_new(GTK_WINDOW_TOPLEVEL);gtk_window_set_title(window, "window title");
gtk_window_set_position(window, GTK_WIN_POS_CENTER_ALWAYS);
gtk_window_set_default_size(window, 400, 300);
gtk_window_set_resizable(window, TRUE);
原因是当时的机器内存太小,一个函数的链接符号要占有一个字长的地址空间,所以能省就省。这也是当时诸多系统API设计的惯例,如之后苹果的Carbon库,参数多到惨不忍睹的函数也是比比皆是。这就是所谓的“技术限制”的一例。
此外,上例中第一步“注册窗口类”和第三步“消息循环”有必要强制要求用户来指明各个参数项吗。从后来的实践看,答案是没有必要。但作为“第一个吃螃蟹的”,怎么会知道。这就是所谓的“经验上的匮乏”一例。
作为后起之秀的Qt,同样是显示一个窗口,用户代码就简洁得多:
int main(int argc, char *argv[]){//1 create application instanceQApplication app(argc, argv);//2 create a windowQWidget *window = new QWidget;window->setWindowTitle("title");window->show();//3 message loopreturn app.exec();
}
正由于Windows SDK的不如意,于是就出现的MFC。
这里我想插一个题外话:为什么用户终端系统(包括Windows、mac OS这样的PC端,Android、iOS这样的移动平台,也包括Play Station、xbox这样的家用主机),所提供的的API和程序库接口,编程语言都是类C(C、C++、ObjC、Java等)的。这主要是技术积累的缘故。早期探索用户终端系统的开拓者,使用的C语言,先驱们在这一语言基础上构建起各种基础设施,包括教育环境与人才储备,项目管理的流程与经验,开发、分析、测试工具,建议做法与禁忌。作为后来者当然不会舍弃这些基础设施而另起炉灶从零开始,于是使用类C语言就成了传统。可以预见:下一代的用户终端与的程序库接口,也是类C的编程语言。
我们回到MFC的话题。MFC只是对Windows SDK的封装,按后世的看法,MFC不按“套路”出牌!包括作为同时代竞争产品的Borland公司的VCL,还有稍晚的Java awt,也是不按“套路”出招!这里我需要解释下图形库构建的“套路”是什么,读者才能理解什么叫“不走套路”。
对于一个图形界面的程序,大致可以分为3个层:
+----------------------+
| user application |
+----------------------+
| ui framework |
+----------------------+
| operation system api |
+----------------------+
最下面的是操作系统API,无论是UI库还是用户程序,要实现某功能最终都是要依赖于操作系统API的。关键点在于,操作系统需要提供多少数量的API函数,才足以构建一个图形界面程序。答案是:很少。
首先,操作系统需要为UI框架和用户程序提供一块屏幕区域:
struct window *window_create();
其次,这块区域需要能够接收用户事件(这里以鼠标点击为例):
enum mouse_event {mouse_event_down,mouse_event_move,mouse_event_up
};typedef void (*mouse_handler)(struct window *, mouse_event event, int x, int y);void window_set_mouse_handler(struct window *, mouse_handler handler);
最后,UI框架与用户程序需要在这块区域绘制各种控件(下例是矩形):
struct context *context_get_form_window(struct window *);void context_set_color(struct context *, int rgba);
void context_fill_rect(struct context *, int x, int y, int width, int height);
只要有了这3类API,一个图形界面程序就可以构建出来了,即使如今复杂的3D图像程序也是如此。这些作为基础API的函数数量很少,往大的说不到一百个,往小的说,十多个也能成事。庞大的UI框架,诸如Qt、Xamarin、WinForm,仅仅是以这几十个操作系统API函数作为自己的基础;对操作系统极小的依赖,也是可移植的保障;也是UI框架构建的“套路”。
所以说微软的MFC、Borland的VCL不走“套路”,因为它们都是对Windows SDK的封装,而不是选择少量Windows SDK核心函数并在其上构建自己的工作逻辑。因为Windows SDK使用繁琐,于是有了MFC,但MFC是对Windows SDK的直接封装,虽然提升了易用性,但终究要沿用Windows SDK所定义的工作流程。当然这种做法也是有好处的,例如工作量更小、用户可以更方便地直接调用系统API。
说穿了,MFC(当然也包括VCL)需要解决的是“有无”的问题。Windows 1.0这样的图形界面操作系统已经开始在大众领域普及,开发者也需要一套框架来开发图形界面程序。MFC在上世纪90年代取得了巨大的商业成功,但以后世程序员的眼光看,MFC还是太稚气了。我曾经接触过一些学习Windows程序开发的新人,他们对MFC充满鄙夷,认为MFC是上个世纪的遗留产物,它概念多、晦涩难懂、代码量大、界面也丑,他们更倾向于Qt、WPF这样的新秀。他们的结论是对的,MFC确实是上个世纪的遗留产物;但推导过程不对,MFC与Qt、WPF本质上是一样的东西,在MFC上遇到的问题,在使用Qt、WPF时极可能也会遇到,不过是早还是晚。只能说“MFC对新人极不友好”。
在MFC同时代,也正是上世纪80、90年代,出现了对后世UI框架设计有极大影响的技术方案:用web浏览器作为图形界面程序的容器。由于篇幅的限制,我这里直接说结论:作为一个整体性的技术方案,它失败了。失败的原因可以大致归为3点:
- 其一是观念上的落后。基于html、js、css的网页技术,最初的设计意图是解决文档浏览的问题,采用html为主,js、css相辅的设计方式。这样的设计在界面表现上有优势,但也仅此而已,其它方面诸如程序生命周期控制、数据处理等就太糟糕了。
- 其二是基础设施的不如意。相关的人才与技术储备太欠缺,所能实现的产出物,无论在功能上还是性能上都无法与MFC、VCL这样的传统程序相同并论。
- 其三是技术开拓者的急功近利。当时热衷于以浏览器作为图形程序容器的技术方案的厂商,如网景,还有后来的google和facebook,它们的意图很明显,就是挑战微软的平台霸权,建立有利于自身的生态环境(说人话就是:招揽开发者、提供生产工具、生产特定的程序、平台吃流量)。充满鼓动性的价值观营销在具有叛逆属性的年轻人中可以快速取得影响力,但得不到主流的支持和强势技术团队的示范,一切都是空。
尽管在新世纪的第二个10年以web前端为技术基础的UI框架,如electron、reactive native,取得了喜人的成果,但与上世纪的雏形相比,它们所在的大环境与技术本质已有了根本的区别。
但失败的方案并不代表没有借鉴意义。本世纪初出现了一种被称为“direct ui”的思潮,其中一大观点就是程序启动时加载xml文件作为UI。眼亮的同仁一定会说:这不就是资源编辑器莫。对的,这就是现代意义的资源编辑器的雏形。另外也多有程序会在自身嵌入一个web容器来显示特定内容的UI,至今Android、iOS App上这样的做法也相当常见。出于篇幅的限制这里的技术因果就不展开了。
上世纪90年代末到本世纪初是UI库百花齐放的年代,如今在PC领域,为人熟知的Qt、Gtk、wxWidgets都出现在这个时间段,这是与大环境有关。
- 首先MFC解决了“有无”的问题,接下来就是“好用难用”的问题;
- 其次由于前一个10年图形系统的普及,业界在图形程序的开发上有了大量的人才、技术、经验上的积累,开发一套UI库对于小团队来说也是敢想敢干的事;
- 再次定制化的需求开始出现,是需要能实现快速开发的程序框架(WTL),还是可以实现跨平台的程序框架(Qt)?是需要能实现常见功能的中小程序框架(wxWidgets),还是得安装几个G的包但可以实现复杂应用的程序框架(WPF)?不同的团队面对不同的任务,一定会有不同的选择。
- 此外当时微软作为处于垄断地位但又不思进取的操作系统厂商,也有推波助澜的作用。本世纪第一个10年,MFC已很老旧,但微软却一直没有给出升级方案;微软一味将开发者向.Net上推,但迁移成本太高,并且后者的性能问题也迟迟不能解决。于是开发者只能自己想办法。
Qt是传统PC领域程序框架集大成者,除了UI,它还提供数据库、多媒体等功能,已经不是单纯的UI框架,而是一套完整的程序开发解决方案;wxWidgets就要轻量级一些;WPF则是微软官方作为取代曾经的MFC、后来的WinForm的替代方案。
我这里谈一下跨平台开发的一些经验。问:使用跨平台的程序框架开发程序,相比于每个目标平台单独组建一个开发组,前者有更高的性价比?回答是:不一定。开发程序不仅仅是程序员的事,还涉及到产品策划、美术、市场运营、第三方技术供应商等方方面面,具体问题要具体分析。事实上资金与人力充足的团队,更倾向于不同目标平台组建各自的开发组。
新世纪的第二个10年,以iOS、Android主导的移动平台兴起。Qt推出了移动平台版本,但终究没有形成气候;微软推出UWP,WPF还是被舍弃了。这又是另一个话题了。
作者:wzsayiie
链接:https://www.zhihu.com/question/23480014/answer/658825482
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
MFC和QT等UI框架的特点相关推荐
- 基于halcon实现视觉定位框架(C#做主算法,C#、MFC、Qt二次开发)【附源码】
文章目录 前言 演示视频 一.项目文件目录讲解 1.CtuVisionControlLibrary 2.CtuVisionDLLTest_CSharp 2.CtuVisionDLLTest_MFC 2 ...
- qt ui框架_5个开源Python GUI框架
您的Python程序需要图形用户界面吗?这里有五个工具可以帮助您构建一个. 在Python中,开始GUI编程的步骤并不十分复杂,但是它们确实需要用户开始做出一些选择.由于Python是一种通用编程语言 ...
- 桌面应用程序UI框架有哪些
Electron 是一种基于Node.js和Chromium的跨平台框架,可以用于构建桌面应用程序.Electron使用HTML.CSS和JavaScript编写,可以使开发人员使用Web技术开发桌面 ...
- C语言 英汉互译电子词典 命令行,MFC,QT 3种版本
需要1个字典文件. 命令行版 MFC版 QT版 1,命令行版 -- [1] #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #incl ...
- 跨平台界面库 linux,超轻量/跨平台UI框架(目前已经支持: Windows, Android, Linux, VR)...
今天的大部分的软件,都被三大平台牢牢占据:PC上面的Windows, 嵌入式设备上的Linux,手机设备的Android. 如果分别为这三个平台开发软件,工作量和维护量可想而知.特别是界面部分,都意味 ...
- android ui框架详解,多图详解 “Android UI”设计官方教程(二)
编者注:本文为Android的官方开发者博客发了一份幻灯片的翻译文档的第二部分,专门介绍了一些Android UI设计的小贴士,我们在介绍这个幻灯片的第一部分<多图详解 "Androi ...
- Unity手游实战:从0开始SLG——UI框架篇(一)各种UI框架模型简介
提到游戏的UI开发,几乎没人没听说过MVC吧?MVC最早是为软件架构设计的框架,这里不打算讲MVC的演变过程,需要的了解的可以参考大神的文章,传送门: 你对MVC.MVP.MVVM 三种组合模式分别有 ...
- bootstrap 新闻列表_kuapingUI 2.2 版本发布,跨屏 UI-bootstrap 大组件 UI 框架
kuapingUI 2.2 版本发布,增加了一个比较实用的工具栏web组件,是由分享按钮组 + 联系按钮组构成,分享按钮组包含了 QQ空间.朋友圈.QQ.微信.微博等分享:联系按钮组包含了 微信.QQ ...
- 前端Js框架 UI框架汇总 特性 适用范围 选择
身为一个资深后端工程师,面对层出不穷的前端框架,总让人眼花缭乱,做一个综合解析贴,从全局着眼,让我们明白各种前端框架的应用范围,为如何选择前端框架,从不同的维度提供一些线索,做为一个长期优化贴,欢迎指 ...
最新文章
- 11.PHP与MySQL
- 多线程情况下创建连接池
- girton college map
- java异步线程内存可见性实验
- Wix 安装部署(二)自定义安装界面和行为
- 《Effective C#中文版:改善C#程序的50种方法》简介
- 考研过程中最容易犯的八大错误
- [USACO14JAN]Recording the Moolympics
- linux 时间戳 c语言,C语言实现字符转unix时间戳
- eat pray love
- 美服fgo显示服务器异常,FGO日服美服错误代码合集_FGO日服美服错误代码汇总_牛游戏网...
- Word 论文排版操作顺序
- python求n的阶乘_python如何计算n的阶乘
- 链家网爬取深圳租房分析
- 为什么RSA 公钥指数(e=65537)
- 2.初学者初始Elasticsearch
- OAuth2.0实现自定义颁发token
- 【回炉重造】——反射
- 用腾讯云COS制作个人图床
- 30秒让你弄懂pdf怎么翻译,还在犹豫什么
热门文章
- python学习-异常(异常类型,异常处理、自定义异常)
- 3算法全称_全网最通俗的KMP算法图解
- mysql如何植入到oracle_MySQL产品的生命周期
- mysql php 迁移_MySQL数据复制、迁移、转换
- java 8 并行_Java 8新特性之 并行和并行数组(八恶人-8)
- java 有穷自动机_Java实现雪花算法(snowflake)
- boot spring test 文档_Spring、Spring Boot 和 TestNG 测试指南 ( 3 )
- 常用的分隔符有哪三种_三种废水处理方法
- 国家电网是“围城”?辞职吗?
- verilog简易密码锁设计