Duilib自定义控件

新版博客已经搭建好了,有问题请访问 htt://www.crazydebug.com

在公司二期项目中为了将谷歌内核嵌入到duilib中,采用了自定义duilib控件的方法,由于也是第一次用duilib,边学边用,所有网上的资料给了我很大的帮助,尤其Redrain兄弟的文章给我启发很大,再次感谢互联网具有开源精神的程序员。

今天简单总结下duilib的自定义控件,要实现自定义控件需要做两件事情

      1、继承现有的控件类创建新的控件类
      2、让程序识别新的控件并可以在xml中使用
第一步继承我就不多说了,直接看代码吧
1 #incude <stdio.h>
2 int main()
3 {
4     printf("hello world");
5 }

 

 
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;
}

这样一个自定义控件就搞完了,而且我用着也是很不错的,上个图吧,无图无真相

 

posted @ 2016-10-21 10:40  IT莽撞人  阅读(4226)  评论(9编辑  收藏  举报