duilib入門簡明教程 -- 自繪控件 (15)

   在【2013 duilib入門簡明教程 -- 複雜控件介紹 (13)】中雖然介紹了界面設計器上的所有控件,但是還有一些控件並沒有被放到界面設計器上,還有一些常用控件duilib並沒有提供(比如菜單控件)。雖然duilib沒有提供這些控件,但是自己繪製起來也是非常方便的,不過duilib的自繪可比MFC方便得不止一點點了,其實duilib的自繪大都不用自己繪製,就是一些控件和圖片的組合而已,相當簡單方便~~~

 

    一、菜單控件

    其實菜單控件的外觀和ListBox非常像,所以我們可以用教程13的ListBox控件模擬,也可以自行用其他的組合,由於duilib自帶的Demo裏有兩個Menu,而且樣式還很不錯,所以Alberl就拿來用了,不過那幾個Demo同樣是複雜得要命,還記得教程13中的ListCtrl使用起來多麼簡單嗎?如果不覺得它簡單,那麼再對比一下duilib自帶的ListDemo,就能感覺到它的簡單啦~O(∩_∩)O~


    相信看過duilib自帶的MenuDemo以及ListDemo裏面的菜單,都不會覺得菜單很簡單吧,那麼來看看下面這個菜單的實現吧~O(∩_∩)O~


    1、新建一個menu.xml,如下:

<?xml version="1.0" encoding="utf-8"?><Window size="120,82"><VerticalLayout bkimage="file='Menu/menu_bk.png' corner='40,8,8,8'" hole="false">    <List header="hidden" inset="8,8,8,8" itemhotimage="file='Menu/menu_hot_bk.png' corner='2,2,2,2'">        <ListContainerElement name="menu_Open" height="22" inset="40,0,0,0">            <Label text="打開" mouse="false"/>        </ListContainerElement>        <ListContainerElement name="menu_Mark" height="22" inset="40,0,0,0">            <Label text="標註" mouse="false"/>        </ListContainerElement>        <ListContainerElement name="menu_Delete" height="22" inset="40,0,0,0">            <Label text="刪除" mouse="false"/>        </ListContainerElement>    </List></VerticalLayout></Window>

    可以看到Menu其實就是一個List和圖片組合的,當然,親們也可以用教程13中的ListBox來替換上述內容,只不過需要自己調整一下。這裏非常感謝提供MenuDemo的大神,菜單樣式非常漂亮~O(∩_∩)O~

  

  2、新建一個DuiMenu.h,如下(爲了方便演示,將cpp的代碼都放到了.h裏,並且減少了空行,在最後的教程裏,會有一個完整的工程下載):

