從CDialogBar派生自己的類進行控件的初始化(例:給按鈕添加圖標bitmap)
當創建一些簡單的形如只包含了一些BUTTON的DialogBar的時候,是不需要從CDialogBar派生,因爲CDialogBar本身就是從CControlBar派生而來,它可以接收任何的通告消息。
然而,在一下的諸多較爲複雜的情形下,我們就需要利用CDialogBar派生出自己的類了(子控件是指用作子窗口的控件------個人理解)。
· dialogbar包含了具有drop-down屬性的COMBOBOX;
· dialogbar包含了treeview或者tree控件,listview, list控件;
· dialogbar包含了ActiveX控件;
諸如上面所說的任何較爲複雜的情形下,我們都應該對Dialogbar進行派生,以便在派生的類中對其他的控件進行初始化。因爲在ClassWizard並沒有支持以CDialogBar爲基類的派生。所以我們必須自己手動完成該派生過程。這篇文章就是要闡述如何將CDialog的派生類轉換爲CDialogBar的派生類。
在開始正題之前,有必要說明一點:CDialogBar類是從CControlBar類派生而來的,而CControlBar類則是從CWnd類派生而來,所以CDialogBar並非CDialog的派生類。
首先打開VS2008,創建一個DialogBar類型的dialog資源(在創建對話框資源的時候,單擊Dialog選項前面的"+"號進行選擇)。並以CDialog類爲基類生成派生類,然後按照下面的步驟對所產生的類進行修改。
1. 在類的聲明中,將基類CDialog改爲CDialogBar,同時將.cpp文件中,BEGIN_MESSAGE_MAP中的基類也改爲CDialogBar.
2. 修改.h文件和.cpp文件中的析構函數,同時修改DoDataExchange()函數,具體修改後的效果如下圖:
//修改前的代碼:
1 CMyDlgBar (CWnd* pParent = NULL); // standard constructor
2
3 CMyDlgBar:: CMyDlgBar (CWnd* pParent /*=NULL*/)
4 : CDialog(CMyDlgBar::IDD, pParent)
5 {
6 ...
7
8 void CMyDlgBar::DoDataExchange(CDataExchange* pDX)
9 {
10 CDialog::DoDataExchange(pDX);
11 ...
12
1 CMyDlgBar (CWnd* pParent = NULL); // standard constructor
2
3 CMyDlgBar:: CMyDlgBar (CWnd* pParent /*=NULL*/)
4 : CDialog(CMyDlgBar::IDD, pParent)
5 {
6 ...
7
8 void CMyDlgBar::DoDataExchange(CDataExchange* pDX)
9 {
10 CDialog::DoDataExchange(pDX);
11 ...
12
//修改後的代碼
1 CMyDlgBar (); // standard constructor
2
3 CMyDlgBar:: CMyDlgBar (CWnd* pParent)
4 {
5 ...
6
7 void CMyDlgBar::DoDataExchange(CDataExchange* pDX)
8 {
9 CDialogBar::DoDataExchange(pDX);
10 ...
1 CMyDlgBar (); // standard constructor
2
3 CMyDlgBar:: CMyDlgBar (CWnd* pParent)
4 {
5 ...
6
7 void CMyDlgBar::DoDataExchange(CDataExchange* pDX)
8 {
9 CDialogBar::DoDataExchange(pDX);
10 ...
3.從文章開始所談到的繼承關係可以看出,在CDialogBar中並沒有用來響應WM_INITDIALOG消息的虛函數。我們需要將.h文件中用來響應WM_INITDIALOG消息的虛函數OnInitDialog變化成爲一個消息響應函數。首先將.h文件中的“virtual BOOL OnInitDialog();”從文件中刪掉,然後在相同的位置上添加“afx_msg LONG OnInitDialog ( UINT, LONG );”函數。然後在.cpp文件中做相應的改動,並將.cpp文件中消息映射ON_WM_INITDIALOG()改爲OM_MESSAGE(WM_INITDIALOG, OnInitDialog),例如:
//在頭文件中
1 class CMyDlgBar : public CDialogBar
2 {
3 ...
4 // Implementation
5 protected:
6
7 // Generated message map functions
8 //{{AFX_MSG(CMyDlgBar)
9 virtual BOOL OnInitDialog(); // <-刪除這一行.
10 //}}AFX_MSG
11
12 afx_msg LONG OnInitDialog ( UINT, LONG ); // <-添加這一行.
13 DECLARE_MESSAGE_MAP()
14 };
1 class CMyDlgBar : public CDialogBar
2 {
3 ...
4 // Implementation
5 protected:
6
7 // Generated message map functions
8 //{{AFX_MSG(CMyDlgBar)
9 virtual BOOL OnInitDialog(); // <-刪除這一行.
10 //}}AFX_MSG
11
12 afx_msg LONG OnInitDialog ( UINT, LONG ); // <-添加這一行.
13 DECLARE_MESSAGE_MAP()
14 };
1 //在源文件中
2 BEGIN_MESSAGE_MAP(CMyDlgBar, CDialogBar)// 把原來的CDialog改爲CDialogBar
3 ...
4 ON_MESSAGE(WM_INITDIALOG, OnInitDialog ) // <-- 添加這一行.
5 END_MESSAGE_MAP()
2 BEGIN_MESSAGE_MAP(CMyDlgBar, CDialogBar)// 把原來的CDialog改爲CDialogBar
3 ...
4 ON_MESSAGE(WM_INITDIALOG, OnInitDialog ) // <-- 添加這一行.
5 END_MESSAGE_MAP()
//將函數實現從:
BOOL CMyDlgBar::OnInitDialog()
{
CDialog::OnInitDialog(); // <-- 這行被替代掉:
...
//改爲:
LONG CMyDlgBar::OnInitDialog ( UINT wParam, LONG lParam)
{
// <-- 用以下的代碼替代上面需要替代的部分. -->
BOOL bRet = HandleInitDialog(wParam, lParam);
if (!UpdateData(FALSE))
{
TRACE0("Warning: UpdateData failed during dialog init.\n");
}
...
return bRet;
BOOL CMyDlgBar::OnInitDialog()
{
CDialog::OnInitDialog(); // <-- 這行被替代掉:
...
//改爲:
LONG CMyDlgBar::OnInitDialog ( UINT wParam, LONG lParam)
{
// <-- 用以下的代碼替代上面需要替代的部分. -->
BOOL bRet = HandleInitDialog(wParam, lParam);
if (!UpdateData(FALSE))
{
TRACE0("Warning: UpdateData failed during dialog init.\n");
}
...
return bRet;
到此爲止所有需要修改的地方都已經完成,剩下的就是使用了。在CMainFrame中定義變量,並在CMainFrame::OnCreate()函數中添加代碼:
1 if (!m_wndDlgBar.Create(this, IDD_DIALOGBAR, WS_CHILD | WS_VISIBLE | CBRS_BOTTOM
2 | CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC, IDD_DIALOGBAR))
3 {
4 TRACE0("Failed to create Dialog bar\n");
5 return -1; // fail to create
6 }
7
8 //如果需要實現可停靠的功能,則添加如下代碼:
9 m_wndDlgBar.EnableDocking(CBRS_ALIGN_BOTTOM );
10 EnableDocking(CBRS_ALIGN_ANY); //這句很重要
11 DockControlBar(&m_wndDlgBar, AFX_IDW_DOCKBAR_BOTTOM);
2 | CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC, IDD_DIALOGBAR))
3 {
4 TRACE0("Failed to create Dialog bar\n");
5 return -1; // fail to create
6 }
7
8 //如果需要實現可停靠的功能,則添加如下代碼:
9 m_wndDlgBar.EnableDocking(CBRS_ALIGN_BOTTOM );
10 EnableDocking(CBRS_ALIGN_ANY); //這句很重要
11 DockControlBar(&m_wndDlgBar, AFX_IDW_DOCKBAR_BOTTOM);
9 10 11這三行可以註釋掉
接下來在mainframe.h中添加
virtual BOOL OnCmdMsg(UINT nID,int nCode,void* pExtra,AFX_CMDHANDLERINFO* pHandlerInfo);
.cpp中添加
BOOL CMainFrame::OnCmdMsg(UINT nID,int nCode,void* pExtra,AFX_CMDHANDLERINFO* pHandlerInfo)
{
if(m_DlgToolBar.OnCmdMsg(nID,nCode,pExtra,pHandlerInfo))
return TRUE;
return CFrameWnd::OnCmdMsg(nID,nCode,pExtra,pHandlerInfo);
}
這個消息函數處理button發到mainframe的消息,所以必須添加
然後在oninitdialog函數中初始化,使位圖貼到按鈕上
HBITMAP hBmp=::LoadBitmap(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDB_BITMAP1));
button = (CButton*)GetDlgItem(IDC_BUTTON1);
button ->SetBitmap(HBITMAP(hBmp));
button是在頭文件中定義 Cbutton* button;
這裏因爲不能添加control類型的button變量,不知道爲什麼,所以只能通過獲取ID的方法來控制,不知道爲啥。這樣就能把位圖貼到按鈕上了。(注意:得把按鈕的第一個屬性設爲bitmap)