CWnd::UpdateDialogControls 与DialogBar的创建

本文详细介绍如何在MFC应用程序中创建和定制对话栏(DialogBar),包括如何从CDialog派生自定义类、修改构造函数及消息映射、实现初始化对话逻辑、调整对话栏尺寸、更改背景颜色等。

调用该成员函数的更新对话框按钮状态和在使用 ON_UPDATE_COMMAND_UI 回调结构的对话框或窗口的其他控件。

void UpdateDialogControls(
   CCmdTarget* pTarget,
   BOOL bDisableIfNoHndler 
);

pTarget

指向应用程序的主框架窗口以及路由更新消息使用

bDisableIfNoHndler

标记指示存在是否应自动显示的控件不更新处理程序作为禁用。

如果子控件没有处理程序,并 bDisableIfNoHndlerTRUE,则子控件将被禁用。

作为应用程序的空闲进程的一部分,框架调用控件的此成员函数在对话栏或工具栏。

头文件位置: afxwin.h

 

 

在单文档中创建DialogBar
当创建一些简单的形如只包含了一些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的派生类。

首先创建一个DialogBar类型的dialog资源(在创建对话框资源的时候,单击Dialog选项前面的"+"号进行选择)。并以CDialog类为基类生成派生类,然后按照下面的步骤对所产生的类进行修改。

  1. 在类的声明中,将基类CDialog改为CDialogBar,同时将.cpp文件中,BEGIN_MESSAGE_MAP中的基类也改为CDialogBar.
  2. 修改.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 ...
11
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 };
1   // 在源文件中
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()函数中添加代码:

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_ANY );
10 EnableDocking(CBRS_ALIGN_ANY); //申明 窗口边界可被停靠,如果上文已出现过,可不必写这句了
11 DockControlBar( & m_wndDlgBar, AFX_IDW_DOCKBAR_BOTTOM);
 
改变DialogBar的背景及其控件的颜色
在CMyDlgBar类中响应WM_CTLCOLOR消息:
HBRUSH CMyDlgBar::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
 HBRUSH hbr = CDialogBar::OnCtlColor(pDC, pWnd, nCtlColor);
 int nID=pWnd->GetDlgCtrlID();
 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;
}
上面的List Control是用位图画刷装饰的,下面将为List Control贴图:
为List Control添加一个类CMyList,基类CListBox,在类中响应WM_ERASEBKGND消息:
BOOL CMyList::OnEraseBkgnd(CDC* pDC)
{
 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;
 //return CDialog::OnEraseBkgnd(pDC);
}
接下来,将列表框资源和类CMyList关联起来,在CMyDlgBar类的头文件中加入CMyList m_list;源文件的DoDataExchange函数中加入
DDX_Control(pDX, IDC_LIST1, m_list);这样就可以了。
 
实用技巧
(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)

{
     pCmdUI -> Enable(TRUE);
}
 
(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;
 }
}

 

