duilib入門簡明教程 -- 部分bug (11)

 一、WindowImplBase的bug

    在第8個教程【2013 duilib入門簡明教程 -- 完整的自繪標題欄(8)】中,可以發現窗口最大化之後有兩個問題,

    1、最大化按鈕的樣式還是沒變圖片,正確的樣式應該是這樣的圖片

    2、再次點擊最大化按鈕,不能還原到正常大小。


    這個是WindowImplBase的bug,已經提交給官方有一段時間了,但是貌似沒有被合併到SVN上去,所以這裏說明一下,


我們需要在WindowImplBase的OnSysCommand函數裏,在if( ::IsZoomed(*this) != bZoomed )裏面加上下面這段代碼:

 if( ::IsZoomed(*this) != bZoomed )    {        CControlUI* pbtnMax     = static_cast<CControlUI*>(m_PaintManager.FindControl(_T("maxbtn")));       // 最大化按鈕        CControlUI* pbtnRestore = static_cast<CControlUI*>(m_PaintManager.FindControl(_T("restorebtn")));   // 還原按鈕         // 切換最大化按鈕和還原按鈕的狀態        if (pbtnMax && pbtnRestore)        {            pbtnMax->SetVisible(TRUE == bZoomed);       // 此處用表達式是爲了避免編譯器BOOL轉換的警告            pbtnRestore->SetVisible(FALSE == bZoomed);        }    }

 

二、CDuiString的bug (重溫了一下 Effective C++,發現這就是條款24所指出的問題,看來讀書百遍不如寫代碼一遍啊)


    在Notify處理消息時會有很多if語句,我通常喜歡把常量放在雙等號前面,變量放在後面,比如:


    if( _T("click") ==  msg.sType )    {    }


    但是卻發現並沒有進到這個if裏,調試發現,將常量調到前面時,並沒有進入到CDuiString重載的 == 函數裏面,所以這裏必須將常量放到後面。


    if( msg.sType == _T("click") )    {    }


    這個bug的原因是因爲將常量放在前面時,並沒有調用CDuiString重載的 == 函數,而是調用了CDuiString重載的 ()函數,然後用系統自帶的==函數做比較,而系統自己的==函數只是比較兩個指針的首地址是否相等。_T("click") 的首地址指向的是一塊臨時變量,而msg.sType 是返回了CDuiString裏面那個字符串的指針,很顯然這兩個指針地址是不相等的,所以我們只能把它放在前面,或者直接調用_tcscmp

 

   if( ! _tcscmp( _T("click"), msg.sType) )    {    }


 

    當然,如果要解決這個bug,就要重載多個==操作符,

    由於CDuiString是將==函數作爲成員函數重載的,所以只有CDuiString對象在操作符左邊時,纔會調用這個重載函數,如果想要CDuiString對象在右邊時也能調用重載的==函數,那麼必須將重載操作符放到外部。這裏我們可以看一下MFC的CString是怎麼重載的:

圖片

    

    CString 重載了5個==操作符,都是友元函數,定義在#include<cstringt.h>裏面。

    再看下STL的std::string :

圖片

    std::string重載了3個==操作符,都是全局函數,定義在#include<string>裏面。

 

圖片

  不過需要提醒的是,我稍微看了下CDuiString的代碼,有很多漏洞,比如在清零字符串時,只是調用了 m_szBuffer[0] = '\0'; 並不是調用memset,那麼就會有以下問題,我們隨意現在用下面兩種方式給CDuiString 附值,然後監視字符串數組的內容,可以發現雖然顯示是正確的,但是在零值後面的值全部是亂碼:

圖片

 

圖片

 

    這樣的話,雖然_tcslen、_tcscmp等函數能用,但是還有很多函數都會出問題的。


    所以這個CDuiString能不用則不用,如果嫌MFC生成的exe體積大,可以用WTL的CString,如果WTL也不想用,那就只好用STL的string了。


    當然,爲了保證代碼的兼容性,一些簡單的處理還是用CDuiString比較好,比如 msg.sType。


    而邏輯處理等複雜的場景,最好用久經考驗的代碼。  雖然微軟的CString很強大,而用STL的string時可能不方便,但是我現在越來越喜歡STL的string啦,當然,我是定義了一個string_t,加上一個名字空間,以防和一些開源庫衝突,


    一些著名的開源庫喜歡如下定義:

#ifdef _UNICODE    typedef std::basic_string<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t> > string_t;#else    typedef std::basic_string<char, std::char_traits<char>, std::allocator<char> > string_t;#endif

     不過我喜歡更簡短的定義:

#ifdef _UNICODE    typedef std::wstring string_t;#else    typedef std::string  string_t;#endif

     下面是我常用的Unicode定義:

#include <string>#include <sstream>  namespace duilib{#ifdef _UNICODE    typedef wchar_t              char_t;    typedef std::wstring         string_t;    typedef std::wstringstream   stringstream_t;#else    typedef char                 char_t;    typedef std::string          string_t;    typedef std::stringstream    stringstream_t;#endif}

 

圖片


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