wxAuiNotebook的wxAUI_NB_TAB_EXTERNAL_MOVE樣式用法

來源:互聯網
上載者:User

     wxAuiNotebook是wxWidgets庫中用於實現同一視窗顯示多頁的頁面tab,這是一種很流行的頁面配置方式。在wxWidgets中,可以將從wxWindow繼承的頁面添加到notebook中,頁面上可以再放多個控制項。另外,因為控制項本身也從wxWindow繼承,所以也可以將單個的一個控制項添加到notebook中。

 

    notebook的分頁可以支援頁面拖放,即拖動頁面的位置。但要支援拖動需要在建立notebook時指定style。有兩個支援拖動的style:

    wxAUI_NB_TAB_MOVE:支援將頁面在同一個notebook從一個位置拖動到另一個位置。

    wxAUI_NB_TAB_EXTERNAL_MOVE:支援將頁面從一個notebook拖動到另一個notebook。

 

    下面的代碼片斷建立了兩個notebook,每個notebook上添加兩個text控制項,即每個notebook有兩個分頁。

 

  //wxAuiNotebook的style。<br /> long noteStyle = wxAUI_NB_TOP | wxAUI_NB_TAB_SPLIT | wxAUI_NB_TAB_MOVE | wxAUI_NB_SCROLL_BUTTONS | wxAUI_NB_CLOSE_ON_ACTIVE_TAB | wxAUI_NB_WINDOWLIST_BUTTON | wxAUI_NB_TAB_EXTERNAL_MOVE;</p><p> //建立兩個notebook<br />wxAuiNotebook *pNoteBook1 = new wxAuiNotebook(this, idNotebook1, wxDefaultPosition, wxSize(200,200), noteStyle);<br />wxAuiNotebook *pNoteBook2 = new wxAuiNotebook(this, idNotebook2, wxDefaultPosition, wxSize(100,100), noteStyle);</p><p> //建立四個控制項<br />wxTextCtrl *pText1 = new wxTextCtrl(this, wxID_ANY);<br />wxTextCtrl *pText2 = new wxTextCtrl(this, wxID_ANY);<br />wxTextCtrl *pText3 = new wxTextCtrl(this, wxID_ANY);<br />wxTextCtrl *pText4 = new wxTextCtrl(this, wxID_ANY);</p><p> //將四個控制項分別添加到兩個notebook上<br />pNoteBook1->AddPage(pText1, "text1");<br />pNoteBook2->AddPage(pText2, "text2");<br />pNoteBook1->AddPage(pText3, "text3");<br />pNoteBook2->AddPage(pText4, "text4");</p><p> //將兩個notebook分別停靠在左邊和下面<br />m_Mgr.AddPane(pNoteBook1, wxLEFT, "Pane Caption");<br /> m_Mgr.AddPane(pNoteBook2, wxBOTTOM, "Pane Caption");</p><p> //更新視窗布局管理器<br /> m_Mgr.Update();

     建立完後,試了一下拖動功能。在同一個notebook拖動頁面是沒問題了。但是當將頁面拖動到另一個notebook上時卻發現不行。原本以為是個bug,後來看了下wxWidgets原始碼關於wxAUI_NB_TAB_EXTERNAL_MOVE樣式的控制,才發現另有玄機。

        看看wxWidgets處理拖動的代碼:

    

