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 class
    WNDCLASS 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 winow
    HWND hwnd = CreateWindow(
        "MainWndClass",
        "Window Title",
        WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT,
        CW_USEDEFAULT,
        CW_USEDEFAULT,
        CW_USEDEFAULT,
        NULL,
        NULL,
        hInstance,
        NULL);

    //3 message loop
    MSG 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 instance
    QApplication app(argc, argv);

    //2 create a window
    QWidget *window = new QWidget;
    window->setWindowTitle("title");
    window->show();

    //3 message loop
    return 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
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
MFC和WinForm都是用于创建桌面应用程序的GUI框架MFC是微软提供的一个C++ UI,它提供了一些控件,使开发者能够方便地创建漂亮的UI界面。MFC还提供了其他许多类,功能较为强大。WinForm是C#中针对桌面应用程序提供的UI,相对于MFC而言,WinForm提供了更多的控件和更强大的功能,使用起来更加方便。如果习惯了WinForm,再来使用MFC可能会感到不太方便。总结来说,MFC和WinForm都是用于桌面应用程序开发的GUI框架,它们各自有不同的特点和优势。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [MFC Window and WinForm Plugins 最新版本](https://download.csdn.net/download/xfingerx/10141410)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [MFC与WinForm对比学习:简单介绍](https://blog.csdn.net/iteye_3619/article/details/82435079)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [MFC,QT与WinForm,WPF简介](https://blog.csdn.net/iteye_3619/article/details/82451714)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值