MFC浮動窗口使用方法和注意事項


使用VS2008+SP1創建懸浮窗口的步驟:

1. 創建懸浮窗口類
每一個懸浮窗口都是一個CDockablePane的派生類的對象, 因此要為每一個懸浮窗口創建一個新類

1.1 添加類
通過菜單Project->Add Class...或者在類視圖中工程名字處右鍵選擇Add->Class...添加類
選擇MFC Class, 點Add按鈕進入下一步
Class name處寫入新類的名字, 這里用CDock, 選擇Base class為CDockablePane
按Finish按鈕, 添加類完成.

1.2 添加消息處理函數
一般至少要處理兩個消息, 一個是WM_CREATE, 一個是WM_SIZE, 具體步驟為:
(1) 頭文件中添加函數聲明(函數名及參數不可寫錯)
protected:
 afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
 afx_msg void OnSize(UINT nType, int cx, int cy);
(2) cpp文件中添加消息映射
BEGIN_MESSAGE_MAP(CDock, CDockablePane)
 ON_WM_CREATE()
 ON_WM_SIZE()
END_MESSAGE_MAP()
這里BEGIN_MESSAGE_MAP和END_MESSAGE_MAP宏都是自動生成的, 只需要添加中間兩行代碼即可
(3) 添加函數實現部分
int CDock::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
 if (CDockablePane::OnCreate(lpCreateStruct) == -1)
  return -1;
 // 在這兒創建控件
 return 0;
}
void CDock::OnSize(UINT nType, int cx, int cy)
{
 CDockablePane::OnSize(nType, cx, cy);
 // 這兒添加代碼
}

1.3 添加控件
現在創建的CDock類中由於沒有任何控件, 因此如果現在創建該類的對象並顯示, 該區域中由於全是垃圾數據, 故可能該窗口顯示時為花屏. 如果程序運行期間出現類似花屏的問題, 大概會有幾種可能性: 1. 沒有創建控件 2. 已創建控件, 但控件位置不對或未覆蓋整個的dockablePane 3. 控件雖然占據整個區域, 但不能自動刷新
這里以添加一個listBox為例:
(1) 在類的頭文件中添加控件對象, 代碼為:
protected:
 CListBox _listBox;
(2) 在OnCreate()中添加創建控件窗口的代碼:
這里必須要注意, 需要先調用基類的函數OnCreate()
int CDock1::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
 if (CDockablePane::OnCreate(lpCreateStruct) == -1)
  return -1;

 // 在這兒創建控件
 // nID為該控件的ID, 可以自行設置, 如果對ID不感興趣, 也可以選擇傳遞0讓系統做處理
 if (!_listBox.Create(WS_CHILD | WS_VISIBLE, CRect(0, 0, 0, 0), this, nID))
 {
  TRACE0("創建listbox失敗");
  return -1;
 }

 return 0;
}
(3) 在OnSize中設置各個控件的位置
這里要注意的是, 需要將控件布滿整個窗口. 這里只有一個listBox, 故可以直接用listBox覆蓋窗口.
同理, 必須要先調用基類函數CDockablePane::OnSize(nType, cx, cy)
void CDock::OnSize(UINT nType, int cx, int cy)
{
 CDockablePane::OnSize(nType, cx, cy);
 // 這兒添加代碼
 if (GetSafeHwnd() == NULL)
 {
  return;
 }

 if (_listBox.GetSafeHwnd() != NULL)
 {
  CRect rectClient;
  GetClientRect(rectClient);
  _listBox.SetWindowPos(NULL, rectClient.left, rectClient.top, rectClient.Width(), rectClient.Height(), SWP_NOACTIVATE | SWP_NOZORDER);
 }

}

 

2. 在程序中添加懸浮窗口對象
上面一步只是給工程添加了一個懸浮窗口類, 但並沒生成該類的實例. 這里創建該實例(在CMainFrame類中)

2.1 在主框架類聲明中添加對象, 代碼為:
protected:  
 CDock m_wndDock;

