Duilib教程-自動佈局2

在上一節中,我簡單介紹了控件隨父LAYOUT自由移動的設置。在這一節,我將介紹一種常見的狀況:嵌入窗口。函數

 

在項目中,咱們不多會100%的編寫一個軟件,特別是界面相關的,咱們會使用之前已經編寫好的窗口,或網上的開源模塊。舉一個簡單的例子來講,若是你要編寫一個視頻播放器,關於視頻的播放窗口,就用不着用DUI來實現,咱們徹底可使用網上的開源庫,嵌入一個播放的WND便可(固然有的庫也支持回調的方式,用戶能夠在本身的窗口中將回調出來的圖片進行自由繪製)。ui

 

咱們須要在窗口大小改變時,即時地改變播放窗口的大小。也許你會說這很是簡單,直接重載OnSize,而後獲取佔位控件(使用佔位控件纔是最正確的選擇,若是在程序中判斷左邊距、右邊距,就作不到UI、CODE分離了)的大小,而後設置便可。可是當你真正使用的時候,發現並無那麼簡單。來看代碼:this

 

UIManager.cpp 第750行:spa

    case WM_SIZE:

        {

            if( m_pFocus != NULL ) {

                TEventUI event = { 0 };

                event.Type = UIEVENT_WINDOWSIZE;

                event.pSender = m_pFocus;

                event.dwTimestamp = ::GetTickCount();

                m_pFocus->Event(event);

            }

            if( m_pRoot != NULL ) m_pRoot->NeedUpdate();

        }

        return true;

 

咱們看到,窗口大小改變,ROOT只是簡單的 NeedUpdate,重繪而已,它的大小並無設置爲與窗口同樣的大小。code

 

在WinImplBase.cpp 第214 行:視頻

LRESULT WindowImplBase::OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)

{

         SIZE szRoundCorner = m_PaintManager.GetRoundCorner();

#if defined(WIN32) && !defined(UNDER_CE)

         if( !::IsIconic(*this) && (szRoundCorner.cx != 0 || szRoundCorner.cy != 0) ) {

                   CDuiRect rcWnd;

                   ::GetWindowRect(*this, &rcWnd);

                   rcWnd.Offset(-rcWnd.left, -rcWnd.top);

                   rcWnd.right++; rcWnd.bottom++;

                   HRGN hRgn = ::CreateRoundRectRgn(rcWnd.left, rcWnd.top, rcWnd.right, rcWnd.bottom, szRoundCorner.cx, szRoundCorner.cy);

                   ::SetWindowRgn(*this, hRgn, TRUE);

                   ::DeleteObject(hRgn);

         }

#endif

         bHandled = FALSE;

         return 0;

}

 

也是啥也沒作。對象

因此在OnSize裏面設置窗口位置,並不會達到效果。blog

 

那麼DUILIB是在哪裏設置ROOT的大小呢?UIManager.cpp 第 615行,即在WM_PAINT中進行設置。事件

m_pRoot->SetPos(rcClient);圖片

 

1.SetPos

當你看到這裏時,我想你已經知道第一種方法了。即在 OnSize中,

RECT rc; GetClientRect (m_hWnd, &rc); m_PaintManager.GetRoot()->SetPos (rc);

const RECT& rc_pos = targer_ui_->GetPos ();

::MoveWindow (move_wnd, rc_pos.left, rc_pos.top, rc_pos.right – rc_pos.left, rc_pos.bottom – rc_pos.top, TRUE);

 

 

即咱們主動設置大小,ROOT設置了POS後,會將它的子控件也設置POS,詳情請看源碼。因此,咱們就可以獲得正確的位置信息了。

 

可是這並非最好的方式,緣由很簡單,OnSize會被頻繁的調用,特別是在程序初始化的時候,OnSize被調用N次,並且在最小化的時候也會被調用。並且當你看1.SetPos時,你也猜到了會有第二種方式了。

 

2.委託 OnSize

假設咱們的佔位控件爲 target_ui_,它有一個委託成員變量:OnSize。直接看代碼吧:

target_ui_->OnSize += MakeDelegate (this, &CYourWnd::OnTargetSizeChanged);

 

bool CYourWnd:: OnTargetSizeChanged (void* param)

{

const RECT& rc_pos = targer_ui_->GetPos ();

::MoveWindow (move_wnd, rc_pos.left, rc_pos.top, rc_pos.right – rc_pos.left, rc_pos.bottom – rc_pos.top, TRUE);

}

 

如此簡單,又如此優美的代碼。

注意使用的是 +=

在這裏,咱們也看到了做者本身實現了委託的編寫(我不清楚是否是使用了開源庫),可見做者的C++功底是至關深厚的。

 

 

看CControlUI的源碼,你會發現以下委託對象:

public:

    CEventSource OnInit;

    CEventSource OnDestroy;

    CEventSource OnSize;

    CEventSource OnEvent;

    CEventSource OnNotify;

 

顧名思義,無需贅述。

 

這裏說一下Event和Notify的區別。

Event是控件本身收到的消息,好比鼠標左鍵按下、彈起、雙擊等,DUILIB先向控件本身發一個事件。

Notify通知,是向WND發送的通知消息,相似MFC中對話框收到控件的NOTIFY(包括按鈕的單擊),它默認狀況下是由窗口接收的,在窗口的Notify函數中進行響應。

 

DUILIB的處理流程是,先向CONTROL發送事件,而後向WND發送通知。

 

OnNotify至關有用,由於你能夠定製每一個控件的響應,而不須要在WND的Notify中進行一大堆的if..else..了。

 

OnEvent用處也很大,看狀況使用了。

相關文章
相關標籤/搜索