新版博客已經搭建好了,有問題請訪問 htt://www.crazydebug.com
在公司二期項目中為了將谷歌內核嵌入到duilib中,采用了自定義duilib控件的方法,由於也是第一次用duilib,邊學邊用,所有網上的資料給了我很大的幫助,尤其Redrain兄弟的文章給我啟發很大,再次感謝互聯網具有開源精神的程序員。
今天簡單總結下duilib的自定義控件,要實現自定義控件需要做兩件事情
class CBrowserUI :public CControlUI { public: CBrowserUI(); ~CBrowserUI(); virtual LPCTSTR GetClass() const; virtual LPVOID GetInterface(LPCTSTR pstrName); //這個一定要設置,不然控件無法顯示 virtual void SetPos(RECT rc, bool bNeedInvalidate = true); CefRefPtr<CefBrowser> GetBrowser() { return m_Browser->GetBrowser(); } CefRefPtr<CefFrame> GetMainFrame() { return m_Browser->GetMainFrame(); } void CloseAllBrowser(); bool CreateBrowser(const CefString & szHomePage, CHaoMainFrame * pWnd); void LoadUrl(const CefString & url); protected: CefRefPtr<CHaoBrowserHandler> m_Browser; };
下面是實現文件
CBrowserUI::CBrowserUI() :m_Browser(NULL)// m_Browser(NULL) { } CBrowserUI::~CBrowserUI() { } LPCTSTR CBrowserUI::GetClass() const { return _T("BrowserUI"); } LPVOID CBrowserUI::GetInterface(LPCTSTR pstrName) { if (_tcsicmp(pstrName, _T("Browser")) == 0) { return static_cast<CBrowserUI*>(this); } return CControlUI::GetInterface(pstrName); } void CBrowserUI::SetPos(RECT rc, bool bNeedInvalidate /* = true */) { CControlUI::SetPos(rc, bNeedInvalidate); if (m_Browser.get()) { CefRefPtr<CefBrowser> browser = m_Browser->GetBrowser(); DuiLib::CDuiRect rc = GetPos(); if (browser && !rc.IsNull()) { ::SetWindowPos(browser->GetHost()->GetWindowHandle(), NULL, rc.left, rc.top, rc.GetWidth(), rc.GetHeight(), SWP_NOZORDER | SWP_NOACTIVATE); } } } void CBrowserUI::CloseAllBrowser() { if (m_Browser.get()) { m_Browser->CloseAllBrowsers(true); } } bool CBrowserUI::CreateBrowser(const CefString & szHomePage, CHaoMainFrame * pWnd) { CefWindowInfo info; if (m_Browser == NULL) { m_Browser = new CHaoBrowserHandler(pWnd); } m_Browser->SetHomePage(szHomePage); if (m_Browser != NULL) { info.SetAsChild(GetManager()->GetPaintWindow(), GetPos()); CefBrowserSettings browserSettings; return CefBrowserHost::CreateBrowser(info, m_Browser.get(), szHomePage,browserSettings,NULL); } return false; } void CBrowserUI::LoadUrl(const CefString & url) { if (m_Browser.get()) { CefRefPtr<CefFrame> mainframe = m_Browser->GetMainFrame(); if (mainframe) mainframe->LoadURL(url); } }
建立新控件后,最先應該重寫的兩個函數是GetClass和GetInterface。他們后用來區分控件的類型的虛函數,用於動態識別控件類型和做控件的類型轉換。
從Duilib的自帶控件上可以看出,比如當前的自定義控件類名為CBrowserUI,那么GetClass函數返回的字符串BrowserUI。而GetInterface函數是根據傳入的參數是否與自身的字符串匹配,來決定能否把自己轉換為需要的控件類型。GetInterface中用來匹配的字符串,應該與xml中的對應的控件的標簽名稱一直,這里應該是Browser。
ButtonUI類,GetClass對應ButtonUI,GetInterface對應Button。這不是強制的,但是保持這個風格很重要
好了控件類的定義實現都有了,那么如何讓xml可以識別我們定義的控件?這才是最重要的問題
為了讓xml布局識別我們的新控件,我們需要完成Duilib的IDialogBuilderCallback接口,重寫這個接口中的CreateControl函數。
通常情況下,可以讓窗體類繼承IDialogBuilderCallback接口並且重寫CreateControl(DuiLib自帶的WindowImplBase窗體類已經繼承了這個接口,如果是繼承WindowImplBase的話就直接重寫CreateControl就可以了)。函數處理方法是比較傳入的字符串,根據字符串來決定返回什么控件的指針,這個傳入的字符串就是xml文件中控件的標簽,比如<Button />中的字符串Button
CControlUI * CHaoMainFrame::CreateControl(LPCTSTR pstrClass) { CControlUI * pUI = NULL; if (_tcsicmp(pstrClass, _T("MyBrowser")) == 0) { pUI = m_browser = new CBrowserUI; } return pUI; }
這樣一個自定義控件就搞完了,而且我用着也是很不錯的,上個圖吧,無圖無真相