毫無(wú)疑問(wèn),Windows的流行推動(dòng)了圖形界面的發(fā)展,從最原始的Win32界面庫到MFC,再到最近UWP界面庫,Windows界面庫的發(fā)展也代表了界面庫和整個(gè)軟件行業(yè)的發(fā)展方向。本文就簡(jiǎn)單梳理下整個(gè)Windows界面庫的發(fā)展歷程和現狀。
Windows 整個(gè)系統的圖形界面是建立在Win32圖形界面接口上的,它提供了Windows界面編程的基本模型——顯示管理窗口和消息循環(huán)分發(fā)事件。Win32是C接口形式,一個(gè)典型的窗口程序如下,可以看到就是按照通用界面庫模型來(lái)的,不再贅述,對此感興趣的可以看Petzold的《Windows程序設計》。Win32需要考慮細節太多,目前實(shí)際編程很少再用原生win32了,一般是第三方界面庫基于Win32包裝或其他語(yǔ)言通過(guò)包裝Win32來(lái)提供基本界面功能。
- #include <windows.h>
- LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
- int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
- {
- static TCHAR szAppName[] = TEXT ("窗口類(lèi)名稱(chēng)");
- HWND hwnd;
- MSG msg;
- WNDCLASSEX wndclassex = {0};
- //設計窗口類(lèi)
- wndclassex.cbSize = sizeof(WNDCLASSEX);
- wndclassex.style = CS_HREDRAW | CS_VREDRAW;
- wndclassex.lpfnWndProc = WndProc;
- wndclassex.cbClsExtra = 0;
- wndclassex.cbWndExtra = 0;
- wndclassex.hInstance = hInstance;
- wndclassex.hIcon = LoadIcon (NULL, IDI_APPLICATION);
- wndclassex.hCursor = LoadCursor (NULL, IDC_ARROW);
- wndclassex.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH);
- wndclassex.lpszMenuName = NULL;
- wndclassex.lpszClassName = szAppName;
- wndclassex.hIconSm = wndclassex.hIcon;
- //注冊窗口類(lèi)
- if (!RegisterClassEx (&wndclassex))
- {
- MessageBox (NULL, TEXT ("RegisterClassEx failed!"), szAppName, MB_ICONERROR);
- return 0;
- }
- //產(chǎn)生窗口
- hwnd = CreateWindowEx (WS_EX_OVERLAPPEDWINDOW,
- szAppName,
- TEXT ("窗口名稱(chēng)"),
- WS_OVERLAPPEDWINDOW,
- CW_USEDEFAULT,
- CW_USEDEFAULT,
- CW_USEDEFAULT,
- CW_USEDEFAULT,
- NULL,
- NULL,
- hInstance,
- NULL);
- //顯示窗口
- ShowWindow (hwnd, iCmdShow);
- UpdateWindow (hwnd);
- //啟動(dòng)消息循環(huán)泵循環(huán)獲取消息分配到窗體過(guò)程函數處理
- while (GetMessage (&msg, NULL, 0, 0))
- {
- TranslateMessage (&msg);
- DispatchMessage (&msg);
- }
- return msg.wParam;
- }
- //窗體過(guò)程函數
- LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
- {
- HDC hdc;
- PAINTSTRUCT ps;
- switch (message)
- {
- case WM_CREATE:
- return (0);
- case WM_PAINT:
- hdc = BeginPaint (hwnd, &ps);
- EndPaint (hwnd, &ps);
- return (0);
- case WM_DESTROY:
- PostQuitMessage (0);
- return (0);
- }
- return DefWindowProc (hwnd, message, wParam, lParam);
- }
可以看到Win32創(chuàng )建一個(gè)簡(jiǎn)單的界面需要大段的代碼,既然是遵循相同的模型,恰好適逢C++技術(shù)發(fā)展,微軟借助C++技術(shù)將界面編程抽象成許多類(lèi),包裝諸多細節,最明顯的兩個(gè)特征:
1.簡(jiǎn)化窗口創(chuàng )建,窗口創(chuàng )建和類(lèi)綁定,創(chuàng )建的公共操作封裝到基類(lèi)中
2.窗口過(guò)程統一勾到一個(gè)處理函數中,然后分發(fā)到對應的每個(gè)窗口類(lèi)中(可以參考我的這篇文章)
這樣開(kāi)發(fā)者只需要重寫(xiě)部分虛函數,填充消息消息響應表實(shí)現響應函數即可,大大減少了開(kāi)發(fā)者的工作量,而且結合VC提供的可視化功能,能夠快速的完成界面代碼的生成。但是MFC封裝臃腫了,繼承層次過(guò)多,且當時(shí)的C++標準尚未完善為了彌補有很多hack設計,但是MFC經(jīng)過(guò)這么多年的發(fā)展已經(jīng)相當穩定了,所以現在主要用在工業(yè)領(lǐng)域,算是工業(yè)領(lǐng)域的一個(gè)標準了,一些小公司和小工具也還是在用MFC,感興趣的入門(mén)可以看看孫鑫《VC++深入詳解》,提高可以看侯捷的《深入詳解MFC》和David《Visual C++ 技術(shù)內幕》。
因為MFC的臃腫,微軟的一個(gè)開(kāi)發(fā)小組業(yè)余開(kāi)發(fā)了WTL,并且逐漸被大家接受,WTL主要基于C++ 模板技術(shù),封裝很輕量級,而且兼具M(jìn)FC的諸多優(yōu)點(diǎn),還可以和MFC混用。但是因為WTL技術(shù)上相對MFC要求較高,目前主要是一些大廠(chǎng)(360、金山等)在用,而且由于WTL的封裝很易于擴展,國內大多數Windows C++界面庫都是基于WTL開(kāi)發(fā)的,接下來(lái)關(guān)于界面庫的編寫(xiě)也主要基于WTL講解。
WTL出來(lái)的相對較晚,微軟也沒(méi)有大力宣傳過(guò),市面上講解的書(shū)不多,詳細了解WTL可以看看WTL for MFC Programmers系列文章,這是中文版本鏈接。
qt并非微軟的界面庫,他是一個(gè)跨平臺的C++界面庫,最早由諾基亞開(kāi)發(fā)用于手機界面展示,現在由奇趣公司維護。之所以把Qt放在這里講,是因為Qt在Windows上使用非常廣泛,而且引入了非常多新的設計。如果把原生Win32比作界面庫1.0,MFC/WTL比作界面庫2.0,那么Qt Widget可以算是界面庫3.0。它引入了xml布局界面,支持Qss樣式,支持非常多系統組件,非常易于編寫(xiě)現代化的DirectUI界面,現在Qt被廣泛的用在了工業(yè)領(lǐng)域,互聯(lián)網(wǎng)產(chǎn)品比如WPS,YY語(yǔ)音等也都是基于Qt編寫(xiě)??梢哉f(shuō)如果需要一種跨平臺的C++界面庫,那么Qt是最好的選擇??梢詤⒖紩?shū)籍Jasmin 《C++ GUI Qt 4編程(第2版)》,這本書(shū)有點(diǎn)老,可以結合現在文檔一起看,Qt的文檔寫(xiě)的非常好。
winform并非C++界面庫,但是微軟后期的主要精力在于推廣自己的C#語(yǔ)言,因此winform可以看做是微軟界面庫發(fā)展的延續。Winform是基于Win32封裝,屏蔽了很多細節,擁有超多組件,結合VC編寫(xiě)所見(jiàn)即所得界面非常簡(jiǎn)單。但是打包發(fā)布Winform窗體程序時(shí),一般需要帶上對應.Net 運行時(shí),因此程序體積比較大,但是勝在開(kāi)發(fā)效率快和COM、數據庫集合非常好,很多企業(yè)化辦公和管理系統都是基于Winform來(lái)編寫(xiě)的。
Winform主要還是基于win32界面庫,在新的互聯(lián)網(wǎng)時(shí)代DirectUI的誕生讓開(kāi)發(fā)者可以編寫(xiě)更加現代化更加炫酷支持更多自定義的界面,為此微軟大力推出了WPF。DirectUI技術(shù)某種程度上其實(shí)就是在客戶(hù)端界面編程做到類(lèi)似Web前端開(kāi)發(fā),通過(guò)聲明式的類(lèi)xml和css控制顯示,通過(guò)類(lèi)腳本控制界面動(dòng)作和效果,做到顯示和邏輯分離。
WPF曾是微軟大力推的界面技術(shù),它引入了很多革新的概念——xaml布局、數據綁定技術(shù)等等,支持更加復雜的繪制和特效,和Qt Widget類(lèi)似,但是更加強大,進(jìn)一步提高了開(kāi)發(fā)效率,可以看做界面庫3.5。但是由于WPF最開(kāi)始基于CPU渲染,有很大的性能問(wèn)題,現在某種程度上已經(jīng)得到了很好的優(yōu)化,然而和winform一樣有依賴(lài).net運行時(shí)的問(wèn)題,而許多互聯(lián)網(wǎng)公司的產(chǎn)品都是需要支持Window XP(比如QQ、360安全衛士等),所以WPF不是桌面應用程序界面開(kāi)發(fā)首選,WPF現在還是主要用在企業(yè)化辦公和管理系統。
在移動(dòng)互聯(lián)網(wǎng)的路上,微軟并沒(méi)有走的很好,為了打出差異,推出了手機/平板/PC一體的Win8,隨之推出的是號稱(chēng)一次編寫(xiě)到處運行UWP應用,其實(shí)UWP很像WPF,但是界面編寫(xiě)方式更貼近Web前端。UMP應用市場(chǎng)正在逐漸完善,但是畢竟操作體驗和傳統PC windows有差別,且很多地方還是處于一種混合的方式,只能等待微軟改進(jìn)和時(shí)間磨合了,具體前途怎樣現在很難說(shuō),依賴(lài)于.Net的問(wèn)題同樣是現階段的一個(gè)制約,微軟馬上要停止Win7的支持,可能有利于UWP的發(fā)展,國內的一些大廠(chǎng)都推出了自家的UWP應用(比如QQ、愛(ài)奇藝等)做提前布局。UWP可以看做界面庫4.0,當然這是我個(gè)人的排序,僅做參考,感興趣的可以直接看官方MSDN文檔,示例非常全。
Qt QML和UWP很像,同時(shí)支持PC/平板/應用編寫(xiě),編寫(xiě)方式也很類(lèi)似Web前端,如果之前就是Qt Widget開(kāi)發(fā)者可以很快入門(mén),特別是有一些有跨平臺需求多系統支持的場(chǎng)合應用較多,感興趣的可以看看Qt官方文檔。
前面說(shuō)過(guò)因為Web前端的方式真正做到了顯示和邏輯分離,PC界面庫越來(lái)越模仿Web前端的方式,與其模仿Web前端不如直接就用Web前端來(lái)寫(xiě)界面。之前介紹過(guò)通過(guò)內嵌IE瀏覽器來(lái)編寫(xiě)桌面應用的程序,但是因為微軟各個(gè)版本的IE對現代化Web前端的支持有限,只能做有限的工作。得益于Google開(kāi)源的Chromium項目,開(kāi)發(fā)者們基于Chromium改造提供基于Web瀏覽器的界面庫libcef/node-webkit/electron:
1.libcef打包了一部分Chromium常用功能,封裝成庫,開(kāi)發(fā)者可以在程序中直接調用就完成了瀏覽器的嵌入
2.node-webkit/electron更甚,直接基于 Chromium 和 Node.js打造一套完整框架, 讓你可以使用 HTML, CSS 和 JavaScript 構建應用
越來(lái)越多的應用開(kāi)始采用這種方式,比如網(wǎng)易云音樂(lè )、網(wǎng)易云筆記甚至微軟自家產(chǎn)品VS Code,唯一限制這種方式流行的是需要打包很多Chromium庫,安裝包體積較大,但是在現在這種寬帶和磁盤(pán)體積下,似乎也不是什么大問(wèn)題。
這種方式支持跨平臺,支持老系統,且直接使用現有Web前端開(kāi)發(fā)人員即可完成開(kāi)發(fā),減少學(xué)習成本,可以說(shuō)是一個(gè)非常好的方式,這也是我強烈推薦的現階段桌面應用構建方式。當然它也不是萬(wàn)能的,如果你想寫(xiě)個(gè)簡(jiǎn)單工具,或者系統優(yōu)化應用最好還是用傳統的方式。
Windows界面庫的發(fā)展就介紹到這里,基本上整個(gè)脈絡(luò )如此,由于主要討論的是一般PC桌面應用開(kāi)發(fā),相關(guān)的其他技術(shù)比如DirectX、OpenGL、SiverLight不在討論范圍,感興趣的可以自行查找下相關(guān)資料。
聯(lián)系客服