2.2 創建dockablePane的窗口, 在主框架的OnCreate()函數中
(注: 這里我建議在OnCreate函數中自動生成代碼EnableAutoHidePanes(CBRS_ALIGN_ANY)的后面添加)
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
 ...
 EnableAutoHidePanes(CBRS_ALIGN_ANY);
 // 利用這里的CBRS_RIGHT來設置最初的窗口停靠的位置, 可以的取值是
 // CBRS_NOALIGN, CBRS_LEFT, CBRS_TOP, CBRS_RIGHT, CBRS_BOTTOM
 DWORD style = WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | CBRS_RIGHT | CBRS_FLOAT_MULTI;
 if (!wndDock1.Create(
  // 該dock窗口的標題(如果可以有的話...)
  _T("Dock1"),
  // 該dock窗口的parent, 設置為this
  this,
  //  窗口的大小, 注意是"懸浮"的情況下的大小, 處於dock狀態時大小與該值無關
  CRect(0, 0, 200, 200),
  // 該dock窗口是否有標題, 如果為FALSE, 則第一個字符串參數顯示不出來
  TRUE,
  // 該dock窗口的ID值. 注意: 如果希望dock窗口的狀態可以保存在注冊表中(這樣下次啟動程序時仍保持該狀態),  則該值必須的唯一的
  nID,
  // 
  style))
 {
  return FALSE;
 }
 ...

2.3去掉CDockablePane的Close按鈕?

方法一:

在繼承CDockablePane的類中重寫CanBeClosed()方法: 

virtual BOOL CanBeClosed() const; ... BOOL COutputWnd::CanBeClosed() const { return FALSE;

}

方法二:

if (!m_wndView.Create(strFileView, this, CRect(0, 0, 250, 200), TRUE, ID_VIEW_VIEW,

  WS_CHILD | WS_VISIBLE | CBRS_LEFT | CBRS_HIDE_INPLACE | WS_CAPTION, AFX_CBRS_REGULAR_TABS, AFX_CBRS_RESIZE))在Create的時候 后面加上這樣的參數設置AFX_CBRS_REGULAR_TABS, AFX_CBRS_RESIZE 就不會有那個關閉按鈕了

2.4顯示隱藏CDockablePane

m_wndFileView.ShowPane(TRUE,FALSE,TRUE);//顯示

m_wndFileView.ShowPane(FALSE,FALSE,TRUE);//隱藏

2.5 給懸浮窗口添加icon, 暫時省略.

 

3. 設置窗口懸浮方式, 令窗口懸浮

3.1 設置窗口懸浮位置
這部分代碼也應該在MainFrame類的OnCreate函數中, 而且緊跟創建懸浮窗口的后面.
設置懸浮位置只需要調用CDockablePane::EnableDocking即可
 m_wndDock.EnableDocking(CBRS_ALIGN_ANY);
其中, 參數可以是CBRS_ALIGN_TOP, CBRS_ALIGN_RIGHT, CBRS_ALIGN_BOTTOM, CBRS_ALIGN_ANY

3.2 令窗口懸浮
欲使一個CDockablePane對象懸浮, 只需要調用框架類的DockPane函數即可:
 DockPane(&m_wndDock);
但是若有另外一個懸浮窗口的對象需要和m_wndDock在一起顯示, 構成一個組(就像VS的資源視力和類視圖), 那么第二個懸浮窗口需要使用CDockablePane類的AttchToTabWnd函數, 代碼如下:
 DockPane(&m_wndDock);
 CDockablePane *pTabbedBar = NULL;
 m_wndDock2.AttachToTabWnd(&m_wndDock, DM_SHOW, FALSE, &pTabbedBar);

 

 

CDockablePane 使用

這個是轉載的

int m_nshowCurrent;

m_nshowCurrent=theApp.GetProfileInt(_T("Workspace//Pane-377"),_T("IsFloating"),0);  //在構造函數中

首先派生兩個子類,源碼就不用寫出來了,占篇幅,在MainFrm里申明如:
CCurrentDockablePane         m_wndCurrentDockablePane;
CHistoryDockablePane        m_wndHistoryDockablePane;
CDockablePane* m_pTabbedBar;

