调用该成员函数的更新对话框按钮状态和在使用 ON_UPDATE_COMMAND_UI 回调结构的对话框或窗口的其他控件。
void UpdateDialogControls( CCmdTarget* pTarget, BOOL bDisableIfNoHndler );
头文件位置: afxwin.h
然而,在一些诸多较为复杂的情形下,我们就需要利用CDialogBar派生出自己的类了。
- dialogbar包含了具有drop-down属性的COMBOBOX;
- dialogbar包含了treeview或者tree控件,listview, list控件;
- dialogbar包含了ActiveX控件;
诸如上面所说的任何较为复杂的情形下,我们都应该对Dialogbar进行派生,以便在派生的类中对其他的控件进行初始化。因为在ClassWizard并没有支持以CDialogBar为基类的派生。所以我们必须自己手动完成该派生过程。这篇文章就是要阐述如何将CDialog的派生类转换为CDialogBar的派生类。
在开始正题之前,有必要说明一点:CDialogBar类是从CControlBar类派生而来的,而CControlBar类则是从CWnd类派生而来,所以CDialogBar并非CDialog的派生类。
首先创建一个DialogBar类型的dialog资源(在创建对话框资源的时候,单击Dialog选项前面的"+"号进行选择)。并以CDialog类为基类生成派生类,然后按照下面的步骤对所产生的类进行修改。
- 在类的声明中,将基类CDialog改为CDialogBar,同时将.cpp文件中,BEGIN_MESSAGE_MAP中的基类也改为CDialogBar.
- 修改.h文件和.cpp文件中的构造函数,同时修改DoDataExchange()函数,具体修改后的效果如下图:
1 CMyDlgBar (CWnd * pParent = NULL); // standard constructor
2 IMPLEMENT_DYNAMIC(CDlg_Bar, CDialog)
3 CMyDlgBar:: CMyDlgBar (CWnd * pParent )
4 : CDialog(CMyDlgBar::IDD, pParent)
5 {
6 ...
7
8 void CMyDlgBar::DoDataExchange(CDataExchange * pDX)
9 {
10 CDialog::DoDataExchange(pDX);
11 ...
12 BEGIN_MESSAGE_MAP(CDlg_Bar, CDialog)
1 CMyDlgBar (); // standard constructor
2 IMPLEMENT_DYNAMIC(CDlg_Bar, CDialogBar) //这句不可忘记做修改
3 CMyDlgBar:: CMyDlgBar ()
4 {
5 ...
6
7 void CMyDlgBar::DoDataExchange(CDataExchange * pDX)
8 {
9 CDialogBar::DoDataExchange(pDX);
10 ...
12 BEGIN_MESSAGE_MAP(CDlg_Bar, CDialogBar)
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 };
2 BEGIN_MESSAGE_MAP(CMyDlgBar, 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;
到此为止所有需要修改的地方都已经完成,剩下的就是使用了。在CMainFrame中定义变量,并在CMainFrame::OnCreate()函数中添加代码:
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_ANY );
10 EnableDocking(CBRS_ALIGN_ANY); //申明 窗口边界可被停靠,如果上文已出现过,可不必写这句了
11 DockControlBar( & m_wndDlgBar, AFX_IDW_DOCKBAR_BOTTOM);
{
HBRUSH hbr = CDialogBar::OnCtlColor(pDC, pWnd, nCtlColor);
if (nID==IDC_EDIT1) //编辑控件
{
pDC->SetBkMode(TRANSPARENT); //文字背景模式
pDC->SetTextColor(RGB(255,0,0));
return CreateSolidBrush(RGB(255,255,200));
}
if (nID==IDD_DIALOGBAR) //自身DialogBar
{
return CreateSolidBrush(RGB(122,122,122));
}
return hbr;
}
{
pDC->SetBkMode(TRANSPARENT);
if (!m_compatibleDC.m_hDC) //CDC m_compatibleDC;在MyList头文件中加此句
{
m_compatibleDC.CreateCompatibleDC(pDC);
}
CBitmap bitmap;
bitmap.LoadBitmap(IDB_BITMAP1);
BITMAP bit;
bitmap.GetBitmap(&bit);
m_compatibleDC.SelectObject(&bitmap);
CRect rect;
GetClientRect(&rect);
pDC->StretchBlt(0,0,rect.Width(),rect.Height(),&m_compatibleDC,0,0,bit.bmWidth,bit.bmHeight,SRCCOPY);
return FALSE;
}
(1)如果有很多个CDialogBar同时出现在你的面板上,那可能会出现显示错误的问题,你可以在ShowWindow()之后,调用MainFrame的RecalcLayout()来将屏幕位置合理调整。
(2)CButton不能使用,如何解决? 同样是添加函数,头文件中插入:
afx_msg void OnUpdateButton(CCmdUI * pCmdUI);
在cpp文件中插入:
ON_UPDATE_COMMAND_UI(IDC_BUTTON, OnUpdateButton)
并且在cpp文件中实现之:
void CMyDlgBar::OnUpdateButton(CCmdUI * pCmdUI)
(3)如何在Button上添加bitmap?
还是消息函数,在OnInitDialog中添加:
OnInitDialog(){
…;
HBITMAP hBitmap = LoadBitmap(AfxGetApp() ->m_hInstance, MAKEINTRESOURCE(IDB_BITMAP);
HWND hwnd = ::GetDlgItem(this -> GetSafeHwnd(), IDOK);
::SendMessage(hwnd, BM_SETIMAGE, IMAGE_BITMAP, (long)hBitmap);
…;
}
(4)改变CMyDlgBar的大小,比如永远为主窗口的左1/3:
在头文件的重载函数声明中插入:
Virtual CSize CalcDynamicLayout(int nLength, DWORD nMode);
在cpp文件中实现:
CSize CMyDlgBar::CalcDynamicLayout(int nLength, DWORD nMode){
CRect rcFrame;
GetDockingFrame() ->GetClientRect(&rcFrame);
return CSize(rcFrame.width() / 3, rcFrame.Height());
}
(5)去掉CMyDlgBar浮动时的标题栏
响应WM_WINDOWPOSCHANGED消息:
void CDlg_Bar::OnWindowPosChanged(WINDOWPOS* lpwndpos)
{
CDialogBar::OnWindowPosChanged(lpwndpos);
static BOOL m_bMenuRemoved=TRUE;
if( IsFloating() )
{
if( m_pDockBar && !m_bMenuRemoved )
{
CWnd* pParent = ((CWnd*)m_pDockBar)->GetParent();
if( pParent->IsKindOf(RUNTIME_CLASS(CMiniFrameWnd)))
{
pParent->ModifyStyle( WS_CAPTION, 0, 0 );
m_bMenuRemoved = TRUE;
}
}
}
else if( m_bMenuRemoved ) {
m_bMenuRemoved = FALSE;
}
}