由於最近換工作的原因,也沒啥事,就簡單學習了一下cef3和duilib,樓主之前是做MFC框架下的windows開發的,對界面庫和新的客戶端開發模式也有所了解,現在的大部分客戶端都是基本的客戶端框架下組合一個web 容器,web容器當然要看google的開源引擎cef3了,像Qt最近的版本好像也集成了,釘釘,微信、這些桌面應用都是基於web的客戶端來開發的。
所以樓主就也想學習一下,學習東西最快的方式就是做項目!!!所以我選擇了duilib做界面,因為這個庫是基於win32的,也是開源的,我也比較熟悉,然后web引擎當然是cef3了,開源的。花了一個星期吧話不多說,先放圖
主界面:
動態圖演示:
程序實現簡單介紹:
軟件包括部分:界面繪圖+容器填充。
一開始我是先在Github上面下載了開源的duilib,然后看了看,模仿了里面的幾個Demo例子,就開始動手。
Duilib界面設計,一部分是手寫xml,這個我相信大家看了幾個Demo之后就可以上手寫了,然后再看一下網上的幾篇布局的教程,Redrain寫的,就可以了,界面控件與XML文件控件的對應關系要理解,實現的時候我是使用了 WindowImplBase這個類,所有與界面相關的操作只需要繼承這個即可完成,實現簡單的功能無非就是按鈕的響應,按鈕的選擇等等,這些只需要到Notify(TNotifyUI& msg);函數中去處理,細節不多說,Duilib是可以根據xml中的控件名字去映射到控件類,
1 CTabLayoutUI*pTabTest=static_cast<CTabLayoutUI*>(m_PaintManager.FindControl(_T("tabTest")));
以上語句就是通過xml中的tabTest去定位到pTabTest,所有的控件都可以這樣定位,定位到控件就簡單了,剩下的控件操作看duilib提供的API文檔即可。
下面是界面的主界面類,包含web容器窗口的調整,主界面控件響應的操作實現,相信看過兩次duilib的人都能看懂,這下面的WindowImplBase的虛函數接口是自己要實現的,
1 class CMainFrame : public WindowImplBase 2 { 3 public: 4 CMainFrame(); 5 virtual ~CMainFrame(); 6 public: 7 LPCTSTR GetWindowClassName() const; 8 virtual void OnFinalMessage(HWND hWnd); 9 virtual void InitWindow(); 10 virtual LRESULT ResponseDefaultKeyEvent(WPARAM wParam); 11 virtual UILIB_RESOURCETYPE GetResourceType() const; 12 virtual CDuiString GetSkinFile(); 13 virtual CDuiString GetSkinFolder(); 14 virtual CControlUI* CreateControl(LPCTSTR pstrClass); 15 virtual LRESULT HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam); 16 virtual LRESULT OnSysCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); 17 virtual LRESULT HandleCustomMessage(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); 18 virtual LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); 19 void FirstLoadCef(); 20 void HideCefWindow(); 21 HWND GetMainWnd(){ return this->m_hWnd; } 22 protected: 23 void Notify(TNotifyUI& msg); 24 void OnPrepare(TNotifyUI& msg); 25 void OnExit(TNotifyUI& msg); 26 void OnTimer(TNotifyUI& msg); 27 // 28 void OnSelChanged(CControlUI* pSender); 29 void OnClick(CControlUI * pSender); 30 //cef 31 void AdjustCefWindow(); 32 void UpdateTransString(int nNum); 33 //create wnd 34 void ShowTransSelectFrame(); 35 void ShowWordClassifyFrame(); 36 void ShowWordSortFrame(); 37 void ShowWordManagerFrame(); 38 void HideLayoutFrame(); 39 void ShowMiniModeFrame(); 40 private: 41 BOOL m_bIsInit; 42 CTransSelectWnd *m_pTransSelectFrame; 43 CWordClassifyWnd *m_pWordClassifyFrame; 44 CWordSortWnd *m_pWordSortFrame; 45 CWordManagerWnd *m_pWordManagerFrame; 46 CMiniModeWnd *m_pMiniModeFrame; 47 };
界面實現就不寫了,源碼會分享給大家的。
容器填充,就是通過cef3內核加載web界面了,這個也不難,復雜的功能我沒用到,只是簡單啟動了一個cef3的瀏覽器渲染進程,
這里只實現了兩個類,就滿足了要求:cef進程實例類和和維護具體瀏覽器句柄類,
1 class SimpleApp 2 : public CefApp 3 , public CefBrowserProcessHandler 4 { 5 public: 6 SimpleApp(); 7 virtual CefRefPtr<CefBrowserProcessHandler> GetBrowserProcessHandler() 8 OVERRIDE{ return this; } 9 virtual void OnContextInitialized() OVERRIDE; 10 private: 11 IMPLEMENT_REFCOUNTING(SimpleApp); 12 }; 13 14 class SimpleHandler 15 : public CefClient 16 , public CefDisplayHandler 17 , public CefLifeSpanHandler 18 { 19 public: 20 SimpleHandler(); 21 virtual ~SimpleHandler(); 22 virtual CefRefPtr<CefDisplayHandler> GetDisplayHandler() OVERRIDE 23 { 24 return this; 25 } 26 virtual CefRefPtr<CefLifeSpanHandler> GetLifeSpanHandler() OVERRIDE 27 { 28 return this; 29 } 30 31 virtual void OnTitleChange(CefRefPtr<CefBrowser> browser,const CefString& title) OVERRIDE; 32 virtual void OnAfterCreated(CefRefPtr<CefBrowser> browser) OVERRIDE; 33 virtual void OnBeforeClose(CefRefPtr<CefBrowser> browser) OVERRIDE; 34 CefRefPtr<CefBrowser> GetCurrentBrowser(); 35 private: 36 typedef std::list<CefRefPtr<CefBrowser> > BrowserList; 37 BrowserList browser_list_; 38 39 private: 40 IMPLEMENT_REFCOUNTING(SimpleHandler); 41 };
兩個類足夠了,主函數啟動的代碼,
1 CPaintManagerUI::SetInstance(hInstance); 2 #if defined(WIN32) && !defined(UNDER_CE) 3 HRESULT Hr = ::CoInitialize(NULL); 4 #else 5 HRESULT Hr = ::CoInitializeEx(NULL, COINIT_MULTITHREADED); 6 #endif 7 if( FAILED(Hr) ) return 0; 8 CefMainArgs args(hInstance); 9 //創建CefApp實例 10 CefRefPtr<SimpleApp> app(new SimpleApp); 11 int exitCode = CefExecuteProcess(args, app, NULL); 12 if (exitCode >= 0) 13 { 14 return exitCode; 15 } 16 //填充這個結構體,定制CEF的行為。 17 CefSettings settings; 18 //初始化CEF 19 CefInitialize(args, settings, app, NULL); 20 CMainFrame* pFrame = new CMainFrame(); 21 if( pFrame == NULL ) return 0; 22 #if defined(WIN32) && !defined(UNDER_CE) 23 pFrame->Create(NULL, _T("PLApp"), UI_WNDSTYLE_FRAME, WS_EX_STATICEDGE | WS_EX_APPWINDOW, 0, 0, 600, 800); 24 #else 25 pFrame->Create(NULL, _T("PLApp"), UI_WNDSTYLE_DIALOG, WS_EX_TOPMOST, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN)); 26 #endif 27 HICON hIcon = ::LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON1)); 28 ::SendMessage(*pFrame, STM_SETICON, IMAGE_ICON, (LPARAM)(UINT)hIcon); 29 30 pFrame->CenterWindow(); 31 ::ShowWindow(*pFrame, SW_SHOW); 32 //執行消息循環,此時會堵塞,直到CefQuitMessageLoop()函數被調用。 33 CefRunMessageLoop(); 34 // 關閉CEF,釋放資源 35 CefShutdown();
加載瀏覽器的關鍵實現,使用g_handler句柄來操作,
1 CefRefPtr<SimpleHandler> g_handler(new SimpleHandler()); 2 CefBrowserSettings browser_settings; 3 CefWindowInfo window_info; 4 window_info.SetAsChild(m_hWnd, rt); 5 BOOL bSucced = CefBrowserHost::CreateBrowser(window_info 6 , g_handler 7 , _T("http://dict.youdao.com/?keyfrom=cidian") 8 , browser_settings 9 , NULL);
關於以上代碼的具體的功能解釋我也不多說了,最近工作太累,博客也是剛更新的,希望這個我自己學習的代碼對大家有點幫助,開放給大家,對cef3和duilib學習起到參考入門的作用,代碼放在這里了,github : https://github.com/karllen/cef3-duilib-YDDemo 。
好了,博客完事,睡覺,明天看勇士和騎士的第四場比賽。
對了:有道詞典的一切資源文件歸有道所有,禁止大家使用於商業用途,這個項目,僅供新手學習參考,如有侵權,聯系我刪除吧。
郵箱 :1160113606@qq.com