前半部分讲解的很基础而详细,后半部分附有大量案例。发下目录,自己看着办吧。 目 录 译者序 前言 第一部分 基础 第1章 概述 1 1.1 Windows基础 1 1.1.1 窗口类结构 2 1.1.2 消息 2 1.1.3 客户区和非客户区 2 1.1.4 重叠窗口、弹出窗口和子窗口 2 1.1.5 父窗口和宿主窗口 3 1.2 Windows消息 3 1.2.1 发送或寄送消息 4 1.2.2 消息类型 4 1.2.3 接收消息 4 1.2.4 窗口处理函数的子类化 5 1.3 窗口绘图 5 1.3.1 设备环境 5 1.3.2 绘图工具 6 1.3.3 映射模式 6 1.3.4 窗口视和视口视 6 1.3.5 逻辑单位和设备单位 7 1.3.6 绘图函数 7 1.3.7 抖动和非抖动颜色 7 1.3.8 设备无关位图 8 1.3.9 元文件 8 1.3.10 何时绘图 8 1.4 MFC基础 8 1.5 Developer Studio基础 9 1.6 WindowsMFC总结 10 1.7 基本类 10 1.8 应用类 11 1.8.1 文档视 11 1.8.2 CWinApp(OC) 11 1.8.3 文档模板 12 1.8.4 线程 12 1.8.5 CFrameWnd(OCW) 12 1.8.6 CDocument(OC) 12 1.8.7 CView(OCW) 13 1.8.8 对话框应用程序 13 1.8.9 SDI应用程序 13 1.8.10 MDI应用程序 13 1.9 其余用户界面类 13 1.9.1 通用控件类 13 1.9.2 菜单类(O) 14 1.9.3 对话框类 15 1.9.4 通用对话框MFC类 15 1.9.5 控件条类 (OCW) 15 1.9.6 属性类 15 1.10 绘图类 16 1.11 其他MFC类 16 1.11.1 文件类 16 1.11.2 CArchive和序列化 16 1.11.3 数据库类 17 1.11.4 ODBC类 17 1.11.5 DAO类 17 1.11.6 数据集合类 17 1.11.7 通信类 18 1.12 类的消息机制 18 1.12.1 MFC如何接收一个寄送消息 18 1.12.2 MFC如何处理接收的消息 18 1.12.3 UI对象 20 1.13 小 结 20 第2章 控制条 21 2.1 通用控制条 21 2.2 用API创建控制条 22 2.3 用MFC创建控制条 24 2.3.1 CToolBarCtrl和CStatusBarCtrl 24 2.3.2 CToolBar和CStatusBar 24 2.3.3 CControlBar 26 2.4 停靠栏 27 2.4.1 设置停靠功能 28 2.4.2 自动改变大小和移动 30 2.4.3 停靠栏小结 30 2.5 浮动条 31 2.6 MFC的高级控制条类小结 32 2.7 视和控制条如何共享客户区 32 2.7.1 CFrameWnd::RecalcLayout() 32 2.7.2 CWnd::RepositionBars() 33 2.7.3 CControlBar::OnSizeParent() 33 2.7.4 CalcDynamicLayout()和 CalcFixedLayout () 34 2.7.5 CToolBar::CalcFixedLayout()和CTool Bar:: CalcDynamicLayout() 35 2.7.6 工具栏布局 35 2.7.7 CStatusBar::CalcFixedLayout() 36 2.7.8 CDockBar::CalcFixedLayout() 36 2.7.9 共享客户区小结 36 2.8 对话条 37 2.9 伸缩条 38 2.9.1 CReBar和CReBarCtrl 39 2.9.2 CReBar::CalcFixedLayout() 39 2.10 命令条 39 2.11 控制条窗口小部件风格 40 2.11.1 工具栏按钮风格 40 2.11.2 状态栏窗格风格 40 2.11.3 伸缩条段风格 40 2.12 设计自己的控制条 41 2.12.1 重载CControlBar::CalcDynamic-Layout() 41 2.12.2 增加WM_SIZEPARENT消息处理器 41 2.12.3 重载CMainFrame::RecalcLayout() 41 2.12.4 从CDockBar派生 42 2.13 实例 42 2.14 总结 42 第3章 通信 43 3.1 进程间通信 43 3.1.1 通信策略 43 3.1.2 同步和异步通信 44 3.2 窗口消息 44 3.2.1 打开和关闭 44 3.2.2 读写 45 3.2.3 回顾 45 3.3 动态数据交换 46 3.3.1 客户/服务器 46 3.3.2 打开和关闭 46 3.3.3 读和写 47 3.3.4 其他DDE函数 48 3.3.5 MFC支持 48 3.3.6 回顾 49 3.4 消息管道 49 3.4.1 打开和关闭 49 3.4.2 读和写 50 3.4.3 回顾 51 3.5 Windows套接字 51 3.5.1 打开和关闭 52 3.5.2 读和写 52 3.5.2 通过Windows套接字序列化 53 3.5.3 数据流和数据报 53 3.5.4 回顾 54 3.6 串行/并行通信 54 3.6.1 打开和关闭 54 3.6.2 读和写 54 3.6.3 配置端口 55 3.6.4 回顾 55 3.7 Internet通信 56 3.7.1 打开和关闭文件 56 3.7.2 读文件 56 3.7.3 打开和关闭连接 56 3.7.4 其他Internet类 57 3.8 通信方式小结 57 3.9 共享数据 58 3.10 共享内存文件 58 3.10.1 创建和销毁 58 3.10.2 读和写 58 3.10.3 回顾 59 3.11 文件映射 59 3.11.1 打开和关闭 59 3.11.2 读和写 60 3.11.3 数据同步 60 3.11.4 回顾 60 3.12 客户/服务器 61 3.12.1 传递调用参数 61 3.12.2 远程过程调用 62 3.13 小结 62 第二部分 用户界面实例 第4章 应用程序和环境 64 4.1 实例1:在工具栏中添加静态标识符 64 4.2 实例2:在工具栏中添加动态标识符 71 4.3 实例3:只启动一个实例 75 4.4 实例4:创建对话框/MDI混合式 应用程序 77 4.5 实例5:在系统托盘中添加图标 79 4.6 实例6: 主菜单状态栏中的标记 81 第5章 菜单、控件条和状态栏 85 5.1 实例7:在菜单中添加图标 85 5.2 实例8:调整命令条外观 97 5.3 实例9:可编程工具栏 102 5.4 实例10:在对话框中添加工具栏、 菜单和状态栏 127 5.5 实例11:在弹出菜单中增加位图标记 129 5.6 实例12:工具栏上的下拉按钮 131 5.7 实例13:在状态栏中添加图标 136 5.8 实例14:使用伸缩条 141 第6章 视 143 6.1 实例15:创建标签窗体视 143 6.2 实例16:创建具有通用控件的视 150 6.3 实例17 :打印报表 156 6.4 实例18: 打印视 167 6.5 实例19:绘制MDI客户视 174 6.6 实例20:拖放文件到视 177 第7章 对话框和对话条 179 7.1 实例21:动态改变对话框的尺寸 179 7.2 实例22:自定义数据交换并验证 184 7.3 实例23:重载通用文件对话框 187 7.4 实例24:重载通用颜色对话框 190 7.5 实例25:获得目录名 192 7.6 实例26:子对话框 197 7.7 实例27:子属性表 198 第8章 控件窗口 200 8.1 实例28:自己绘制的控件 200 8.2 实例29:在窗口标题中添加按钮 204 8.3 实例30:添加热键控件 211 第9章 绘图 213 9.1 实例31:使用非散射颜色 213 9.2 实例32:伸展位图 227 9.3 实例33:抓取屏幕 231 9.4 实例34:输出DIB位图文件 236 第10章 帮助 243 10.1 实例35:添加帮助菜单项 243 10.2 实例36:添加上下文相关帮助 245 10.3 实例37:添加气泡帮助 247 第11章 普通窗口 254 11.1 实例38:创建普通窗口 254 11.2 实例39:创建短调用形式窗口类 256 11.3 实例40:创建长调用形式窗口类 258 第12章 特定的应用程序 261 12.1 实例41:创建简单的文本编辑器 261 12.2 实例42:生成简单的RTF编辑器 262 12.3 实例43:创建资源管理器界面 265 12.4 实例44:创建简单的ODBC数据库 编辑器 284 12.5 实例45:创建简单的DAO数据库 编辑器 287 12.6 实例46:创建简单的向导 289 第三部分 内部处理实例 第13章 消息和通信 295 13.1 实例47:等待消息 296 13.2 实例48:清除消息 297 13.3 实例49:向其他应用程序发送消息 298 13.4 实例50:其他应用程序共享数据 300 13.5 实例51:使用套接字任意的应用 程序通信 301 13.6 实例52:使用串行或并行I/O 321 第14章 多任务 331 14.1 实例53:后台处理 331 14.2 实例54:运行其他应用程序 332 14.3 实例55:改变优先级 334 14.4 实例56:应用程序内部的多任务 工作者线程 336 14.5 实例57:应用程序内部的多任务 —用户界面线程 339 14.6 实例58:向用户界面线程发送消息 342 14.7 实例59:线程间的数据共享 343 第15章 其他 347 15.1 实例60:创建定时器 347 15.2 实例61:播放声音 349 15.3 实例62:创建VC++宏 350 15.4 实例63:使用函数地址 351 15.5 实例64:二进制字符串 352 15.6 实例65:重新启动计算机 356 15.7 实例66:获得可用磁盘空间 357 15.8 实例67:闪烁窗口和文本 358 第四部分 附录 附录A 消息和重载顺序 361 附录B 绘图结构 385
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值