void wxAuiNotebook::OnTabEndDrag(wxAuiNotebookEvent& evt)<br />{<br /> m_mgr.HideHint();</p><p> wxAuiTabCtrl* src_tabs = (wxAuiTabCtrl*)evt.GetEventObject();<br /> wxCHECK_RET( src_tabs, _T("no source object?") );</p><p> src_tabs->SetCursor(wxCursor(wxCURSOR_ARROW));</p><p> // get the mouse position, which will be used to determine the drop point<br /> wxPoint mouse_screen_pt = ::wxGetMousePosition();<br /> wxPoint mouse_client_pt = ScreenToClient(mouse_screen_pt);</p><p> // check for an external move<br /> if (m_flags & wxAUI_NB_TAB_EXTERNAL_MOVE)<br /> {<br /> wxWindow* tab_ctrl = ::wxFindWindowAtPoint(mouse_screen_pt);</p><p> while (tab_ctrl)<br /> {<br /> if (tab_ctrl->IsKindOf(CLASSINFO(wxAuiTabCtrl)))<br /> break;<br /> tab_ctrl = tab_ctrl->GetParent();<br /> }</p><p> if (tab_ctrl)<br /> {<br /> wxAuiNotebook* nb = (wxAuiNotebook*)tab_ctrl->GetParent();</p><p> if (nb != this)<br /> {<br /> // find out from the destination control<br /> // if it's ok to drop this tab here<br /> wxAuiNotebookEvent e(wxEVT_COMMAND_AUINOTEBOOK_ALLOW_DND, m_windowId);<br /> e.SetSelection(evt.GetSelection());<br /> e.SetOldSelection(evt.GetSelection());<br /> e.SetEventObject(this);<br /> e.SetDragSource(this);<br /> e.Veto(); // dropping must be explicitly approved by control owner</p><p> nb->GetEventHandler()->ProcessEvent(e);</p><p> if (!e.IsAllowed())<br /> {<br /> // no answer or negative answer<br /> m_mgr.HideHint();<br /> return;<br /> }</p><p> // drop was allowed<br /> int src_idx = evt.GetSelection();<br /> wxWindow* src_page = src_tabs->GetWindowFromIdx(src_idx);</p><p> // Check that it's not an impossible parent relationship<br /> wxWindow* p = nb;<br /> while (p && !p->IsTopLevel())<br /> {<br /> if (p == src_page)<br /> {<br /> return;<br /> }<br /> p = p->GetParent();<br /> }</p><p> // get main index of the page<br /> int main_idx = m_tabs.GetIdxFromWindow(src_page);<br /> wxCHECK_RET( main_idx != wxNOT_FOUND, _T("no source page?") );</p><p> // make a copy of the page info<br /> wxAuiNotebookPage page_info = m_tabs.GetPage(main_idx);</p><p> // remove the page from the source notebook<br /> RemovePage(main_idx);</p><p> // reparent the page<br /> src_page->Reparent(nb);</p><p> // found out the insert idx<br /> wxAuiTabCtrl* dest_tabs = (wxAuiTabCtrl*)tab_ctrl;<br /> wxPoint pt = dest_tabs->ScreenToClient(mouse_screen_pt);</p><p> wxWindow* target = NULL;<br /> int insert_idx = -1;<br /> dest_tabs->TabHitTest(pt.x, pt.y, &target);<br /> if (target)<br /> {<br /> insert_idx = dest_tabs->GetIdxFromWindow(target);<br /> }</p><p> // add the page to the new notebook<br /> if (insert_idx == -1)<br /> insert_idx = dest_tabs->GetPageCount();<br /> dest_tabs->InsertPage(page_info.window, page_info, insert_idx);<br /> nb->m_tabs.AddPage(page_info.window, page_info);</p><p> nb->DoSizing();<br /> dest_tabs->DoShowHide();<br /> dest_tabs->Refresh();</p><p> // set the selection in the destination tab control<br /> nb->SetSelectionToPage(page_info);</p><p> // notify owner that the tab has been dragged<br /> wxAuiNotebookEvent e2(wxEVT_COMMAND_AUINOTEBOOK_DRAG_DONE, m_windowId);<br /> e2.SetSelection(evt.GetSelection());<br /> e2.SetOldSelection(evt.GetSelection());<br /> e2.SetEventObject(this);<br /> GetEventHandler()->ProcessEvent(e2);</p><p> return;<br /> }<br /> }<br /> }</p><p> //。。。<br />}

        原來wxWidgets對於拖動到另一個notebook的情況並不直接放進去,而是先發一個wxEVT_COMMAND_AUINOTEBOOK_ALLOW_DND事件給目標notebook,問一下是否允許放進去,

                if (!e.IsAllowed()) //wxEVT_COMMAND_AUINOTEBOOK_ALLOW_DND是否被allowed
                {
                    // no answer or negative answer
                    m_mgr.HideHint();
                    return;        //不allowed,直接return,當然就沒法拖放了。
                }

       

        看了這個之後就明白了,那我們只要處理目標notebook的wxEVT_COMMAND_AUINOTEBOOK_ALLOW_DND事件就可以了。下面就添加notebook的事件處理:

BEGIN_EVENT_TABLE(wxNote1Frame, wxFrame)<br /> EVT_AUINOTEBOOK_ALLOW_DND(idNotebook1, wxNote1Frame::AllowDND)<br /> EVT_AUINOTEBOOK_ALLOW_DND(idNotebook2, wxNote1Frame::AllowDND)<br />END_EVENT_TABLE()</p><p>void wxNote1Frame::AllowDND(wxAuiNotebookEvent& event)<br />{<br /> //EVT_AUINOTEBOOK_ALLOW_DND處理,允許拖放<br /> event.Allow();<br />}

        編譯完,再跑一下,果然可以拖動到外部了。

        wxWidgets確實是個挺好用的介面庫,類體系和MFC差不多,但卻封裝了很多MFC沒有的控制項,省去自己再擴充MFC的麻煩。只是文檔還是不夠全面。像這個wxAUI_NB_TAB_EXTERNAL_MOVE樣式支援外部拖放需要自己再處理事件的都沒寫清楚。看來要推廣開來還需要努力啊。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.