由于最近换工作的原因,也没啥事,就简单学习了一下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