新書推薦:
《
甲骨文丛书·消逝的光明:欧洲国际史,1919—1933年(套装全2册)
》
售價:NT$
1265.0
《
剑桥日本戏剧史(剑桥世界戏剧史译丛)
》
售價:NT$
918.0
《
中国高等艺术院校精品教材大系:材料的时尚表达??服装创意设计
》
售價:NT$
347.0
《
美丽与哀愁:第一次世界大战个人史
》
售價:NT$
653.0
《
国家豁免法的域外借鉴与实践建议
》
售價:NT$
857.0
《
大单元教学设计20讲
》
售價:NT$
347.0
《
儿童自我关怀练习册:做自己最好的朋友
》
售價:NT$
316.0
《
高敏感女性的力量(意大利心理学家FSP博士重磅力作。高敏感是优势,更是力量)
》
售價:NT$
286.0
編輯推薦:
Visual C在Windows应用程序开发工具中占有重要的地位, Visual C 2013版本和前面的版本相比有了不少改进。针对Windows系统下对Visual C 2013的开发介绍书不是很多、也不够全面的现状,本书作者撰写了这本针对初中级读者的Visual C 2013开发书。 作者在长期的编程实践中使用过许多Visual C系列开发工具(从6.0到2013都用过),积累了不少技术心得和开发经验,但这些技术比较零散,系统性不强,借助本书将这些内容整理成一个完整的系统,并且将所涉及的技巧和方法讲述出来,是一件很荣幸的事。 软件开发是一门需要实践的技术,本书理论尽量用简单易懂的语言表达,然后配以相应的实例,避免空洞的说教。对于其中的技术细节,都尽量讲深讲透,为读者提供翔实可靠的技术资料。对于Visual C 2013中的开发环境和开发技巧,本书从基本的内容讲起,然后进行提高,所以本书可以说是从入门到精通 。
內容簡介:
本书从初学者的角度出发,以通俗易懂的语言,配合丰富多彩的实例,详细介绍了使用Visual C 2013进行程序开发应该掌握的各方面知识。 全书共分11章,包括Visual C 2013概述,Windows编程基础,MFC对话框程序设计,MFC控件程序设计,菜单、工具栏和状态栏的开发使用,图形和图像,动态链接库,多线程编程,数据库编程,网络Sochet编程,Visual C 2013程序发布。书中所有知识都结合具体实例进行介绍,涉及的程序代码给出了详细的注释,可以使读者轻松领会Visual C 2013程序开发的精髓,快速提高开发技能。 本书适合作为软件开发入门者的自学用书,可供开发人员查阅、参考,也适合作为高等院校相关专业的教学参考书。
關於作者:
朱文伟,无锡江南计算研究所担任软件工程师。
目錄 :
目 录
第1章 Visual C 2013概述 1
1.1 Visual C 2013简介 1
1.2 安装Visual C 2013及其帮助 2
1.3 认识Visual C 2013 集成开发环境 2
1.3.1 起始页 2
1.3.2 主界面 4
1.3.3 标题栏 4
1.3.4 菜单栏 4
1.3.5 工具栏 5
1.3.6 类视图 6
1.3.7 解决方案资源管理器 7
1.3.8 输出窗口 7
1.3.9 错误列表 7
1.3.10 设置源码编辑窗口的颜色 7
1.3.11 显示行号 8
第2章 Windows编程基础 9
2.1 开发Windows程序的三种方式 9
2.2 SDK方式 9
2.3 MFC方式 12
2.3.1 通过向导生成一个简单的MFC程序 13
2.3.2 手工写一个简单的MFC程序 13
2.3.3 手工写一个稍复杂的MFC程序 17
2.4 托管方式 19
2.4.1 .NET Framework的概念 20
2.4.2 公共语言运行时库(CLR) 20
2.4.3 .NET Framework类库 20
2.4.4 第一个托管C控制台程序 21
2.4.5 第一个托管C表单程序 22
2.5 字符集 23
2.5.1 计算机上的三种字符集 23
2.5.2 Unicode编码的实现 28
2.5.3 C运行时库对Unicode的支持 32
2.5.4 C标准库对Unicode的支持 34
2.5.5 Windows API对Unicode的支持 34
2.5.6 Visual C 2013开发环境对Unicode的支持 35
2.5.7 字符集相关范例 36
2.6 SDK编程基础 39
2.6.1 消息的定义 39
2.6.2 预定义消息 41
2.6.3 自定义消息 45
2.6.4 消息和事件 45
2.6.5 消息和窗口 45
2.6.6 工程目录结构 55
2.6.7 调试初步 56
2.6.8 Win32控件编程 58
2.6.9 Win32对话框编程 95
2.7 MFC编程基础 109
2.7.1 MFC类库概述 109
2.7.2 MFC应用程序类型 112
2.7.3 添加菜单 114
2.7.4 窗口客户区 116
2.8 键盘 120
2.8.1 键盘概述 120
2.8.2 键盘消息 122
2.9 鼠标 131
2.9.1 鼠标概述 131
2.9.2 鼠标消息 132
2.10 字符串 138
2.10.1 几个字符串类型 139
2.10.2 Win32 API中的字符串 141
2.10.3 MFC中的字符串 141
2.11 控制台编程 148
2.12 内存管理 150
2.13 文件操作 152
2.13.1 Win32 API操作文件 152
2.13.2 MFC类操作文件 155
2.14 MFC的异常处理 163
2.15 调试输出 164
2.15.1 调试程序常用快捷键 164
2.15.2 利用Win32 API进行调试输出 165
2.15.3 在MFC程序调试输出 165
2.15.4 可视化查看变量的值 165
第3章 MFC对话框程序设计 166
3.1 对话框程序设计概述 166
3.2 建立一个简单的对话框程序 167
3.3 设置对话框的属性 168
3.3.1 打开对话框资源的属性视图 170
3.3.2 设置对话框的边框 172
3.3.3 设置对话框的标题 172
3.3.4 设置对话框运行后所处的坐标 172
3.3.5 设置对话框的大小 173
3.3.6 设置对话框的字体 173
3.3.7 设置对话框的最大化和最小化按钮 173
3.4 在对话框上使用按钮控件 174
3.4.1 显示工具箱 174
3.4.2 一次在对话框上放置一个按钮 175
3.4.3 一次在对话框上放置多个按钮 175
3.4.4 选中按钮控件 176
3.4.5 移动对话框上的按钮控件 176
3.4.6 对齐对话框上的按钮控件 176
3.4.7 调整按钮控件的大小 176
3.4.8 删除对话框上的按钮控件 177
3.4.9 为按钮添加变量 177
3.4.10 为按钮控件添加事件处理程序 179
3.5 显示消息对话框 180
3.5.1 MessageBox的常见应用 180
3.5.2 AfxMessageBox的常见应用 182
3.6 对话框的窗口消息 185
3.6.1 为对话框添加消息处理函数 186
3.6.2 为对话框添加自定义消息 187
3.7 模态对话框和非模态对话框 190
3.8 通用对话框 194
3.8.1 文件对话框的使用 194
3.8.2 字体对话框的使用 198
3.8.3 颜色对话框的使用 202
3.8.4 浏览文件夹对话框的使用 204
3.8.5 查找替换对话框的使用 206
3.8.6 打印对话框的使用 211
3.9 对话框的高级话题 213
3.9.1 在对话框非标题栏区域实现拖动 213
3.9.2 在对话框上显示状态栏 215
3.9.3 在对话框状态栏上显示菜单提示 216
3.9.4 对话框上显示带下拉菜单的工具栏 218
3.9.5 创建一个向导式对话框 223
3.9.6 为对话框添加BMP图片作为背景 226
3.9.7 动画的方式显示对话框 227
3.9.8 替换对话框的最小化和关闭按钮 229
3.9.9 为对话框添加PNG图片作为背景 232
3.9.10 为PNG背景的对话框添加控件 234
3.9.11 使对话框大小可调整 236
3.9.12 限制对话框最大化时对话框的大小 236
3.9.13 显示或隐藏对话框窗口标题栏 237
3.9.14 带启动文字界面的对话框程序 238
3.9.15 让带图像的对话框渐进渐出 240
3.9.16 对话框上实现3D文字 242
3.9.17 对话框程序向另一个对话框发送消息 243
3.9.18 枚举当前所有打开的窗口 244
3.9.19 在动态链接库dll中调用对话框 245
3.9.20 改变对话框的默认背景色 247
第4章 MFC控件程序设计 249
4.1 控件概述 249
4.2 按钮控件 249
4.2.1 设置按钮的标题 250
4.2.2 制作图片按钮 252
4.2.3 实现一个三角形按钮 252
4.2.4 实现类似Visual C属性表中的钉子按钮 253
4.2.5 实现具有不同状态的图片按钮 255
4.2.6 为按钮动态加载的4幅状态图 259
4.2.7 反映3种不同状态的图片按钮 263
4.2.8 实现一个不自动弹起的按钮 268
4.2.9 3种选中radio button的方法 271
4.2.10 利用CXPButton实现图片按钮 274
4.2.11 CButtonST类的基本使用 275
4.2.12 CButtonST类的高级使用 278
4.2.13 实现CButtonST类的透明效果 281
4.2.14 CButtonST类的阴影效果 283
4.2.15 同一程序内模拟按钮事件 286
4.2.16 不同的程序间发送消息给对方按钮 287
4.2.17 实现按钮凹下和弹起效果 289
4.2.18 在非客户区上实现按钮 290
4.2.19 鼠标移过按钮时发出声音 292
4.2.20 实现一个类似网址形式的链接按钮 294
4.2.21 通过自绘实现XP样式的按钮 295
4.2.22 鼠标停留背景改变的按钮 296
4.2.23 实现圆形按钮 296
4.2.24 更完美的XP样式按钮 297
4.2.25 一个圆形的图片按钮 297
4.2.26 又一个XP风格按钮的实现 299
4.2.27 实现头像选择按钮 299
4.3 编辑控件 301
4.3.1 编辑控件的常用属性 302
4.3.2 设置和获取编辑框内容 303
4.3.3 设置和获取密码框 305
4.3.4 设置CEdit控件的字体颜色 306
4.3.5 自定义编辑控件的上下文菜单 306
4.3.6 代码方式实现内容全选 308
4.3.7 用位图更换编辑框的背景 309
4.3.8 实现一个简单的记事本 311
4.3.9 实现可设断点的多文档程序 312
4.3.10 日期格式化输入的编辑框 314
4.3.11 实现联想输入的编辑框 316
4.3.12 在编辑框中加载位图 317
4.3.13 在Rich编辑框中实现末尾和当前位置插入文本 318
4.3.14 在编辑框末尾追加文本 319
4.3.15 让编辑框支持自动换行 320
4.3.16 让滚动条随着设置的内容滚动到最后一行 321
4.3.17 让编辑框一直滚屏 322
4.4 列表框控件 323
4.4.1 向列表框中插入和获取数据 324
4.4.2 向列表框指定位置插入数据 327
4.4.3 实现一个支持复选框的列表框 328
4.4.4 让列表框支持多选 330
4.4.5 让列表框出现水平滚动条 331
4.4.6 为列表框替换背景图片 332
4.4.7 列表框自动选中最后一行 335
4.5 列表控件 336
4.5.1 添加和获取、删除数据项 338
4.5.2 图标方式显示列表控件内的项目 342
4.5.3 为列表控件增加背景图片 343
4.5.4 可设置单元格颜色的ClistCtrl类 344
4.5.5 在列表框中实现列表项目的上下移动 345
4.5.6 对列表控件的列头的字体、颜色、背景进行更改 348
4.5.7 让列表控件的主项可以编辑 353
4.5.8 使列表控件支持子项可编辑 355
4.5.9 使列表控件列表方式时呈现网格 356
4.5.10 让列表视图的表头无法改变大小 357
4.5.11 让列表控件可以修改行、列和单元格颜色 359
4.5.12 在dll中设置外部列表控件 362
4.6 标签控件 363
4.6.1 标签控件的基本使用 364
4.6.2 带图标的标签控件 367
4.7 静态文本控件 368
4.7.1 设置和获取静态文本控件的内容 369
4.7.2 让静态文本控件显示不同风格的字体 370
4.7.3 实现边框为3D样式的静态框 373
4.7.4 用空格键操作超级链接静态控件访问网址 374
4.7.5 用静态控件实现电子式时钟 376
4.7.6 一个功能强大的静态控件类 378
4.7.7 静态控件实现电子8段管仿真程序 379
4.7.8 用静态框实现项目和颜色列表功能 381
4.7.9 设置静态文本控件的文本颜色 383
4.7.10 让静态文本控件响应单击 384
4.8 组合框 385
4.8.1 组合框的基本使用 386
4.8.2 组合框实现联想输入 389
4.8.3 实现一个颜色组合框 390
4.8.4 支持自动完成的扁平组合框 391
4.8.5 自定义组合框背景 392
4.8.6 带图标的组合框 393
4.9 进度条 394
4.9.1 进度条的基本使用 394
4.9.2 实现一个位图进度条 396
4.9.3 实现一个带文字指示的进度条 398
4.9.4 在状态栏中实现进度条显示 398
4.10 图像列表控件 400
4.11 树形控件 404
4.11.1 树形控件的基本使用 406
4.11.2 判断某节点的复选框是否打勾 408
4.11.3 某节点的复选框打勾的时候,其儿子节点也打勾 409
4.11.4 隐藏某些节点的复选框 410
4.11.5 修改某节点字体和颜色 411
4.11.6 通过代码选中某个节点 413
4.11.7 判断某节点是否展开 413
4.11.8 判断某节点是否处于选中状态 414
4.11.9 判断是否单击了复选框 415
4.11.10 使节点标题可以编辑 416
4.11.11 使节点可以编辑,并且限制标题长度 417
4.11.12 通过代码的方式使树形控件具有Edit Label风格 418
4.11.13 编辑节点Label的时候支持回车键和Esc键 420
4.11.14 通过代码取消选中某个节点 421
4.11.15 让树形控件出现ToolTips 422
4.11.16 某节点的checkbox打勾的时候,其所有的子孙节点也打勾 423
4.11.17 加载图标文件方式为树形控件加入图标 425
4.11.18 把磁盘某目录下的内容添加到树形控件中 425
4.11.19 通过代码展开某个含有子节点的父节点 427
4.11.20 实现类似Delphi的属性列表功能 428
4.11.21 对树形控件中的节点进行拖动 429
4.11.22 设置树形控件字体颜色 431
4.11.23 通过加载位图文件,让树形控件的节点带有图标 431
4.11.24 添加数据库里内容到树形控件节点 432
4.11.25 实现类似QQ游戏大厅导航的树形控件 436
4.11.26 通过树形控件节点来显示不同的子对话框 439
4.11.27 树形控件和文档类程序的联合作战 441
4.11.28 一个简单的Windows资源管理器的界面 443
4.11.29 递归添加磁盘上的任一目录 446
4.11.30 支持编辑框的方式插入节点 447
4.11.31 节点检查框的隐藏和显示 451
4.11.32 实现一个三态树 453
4.11.33 把位图作为树形控件的背景 455
4.12 滑块控件 456
4.12.1 滑块控件的基本使用 457
4.12.2 让位图作为滑块控件的背景 459
4.13 调节控件 461
4.13.1 调节控件的基本使用 462
4.13.2 用调节控件调节小数 463
4.14 滚动条控件 464
4.14.1 滚动条控件基本使用 465
4.14.2 区分多个滚动条 468
4.15 IP Address控件 469
4.15.1 IP Address控件的基本使用 470
4.15.2 获取和设置IP地址的另一种用法 472
4.15.3 在IP控件中显示本机地址 473
4.16 日期时间拾取控件 475
4.16.1 日期时间拾取控件的基本使用 475
4.16.2 设置日期时间拾取控件的选择范围 477
4.16.3 设置日期时间拾取控件的显示格式 479
4.17 月历控件 480
4.17.1 月历控件的基本使用 481
4.17.2 月历控件的其他使用 482
4.18 动画控件 485
4.19 热键控件 487
4.20 Custom 控件 489
4.20.1 让Custom 控件关联已有控件 489
4.20.2 把Custom 控件设置为一个自定义类 490
4.20.3 实现一个能自绘的Custom控件 491
4.21 Picture控件 493
4.21.1 Picture控件静态显示图片 493
4.21.2 Picture控件动态显示图片 494
4.22 Syslink控件 496
4.23 Command Button控件 498
4.24 Network Address控件 499
4.25 Split Button控件 501
4.26 MFC新控件 502
4.26.1 MFC Button控件 502
4.26.2 MFC ColorButton控件 505
4.26.3 MFC EditBrowse 控件 506
4.26.4 MFC VSListBox控件 508
4.26.5 MFC FontComboBox控件 509
4.26.6 MFC MaskedEdit控件 510
4.26.7 MFC MenuButton控件 512
4.26.8 MFC PropertyGrid控件 514
4.26.9 MFC ShellList控件和MFC ShellTree控件 519
4.26.10 MFC Link控件 521
4.27 动态创建控件 521
4.27.1 在对话框上动态创建CMFCListCtrl控件和CStatic控件 521
4.27.2 在视图上动态创建控件 524
第5章 菜单、工具栏和状态栏的开发使用 527
5.1 菜单的设计与开发 527
5.1.1 添加菜单项并添加消息 528
5.1.2 为菜单添加快捷键 529
5.1.3 设置菜单的状态来标记任务栏是否隐藏 530
5.1.4 绘制漂亮的快捷菜单 531
5.1.5 向记事本程序发送菜单信息 533
5.1.6 动态生成菜单 534
5.1.7 实现动态菜单的状态栏提示 536
5.1.8 代码方式为对话框加载菜单 537
5.1.9 自定义类CMenuEx的简单使用 538
5.1.10 通过类CMenuEx给菜单增加背景色和左边位图 539
5.1.11 实现中英文菜单的动态切换 540
5.1.12 修改并增加系统菜单项 542
5.2 工具栏的设计与开发 544
5.2.1 显示或隐藏工具栏 545
5.2.2 设置工具栏标题 545
5.2.3 显示或隐藏工具栏上所有按钮 546
5.2.4 在视图类中判断工具栏是否处于浮动状态 547
5.2.5 资源法创建工具栏 547
5.2.6 非资源法创建工具栏 549
5.2.7 使工具栏具有任意停靠和漂浮功能 550
5.2.8 通过菜单出现工具栏提示 550
5.2.9 通过字符串表出现工具栏提示 551
5.2.10 工具栏上放置组合框 552
5.2.11 让工具栏不出现提示 552
5.2.12 让工具栏按钮出现提示 553
5.2.13 使工具栏按钮出现下拉箭头 554
5.2.14 使工具栏按钮失效和生效 555
5.2.15 使工具栏按钮保持下压状态 556
5.2.16 使工具栏在任意一边停靠 556
5.2.17 通过工具栏指针动态为工具栏按钮保存一段文本 557
5.2.18 设置工具栏按钮的大小 558
5.2.19 在工具栏按钮下方显示文本 558
5.2.20 动态修改工具栏按钮的显示文本 559
5.2.21 在工具栏上显示字体组合框 560
5.2.22 工具栏上出现对话框 562
5.3 状态栏的设计与开发 562
5.3.1 在单文档程序的状态栏上显示自定义字符串 563
5.3.2 在状态栏已有窗格上动态显示字符串 564
5.3.3 在状态栏新的窗格上动态显示自定义字符串 565
5.3.4 在状态栏上显示图片 566
5.3.5 在状态栏上显示按钮 567
5.3.6 显示或隐藏状态栏 568
5.3.7 在状态栏中新增窗格,通过自定义字符串资源 569
5.3.8 在状态栏中新增窗格,通过使用预定义ID 570
第6章 图形和图像 571
6.1 Windows图形编程的几个重要概念 571
6.1.1 图形输出设备 571
6.1.2 GDI的概念 571
6.1.3 GDI对象的概念 572
6.1.4 设备描述表 572
6.2 Win32图形编程 573
6.2.1 点的坐标POINT 573
6.2.2 矩形尺寸SIZE 573
6.2.3 矩形坐标RECT 573
6.2.4 更新区域、WM_PAINT和WM_ERASEBKGND消息 575
6.2.5 设备描述表的获取和释放 579
6.2.6 设备描述表的属性 583
6.3 设备坐标系 587
6.4 逻辑坐标和映射模式 589
6.4.1 映射模式 591
6.4.2 原点的坐标 592
6.4.3 视口范围和窗口范围 595
6.5 Win32中的GDI对象 601
6.5.1 画笔 603
6.5.2 画刷 606
6.5.3 字体 608
6.5.4 GDI位图 613
6.5.5 区域 622
6.5.6 调色板 629
6.6 路径 630
6.7 裁剪 632
6.8 更新区域 633
6.9 双缓冲绘图 637
6.10 颜色 640
6.10.1 颜色的表示 640
6.10.2 窗口背景色 642
6.10.3 文本背景色 643
6.10.4 文本前景色 644
6.11 背景模式 645
6.12 绘图模式 645
6.13 MFC图形编程 647
6.13.1 点的坐标CPoint 647
6.13.2 矩形尺寸CSize 648
6.13.3 矩形坐标CRect 649
6.13.4 设备描述表的获取和释放 651
6.13.5 设备描述表的属性 654
6.13.6 在对话框上画点和线 655
6.13.7 在单文档视图上画填充图形 658
6.13.8 OnDraw和OnPaint的关系 660
6.14 MFC中的GDI对象 661
6.14.1 画笔 662
6.14.2 画刷 663
6.14.3 GDI位图 663
6.14.4 字体 664
6.14.5 区域 665
6.14.6 调色板 666
第7章 动态链接库 668
7.1 动态链接库的定义 668
7.2 使用动态链接库的好处 669
7.3 动态链接库的分类 669
7.4 Win32 DLL的开发 669
7.4.1 在DLL中导出全局函数 669
7.4.2 C语言使用DLL 673
7.4.3 DllMain函数 678
7.4.4 在DLL中导出变量 680
7.4.5 在DLL中导出类 684
7.4.6 其他语言调用DLL 687
7.5 MFC下DLL的开发 693
第8章 多线程编程 699
8.1 多线程编程的基本概念 699
8.1.1 为何要用多线程 699
8.1.2 操作系统和多线程 699
8.1.3 进程和线程 699
8.1.4 线程调度 701
8.1.5 线程函数 703
8.1.6 线程对象和句柄 703
8.1.7 线程对象的安全属性 704
8.1.8 线程标识 704
8.1.9 多线程编程的三种库 704
8.2 利用Win32 API函数进行多线程开发 705
8.2.1 线程的创建 705
8.2.2 线程的结束 709
8.2.3 线程和MFC控件交互 714
8.2.4 线程的暂停和恢复 720
8.2.5 消息线程和窗口线程 723
8.2.6 线程同步 725
8.3 CRT库中的多线程函数 738
8.4 MFC多线程开发 744
8.4.1 线程的创建 745
8.4.2 线程同步 748
第9章 数据库编程 761
9.1 数据库的基本概念 762
9.1.1 数据库 762
9.1.2 DBMS 762
9.1.3 SQL 762
9.2 ODBC的概念 762
9.3 通过MFC ODBC来开发数据库应用程序 763
9.3.1 建立数据库 763
9.3.2 建立ODBC数据源 764
9.3.3 在MFC中通过ODBC进行数据库开发 765
第10章 网络Socket编程 772
10.1 TCPIP协议 772
10.1.1 基本概念 772
10.1.2 TCPIP协议的分层结构 772
10.1.3 TCP协议 774
10.1.4 UDP协议 774
10.1.5 IP协议 775
10.1.6 IP地址 776
10.1.7 MAC地址 778
10.1.8 ARP协议 779
10.1.9 RARP协议 780
10.1.10 DNS 781
10.1.11 端口 781
10.2 Socket基础 782
10.2.1 基本概念 782
10.2.2 网络字节序 782
10.2.3 IO模式和IO模型 784
10.3 Winsock API套接字编程 784
10.3.1 Winsock API编程的基本步骤 784
10.3.2 常用的Winsock API函数 785
10.3.3 阻塞套接字的使用 791
10.3.4 非阻塞套接字的使用 794
10.4 MFC套接字编程 797
10.4.1 类CAsyncSocket 798
10.4.2 类CSocket 802
第11章 Visual C 2013程序发布 808
11.1 Debug和Release的区别 808
11.2 Win32程序在干净的Windows XP上运行 808
內容試閱 :
前 言
这是一本Visual C入门的经典书籍。任何学过CC语言并立志成为一名Windows开发工程师的朋友,都可以从本书起步。本书虽然有点厚实,但内容通俗易懂,由浅入深,并且实例丰富,步骤详细,注释充分,相信大家都能看得懂。对于中高级开发人员,也可以通过本书快速上手Visual C 2013这个强大的开发工具。本书并没有讲述C语言部分,因为这是一本Windows编程的书籍,里面都是实实在在Windows编程的干货。此外,实例丰富是本书的一大特点,大家知道,编程开发光了解理论是不够的,只有自己上机调试运行下例子,才能深刻理解编程,尤其对于Visual C更是如此。另外,为了照顾初学者,每个实例步骤非常详细,从建立工程到运行工程,都有着丰富的注释,步骤注释详细是本书的另外一大特点。Visual C在当前Windows编程开发平台上已是霸主地位,其功能之强大令人叹为观止。希望大家能够通过本书的学习,打好Windows开发的基础,早日成为Visual C高手。本书配套一张DVD光盘,按本书各章分10个目录为读者提供示例项目文件,读者可以在阅读示例的时候,运行这些项目以加深对相关内容的理解,并培养自己动手编程的能力。虽然作者尽了自己最大努力,但是不可避免地在书中仍然会有一些小错误出现。希望大家斧正,作者的邮箱是itrzw@sohu.com,关于本书的最新动态和错误列表,可以关注作者博客http:itrzw.blog.sohu.com,读者反映的建议或书中错误会更新到博客上。本书所有例子都在Windows 7上用Visual C 2013编译通过。非特别说明,默认情况下工程字符集都是Unicode版本,这也是Visual C 2013默认采用的字符集。此外,为了帮助初学者顺利求职成功,对于购买本书的读者在求职试用期内提供免费的技术咨询服务,具体情况详见博客http:itrzw.blog.sohu.com。
编者2017年2月
第 5 章菜单、工具栏和状态栏的开发使用
虽然菜单、工具栏和状态栏可以用在对话框工程中,但它们更多是用在文档视图类工程中。菜单和工具栏通常是位于主窗口的上方位置,状态栏位于主窗口的下方位置。菜单和工具栏都是用来接收用户的鼠标单击,以此来引发相应的操作,比如用户单击退出菜单项,程序就退出,工具栏和菜单都是执行用户命令的,它们接收的Windows消息,称为命令消息,如WM_COMMAND。状态栏通常是显示当前程序处于某种状态或对某个菜单项(工具栏按钮)进行解释,状态栏上有多个分隔的区域,来显示不同的信息。在本章中,大部分实例的应用程序类型都是基于单个文档,并且项目类型是MFC标准,这是最传统的单文档工程,这两个选项可以在MFC应用程序向导对话框的第一步上看到。本节默认情况下新建的单文档工程就是指MFC标准的单文档工程。5.1 菜单的设计与开发菜单是Windows程序中最常见的界面元素,几乎所有的Windows程序都有菜单,无论是单文档程序、多文档程序还是对话框程序,菜单是用户操作应用程序功能的重要媒介。菜单一般分两种,一种是位于程序界面的顶端,它使用鼠标左键单击后才发生动作;另一种是在界面无须的地方右击鼠标,然后出现一个小菜单,接着再用鼠标左键去单击某个菜单项,这种菜单称为快捷菜单。程序中所有的功能基本都可以在菜单中表达。一个菜单包括很多菜单项,当我们单击某个菜单项的时候,会发出一个命令消息,然后就引发相应的消息处理函数的执行。在Visual C 2013中,菜单由类CMenu实现。CMenu常用的成员函数如下表。成员函数含义CMenu 构造一个CMenu对象Attach附加一个Windows菜单句柄给CMenu对象Detach从CMenu对象中分离Windows菜单的句柄,并返回该句柄FromHandle返回一个指向给定Windows菜单句柄的CMenu对象的指针GetSafeHmenu返回由CMenu对象包含的m_hMenu值DeleteTempMap删除由FromHandle成员函数创建的所有临时CMenu对象CreateMenu创建一个空菜单,并将其附加给CMenu对象CreatePopupMenu创建一个空的弹出菜单,并将其附加给CMenu对象LoadMenu从可执行文件中装载菜单资源,并将其附加给CMenu对象LoadMenuIndirect从内存的菜单模板中装载菜单,并将其附加给CMenu对象DestroyMenu销毁附加给CMenu对象的菜单,并释放菜单占用的内存DeleteMenu从菜单中删除指定的项。如果菜单项与弹出菜单相关联,那么将销毁弹出菜单的句柄,并释放它占用的内存(续表)成员函数含义TrackPopupMenu在指定的位置显示浮动菜单,并跟踪弹出菜单的选择项AppendMenu在该菜单末尾添加新的菜单项CheckMenuItem在弹出菜单的菜单项中放置或删除检测标记CheckMenuRadioItem将单选按钮放置在菜单项之前,或从组中所有的其他菜单项中删除单选按钮SetDefaultItem为指定的菜单设置默认的菜单项GetDefaultItem获取指定的菜单默认的菜单项EnableMenuItem使菜单项有效、无效或变灰GetMenuItemCount决定弹出菜单或顶层菜单的项数GetMenuItemID获取位于指定位置菜单项的菜单项标识GetMenuState返回指定菜单项的状态或弹出菜单的项数GetMenuString获取指定菜单项的标签GetMenuItemInfo获取有关菜单项的信息GetSubMenu获取指向弹出菜单的指针InsertMenu在指定位置插入新菜单项,并顺次下移其他菜单项ModifyMenu改变指定位置的已存在的菜单项RemoveMenu从指定的菜单中删除与弹出菜单相关联的菜单项下面通过几个实例对菜单的常用属性、方法和事件进行介绍。5.1.1 添加菜单项并添加消息本例很基本,就是新建一个单文档工程,然后添加菜单项,并添加代码来响应菜单事件。添加菜单项十分简单,所有过程都是可视化操作。只要切换到资源编辑器,然后打开菜单编辑器,添加菜单并添加菜单消息响应。【例5.1】添加菜单项并添加消息(1)新建一个单文档工程,设置工程字符集为使用多字节字符集。(2)切换到资源视图,双击打开Menu下面的IDR_MAINFRAME(IDR_MAINFRAME是菜单的资源名),然后单击编辑菜单,在末尾添加我添加的菜单项,如图5-1所示。图5-1然后在属性视图中设置该菜单项的ID为ID_EDIT_MYMENUITEM,如图5-2所示。(3)对我添加的菜单项右击,然后选择添加事件处理程序,Visual C会弹出事件处理程序向导对话框,在该对话框上的类列表中选择CMainFrame,然后单击添加编辑按钮,如图5-3所示。图5-2图5-3Visual C会自动打开菜单处理函数,可以在该函数中添加相应代码:void CMainFrame::OnEditMymenuitem{ TODO: 在此添加命令处理程序代码AfxMessageBox"你好,世界";}(4)保存并运行工程,运行结果如图5-4所示。图5-45.1.2 为菜单添加快捷键快捷键又称为键盘快捷键,通常是键盘上2个键的组合,比如在Word程序中,Ctrl和N,同时按下并一起放开会新建一个文档。其功能和通过菜单文件|新建是一样的。快捷键就是为了不用鼠标直接用键盘来操作界面以达到更快捷的效果。添加菜单的快捷键很简单,只要在菜单设计器里的相应菜单后面添加即可。【例5.2】为菜单添加快捷键(1)新建一个单文档工程,设置工程字符集为使用多字节字符集。(2)切换到资源视图,展开Menu,双击打开IDR_MAINFRAME,在视图菜单下增加一个菜单项,菜单的caption属性是现在时间\tCtrl T,\t为前后文本隔开一个tab长度,Ctrl T用来指示该菜单项的快捷键是Ctrl T,但仅仅用来指示,要实现其作用,还要在下一步中设置。该菜单项的ID为ID_NOW_TIME,然后为其添加消息函数,让它跳出一个框,上面显示当前时间。代码如下:void CMainFrame::OnNowTime{ TODO: 在此添加命令处理程序代码CString str;CTime t = CTime::GetCurrentTime;得到当前时间str = t.Format "%Y-%m-%d %H:%M:%S"; 把时间转换为字符串并存入strAfxMessageBoxstr; 显示结果}其中,CTime是MFC类库中的表示时间的类。(3)切换到资源视图,展开Accelerator,双击打开Accelerator下的IDR_MAINFRAME,可以在右边看到系统已经预定义的快捷键,我们在右边空白地方右击,然后在快捷菜单中选择新建快捷键,然后在属性窗口中定义该快捷键的ID为ID_NOW_TIME,这样该快捷键和我们上一步定义的菜单项联系起来了,然后在属性窗口中定义Key为T,因为在该快捷键的Ctrl属性默认已经为True,所以该快捷键的按键组合为Ctrl T。定义好的快捷键属性如图5-5所示。(4)保存并运行工程,按Ctrl T快捷键就会出现当前时间的对话框了,运行结果如图5-6所示。图5-5图5-65.1.3 设置菜单的状态来标记任务栏是否隐藏所谓菜单的状态,通常指菜单项是否可用(不可用的状态是灰的)、菜单项前是否打勾等,比如我们打开记事本程序,然后单击菜单格式下的自动换行,可以发现每一次单击它后前面的勾会出现或者不出现,出现表示自动换行功能启用,不出现表示自动换行功能没启用,这就是通过设置菜单状态来表明当前的一些功能。本例中我们也在菜单项前设置打勾标记,用来标记任务栏是否显示。菜单状态的变化是响应UpdateCommandUI消息类型,然后在该事件处理函数中可以获取CCmdUI的指针,通过该指针用来设置菜单是否打勾(SetCheck)、是否可用(Enable)、设置选项(SetRadio)等状态。【例5.3】设置菜单的状态来标记任务栏是否隐藏(1)新建一个单文档工程,设置工程字符集为使用多字节字符集。(2)切换到类视图,双击类CMainFrame来打开MainFrame.h,然后为CMainFrame类添加一个成员变量:BOOL m_bHide;是否隐藏任务栏。TRUE为隐藏;否则为显示在类CMainFrame的构造函数中进行初始化,代码如下:CMainFrame::CMainFrame{ TODO: 在此添加成员初始化代码m_bHide = FALSE; 开始的时候为不隐藏}(3)切换到资源视图,打开菜单资源,然后在视图下添加一个菜单项任务栏,ID为ID_HIDE,并为其添加消息函数,代码如下:void CMainFrame::OnHide{ TODO: 在此添加命令处理程序代码int nCmdShow;CWnd *pWnd;LPARAM lParam;
m_bHide = !m_bHide; 更新隐藏标记查找任务栏,并把任务栏窗口的指针存入pWndpWnd = FindWindow"Shell_TrayWnd",NULL;ifm_bHide == TRUE 如果要设为隐藏{nCmdShow = SW_HIDE; 设置隐藏lParam = ABS_AUTOHIDE | ABS_ALWAYSONTOP; 设置自动隐藏}else{nCmdShow = SW_SHOW; 设置显示lParam = ABS_ALWAYSONTOP; 设置总在前面显示}pWnd-ShowWindownCmdShow;显示或隐藏任务栏}此时运行程序,发现每次单击该菜单,任务栏会隐藏或显示了。下面开始标记菜单的状态。(4)切换到资源视图,对刚才添加的菜单任务栏右击,选择添加事件处理程序,然后在事件处理程序向导对话框上的类列表中选择CMainFrame,在消息类型中选择UpdateCommandUI,然后单击添加编辑按钮来添加菜单状态变化处理程序,代码如下:void CMainFrame::OnUpdateHideCCmdUI *pCmdUI{ TODO: 在此添加命令更新用户界面处理程序代码ifm_bHidepCmdUI-SetCheck0; 去掉菜单项前面的勾elsepCmdUI-SetCheck1;显示菜单项前面的勾}(5)保存工程并运行,运行结果如图5-7所示。5.1.4 绘制漂亮的快捷菜单快捷菜单又称Popup菜单,是右击鼠标时显示的菜单。在默认情况下,调用快捷菜单函数显示的菜单是和系统当前主题相关的,如果是XP主题,那么菜单样式是XP样式的,如果是经典的Windows主题,显示的菜单是经典的样式。在本例中,我们通过自己绘制菜单的样式,使得快捷菜单十分漂亮,并且不随着系统主题的改变而改变,显示出专业的软件水准。基本思路是从类CMenu继承为一个我们自己的菜单类CMyMenu,然后通过2个虚拟函数MeasureItem和DrawItem,把位图作为菜单项的背景,并重绘菜单项的大小和文字。【例5.4】绘制漂亮的快捷菜单(1)新建一个对话框工程,设置工程字符集为使用多字节字符集。(2)打开资源视图,新建一个菜单,菜单名为:IDR_MENU1,如图5-8所示。(3)切换到类视图,添加一个继承自CMenu的菜单类CMyMenu,注意选择基类类型的时候要选择C类,MFC类下面没有CMenu。(4)添加2个图片作为菜单项的背景图和左边竖向图,两个bmp图片的ID分别为IDB_ITEM和IDB_LEFT。(5)在MyMenu.h中,添加3个全局变量和菜单项的结构体。菜单项数量、菜单项的高度和宽度const int MAX_MENUCOUNT = 20,ITEMHEIGHT = 26,ITEMWIDTH= 120;CMenuItemInfo结构用于记录菜单项信息struct CMenuItemInfo{CString m_ItemText;菜单项文本int m_IconIndex;菜单项索引int m_ItemID;菜单标记 -2顶层菜单,-1弹出式菜单,0分隔条,其他普通菜单};(6)为类CMyMenu添加成员变量:public:int m_index; 临时索引int m_iconindex; 图像索引BOOL m_isdrawtitle; 是否重绘标题CFont m_titlefont; 标题字体int m_save;CMenuItemInfo m_ItemLists[MAX_MENUCOUNT]; 菜单项信息(7)为类CMyMenu添加2个虚拟函数MeasureItem和DrawItem。其中,MeasureItem的作用是设置菜单项大小;DrawItem的作用是重绘菜单项。MeasureItem的原型是:virtual void MeasureItemLPMEASUREITEMSTRUCT lpMeasureItemStruct;当一个具有自画风格的菜单创建后,MeasureItem函数会被由MFC框架调用来设置菜单项的大小,我们只需通过lpMeasureItemStruct结构体来定义菜单项的大小即可。DrawItem的原型是:virtual void DrawItemLPDRAWITEMSTRUCT lpDrawItemStruct ;当一个具有自画风格的菜单的外观发生改变的时候,MFC框架会自动调用该函数来重绘菜单项,所以我们可以在该函数中,画出我们所无须的菜单风格,包括菜单文本、菜单风格条等。(8)为CMyMenu添加成员函数:BOOL ChangeMenuItemCMenu* m_menu,BOOL m_Toped = FALSE;BOOL AttatchMenuHMENU m_hmenu;void DrawItemTextCDC* m_pdc,LPSTR str,CRect m_rect;绘制顶层菜单void DrawTopMenuCDC* m_pdc,CRect m_rect,BOOL m_selected = FALSE;void DrawSeparaterCDC* m_pdc,CRect m_rect;绘制分隔条void DrawComMenuCDC* m_pdc,CRect m_rect, COLORREF m_fromcolor,COLORREF m_tocolor, BOOL m_selected = FALSE;void DrawMenuIconCDC* m_pdc,CRect m_rect,int m_icon ;void DrawMenuTitleCDC* m_pdc,CRect m_rect,CString m_title;这些函数都是功能函数,主要功能是用于绘制菜单,从函数名就可以一目了然。具体实现可见配套源码。(9)为对话框类CTestDlg添加成员变量:CMyMenu m_menu; 定义菜单变量CMyMenu* m_submenu; 定义子菜单指针(10)在CTestDlg的初始化函数OnInitDialog中添加菜单加载代码: TODO: 在此添加额外的初始化代码m_menu.LoadMenuIDR_MENU1; 加载菜单资源m_menu.ChangeMenuItem&m_menu; 调用成员函数改变菜单(11)为对话框类CTestDlg添加快捷菜单事件函数OnContextMenu、菜单更改事件函数OnDrawItem和菜单大小改变事件函数OnMeasureItem,具体代码如下:void CTestDlg::OnContextMenuCWnd* *pWnd*, CPoint point{ TODO: 在此处添加消息处理程序代码CMenu* m_tempmenu = m_menu.GetSubMenu0; 获取第一个菜单项指针显示快捷菜单m_tempmenu-TrackPopupMenuTPM_LEFTBUTTON|TPM_LEFTALIGN,point.x,point.y,this;}
void CTestDlg::OnDrawItemint nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct{ TODO: 在此添加消息处理程序代码和或调用默认值m_menu.DrawItemlpDrawItemStruct; 画菜单CDialog::OnDrawItemnIDCtl, lpDrawItemStruct;}
void CTestDlg::OnMeasureItemint nIDCtl, LPMEASUREITEMSTRUCT lpMeasureItemStruct{ TODO: 在此添加消息处理程序代码和或调用默认值m_menu.MeasureItemlpMeasureItemStruct; 计算菜单项CDialog::OnMeasureItemnIDCtl, lpMeasureItemStruct;}(12)在TestDlg.h中添加#include "MyMenu.h"。(13)保存工程并运行,运行结果如图5-9所示。5.1.5 向记事本程序发送菜单信息本例实现向Windows自带的记事本程序发送菜单消息。还可以发送一段文字给记事本,然后记事本把收到的文字显示出来。基本思路是先查找记事本程序窗口句柄,如果没有找到则运行记事本程序,然后通过句柄发送菜单消息。【例5.5】向记事本程序发送菜单信息(1)新建一个对话框工程,设置工程字符集为使用多字节字符集。(2)在对话框上放置一个按钮发送文本内容,单击按钮事件代码如下:void CTestDlg::OnBnClickedButton1{ TODO: 在此添加控件通知处理程序代码执行记事本程序WinExec"notepad.exe", SW_SHOW; 执行记事本程序Sleep1000; 暂停1秒,为了让记事本出现gpWnd = FindWindowNULL, _T"无标题 - 记事本"; 查找记事本HWND parent = gpWnd-m_hWnd; 保存指针 向记事本发送字符串信息EnumChildWindowsparent, EnumProcTxt, LPARAM_T"你好,记事本!";}(3)在对话框上放置一个按钮发送保存消息,事件代码如下:void CTestDlg::OnBnClickedButton2{ TODO: 在此添加控件通知处理程序代码if!gpWndreturn;
HWND parent = gpWnd-m_hWnd; 选择记事本的文件菜单下的保存菜单项::SetForegroundWindowparent;keybd_eventVK_MENU, 0, 0, 0;Sleep10; keybd_eventVK_MENU, 0, KEYEVENTF_KEYUP, 0;keybd_event''F'', 0, 0, 0;Sleep10;keybd_event''F'', 0, KEYEVENTF_KEYUP, 0;keybd_event''S'', 0, 0, 0;Sleep10;keybd_event''S'', 0, KEYEVENTF_KEYUP, 0;}(4)在对话框上放置一个按钮发送展开菜单,事件代码如下:void CTestDlg::OnBnClickedButton3{ TODO: 在此添加控件通知处理程序代码if!gpWndreturn;
HWND parent = gpWnd-m_hWnd;::SetForegroundWindowparent;设置窗口在前 展开菜单,注意只能展开文件菜单,无法后续选择菜单项::SendMessageparent, WM_SYSCOMMAND, SC_KEYMENU, WPARAM''F'';}(5)保存工程并运行,运行结果如图5-10所示。5.1.6 动态生成菜单在实际开发中,经常无须根据操作来增减菜单和菜单项。在Visual C开发环境下,动态生成菜单的方法有多种。例如:可以利用资源编辑器创建菜单资源,然后在程序运行中动态加入菜单,这种动态生成菜单的方法比较常见,运用比较多。用这种方法动态增加菜单时,首先无须在Resource.h中添加菜单ID;由于是动态生成的菜单选项,所以要实现它的功能就不能在ClassWizard中映射函数了,无须在头文件中手动添加消息函数原型,在代码文件中手动添加消息映射和添加消息响应函数。动态生成菜单的另一种方法,不能事先对每个菜单ID进行定义,比如从数据库中读出的每条记录内容动态添加为菜单项,菜单项的数量不是固定的,可以在动态添加菜单项时使菜单项的ID顺序递增;对菜单项的消息响应不能事先写出响应代码,而无须根据菜单ID动态响应函数。首先要了解菜单消息的处理。Windows消息分为3类:标准Windows消息、命令消息、控件通知消息。标准消息指除WM_COMMAND之外,所有以WM_前缀开始的消息,包括键盘消息和窗口消息等;命令消息,指来自菜单、快捷键、工具栏按钮等用户界面对象发出的WM_COMMAND消息。其中,在MFC中,通过菜单项的标识(ID)来区分不同的命令消息;在SDK中,通过消息的wParam参数识别。控件通知消息,是对控件操作而引起的消息,是控件和子窗口向其父窗口发出的WM_COMMAND通知消息。菜单命令则属于命令消息,一个菜单命令可以映射到框架类、视图类或文档类的某一个成员函数上,但不能同时映射到多个成员函数上。即使将一个菜单命令同时映射到多个不同的成员函数上,同时只有一个成员的映射是有效的。在MFC文档视图结构中映射有效的优先级高低顺序为视图类、文档类、框架类。 菜单消息一旦在其中一个类中响应,则不再在其他类中查找响应函数。具体来说,菜单命令消息路由过程是这样的:当单击一个菜单项的时候,最先接受菜单项消息的是CMainFrame框架类,CMainFrame框架类将会把菜单项消息交给它的子窗口View类,由View类首先进行处理;如果View类检测到没对该菜单项消息响应,则View类把菜单项消息交由文档类Doc类进行处理;如果Doc类检测到Doc类中也没对该菜单项消息响应,则Doc类又把该菜单项消息交还给View类,由View类再交还给CMainFrame类处理。如果CMainFrame类查看到CMainFrame类中也没对该消息响应,则最终交给App类进行处理。而且一个消息一旦在某个类中被响应过,则不再接着传递。然后要知道常用的几个菜单函数:?GetMenu:获得与框架窗口相链接的菜单。?InsertMenu:在指定位置插入新的菜单项,其他的选项向下移。?GetSubMenu:获得子菜单指针。?GetMenuItemCount:得到菜单下的菜单项的个数。?AppendMenu:添加一个新菜单。?GetMenuString:获得指定菜单项的标记。?DeleteMenu:删除菜单。【例5.6】动态生成菜单(1)新建一个对话框工程,设置工程字符集为使用多字节字符集。(2)在视图下添加一个菜单项添加菜单,事件代码如下:void CTestView::OnAddMenu{ TODO: 在此添加命令处理程序代码CMenu menu; 要定义成员变量,或者用menu.Detach,否则对象离开函数被析构后产生错误menu.CreatePopupMenu; 创建空菜单把菜单添加到现有菜单末尾GetParent-GetMenu-AppendMenuMF_POPUP,UINTmenu.m_hMenu,"动态添加的菜单"; menu.AppendMenuMF_STRING|MF_ENABLED,ID_CMD1,"CMD1"; 添加菜单menu.AppendMenuMF_STRING|MF_ENABLED,ID_CMD2,"CMD2"; 添加菜单menu.Detach; 释放菜单资源GetParent-DrawMenuBar; 画菜单栏
}(3)打开resourc.h,添加两个宏定义:#define ID_CMD1 200 定义菜单项ID#define ID_CMD2 201 定义菜单项ID(4)手工添加两个新增菜单项的事件,ON_COMMANDID_CMD1,OnCMD1手动添加菜单命令映射ON_COMMANDID_CMD2,OnCMD2手动添加菜单命令映射再添加菜单事件代码:void CTestView::OnCMD1{AfxMessageBox"你好";}void CTestView::OnCMD2{AfxMessageBox"世界";}(5)保存工程并运行,运行结果如图5-11所示。5.1.7 实现动态菜单的状态栏提示单文档程序打开文件后,会在文件菜单下显示曾经打开的文件名,如果把鼠标移到这些文件名上时,在状态栏上会显示提示,但不会显示文件名,本例实现在鼠标移到这些动态菜单上时,能在状态栏上显示相应的文件名。当用户的鼠标移动到一个菜单项时,Windows发送WM_MENUSELECT和菜单项的ID。所以要实现动态菜单提示,必须重载CFrameWnd::OnMenuSelect,并用提示串发送WM_SETMESSAGESTRIN消息。【例5.7】实现动态菜单的状态栏提示(1)新建一个单文档工程,设置工程字符集为使用多字节字符集。(2)运行工程,随便打开几个文件,然后再打开菜单文件,可以看到最近打开的几个文件的文件名都在菜单文件下了,但鼠标移到这些文件名上时,发现在状态栏上的提示都是一样的,即都是打开此文档。(3)现在要让它的提示变为打开文件 文件名。为类CMainFrame添加WM_MENUSELECT消息,消息处理函数代码如下:void CMainFrame::OnMenuSelectUINT nItemID, UINT nFlags, HMENU hSysMenu{判断ID所在范围if ID_FILE_MRU_FILE1{ 得到菜单项名称CMenu* pMenu = GetMenu; 得到顶层菜单指针ASSERTpMenu;判断指针是否为空pMenu=pMenu-GetSubMenu0; 得到文件菜单指针ASSERTpMenu;判断指针是否为空CString sFileName;得到菜单标题pMenu-GetMenuStringnItemID, sFileName, MF_BYCOMMAND;去掉空格int nSkip = sFileName.Find'' ''; 查找空格从右边截取sFileName = sFileName.RightsFileName.GetLength-nSkip;创建提示字符串CString sPrompt;sPrompt.Format_T"打开文件 %s", LPCTSTRsFileName;
在状态栏上设置提示字符串SendMessageWM_SETMESSAGESTRING, 0, LPARAMLPCTSTRsPrompt;}else{CFrameWnd::OnMenuSelectnItemID, nFlags, hSysMenu;}}(4)保存工程并运行,运行结果如图5-12所示。5.1.8 代码方式为对话框加载菜单对话框上显示菜单,可以直接用可视化的方法在对话框编辑器中进行设置。本例用代码的方式在程序中实现对话框菜单的显示。首先定义一个菜单资源,然后通过CMenu的成员函数LoadMenu来加载该菜单,再调用对话框类的成员函数SetMenu来为对话框设置菜单。函数CMenu::LoadMenu的定义如下:BOOL LoadMenu LPCTSTR lpszResourceName ;BOOL LoadMenu UINT nIDResource ;这两个函数从应用的可执行文件中装载菜单资源,并将其附加给CMenu 对象。如果菜单没有被指定给某一窗口,那么在离开之前,应用必须释放与菜单相关联的系统资源。应通过调用DestroyMenu成员函数来释放菜单。其中,参数lpszResourceName指向一个空终止的字符串,该字符串包含了要装载的菜单资源名称;nIDResource 指定将要装载的菜单资源的菜单ID号。如果菜单资源装载成功,则返回非零值,否则为0。函数CWnd::SetMenu定义如下:BOOL SetMenu CMenu* pMenu ;这个函数将当前菜单设为指定的菜单。它使窗口被重画以反映菜单的变化,SetMenu不会销毁以前的菜单。应用程序必须调用CMenu::DestroyMenu成员函数以完成这个任务。其中,参数pMenu 标识了新的菜单,如果这个参数为NULL,则当前菜单被清除。如果菜单发生了变化,则返回非零值;否则返回0。【例5.8】代码方式为对话框加载菜单(1)新建一个对话框工程,设置工程字符集为使用多字节字符集。(2)切换到资源编辑器,添加一个菜单IDR_MENU1。(3)为类CTestDlg添加CMenu m_menu。(4)在CTestDlg::OnInitDialog中的末尾处添加加载菜单代码如下:m_menu.LoadMenuIDR_MENU1;SetMenu&m_menu;(5)为退出菜单项添加事件响应函数:void CTestDlg::On32771{ TODO: 在此添加命令处理程序代码PostQuitMessage0; 程序退出}(6)保存工程并运行,运行结果如图5-13所示。5.1.9 自定义类CMenuEx的简单使用通过一个自定义菜单类CMenuEx来实现菜单。CMenuEx的重要成员函数解释如下:(1)CMenuEx::LoadMenuBOOL LoadMenuUINT uMenu;加载菜单项。其中,参数uMenu是菜单资源的ID。(2)CMenuEx::LoadToolBarvoid LoadToolBarUINT uToolBar, UINT uFace;为菜单关联工具栏,这样菜单项就可以有真彩图标了。其中,参数uToolBar是工具栏的资源;参数uFace 是一个替代位图的资源ID。【例5.9】自定义类CMenuEx的简单使用(1)新建一个对话框工程,设置工程字符集为使用多字节字符集。(2)把MenuEx.cpp和MenuEx.h加入工程。(3)切换到资源视图,添加一个菜单IDR_MENU1。(4)为类CTestDlg添加CMenuEx m_menu。(5)在CTestDlg::OnInitDialog中的末尾处添加加载菜单代码:m_menu.LoadMenuIDR_MENU1; 加载菜单资源SetMenu&m_menu; 关联菜单m_menu.SetBackColorRGB128, 128, 255; 设置菜单项的背景色(6)保存工程并运行,运行结果如图5-14所示。5.1.10 通过类CMenuEx给菜单增加背景色和左边位图通过CMenuEx来实现一种漂亮的菜单。本例也是通过类CMenuEx来实现主要功能,但这个类和上例同名的类是有所区别的,主要是接口函数的不同。本例的CMenuEx的重要接口函数解释如下:(1)CmenuEx::InitMenuvoid CmenuEx::InitMenuCmenu *pMenu, UINT uToolBar, CtoolBar *pToolBar;这个函数最重要,如果要改变主窗口的菜单则应在主窗口的OnInitMenu中调用该函数,当然主窗口必须要有工具栏,才会产生菜单项位图。最后还必须重载主窗口的OnMeasureItem函数和OnDrawItem函数,并在两个函数中分别调用菜单类的另外两个函数DrawItem和MeasureItem;其中,参数pMenu指向主窗口的OnInitMenu函数传进来的菜单指针;参数uToolBar表示主窗口工具栏的ID,如IDR_MAINFRAME;参数pToolBar指向主窗口的工具栏指针,如m_wndToolBar。(2)CmenuEx::SetImageLeftvoid SetImageLeftUINT idBmpLeft;这个函数也很重要,主要实现菜单的左边纵向位图(如开始菜单),可以在适当的地方调用该函数,要注意的是,选择位图时要记得高宽的比例。其中,参数idBmpLeft位图的ID。【例5.10】【设计步骤】(1)新建一个单文档工程,设置工程字符集为使用多字节字符集。(2)把MenuEx.cpp和MenuEx.h加入工程中。(3)为类CmainFrame添加变量CmenuEx m_menu;。(4)把res目录下的left.bmp加入工程中。(5)在CmainFrame::OnCreate的末尾处加入以下代码:m_menu.SetImageLeftIDB_BITMAP1; 为菜单加载位图m_menu.SetBackColorRGB0,170,0; 设置菜单项背景色(6)为CmainFrame添加WM_INITMENU消息,响应函数代码如下:void CmainFrame::OnInitMenuCmenu* pMenu{CframeWnd::OnInitMenupMenu;
TODO: 在此处添加消息处理程序代码m_menu.InitMenupMenu,IDR_MAINFRAME,&m_wndToolBar; 初始化菜单}(7)为CmainFrame添加WM_DRAWITEM消息,响应函数代码如下:void CmainFrame::OnDrawItemint nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct{ TODO: 在此添加消息处理程序代码和或调用默认值if!nIDCtlm_menu.DrawItemlpDrawItemStruct; 绘制菜单CframeWnd::OnDrawItemnIDCtl, lpDrawItemStruct;}(8)为CmainFrame添加WM_MEASUREITEM消息,响应函数代码如下:void CmainFrame::OnMeasureItemint nIDCtl, LPMEASUREITEMSTRUCT lpMeasureItemStruct{ TODO: 在此添加消息处理程序代码和或调用默认值if!nIDCtlm_menu.MeasureItemlpMeasureItemStruct; 绘制菜单CframeWnd::OnMeasureItemnIDCtl, lpMeasureItemStruct;}(9)保存工程并运行,运行结果如图5-15所示。图5-155.1.11 实现中英文菜单的动态切换中国软件业正在走向世界,而老外不懂中文,所以在软件界面加入英文菜单非常重要。本例实现中英文菜单的动态切换。基本思路是定义两套菜单资源。【例5.11】实现中英文菜单的动态切换(1)新建一个单文档工程,设置工程字符集为使用多字节字符集。(2)在视图下添加一个菜单项英文,ID为ID_ENGLSIH。(3)用文本形式打开资源文件,找到IDR_MAINFRAME的菜单文本内容如下: Menu
IDR_MAINFRAME MENUBEGINPOPUP "文件&F"BEGINMENUITEM "新建&N\tCtrl N", ID_FILE_NEWMENUITEM "打开&O\tCtrl O",ID_FILE_OPENMENUITEM "保存&S\tCtrl S", ID_FILE_SAVEMENUITEM "另存为&A", ID_FILE_SAVE_ASMENUITEM SEPARATORMENUITEM "打印&P\tCtrl P",ID_FILE_PRINTMENUITEM "打印预览&V",ID_FILE_PRINT_PREVIEWMENUITEM "打印设置&R", ID_FILE_PRINT_SETUPMENUITEM SEPARATORMENUITEM "最近的文件",ID_FILE_MRU_FILE1, GRAYEDMENUITEM SEPARATORMENUITEM "退出&X", ID_APP_EXITENDPOPUP "编辑&E"BEGINMENUITEM "撤消&U\tCtrl Z", ID_EDIT_UNDOMENUITEM SEPARATORMENUITEM "剪切&T\tCtrl X", ID_EDIT_CUTMENUITEM "复制&C\tCtrl C", ID_EDIT_COPYMENUITEM "粘贴&P\tCtrl V", ID_EDIT_PASTEENDPOPUP 视图&V"BEGINMENUITEM "工具栏&T", ID_VIEW_TOOLBARMENUITEM "状态栏&S", ID_VIEW_STATUS_BARMENUITEM "英文&E", ID_ENGLISHENDPOPUP "帮助&H"BEGINMENUITEM "关于 Test&A", ID_APP_ABOUTENDEND在此后加入英文菜单资源,先复制上述文本,然后把其中的中文改成英文,修改后如下:IDR_MAINFRAME_ENGLISH MENU PRELOAD DISCARDABLEBEGINPOPUP "File&F"BEGINMENUITEM "New&N\tCtrl N",ID_FILE_NEWMENUITEM "Open&O\tCtrl O", ID_FILE_OPENMENUITEM "Save&S\tCtrl S", ID_FILE_SAVEMENUITEM "Save as&A",ID_FILE_SAVE_ASMENUITEM SEPARATORMENUITEM "Print&P\tCtrl P",ID_FILE_PRINTMENUITEM "Print Preview&V", ID_FILE_PRINT_PREVIEWMENUITEM "Print Setting&R",ID_FILE_PRINT_SETUPMENUITEM SEPARATORMENUITEM "Recent Files",ID_FILE_MRU_FILE1, GRAYEDMENUITEM SEPARATORMENUITEM "Exit&X",ID_APP_EXITENDPOPUP "Edit&E"BEGINMENUITEM "Undo&U\tCtrl Z",ID_EDIT_UNDOMENUITEM SEPARATORMENUITEM "Cut&T\tCtrl X",ID_EDIT_CUTMENUITEM "Copy&C\tCtrl C",ID_EDIT_COPYMENUITEM "Paste&P\tCtrl V", ID_EDIT_PASTEENDPOPUP "View&V"BEGINMENUITEM "ToolBar&T", ID_VIEW_TOOLBARMENUITEM "StatusBar&S",ID_VIEW_STATUS_BARMENUITEM "Chinese", ID_ENGLISHENDPOPUP "Help&H"BEGINMENUITEM "About Test&A",ID_APP_ABOUTENDEND修改完成后保存资源。要注意的是,英文菜单的资源ID是IDR_MAINFRAME_ENGLISH,这个非常关键,英文菜单ID和中文菜单ID必须不同。(4)在CmainFrame中加入变量Cmenu m_englistmenu 和m_chinesemenu,它们用来保存中英文菜单资源,再加入变量enum Enum{e,c}m_current,该变量用于保存当前菜单。(5)由于默认为中文菜单,所以在 CmainFrame::CmainFrame中设置m_current=c;表示当前为中文菜单,在CmainFrame::OnCreateLPCREATESTRUCT lpCreateStruct中装入英文菜单资源,代码如下:m_englistmenu.LoadMenu"IDR_MAINFRAME_ENGLISH";HMENU m_hMenu=::GetMenuthis-m_hWnd; 保存中文菜单m_chinesemenu.Attachm_hMenu; 保存菜单句柄(6)为英文菜单项加入事件代码:void CmainFrame::OnEnglish{ TODO: 在此添加命令处理程序代码ifm_current==e{SetMenu&m_chinesemenu; 设置中文菜单m_current=c; 记录当前菜单是中文}else{SetMenu&m_englistmenu; 设置英文菜单m_current=e; 记录当前菜单是英文}}(7)保存工程并运行,运行结果如图5-16所示。5.1.12 修改并增加系统菜单项有时候无须在系统菜单中加入自己的菜单项。基本思路是首先获取系统菜单的指针:Cmenu* pSysMenu = GetSystemMenuFALSE;然后调用Cmenu:: AppendMenu来为系统菜单添加菜单项,Cmenu::AppendMenu的定义如下:BOOL AppendMenu UINT nFlags, UINT nIDNewItem = 0, LPCTSTR lpszNewItem = NULL ;BOOL AppendMenu UINT nFlags, UINT nIDNewItem, const Cbitmap* pBmp ;在菜单的末尾添加新项,可以通过设置nFlags的值来指定菜单项的状态,若nIDNewItem指定一个弹出菜单,那么它也将成为被添加菜单的一部分。假如菜单被销毁,那么添加的菜单也将被销毁。添加的菜单应当从Cmenu 对象中分离出来,以避免产生冲突。要注意MF_STRING和MF_OWNERDRAW对于AppendMenu函数的位图版本无效,无论何时,当停留在窗口中的菜单发生变化时(不论窗口是否显示),应用都将调用CWnd::DrawMenuBar函数。其中,参数nFlags 指定了增加到菜单中的新菜单项状态的有关信息,它包括说明中列出的一个或多个值。下面列出的是nFlags可以设置的值:?MF_CHECKED:该值的行为如同使用MF_UNCHECKED来作为一个标记,用于替换项前的检测标记。若应用支持检测标记位图(请参阅SetMenuItemBitmaps成员函数),那么将显示检测标记打开位图。 ?MF_UNCHECKED:该值的行为如同使用MF_CHECKED来作为一个标记,用于删除项前的检测标记。若应用支持检测标记位图(请参阅SetMenuItemBitmaps成员函数),那么将显示检测标记关闭位图。 ?MF_DISABLED:使菜单项无效以便它不能被选择,但菜单项不变灰。 ?MF_ENABLED:使菜单项有效以便它能够被选择,并从灰色状态中恢复原样。 ?MF_GRAYED:使菜单项无效以便它不能被选择,同时使菜单项变灰。 ?MF_MENUBARBREAK:在静态菜单里的新行中或弹出菜单的新列中放置菜单项。新的弹出菜单列与老的菜单列将由垂直分割线分开。 ?MF_MENUBREAK:在静态菜单里的新行中或弹出菜单的新列中放置菜单项。列与列之间没有分割线。 ?MF_OWNERDRAW:指定菜单项为一个拥有者描绘的项。当菜单首次显示时,拥有该菜单的窗口将接收WM_MEASUREITEM消息,以获取菜单项的高度与宽度。WM_DRAWITEM消息将使属主窗口必须更新菜单项的可视界面。该选择项对于顶层菜单项无效。 ?MF_POPUP:指定菜单项有与之相关联的弹出菜单。参数ID指定了与项相关联的弹出菜单的句柄。它用于增加顶层弹出菜单项或用于增加弹出菜单项的下一级弹出菜单。 ?MF_SEPARATOR:绘制一条水平的分割线。它仅仅能用于弹出菜单项。该线不能变灰、无效或高亮度显示。其他的参数将被忽略。 ?MF_STRING:指定菜单项为一个字符串。 下面列出的各组标志互相排斥,不能一起使用:?MF_DISABLED、MF_ENABLED和 MF_GRAYED。?MF_STRING、MF_OWNERDRAW、MF_SEPARATOR和位图版本。?MF_MENUBARBREAK和MF_MENUBREAK。?MF_CHECKED 和MF_UNCHECKED。参数nIDNewItem 指定了新菜单项的命令ID号,或如果nFlags被设置为MF_POPUP,该参数指定弹出菜单的菜单句柄HMENU;如果nFlags被设置为MF_SEPARA-TOR,那么参数NewItem将被忽略。参数lpszNewItem指定了新菜单项的内容;参数pBmp 指向将用作菜单项的Cbitmap对象。如果函数成功,则返回非零值,否则为0。【例5.12】修改并增加系统菜单项(1)新建一个单文档工程,设置工程字符集为使用多字节字符集。(2)切换到资源视图,添加一个字符串资源IDS_HELLO,内容是你好。(3)在CtestDlg::OnInitDialog的中间位置添加增加系统菜单的代码:Cstring strHelloMenu;strHelloMenu.LoadStringIDS_HELLO;pSysMenu-AppendMenuMF_STRING,IDM_HELLO, strHelloMenu;再定位到CtestDlg::OnSysCommand,添加代码如下:void CtestDlg::OnSysCommandUINT nID, LPARAM lParam{if nID & 0xFFF0 == IDM_ABOUTBOX{CaboutDlg dlgAbout;dlgAbout.DoModal;}下面是我们添加的代码else if nID & 0xFFF0==SC_CLOSE{AfxMessageBox"请通过取消按钮关闭";OnClose;这里注释后,关闭将不起作用,只能通过取消按钮了}else if nID & 0xFFF0==IDM_HELLO{AfxMessageBox"你好,世界";}我们代码结束else{Cdialog::OnSysCommandnID, lParam;}}其中,IDM_HELLO是一个宏,定义如下:#define IDM_HELLO 0x0100(4)这样系统菜单里的关闭和右上角的关闭按钮将不起作用了。只能通过取消按钮来退出程序了。(5)保存工程并运行,运行结果如图5-17所示。5.2 工具栏的设计与开发工具栏也是Windows应用程序常见的界面元素,它通常位于菜单下面。在工具栏上有一个一个带图标的小按钮,单击这些小按钮,会执行相应的动作,通常会把某菜单项相同的ID设为工具栏按钮的ID,这样单击工具栏按钮的时候执行的操作就是和菜单项一样的操作。工具栏也是一个窗口,它可以停靠在父类窗口的某一边,也可以处于悬浮状态。工具栏既可以出现在文档工程中,也可以出现在对话框工程中。在Visual C 2013中,工具栏由类CtoolBar实现。CtoolBar常用的成员函数如下表。成员函数含义CtoolBar创建一个CtoolBar对象Create创建Windows工具栏并将它与该CtoolBar连接CreateEx为嵌入的CtoolBarCtrl对象创建一个具有附加风格的CtoolBar对象SetSizes设置按钮及其位图的尺寸SetHeight设置工具条的高度LoadToolBar装入一个用资源编辑器创建的工具栏资源LoadBitmap装入包含位图-按钮图像的位图SetBitmap设置一个位图中的图像SetButtons设置按钮风格和按钮图像在位图中的索引CommandToIndex返回具有给定的命令ID的按钮的索引GetItemID返回具有给定索引值的按钮或分隔线的命令IDGetItemRect获取具有给定索引值的项的显示矩形GetButtonStyle获取一个按钮的风格SetButtonStyle设置一个按钮的风格GetButtonInfo获取一个按钮的ID、风格和图像号SetButtonInfo设置一个按钮的ID、风格和图像号GetButtonText获取要显示在一个按钮上的文本SetButtonText设置要显示在一个按钮上的文本GetToolBarCtrl允许直接访问基本的通用控件下面通过几个实例对工具栏的常用属性、方法和事件进行介绍。5.2.1 显示或隐藏工具栏在默认情况下,单文档程序是有工具栏,本例通过菜单来控制显示或隐藏工具栏。方法很简单,在主框架类中发送消息WM_COMMAND即可。【例5.13】显示或隐藏工具栏(1)新建一个单文档工程,设置工程字符集为使用多字节字符集。(2)在视图菜单下添加一个菜单项显示或隐藏工具栏,然后为其添加事件处理函数如下:void CMainFrame::OnShowhideToolbar{ TODO: 在此添加命令处理程序代码发送WM_COMMAND命令消息SendMessageWM_COMMAND,ID_VIEW_TOOLBAR,NULL;}其中,ID_VIEW_TOOLBAR是系统预定义的用来表示工具栏的ID。(3)保存工程并运行,运行结果如图5-18所示。5.2.2 设置工具栏标题工具栏其实也是一个窗口,可以设置标题,只是平时停靠的时候没有显示。当我们拖动工具栏使其浮动时,就可以看到工具栏的标题了。同普通窗口设置文本类似,调用工具栏的SetWindowText成员函数即可。【例5.14】设置工具栏标题(1)新建一个单文档工程,设置工程字符集为使用多字节字符集。(2)在视图菜单下添加一个菜单项设置工具栏标题,然后为其添加事件处理函数:void CMainFrame::On32771{ TODO: 在此添加命令处理程序代码m_wndToolBar.SetWindowText"真心真意过一生"; 设置工具栏标题AfxMessageBox"工具栏标题设置完毕,拖出工具栏可以看到效果。";}(3)保存工程,运行结果如图5-19所示。5.2.3 显示或隐藏工具栏上所有按钮默认情况下,工具栏上的各个方块小按钮是显示着的,本例实现工具栏上的各个小按钮全部隐藏。同普通窗口设置文本类似,调用工具栏的ShowWindow成员函数即可。【例5.15】显示或隐藏工具栏上所有按钮(1)新建一个单文档工程,设置工程字符集为使用多字节字符集。(2)在视图菜单下添加菜单项隐藏工具栏上所有按钮和显示工具栏上所有按钮,然后为其添加事件处理函数如下:void CMainFrame::OnHide{ TODO: 在此添加命令处理程序代码m_wndToolBar.ShowWindowSW_HIDE; 隐藏工具栏上所有按钮}
void CMainFrame::OnShow{ TODO: 在此添加命令处理程序代码m_wndToolBar.ShowWindowSW_SHOW; 显示工具栏上所有按钮}(3)保存工程并运行,运行结果如图5-20所示。图5-205.2.4 在视图类中判断工具栏是否处于浮动状态获取了工具栏的指针,可以在非CMainFrame类中对工具栏进行操作。本例演示了如何在非框架类中获得工具栏的指针。同普通窗口设置文本类似,调用工具栏的成员函数即可。【例5.16】在视图类中判断工具栏是否处于浮动状态(1)新建一个单文档工程,设置工程字符集为使用多字节字符集。(2)在菜单视图下添加一个菜单项工具栏是否浮动,菜单ID为ID_TOOLBAR_FLOATING,然后为其添加基于视类的事件函数,代码如下:void CTestView::OnToolbarFloating{ TODO: 在此添加命令处理程序代码获取主框架工具栏指针CToolBar * pToolBar= CToolBar *AfxGetMainWnd-GetDescendantWindowAFX_IDW_TOOLBAR;ifpToolBar 指针如果获取到{if!pToolBar-IsFloating 工具栏是否处于浮动状态AfxMessageBox"在视图类中判断工具栏未处于浮动状态";}elseAfxMessageBox"在视图类中判断工具栏处于浮动状态";
}注意,当菜单处于浮动状态时,获取的工具栏指针为NULL。(3)保存工程并运行,运行结果如图5-21所示。图5-215.2.5 资源法创建工具栏通常,单文档工程创建时,工具栏都是默认建立好的,而且外观都是默认样式,如果要自定义工具栏,则必须要学会自己新建工具栏。本例不让系统自动创建工具栏,而是自己通过添加工具栏资源,然后手工新建一个工具栏。首先要在资源编辑器中创建工具栏资源,然后在CMainFrame::OnCreate中通过加载工具栏资源来创建工具栏。
【例5.17】资源法创建工具栏(1)新建一个MFC标准的单文档工程,并且在一步步单击向导时,要注意在用户界面功能那一页上去掉使用传统的停靠工具栏前面的勾,其他都保持默认。如图5-22所示。单击完成按钮将新建一个没有工具栏的单文档工程,此时运行工程后,会发现界面上没有工具栏。然后设置工程字符集为使用多字节字符集。(2)切换到资源视图,通过添加资源来新建一个工具栏,然后单击保存按钮,此时会在工程的res目录下新建一个图片文件toolbar1.bmp,我们可以准备一副16*n*16(就是高是16像素,宽是16的倍数,每个按钮是16*16大小)的位图,如图5-23所示。 图5-22图5-23把这个图片文件复制到工程的res目录下,此时IDE会提示toolbar1.bmp已经被修改,是否要重新加载, 单击是,则工具栏资源会变成我们复制过去的位图模样了。(3)切换到类视图,双击类CMainFrame打开文件MainFrm.h,然后为类CMainFrame添加一个成员变量:CToolBar m_wndMyToolBar; 定义工具栏变量再定位到CMainFrame::OnCreate,在函数末尾处添加代码如下:自己手动创建工具栏if !m_wndMyToolBar.CreateExthis, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP | CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC ||!m_wndMyToolBar.LoadToolBarIDR_TOOLBAR1{TRACE0"未能创建工具栏\n";return -1; 未能创建}(4)如果此时运行,会出现建立空文档失败的提示。我们还要在资源文件里添加每个按钮的定义。切换到解决方案管理器,展开资源文件,然后对Test.rc右击,选择右键菜单项查看代码,然后在文件的 Icon上面添加以下几行代码:IDR_TOOLBAR1 TOOLBAR16, 16BEGINBUTTON ID_FILE_NEWBUTTON ID_FILE_OPENBUTTON ID_FILE_SAVEBUTTON ID_APP_ABOUTEND(5)保存工程并运行,运行结果如图5-24所示。图5-245.2.6 非资源法创建工具栏通常,单文档工程创建时,工具栏都是默认建立好的,而且外观都是默认样式,如果要自定义工具栏,则必须要学会自己新建工具栏。本例之所以称为非资源法,主要是同上例区别,本例不是直接添加工具栏资源的,而是先添加一个位图,然后通过加载位图来创建工具栏的。首先要在资源编辑器中添加一副位图,然后在CMainFrame::OnCreate中通过加载这个位图来创建工具栏。【例5.18】非资源法创建工具栏(1)新建一个不带工具栏的单文档工程,步骤可参考上例,然后设置工程字符集为使用多字节字符集。(2)切换到资源视图,把res目录下的Toolbar.bmp文件导入到资源中。(3)为类CMainFrame添加成员变量CToolBar m_wndMyToolBar;,然后定位到CMainFrame::OnCreate,在末尾处添加代码如下:加载位图并创建工具栏if!m_wndMyToolBar.Createthis,WS_VISIBLE|WS_CHILD|CBRS_SIZE_DYNAMIC|CBRS_LEFT|CBRS_TOOLTIPS|CBRS_FLYBY,10001||!m_wndMyToolBar.LoadBitmapIDB_BITMAP1||!m_wndMyToolBar.SetButtonsbuttons,sizeofbuttonssizeofUINT{TRACE0"创建工具栏失败";return -1;
}(4)在MainFrm.cpp中添加全局变量,这个是工具栏各个按钮的ID定义。static UINT BASED_CODE buttons[]={ID_FILE_NEW,ID_FILE_OPEN,ID_FILE_SAVE,ID_APP_ABOUT};(5)保存工程并运行,运行结果如图5-25所示。5.2.7 使工具栏具有任意停靠和漂浮功能上面两例工具无法浮动和自由停靠,本例在资源法创建工具栏的基础上实现工具的任意停靠和漂浮。主要是几个停靠函数的使用。首先要调用工具栏自己的停靠函数,使得工具栏具有停靠功能,然后要让框架具有停靠功能,最后再通过DockControlBar让工具栏和框架联系起来。【例5.19】使工具栏具有任意停靠和漂浮功能(1)参考实例资源法创建工具栏的办法创建一个工具栏。(2)在CMainFrame::OnCreate末尾处添加工具栏任意停靠和浮动的代码:m_wndMyToolBar.EnableDockingCBRS_ALIGN_ANY; 让工具栏能停靠任何一边EnableDockingCBRS_ALIGN_ANY; 支持任何一边都可以停靠DockControlBar&m_wndMyToolBar; 支持工具栏停靠注意这段代码要放在创建工具栏的代码之后。(3)保存工程并运行,运行结果如图5-26所示。5.2.8 通过菜单出现工具栏提示当鼠标停留在工具栏按钮上时,工具栏按钮就出现提示信息。让工具栏按钮出现提示能使得软件更显专业性。让工具栏按钮的ID和菜单项ID相同,然后通过给菜单项增加提示,这样工具栏按钮也会有提示了,当然创建工具栏的时候不要忘了加CBRS_TOOLTIPS属性。【例5.20】通过菜单出现工具栏提示(1)按照前面实例非资源法创建工具栏来创建一个工具栏。(2)切换到资源视图,然后在视图菜单下添加两个菜单项abc和停止,注意要为两个菜单项增加Prompt属性,前者为ABC\nabc,后者为停止\nStop,其中,\n前面的部分是显示在状态栏最左边的内容,\n后面的部分是工具栏提示的内容。然后分别为两个菜单项添加事件处理函数,代码如下:void CMainFrame::OnAbc{ TODO: 在此添加命令处理程序代码AfxMessageBox"abc";}
void CMainFrame::OnStop{ TODO: 在此添加命令处理程序代码AfxMessageBox"停止";}(3)在MainFrm.cpp中找到全局变量buttons的定义,然后把最后两个元素的值改为ID_ABC和ID_STOP,即:static UINT BASED_CODE buttons[]={ID_APP_ABOUT,ID_FILE_OPEN,ID_ABC,ID_STOP};(4)保存工程并运行,可以发现鼠标停留在工具栏按钮上时有提示了,运行结果如图5-27所示。5.2.9 通过字符串表出现工具栏提示当鼠标停留在工具栏按钮上时,工具栏按钮就出现提示信息。让工具栏按钮出现提示能使得软件更显专业性。在实例非资源法创建工具栏的基础上,添加字符串ID,然后让工具栏按钮关联到该ID。当然创建工具栏的时候不要忘了加CBRS_TOOLTIPS属性。【例5.21】通过字符串表出现工具栏提示(1)新建一个不带工具栏的单文档工程,设置工程字符集为使用多字节字符集。(2)切换到资源视图,把res目录下的Toolbar.bmp文件导入到资源中。(3)为类CMainFrame添加成员变量CToolBar m_wndMyToolBar;,然后定位到CMainFrame::OnCreate,在末尾处添加代码如下:创建工具栏if!m_wndMyToolBar.Createthis,WS_VISIBLE|WS_CHILD|CBRS_SIZE_DYNAMIC|CBRS_LEFT|CBRS_TOOLTIPS|CBRS_FLYBY,10001||!m_wndMyToolBar.LoadBitmapIDB_BITMAP1||!m_wndMyToolBar.SetButtonsbuttons,sizeofbuttonssizeofUINT {TRACE0"创建工具栏失败";return -1;}(4)切换到资源视图,展开String Table,然后添加两个字符串资源,ID分别为ID_ABC和ID_STOP,其标题(Caption)分别为ABC\nabc和停止\nstop,其中,\n前面的部分是显示在状态栏最左边的内容,\n后面的部分是工具栏提示的内容。(5)打开MainFrm.cpp文件,添加一个全局变量:static UINT BASED_CODE buttons[]={ID_APP_ABOUT,ID_FILE_OPEN,ID_ABC,ID_STOP};值得注意的是,ID_ABC和ID_STOP都是上一步添加的字符串ID。(6)保存工程并运行,运行结果如图5-28所示。5.2.10 工具栏上放置组合框工具栏上也可以放置控件,比如Visual C 2005的工具栏上就有下拉组合框。本例实现在工具栏上放置组合框。基本思路是在框架类中定义一个CComboBox对象,然后在框架类的OnCreate创建组合框。【例5.22】工具栏上放置组合框(1)新建一个单文档工程,设置工程字符集为使用多字节字符集。(2)为类CMainFrame添加一个成员变量CComboBox m_cb;,这是一个组合框。(3)打开CMainFrame::OnCreate函数,定位到工具栏创建代码之后,然后添加代码如下:创建组合框CRect rt;m_wndToolBar.GetItemRect1,&rt; 获取工具栏第一个按钮的尺寸rt.right = rt.left rt.Width*2; 重新定义右边创建组合框if!m_cb.CreateWS_CHILD|WS_VISIBLE|CBS_DROPDOWNLIST|WS_VSCROLL,rt,&m_wndToolBar,10001{TRACE0"未能创建组合框\n";return -1; 未能创建}
为组合框增加内容m_cb.AddString"1";m_cb.AddString"2";m_cb.AddString"3";m_cb.SetCurSel0;
组合框的宽度为两个工具栏按钮的宽度CRect rc;m_cb.GetDroppedControlRect&rc; 得到组合框下拉控件的大小m_cb.GetParent-ScreenToClient&rc; 屏幕坐标转为客户坐标rc.bottom= 150; 重新定义下边m_cb.MoveWindow&rc; 移动窗口位置(4)保存并运行工程,运行结果如图5-29所示。5.2.11 让工具栏不出现提示默认情况下,新建的单文档工程中,当鼠标停留在工具栏某个按钮上时,在旁边会出现小的提示框,这个小提示框称为工具栏提示,本例让工具栏不出现提示。一种方法是在创建工具栏的时候,把CBRS_TOOLTIPS风格去掉;另外一种是动态的方法,通过工具栏的成员函数SetBarStyle来实现。【例5.23】让工具栏不出现提示(1)新建一个单文档工程,设置工程字符集为使用多字节字符集。(2)打开CMainFrame::OnCreate函数,然后在工具创建的地方,把CBRS_TOOLTIPS风格去掉。(3)此时运行工程,把鼠标放在某工具栏按钮上,可以看到没有提示了。以上是一种方法,先把CBRS_TOOLTIPS放回CreateEx中。下面采用设置法。(1)先在菜单视图下添加一个菜单项,菜单名是去掉工具栏提示。为该菜单添加事件处理函数如下:void CMainFrame::On32771{ TODO: 在此添加命令处理程序代码DWORD dwToolBarStyle = m_wndToolBar.GetBarStyle;获得工具栏风格dwToolBarStyle &= ~CBRS_TOOLTIPS;在风格中把CBRS_TOOLTIPS位去掉m_wndToolBar.SetBarStyledwToolBarStyle;再重新设置工具栏风格}(2)保存工程并运行,运行结果如图5-30所示。5.2.12 让工具栏按钮出现提示默认情况下,新建的单文档工程中,当鼠标停留在工具栏某个按钮上时,在旁边会出现小的提示框,这个小提示框称为工具栏提示,本例先让工具栏按钮不出现提示,然后通过菜单设置使得提示出现。基本思路是创建工具栏的时候,把CBRS_TOOLTIPS风格去掉,这样工具栏按钮就没有提示了,然后用一个菜单设置工具栏按钮的提示为有。主要通过工具栏的成员函数SetBarStyle来实现,要注意添加风格的方法。【例5.24】让工具栏按钮出现提示(1)新建一个单文档工程,设置工程字符集为使用多字节字符集。(2)默认情况下,工具栏按钮是有提示的,因为工具栏创建的时候默认有CBRS_TOOLTIPS风格属性。现在打开CMainFrame::OnCreate 函数,在m_wndToolBar.CreateEx里把CBRS_TOOLTIPS风格去掉。(3)此时运行工程,工具栏就没有提示框了,然后在视图下增加一个菜单使工具栏出现提示。为该菜单添加事件处理函数:void CMainFrame::On32771{ TODO: 在此添加命令处理程序代码DWORD dwToolBarStyle = m_wndToolBar.GetBarStyle;获得工具栏风格在风格中把CBRS_TOOLTIPS位加上,通过或的方式dwToolBarStyle |= CBRS_TOOLTIPS;m_wndToolBar.SetBarStyledwToolBarStyle;再重新设置工具栏风格}(4)保存工程并运行,先单击使工具栏出现提示,然后把鼠标放到工具栏按钮上,就能看到提示框了,运行结果如图5-31所示。5.2.13 使工具栏按钮出现下拉箭头有时候单个工具栏按钮不能显示同类多个信息,比如帮助下面分为离线帮助和在线帮助,此时如果单击工具栏出现下拉菜单就能解决这个问题。基本思路是响应工具栏的TBN_DROPDOWN,用户单击工具栏按钮的时候发生该事件,代码如下:ON_NOTIFYTBN_DROPDOWN, AFX_IDW_TOOLBAR, OnDropDown然后再添加一个菜单,并在OnDropDown中加载显示该菜单。这样单击下拉箭头的时候,就能出现菜单了。【例5.25】使工具栏按钮出现下拉箭头(1)新建一个单文档工程,设置工程字符集为使用多字节字符集。(2)打开CMainFrame::OnCreate函数,在m_wndToolBar.CreateEx后添加代码如下:设置整个工具栏的下拉风格属性m_wndToolBar.GetToolBarCtrl.SetExtendedStyleTBSTYLE_EX_DRAWDDARROWS;得到该工具栏按钮(关于按钮)的索引int index = m_wndToolBar.CommandToIndexID_APP_ABOUT;得到该工具栏按钮的原有风格属性DWORD dwToolBarStyle = m_wndToolBar.GetButtonStyleindex;dwToolBarStyle|= TBSTYLE_DROPDOWN;为该工具栏按钮增加下拉风格属性为该工具栏按钮设置新的风格属性m_wndToolBar.SetButtonStyleindex,dwToolBarStyle;(3)此时运行工程可以发现工具栏的关于按钮旁边有一个箭头了,但鼠标单击箭头并没有反映。(4)为下拉箭头添加消息处理函数。打开MainFrm.h文件,添加函数声明:afx_msg void OnDropDownNMHDR* pNotifyStruct, LRESULT* pResult;(5)再打开MainFrm.cpp,定位到BEGIN_MESSAGE_MAP,添加消息映射:ON_NOTIFYTBN_DROPDOWN, AFX_IDW_TOOLBAR, OnDropDown(6)添加一个菜单资源IDR_MENU1。(7)再添加下拉事件的消息处理函数:void CMainFrame::OnDropDownNMHDR* pNotifyStruct, LRESULT* pResult{NMTOOLBAR* pToolBar = NMTOOLBAR*pNotifyStruct;
ifID_APP_ABOUT != pToolBar-iItemreturn;加载自定义菜单CMenu Menu;Menu.LoadMenuIDR_MENU1;CMenu* pMenu = Menu.GetSubMenu0;CRect Rect;m_wndToolBar.SendMessageTB_GETRECT,pToolBar-iItem, LPARAM&Rect;m_wndToolBar.ClientToScreen&Rect;pMenu-TrackPopupMenu TPM_LEFTALIGN | TPM_LEFTBUTTON |TPM_VERTICAL,Rect.left, Rect.bottom, this, &Rect;}(8)为新增的菜单添加事件处理函数:void CMainFrame::On32772{ TODO: 在此添加命令处理程序代码AfxMessageBox"显示离线帮助";}
void CMainFrame::On32771{ TODO: 在此添加命令处理程序代码AfxMessageBox"显示在线帮助";}(9)保存工程并运行,运行结果如图5-32所示。5.2.14 使工具栏按钮失效和生效动态设置工具栏按钮失效或生效。基本思路是通过菜单的UPDATE_COMMAND_UI,而菜单是和工具栏按钮的ID一致的,这样菜单的状态变化也会体现到工具栏上。【例5.26】使工具栏按钮失效和生效(1)新建一个单文档工程,设置工程字符集为使用多字节字符集。(2)在MainFrm.cpp中添加一个全局变量gEnableFlag,用来控制工具栏按钮关于的状态。int gEnableFlag = 0;1生效,0失效(3)在视图下添加2个菜单:使工具栏按钮关于失效和使工具栏按钮关于生效。为这2个菜单添加事件处理函数:void CMainFrame::On32771{ TODO: 在此添加命令处理程序代码gEnableFlag = 0;}
void CMainFrame::On32772{ TODO: 在此添加命令处理程序代码gEnableFlag = 1;}(4)为菜单关于添加UPDATE_COMMAND_UI消息处理函数:void CMainFrame::OnUpdateAppAboutCCmdUI *pCmdUI{ TODO: 在此添加命令更新用户界面处理程序代码pCmdUI-EnablegEnableFlag;}(5)保存工程并运行,结果如图5-33所示。5.2.15 使工具栏按钮保持下压状态有时候为了表明一种状态,要让工具栏按钮保持下压状态。基本思路是在UPDATE_COMMAND_UI事件响应里调用SetCheck函数。【例5.27】使工具栏按钮保持下压状态(1)新建一个单文档工程,设置工程字符集为使用多字节字符集。(2)添加一个全局变量gCheckFlag。int gCheckFlag = 0;0表示正常,1表示下压(3)为新建菜单项添加事件处理函数:void CMainFrame::OnFileNew{ TODO: 在此添加命令处理程序代码gCheckFlag = !gCheckFlag;}(4)为新建菜单添加UPDATE_COMMAND_UI事件函数:void CMainFrame::OnUpdateFileNewCCmdUI *pCmdUI{ TODO: 在此添加命令更新用户界面处理程序代码pCmdUI-SetCheckgCheckFlag;}(5)保存工程并运行,运行结果如图5-34所示。5.2.16 使工具栏在任意一边停靠工具栏可以在上下左右四个边上停靠。基本思路是使用停靠函数DockControlBar,并在该函数的第三个参数设置要停靠的方向宏。【例5.28】使工具栏在任意一边停靠(1)新建一个单文档工程,设置工程字符集为使用多字节字符集。(2)添加4个菜单项,分别用来设置工具栏停靠的方位。(3)添加停靠在底部的菜单事件函数:void CMainFrame::On32771{ TODO: 在此添加命令处理程序代码停靠工具栏在下边DockControlBar&m_wndToolBar,AFX_IDW_DOCKBAR_BOTTOM;}(4)添加停靠在左边的菜单事件函数:void CMainFrame::On32772{ TODO: 在此添加命令处理程序代码DockControlBar&m_wndToolBar,AFX_IDW_DOCKBAR_LEFT; 停靠工具栏在左边}(5)添加停靠在右边的菜单事件函数void CMainFrame::On32773{ TODO: 在此添加命令处理程序代码停靠工具栏在右边DockControlBar&m_wndToolBar,AFX_IDW_DOCKBAR_RIGHT;}(6)停靠在顶部的事件函数:void CMainFrame::On32774{ TODO: 在此添加命令处理程序代码DockControlBar&m_wndToolBar,AFX_IDW_DOCKBAR_TOP; 停靠工具栏在上边}(7)保存工程并运行,运行结果如图5-35所示。5.2.17 通过工具栏指针动态为工具栏按钮保存一段文本可以为工具栏某个按钮设置或获取一段文本。通过工具栏类的成员函数SetButtonText和GetButtonText为工具栏某个按钮设置或获取一段文本。【例5.29】通过工具栏指针动态为工具栏按钮保存一段文本(1)新建一个单文档工程,设置工程字符集为使用多字节字符集。(2)在视图下添加一个菜单通过工具栏指针为工具栏按钮ID_FILE_NEW保存一段文本。(3)为该菜单添加处理函数:void CMainFrame::On32771{ TODO: 在此添加命令处理程序代码CToolBar * pToolBar;得到工具栏指针pToolBar = CToolBar * AfxGetMainWnd-GetDescendantWindowAFX_IDW_TOOLBAR;int index = pToolBar-CommandToIndexID_FILE_NEW; 得到工具栏新建按钮的索引pToolBar-SetButtonTextindex,"通过工具栏指针为\r\n工具栏按钮ID_FILE_NEW\r\n保存一段文本:我的新建"; 保存一段文本AfxMessageBoxpToolBar-GetButtonTextindex;得到刚才保存的文本}(4)保存工程并运行,运行结果如图5-36所示。5.2.18 设置工具栏按钮的大小默认情况下,工具栏按钮和图标是一样的大小,比如16*16大小,但是按钮大小也是可以改变的,比如36*36。基本思路是通过工具栏类的成员函数SetSizes来改变。【例5.30】设置工具栏按钮的大小(1)新建一个单文档工程,设置工程字符集为使用多字节字符集。(2)在视图下添加菜单设置工具栏按钮的大小。(3)为该菜单添加处理函数:void CMainFrame::On32771{ TODO: 在此添加命令处理程序代码设置大小,第一个size是按钮的大小,第二个size是工具栏图标的大小m_wndToolBar.SetSizesCSize36,36,CSize16,16;}(4)保存工程并运行,拖拉该菜单,可以发现大小变大了。运行结果如图5-37所示。5.2.19 在工具栏按钮下方显示文本通常,工具栏按钮上只有图标,但有时候为了更加明确的表明工具栏按钮的含义,可以在工具栏按钮的图标下面显示一段文本来表明该工具栏图标的明确意思。【例5.31】在工具栏按钮下方显示文本(1)新建一个单文档工程,设置工程字符集为使用多字节字符集。(2)为要显示的文本的按钮添加文本,在CMainFrame::OnCreate函数中工具栏创建后面添加代码如下:CString str;TBBUTTON tb; 定义工具栏按钮信息变量
为第一个按钮插入文本m_wndToolBar.GetToolBarCtrl.GetButton0,&tb; 得到第一个按钮str = "我的新建";把字符串保存在工具栏中,并关联第一个按钮tb.iString = m_wndToolBar.GetToolBarCtrl.AddStringsstr;m_wndToolBar.GetToolBarCtrl.DeleteButton0; 删除第一个按钮m_wndToolBar.GetToolBarCtrl.InsertButton0,&tb; 再插入第一个按钮m_wndToolBar.GetButtonText0,str; 获得按钮文本
为第二个按钮插入文本m_wndToolBar.GetToolBarCtrl.GetButton1,&tb;str = "我的打开";tb.iString = m_wndToolBar.GetToolBarCtrl.AddStringsstr;m_wndToolBar.GetToolBarCtrl.DeleteButton1;m_wndToolBar.GetToolBarCtrl.InsertButton1,&tb;
为第三个按钮插入文本m_wndToolBar.GetToolBarCtrl.GetButton2,&tb;str = "我的保存";tb.iString = m_wndToolBar.GetToolBarCtrl.AddStringsstr;m_wndToolBar.GetToolBarCtrl.DeleteButton2;m_wndToolBar.GetToolBarCtrl.InsertButton2,&tb;修改工具栏按钮大小CSize sizeImage16,15;CSize sizeButton35,35;第一个size是按钮的大小,第二个size是工具栏图标的大小m_wndToolBar.SetSizessizeButton, sizeImage;(3)保存工程并运行,运行结果如图5-38所示。5.2.20 动态修改工具栏按钮的显示文本在上例中工具栏按钮下方出现了文本,本例将在程序运行过程中,动态地修改工具栏按钮下方的文本。基本思路是通过工具栏类的成员函数来实现,首先通过函数DeleteButton删除工具栏某个按钮,再通过函数InsertButton来添加工具栏按钮,而参数是我们已经设置了新文本的TBBUTTON变量,它是一个结构体。【例5.32】动态修改工具栏按钮的显示文本(1)新建一个单文档工程,设置工程字符集为使用多字节字符集。(2)为要显示文本的按钮添加文本,在CMainFrame::OnCreate中添加代码如下:CString str;TBBUTTON tb;m_wndToolBar.GetToolBarCtrl.GetButton0,&tb;str = "我的新建";为工具栏添加文本并关联第一个按钮tb.iString = m_wndToolBar.GetToolBarCtrl.AddStringsstr;m_wndToolBar.GetToolBarCtrl.DeleteButton0;m_wndToolBar.GetToolBarCtrl.InsertButton0,&tb;m_wndToolBar.GetButtonText0,str;
m_wndToolBar.GetToolBarCtrl.GetButton1,&tb;str = "我的打开";tb.iString = m_wndToolBar.GetToolBarCtrl.AddStringsstr;m_wndToolBar.GetToolBarCtrl.DeleteButton1;m_wndToolBar.GetToolBarCtrl.InsertButton1,&tb;
m_wndToolBar.GetToolBarCtrl.GetButton2,&tb;str = "我的保存";tb.iString = m_wndToolBar.GetToolBarCtrl.AddStringsstr;m_wndToolBar.GetToolBarCtrl.DeleteButton2;m_wndToolBar.GetToolBarCtrl.InsertButton2,&tb;修改工具栏按钮大小CSize sizeImage16,15;CSize sizeButton35,35;调整工具栏大小,第一个size是按钮的大小,第二个size是工具栏图标的大小m_wndToolBar.SetSizessizeButton, sizeImage;此时运行工程可以发现工具栏按钮有文本了。现在在视图菜单下添加一个菜单项修改第一个工具栏按钮的显示文本,并为其添加事件代码如下:void CMainFrame::On32771{ TODO: 在此添加命令处理程序代码CString str;TBBUTTON tb;m_wndToolBar.GetToolBarCtrl.GetButton0,&tb;str = "新建是我的";关联新的文本tb.iString = m_wndToolBar.GetToolBarCtrl.AddStringsstr;m_wndToolBar.GetToolBarCtrl.DeleteButton0;m_wndToolBar.GetToolBarCtrl.InsertButton0,&tb;}(3)保存工程并运行,运行结果如图5-39所示。5.2.21 在工具栏上显示字体组合框在工具栏上不仅可以显示按钮、显示文本,也可以用来显示一个包含字体名字的组合框。基本思路是首先在工具栏上多添加几个按钮,为组合框预留位置,然后在这个位置上调用组合框的Create函数进行创建。【例5.33】在工具栏上显示字体组合框(1)新建一个单文档工程,设置工程字符集为使用多字节字符集。(2)为类CMainFrame增加下列变量定义:CComboBox m_cbFont;存放字体的组合框CStatic m_csSelFont;选择字体的提示的静态文本框(3)为了不破坏原来的工具栏按钮,我们在新增按钮的位置上创建字体选择控件。打开工具栏编辑器,在工具条的右边复制4个按钮,复制方法是先对最右边的灰色按钮进行复制Ctrl C,然后单击下面空白处,进行4次粘贴Ctrl V。(4)在CMainFrame::OnCreate中增加下列代码:创建静态文本框CRect rt;int index = m_wndToolBar.CommandToIndexID_BTN_FONT_SEL1;
设置第一个按钮的新ID,当style是 TBBS_SEPARATOR时,最后一个参数是宽度m_wndToolBar.SetButtonInfoindex, ID_FONT_SEL, TBBS_SEPARATOR, 90;m_wndToolBar.GetItemRectindex,&rt;创建字体静态文本框,其中ID_FONT_SEL是自定义的静态文本框IDif!m_csSelFont.Create"请选择字体:",WS_VISIBLE|WS_TABSTOP,rt, &m_wndToolBar, ID_FONT_SEL{AfxMessageBox"创建字体静态文本框失败\n";return FALSE;}为工具栏创建组合框index = m_wndToolBar.CommandToIndexID_BTN_FONT_SEL2;m_wndToolBar.SetButtonInfoindex, ID_FONT_SEL_COMBO, TBBS_SEPARATOR,150;
m_wndToolBar.GetItemRectindex,&rt;if!m_cbFont.CreateWS_CHILD|WS_VISIBLE|CBS_DROPDOWNLIST|WS_VSCROLL,rt,&m_wndToolBar,ID_FONT_SEL_COMBO{AfxMessageBox"未能创建组合框\n";return -1; 未能创建}
获取系统字体类型,并放入组合框中::EnumFontFamiliesExGetDC-m_hDC, NULL,FONTENUMPROCEnumSysFontFunc, LPARAM&m_cbFont,NULL;m_cbFont.SetCurSel0;设置组合框下拉列表的高度CRect rc;m_cbFont.GetDroppedControlRect&rc;m_cbFont.GetParent-ScreenToClient&rc;rc.bottom= 150;m_cbFont.MoveWindow&rc;(5)手工添加组合框选择事件,先在MainFrm.cpp中的BEGIN_MESSAGE_MAP里添加事件映射宏:BEGIN_MESSAGE_MAPCMainFrame, CFrameWndON_WM_CREATEON_CBN_SELCHANGEID_FONT_SEL_COMBO, OnFontSelChangeEND_MESSAGE_MAP然后添加组合框选择事件响应函数:void CMainFrame::OnFontSelChange{CString str,strFont;m_cbFont.GetLBTextm_cbFont.GetCurSel,strFont;str = "你选择的字体是:" strFont;AfxMessageBoxstr;}最后要在头文件里添加函数声明void OnFontSelChange;(6)保持并运行工程,运行结果如图5-40所示。图5-405.2.22 工具栏上出现对话框在工具栏上不仅可以显示按钮、显示文本,也可以用来显示一个对话框。基本思路是通过对话条类CDialogBar的Create函数来实现。然后创建对话框资源,在对话框资源编辑器内生成一个Dialog资源,并将其风格(Style)属性必须设置为Child,不能设置为 Overlapped或Popup,否则运行肯定出错;至于边界属性必须选择None。其余属性一般没有特殊要求,还是选择默认的好。把这个对话框ID和CDialogBar在Create创建时候,作为参数传入。【例5.34】工具栏上出现对话框(1)新建一个单文档工程,设置工程字符集为使用多字节字符集。(2)添加一个对话框资源IDD_DLGBAR,并设置其属性:Board为None、Style为Child。(3)打开MainFrm.h,然后为CMainFrm添加成员变量:CDialogBar m_dlgBar;(4)在CMainFrame::OnCreate中添加对话栏创建代码:创建对话条if !m_dlgBar.Createthis, IDD_DLGBAR,CBRS_TOP | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_HIDE_INPLACE,NULL{AfxMessageBox"创建对话条失败";return -1;}让对话栏有停靠功能m_dlgBar.EnableDockingCBRS_ALIGN_TOP | CBRS_ALIGN_BOTTOM;EnableDockingCBRS_ALIGN_ANY;DockControlBar&m_dlgBar;此时运行工程,可以看到对话条已经有了,下面我们添加一个控件。(5)打开对话框资源IDD_DLGBAR,把对话条高度调整到普通工具栏一样的高度,并把切换辅助线去掉。(6)保存工程并运行,运行结果如图5-41所示。