#pragma once// 此處需要包含duilib的頭文件#include <UIlib.h>那一段,詳細代碼請見前面教程 class CDuiMenu : public WindowImplBase{protected:    virtual ~CDuiMenu(){};        // 私有化析構函數,這樣此對象只能通過new來生成,而不能直接定義變量。就保證了delete this不會出錯    CDuiString  m_strXMLPath; public:    explicit CDuiMenu(LPCTSTR pszXMLPath): m_strXMLPath(pszXMLPath){}    virtual LPCTSTR    GetWindowClassName()const{ return _T("CDuiMenu "); }    virtual CDuiString GetSkinFolder()          { return _T("");            }    virtual CDuiString GetSkinFile()            { return m_strXMLPath;      }    virtual void       OnFinalMessage(HWND hWnd){ delete this;              }     virtual LRESULT OnKillFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)    {        Close();        bHandled = FALSE;        return 0;    }     void Init(HWND hWndParent, POINT ptPos)    {        Create(hWndParent, _T("MenuWnd"), UI_WNDSTYLE_FRAME, WS_EX_WINDOWEDGE);        ::ClientToScreen(hWndParent, &ptPos);        ::SetWindowPos(*this, NULL, ptPos.x, ptPos.y, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);    }     virtual LRESULT HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)    {        LRESULT lRes = 0;        BOOL    bHandled = TRUE;         switch( uMsg )        {        case WM_KILLFOCUS:                lRes = OnKillFocus(uMsg, wParam, lParam, bHandled);             break;         default:            bHandled = FALSE;        }         if(bHandled || m_PaintManager.MessageHandler(uMsg, wParam, lParam, lRes))         {            return lRes;        }         return __super::HandleMessage(uMsg, wParam, lParam);    }};

    3、此時一個菜單控件的所有代碼就完成啦,下面接下來要顯示菜單控件,我們模仿MFC的方式,即點擊一個菜單按鈕後,彈出菜單項~

    顯然第一步需要添加一個菜單按鈕,XML如下:

  <Button name="btnMenu"   text="選項"   float="true"   pos="475,28,0,0"   width="37"   height="19"   align="center"   normalimage=""   hotimage="Menu/btn_menu_hot.png"   pushedimage="Menu/btn_menu_hot.png"   focusedimage="Menu/btn_menu_hot.png"   textcolor="#FF000000"  hottextcolor="#FFFFFFFF"   pushedtextcolor="#FFFFFFFF"   focusedtextcolor="#FFFFFFFF"   bkcolor="#FFECE9D8" />

    第二步就是響應菜單按鈕的點擊,在主窗口的Notify函數裏添加以下代碼:

  if( msg.sType == _T("click") )         {            if( msg.pSender->GetName() == _T("btnMenu") )             {                POINT pt = {msg.ptMouse.x, msg.ptMouse.y};                CDuiMenu *pMenu = new CDuiMenu(_T("Menu/menu.xml"));                 pMenu->Init(*this, pt);                pMenu->ShowWindow(TRUE);            }        }

    還有最重要的一步就是把圖片資源解壓到exe目錄啦,下載資源猛戳這裏~(注意:此處已給出所有的資源和代碼,後面的教程將不再重複提供資源下載

    

好啦,菜單按鈕是不是和MFC的很像呢,還有陰影哦~O(∩_∩)O~

    (更豐富的菜單樣式請參閱duilib自帶的MenuDemo)

    圖片

 

    【菜單類小知識】

   

  如果不用指針的方式,而直接用變量的方式顯示菜單 CDuiMenu menu(_T("Menu/menu.xml")),則不能用ShowWindow,否則會崩潰,因爲出了作用域後窗口被銷燬了,所以此時可以將CDuiMenu 定義爲成員變量、全局變量、或者靜態變量,但是做爲一個局部使用的類,這些方法顯然不怎麼好;

    

 這時可以用ShowModal代替ShowWindow,於是就能看到窗口啦,但是卻產生了一個問題,那就是菜單窗口不會失去焦點,或者說點擊主窗口的其他區域,菜單不會消失,當然,小夥伴們可以自己捕獲鼠標,來判斷是否點擊了主窗口的其他區域,但顯然這種方法也不太好;

    

 這個時候delete this就派上用場啦(用智能指針也會崩潰,因爲出了作用域同樣會銷燬內存,所以只能用delete this啦~ 用delete this就是將作用域交給duilib了),據說COM裏面就是用delete this來銷燬內存的。Alberl在duilib的Demo裏面見到了大量的delete this,覺得這種自殺的方法很不靠譜,這不,前面教程就提到了ActiveX的一個bug,也是和delete this脫不了干係的~  不過既然COM裏面都用了delete this,那就說明如果用好這把雙刃劍,還是可以帶來很多好處的。

     

因爲duilib提供了一個機制,就是窗口的最後一個函數一定是OnFinalMessage,之後不再調用窗口類的其他函數,這就爲自殺提供了兩個必要條件;delete this而還有一個必要條件就是這個類必須是通過new來申請內存的(而非 "new[]",亦非placement的"new" ,一定要是最原始的 "new",當然malloc也行(需要用free,而不是delete)),所以就將析構函數設置成私有函數,就保證了只有通過new申請內存的方式才能編譯通過。 而duilib的Demo中大量使用delete this卻沒有保證這些必要條件,只要直接用變量的方式來聲明類,則關閉窗口時就會崩潰,作爲Demo,如此不嚴謹,有待好好規範。當然,沒有XX黨,就沒有新中國,沒有那些大神的Demo,也就輪不到Alberl唧唧歪歪啦,這裏Alberl只是覺得Demo應該嚴謹和權威,畢竟是官方的,並沒有其他意思,請多多諒解~O(∩_∩)O~

 

    二、組合框控件

    由於duilib也沒有自帶GroupBox,所以我們一般採用的是Label + Control的組合,迅雷、百度、金山快盤、華爲網盤這些都是這種組合,如圖:

圖片

    這個就不用代碼了吧,左邊的Label 設置文字顏色,右邊的Control設置背景色,高度設置爲1就好了。

 

    三、複選框、單選框

    duilib的TestApp1中有幾個CheckBox,不過也是需要圖片資源的,因爲圖中的方框就是圖片模擬的,代碼也很簡單,後面的教程會有詳細的代碼~

圖片   圖片

 

    四、時間選擇控件

    這個也很簡單,代碼如下:

<DateTime name="DateTimeDemo1" float="true" pos="30,118,0,0" width="120" height="30" bkcolor="#FFE2E5EA" padding="0,5,0,0" />

圖片

 

    五、RichList、樹形控件

    經過前面教程詳細的介紹,相信現在已經基本入門了,由於Alberl暫時也沒看這些控件,所以請自行參閱duilib自帶的Demo。

    RichList請參閱duilib自帶的RichListDemo,效果如圖:

圖片

 

    Tree控件請參閱 (QQDemo、GameDemo,TestApp1),效果如圖:

圖片  圖片

    duilib的控件就基本介紹完啦,其他控件也請自行參閱~O(∩_∩)O~

 

圖片


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章