然后在OnCreate()里面:
CString strHistoryDockablePane;
CString strCurrentView;
strCurrentView.LoadString(IDS_Current_VIEW);
strHistoryDockablePane.LoadString(IDS_History_VIEW);

if (!m_wndHistoryDockablePane.Create(strHistoryDockablePane, this, CRect(0, 0, 200, 200),
   TRUE, ID_VIEW_HistoryDockablePane, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | CBRS_LEFT | CBRS_FLOAT_MULTI))
{
     TRACE0("Failed to create Class View window/n");
      return FALSE; // failed to create
}

if (!m_wndCurrentDockablePane.Create(strCurrentView, this, CRect(0, 0, 200, 200),
   TRUE, ID_VIEW_CurrentView, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | CBRS_LEFT| CBRS_FLOAT_MULTI))
{
    TRACE0("Failed to create File View window/n");
     return FALSE; // failed to create
}

再給她們添加圖標:
HICON hHistoryDockablePaneIcon = (HICON) ::LoadImage(::AfxGetResourceHandle(),
          MAKEINTRESOURCE(bHiColorIcons ? IDI_history : IDI_history), IMAGE_ICON, ::GetSystemMetrics(SM_CXSMICON), ::GetSystemMetrics(SM_CYSMICON), 0);
m_wndHistoryDockablePane.SetIcon(hHistoryDockablePaneIcon, FALSE);
HICON hCurrentViewIcon = (HICON) ::LoadImage(::AfxGetResourceHandle(),
   MAKEINTRESOURCE(bHiColorIcons ? IDI_Currrently : IDI_Currrently), IMAGE_ICON, ::GetSystemMetrics(SM_CXSMICON), ::GetSystemMetrics(SM_CYSMICON), 0);
m_wndCurrentDockablePane.SetIcon(hCurrentViewIcon, FALSE);

m_wndHistoryDockablePane.EnableDocking(CBRS_ALIGN_ANY);
m_wndCurrentDockablePane.EnableDocking(CBRS_ALIGN_ANY);

DockPane(&m_wndHistoryDockablePane);
DockPane(&m_wndCurrentDockablePane);
m_pTabbedBar = NULL;

m_wndCurrentDockablePane.AttachToTabWnd(&m_wndHistoryDockablePane, DM_SHOW, FALSE, &m_pTabbedBar);

相關顯示代碼就這樣的了.后來老大說關閉需要修改工具欄里的顯示狀態,即去掉對勾.在工具欄里控制他們的顯示和隱藏簡單啊,就是用m_wndCurrentDockablePane.ShowPane(TRUE,FALSE,TRUE);可是關閉再去修改工具欄想了半天,以為要重載CDockablePane的Close()消息,又嘗試了他的很多消息,都不對.跟蹤進去才知道是調用MainFrm來關閉的.里面有pMainfrm.onCloseDockingPane(this);好了,我就重載這個方法.

BOOL CMainFrame::OnCloseDockingPane( CDockablePane* pWnd )
{
    CWnd * pfWnd = pWnd->GetFocus();
    if (*pfWnd == m_wndCurrentDockablePane)
    {
        m_nshowCurrent = 0;
    }
    else if(*pfWnd == m_wndHistoryDockablePane)
    {
       m_nshowHistory = 0;
    }
   return TRUE;
}
這樣工具欄里面的信息就更新了.呵呵,高興的太早了,才做了一半,當兩個面板拆開,即處於浮動狀態時關閉根本就不調用這里.又郁悶了半天,還是老大牛逼,說那種情況是OnCloseMiniFrame,於是有如下重載:

BOOL CMainFrame::OnCloseMiniFrame( CPaneFrameWnd* pWnd )
{
      CWnd *ptWnd = pWnd->GetWindow( GW_CHILD );
     if (*ptWnd ==m_wndCurrentDockablePane)
      {
            m_nshowCurrent = 0;
     }
      else if (*ptWnd == m_wndHistoryDockablePane)
    {
             m_nshowHistory = 0;
    }
   return TRUE;
}

 

//寫注冊表,在析構函數中

theApp.WriteProfileInt(_T("Workspace//Pane-377"),_T("IsFloating"),m_nshowCurrent);


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM