比特派官方版安卓下|vxc
VXC系列 - 雅马哈(Yamaha)中国
VXC系列 - 雅马哈(Yamaha)中国
My Account
global navigation
产品
钢琴
电子键盘
吉他、贝斯和音箱
鼓乐器
管乐器 · 吹奏乐器
弦乐器
打击乐器
合成器及音乐制作产品
家庭音响
专业音响
会议系统
App应用程序
高尔夫
车载音响
音乐服务
新闻活动
经销商查询
客户服务
企业用户
关于雅马哈
加入我们
产品
产品
钢琴
电子键盘
吉他、贝斯和音箱
鼓乐器
管乐器 · 吹奏乐器
弦乐器
打击乐器
合成器及音乐制作产品
家庭音响
专业音响
会议系统
App应用程序
高尔夫
车载音响
音乐服务
新闻活动
经销商查询
客户服务
企业用户
关于雅马哈
加入我们
Search this site
发送
搜索
专业音响
Toggle navigation
新闻活动
特别推荐
首页
产品
专业音响
扬声器
吸顶安装扬声器
VXC系列
VXC系列
概要
系列介绍
产品参数
相关下载
更多服务
概要
概要
系列介绍
产品参数
相关下载
更多服务
音质清晰持久的多用途音箱产品系列
雅马哈设计了全新的 VXC 和 VXS 音箱以满足不断增长的固定安装音响市场。该系列承袭了雅马哈音质的一贯精神,同时针对安全和易于安装方面着重进行设计。该系列由吸顶和表面安装两种型号可供选择, 丰富的型号黑白双色兼备, 当然您更可以自己涂装符合任何内部装修的表面颜色。
VXC系列
VXC系列
[吸顶安装扬声器]
立即购买
VXC系列有3个不同尺寸的型号,您可以根据场合的需要择优选择。
产品信息如有变动,恕不另行通知。网站上信息仅供参考,一切以具体实物为准。
产品信息
VXC8 / VXC8W
吸顶安装扬声器
VXC8 / VXC8W
吸顶安装扬声器
8" 低音单元,1" 半球形高音单元
VXC6 / VXC6W
吸顶安装扬声器
VXC6 / VXC6W
吸顶安装扬声器
6.5" 低音单元,0.75" 半球形高音单元
VXC4 / VXC4W
吸顶安装扬声器
VXC4 / VXC4W
吸顶安装扬声器
4"全频单元
相关产品
XMV系列
MA/PA 系列
VXS 系列 "F model"
VXS 系列 "M model"
VXC系列"F model"
MRX7-D
MTX系列
VXS 系列 "S model"
VXS系列
适于任何用途的吸顶音箱
VXC 系列配有 3 种低音单元尺寸不同的型号,您可以选择适合自己场地的音箱型号。每个型号都带有内置转换器,只需切换挡板上的旋钮,用一只音箱即可实现高阻和低阻两种驱动形式。由于一只音箱可在两种驱动形式下运行,所需音箱的数量减少了,还能方便地更改您的系统。
安全牢固的安装
该系列音箱上的防摔带可用来临时安装在天花板上,安装人员可以腾出双手实现安全便捷的安装。牢固连接、便于手提的拎手,使音箱更便携,可以一次性安全搬运多只音箱。另外,VXC 系列还配有 O 型环和瓷导轨,使安装过程更安全更顺畅。
追求好的固定安装音质
公共广播用途中,能够忠实还原优质音乐,同时能播放水晶般清晰的语音广播,此类音箱已成为不断增长的固定安装音响市场的需求,我们开发的 VXC 和 VXS 系列音箱正是为了满足这一要求。两个型号都具有全新定义的喇叭单元,大而有力的磁钢和电路大幅度提升了驱动力和制动力,而专用的高音单元振膜和单元纸盆由合成材料精细加工而成,这种材料有助于声音的佳还原。箱体的制作其符合多种商业环境的要求,材料优选具有适当张力强度的工程塑料,低音反射式设计能产生紧密强劲的低音。从排列单元和接线、焊接的材料,到吸音材料的佳布局,我们甚至对该系列设计中的微小细节,也同样付出了大量的精力。
音箱设计
音箱设计的各个方面都着力强调功能性,而结构上讲求审美和品位——在有效提高声音品质和音箱性能的同时, 还能与装修风格相得益彰。这个概念明确地反映在两种音箱栅格网罩的设计上, 即通过增大开孔提高了声音的清晰度。与此类似,吊装音箱箱体线条流畅,简洁而不失精细的设计让音箱安装时能更接近墙壁——而它的声像定位和朝向依旧能全部指向目标区域。甚至 VXC 的高音单元也采用了创新设计,通过喇叭单元不受约束的运动,提高了声音的清晰度。
可喷涂音箱,满足您的空间设计需要
VXC 系列面罩可喷涂。通过搭配喷涂不同颜色的面罩,诸如浅色或者深色又或者其他符合您空间装饰风格的颜色,VXC 系列在为您的空间提供音质的同时,大大增强了您内部空间的设计感。
VXS/VXC Series Painting Guide
VXC8, VXC6, VXC4
VXC8 / VXC8W
VXC6 / VXC6W
VXC4 / VXC4W
音箱类型
2- 路低频,密闭式箱体
2- 路低频,密闭式箱体
全频,低音反射式
频率范围 (-10dB)
55Hz - 20kHz (Half-space:2π)
56Hz - 20kHz (Half-space:2π)
80Hz - 20kHz (Half-space:2π)
覆盖角
100° conical (Half-space:2π)
110° conical (Half-space:2π)
130° conical (Half-space:2π)
部件
LF
8" Cone
6.5" Cone
-
HF
1" Soft dome
0.75" Soft dome
-
LF-HF
-
-
4" full-range
电功率
噪声
90W
75W
30W
PGM
180W
150W
60W
PEAK
360W
300W
120W
标称阻抗
8Ω
8Ω
8Ω
转换器标签
100V
60W (170Ω), 30W (330Ω), 15W (670Ω)
60W (170Ω), 30W (330Ω), 15W (670Ω)
30W (330Ω), 15W (670Ω), 7.5W (1.3kΩ)
70V
60W (83Ω), 30W (170Ω), 15W (330Ω), 7.5W (670Ω)
60W (83Ω), 30W (170Ω), 15W (330Ω), 7.5W (670Ω)
30W (170Ω), 15W (330Ω), 7.5W (670Ω), 3.8W (1.3kΩ)
SPL
灵敏度 (1W; 1m on axis)
90dB SPL (Half-space:2π)
86dB SPL (Half-space:2π)
87dB SPL (Half-space:2π)
大 SPL (计算所得)
116dB SPL (1m, Calculated based on power rating and sensitivity, exclusive of power compression)
111dB SPL (1m, Calculated based on power rating and sensitivity, exclusive of power compression)
108dB SPL (1m, Calculated based on power rating and sensitivity, exclusive of power compression)
接口
1 x Euroblock (4P) : (Input: + / -, Loop Thru: + / -)
1 x Euroblock (4P) : (Input: + / -, Loop Thru: + / -)
1 x Euroblock (4P) : (Input: + / -, Loop Thru: + / -)
颜色
VXC8: Black / VXC8W: White
VXC6: Black / VXC6W: White
VXC4: Black / VXC4W: White
外观尺寸
Diameter
325mm (12.8")
286mm (11.3")
225mm (8.9")
D
259mm (10.2")
205mm (8.1")
195mm (7.7")
重量
6.6kg (14.6lbs)
4.4kg (9.7lbs)
2.6kg (5.7lbs)
Cutout size
Ø285 mm (Ø11 1/4")
Ø247 mm (Ø9 3/4")
Ø186 mm (Ø7-5/16")
Required ceiling board thickness
5 mm – 35 mm
5 mm – 35 mm
5 mm – 35 mm
附件
O-ring, Tile Rail, Cutout Template
O-ring, Tile Rail, Cutout Template
O-ring, Tile Rail, Cutout Template
Packaging
Packaged in pairs
Packaged in pairs
Packaged in pairs
Certificate
UL1480, UL2043, NFPA70, CE, EAC, RoHS
UL1480, UL2043, NFPA70, CE, EAC, RoHS
UL1480, UL2043, NFPA70, CE, EAC, RoHS
VXC8-VA, VXC6-VA, VXC4-VA
VXC8-VA / VXC8-VAW
VXC6-VA / VXC6-VAW
VXC4-VA / VXC4-VAW
音箱类型
2- 路低音反射式
2- 路低音反射式
Full-range, Acoustic suspension
频率范围 (-10dB)
55Hz - 20kHz (Half-space:2π)
56Hz - 20kHz (Half-space:2π)
80Hz - 20kHz (Half-space:2π)
覆盖角
100° conical (Half-space:2π)
110° conical (Half-space:2π)
130° conical (Half-space:2π)
部件
LF
8" Cone
6.5" Cone
-
HF
1" Soft dome
0.75" Soft dome
-
LF-HF
-
-
4" full-range
电功率
噪声
90W
75W
30W
PGM
180W
150W
60W
PEAK
360W
300W
120W
标称阻抗
8Ω
8Ω
8Ω
转换器标签
100V
60W (170Ω), 30W (330Ω), 15W (670Ω)
60W (170Ω), 30W (330Ω), 15W (670Ω)
30W (330Ω), 15W (670Ω), 7.5W (1.3kΩ)
70V
60W (83Ω), 30W (170Ω), 15W (330Ω), 7.5W (670Ω)
60W (83Ω), 30W (170Ω), 15W (330Ω), 7.5W (670Ω)
30W (170Ω), 15W (330Ω), 7.5W (670Ω), 3.8W (1.3kΩ)
SPL
灵敏度 (1W; 1m on axis)
89dB SPL (Half-space:2π)
86dB SPL (Half-space:2π)
87dB SPL (Half-space:2π)
大 SPL (计算所得)
114dB SPL (1m, Calculated based on power rating and sensitivity, exclusive of power compression)
111dB SPL (1m, Calculated based on power rating and sensitivity, exclusive of power compression)
108dB SPL (1m, Calculated based on power rating and sensitivity, exclusive of power compression)
接口
1x Ceramic terminal block (3P) (input: +/-, Earth)
1x Ceramic terminal block (3P) (input: +/-, Earth)
1x Ceramic terminal block (3P) (input: +/-, Earth)
颜色
VXC8-VA: Black / VXC8-VAW: White
VXC6-VA: Black / VXC6-VAW: White
VXC4-VA: Black / VXC4-VAW: White
Waterproof
IP32
IP32
IP32
外观尺寸
Diameter
325mm (12.8")
286mm (11.3")
225mm (8.9")
D
295mm (11.6")
241mm (9.5")
232mm (9.1")
重量
6.6kg (14.6lbs)
4.4kg (9.7lbs)
2.6kg (5.7lbs)
Cutout size
Ø285 mm (Ø11 1/4")
Ø247 mm (Ø9 3/4")
Ø186 mm (Ø7-5/16")
Required ceiling board thickness
5 mm – 35 mm
5 mm – 35 mm
5 mm – 35 mm
附件
O-ring, Tile Rail, Cutout Template
O-ring, Tile Rail, Cutout Template
O-ring, Tile Rail, Cutout Template
Packaging
Packaged in pairs
Packaged in pairs
Packaged in pairs
Certificate
CE, RoHS
CE, RoHS
CE, RoHS
EN54-24 compliance
Yes (DoP No. 0359-CPR-00405)
Yes (DoP No. 0359-CPR-00405)
Yes (DoP No. 0359-CPR-00405)
声学建模数据
Name
English
English
CLF Data for VXC Series Speakers (V1.0)
—
[14KB]
EASE GLL Data for VXC Series Speakers (V3.0) - EASE Focus / EASE Address enabled
—
[229KB]
产品手册
Commercial Installation Solutions
中文
English
Speakers for Commercial Installations
中文
English
System Examples Catalog
English
固件及软件
Name
OS
Size
Last Update
CISSCA V3.00 for Win 10/8.1/8/7
Win
42.6MB
2019-06-10
NS-1
NS-1
NS-1 是一个功能强大且直观的系统配置和模拟工具,使NEXO和Yamaha用户能够配置和优化广泛的NEXO和Yamaha系统性能。
更多
产品说明书
Name
中文
English
English
VXC4/VXC4W Owner's Manual
—
[649KB]
[3.2MB]
VXC4-VA VXC4-VAW Owner's Manual
—
—
[180KB]
VXC4-VA VXC4-VAW Technical Specifications
—
—
[3MB]
VXC8/VXC8W/VXC6/VXC6W Owner's Manual
—
[603KB]
[3.3MB]
VXC8-VA VXC8-VAW VXC6-VA VXC6-VAW Owner's Manual
—
—
[194KB]
VXC8-VA VXC8-VAW VXC6-VA VXC6-VAW Technical Specifications
—
—
[3.1MB]
VXS/VXC Series Painting Guide
—
—
[357KB]
Y-S3 V3.0 Compatible models for Distributed Speakers
—
—
[279KB]
Y-S3 V3.1 Manual
—
—
[2.5MB]
其他(工程数据参数等)
Name
中文
English
English
CAD Data (VXC 3D)
—
—
[515KB]
Data Sheet (CISSCA)
—
—
[613KB]
Data Sheet (VXC Series)
—
—
[25.9MB]
Data Sheet (VXC6)
—
[13.5MB]
—
Data Sheet (VXC8)
—
[15.5MB]
—
General Speaker Data / CLF Data for VXC Series Speakers (V1.0)
—
—
[14KB]
General Speaker Data / EASE Data for VXC Series Speakers (V1.1.1)
—
—
[72KB]
VXC4 Technical Data Sheet
—
—
[3.7MB]
VXC6 Technical Data Sheet
—
—
[4.5MB]
VXC8 Technical Data Sheet
—
—
[4.8MB]
VXC-VA Declaration of Performance
—
—
[566KB]
VXC-VA EN54 Certificate
—
—
[330KB]
Y-S3 Speaker System Design Guide
—
—
[337KB]
经销商查询
授权服务中心查询
说明书下载
产品注册
首页
产品
专业音响
扬声器
吸顶安装扬声器
VXC系列
×
产品
钢琴
电子键盘
吉他、贝斯和音箱
鼓乐器
管乐器 · 吹奏乐器
弦乐器
打击乐器
合成器及音乐制作产品
家庭音响
专业音响
会议系统
App应用程序
高尔夫
车载音响
音乐服务
雅马哈音乐中心
雅马哈流行音乐课程
雅马哈双排键电子琴教师俱乐部
雅马哈电子键盘专用教室
新闻活动
新闻活动首页
经销商查询
经销商查询首页
客户支持
常见问题(Q&A)
授权服务中心查询
雅马哈会员系统
雅马哈认证技师
下载与支持
经销商专区
雅马哈进口钢琴原产地信息查询
关于雅马哈
雅马哈集团
雅马哈中国
Global
联系我们
在线招聘
使用条款
隐私条款
Copyright© 2021 雅马哈乐器音响(中国)投资有限公司 版权所有 沪ICP备05040406号-1沪公网安备
31010602003422号
VXC系列"F model" - 雅马哈(Yamaha)中国
VXC系列"F model" - 雅马哈(Yamaha)中国
My Account
global navigation
产品
钢琴
电子键盘
吉他、贝斯和音箱
鼓乐器
管乐器 · 吹奏乐器
弦乐器
打击乐器
合成器及音乐制作产品
家庭音响
专业音响
会议系统
App应用程序
高尔夫
车载音响
音乐服务
新闻活动
经销商查询
客户服务
企业用户
关于雅马哈
加入我们
产品
产品
钢琴
电子键盘
吉他、贝斯和音箱
鼓乐器
管乐器 · 吹奏乐器
弦乐器
打击乐器
合成器及音乐制作产品
家庭音响
专业音响
会议系统
App应用程序
高尔夫
车载音响
音乐服务
新闻活动
经销商查询
客户服务
企业用户
关于雅马哈
加入我们
Search this site
发送
搜索
专业音响
Toggle navigation
新闻活动
特别推荐
首页
产品
专业音响
扬声器
吸顶安装扬声器
VXC系列"F model"
VXC系列"F model"
概要
系列介绍
产品参数
相关下载
更多服务
概要
概要
系列介绍
产品参数
相关下载
更多服务
浅轮廓吸顶音箱 只为声音的完美再现
在定义商用空间的美学标准与环境氛围时,音乐起着不可或缺的作用,优质的背景音乐能够显著提升商用空间在客户心中的整体形象。VXC-F 系 列吸顶音箱结合了雅马哈无与伦比的艺术〜品质乐器和专业音响制造工艺,并将灵活的设计及应用理念融入其中,从而简化您的安装过程,为您 的餐厅、零售店或职业环境全面提供高品质声音。VXC-F 系列采用了全新设计的音箱单元,具备的音乐回放能力。音箱的纵深较浅,结构轻 质,即便在严苛的安装限制下,灵活的设计也使其能够安装自如。无论被安装在何处,VXC-F系列吸顶音箱都能发挥出卓越的音质表现。
使用型号:VXC2FB/VXC2FW
VXC2F是VXC系列中最轻薄的型号,可实现灵活的安装解决方案。
VXC系列"F model"
VXC系列"F model"
[吸顶安装扬声器]
立即购买
VXC-F吸顶扬声器能够简化您的安装过程,天衣无缝地将高品质音效融合进餐厅,零售店,或者其他专业类环境。
产品信息如有变动,恕不另行通知。网站上信息仅供参考,一切以具体实物为准。
产品信息
VXC5F / VXC5FW
吸顶安装扬声器
VXC5F / VXC5FW
吸顶安装扬声器
4.5"全频吸顶音箱
4.5"全频音箱单元
专为BGM背景音乐优化设计
单个音箱即拥有宽广覆盖角度
定压、定阻系统均可使用
有限空间的浅轮廓设计
内建手提带,提升安装时的安全性
防跌落卡扣设计,提升临时放置时的安全性
锁定螺帽设计,安装更快速
可喷涂音箱面罩,磁吸式设计
黑色或白色版本可选
3.1kg (6.8lbs), Ø324 x D143 mm (Ø12-13/16" x D5-11/16")
VXC3F / VXC3FW
吸顶安装扬声器
VXC3F / VXC3FW
吸顶安装扬声器
3.5"全频吸顶音箱
3.5"全频音箱单元
专为BGM背景音乐优化设计
定压、定阻系统均可使用
有限空间的浅轮廓设计
内建手提带,提升安装时的安全性
防跌落卡扣设计,提升临时放置时的安全性
锁定螺帽设计,安装更快速
可喷涂音箱面罩,磁吸式设计
黑色或白色版本可选
2.5kg (5.5lbs), Ø285 x D112 mm (Ø11-1/4" x D4-7/16")
VXC2FB / VXC2FW
吸顶安装扬声器
VXC2FB / VXC2FW
吸顶安装扬声器
2.5" 全频吸顶音箱
2.5”全频音箱单元
专为BGM背景音乐优化设计
轻薄的外型设计,更适合在有限的天花板空间安装
定压、定阻系统均可使用
内建手提带,提升安装时的安全性
锁定螺帽设计,安装更快速
可喷涂音箱面罩,磁吸式设计
黑色或白色版本可选
1.7 kg (3.7 lbs),Ø225 x D89 mm (Ø8-7/8" x D3-1/2")
相关产品
XMV系列
MA/PA 系列
VXS 系列 "F model"
VXS 系列 "M model"
MRX7-D
MTX系列
VXS 系列 "S model"
VXS系列
VXC系列
提供高音质的背景音乐
提供高音质的背景音乐
凭借雅马哈对音乐的深入理解,以及在扬声器单元设计和树脂材料应用方面的科技,使得VXC-F系列吸顶扬声器在任何音量下,声学设计的自由度,声音还原的度,和自然声再造都可以达到高的水平。不会出现此类型吸顶扬声器经常发生的中频失真现象。VXC-F系列吸顶扬声器的单元尺寸与背箱容量是完美匹配的,所以从低频到高频才能做到如此的平衡性,即使是在非常低输出电平的情况下,也能有出色表现。
推荐应用
为了更安全、更快速安装的智慧设计
为了更安全、更快速安装的智慧设计
VXC3F 和 VXC5F 两个型号均为浅轮廓背箱、减重设计,多项机械特性显著提升了安装过程中的安全性和便捷性。两款型号同时支持定压和定阻连接, 大程度上降低了额外的安装空间,确保音响系统可以完美匹配任何安装环境。
定压或定阻
定压或定阻
VXC-F 系列同时支持定压 和定阻两种系统连接,即 使在安装完成后,您也可 以轻松调节音箱的功率。
浅轮廓设计
浅轮廓设计
较浅的物理纵深使 VXC-F 能够被安装进有限的天花板空间中。
轻质结构
轻质结构
音箱质量减轻的同时,也减少了安装人员的负重,提高了安装的灵活性。
携带便捷
携带便捷
内置的手提带不仅便于您 随身携带音箱,也提升了 梯子作业时的安全性。
安全安装
安全安装
防摔落装置能够妥善地将 音箱保持在正确位置,确 保整个安装过程安全、高 效。
快速安装
快速安装
用于音箱夹紧装置的双螺纹螺钉能够使音箱得到双重夹紧,但安装速度丝毫不逊色于传统螺钉。
流线型
流线型
音箱的栅格面罩在强力磁铁的作用下被牢牢固定在恰当的位置,防摔落线亦可确保面罩的稳定性。
可喷涂
可喷涂
您可以根据室内的装饰风 格,任意对音箱面罩进行 喷涂。
VXS/VXC Series Painting Guide
VXC5F / VXC5FW
VXC3F / VXC3FW
VXC2FB / VXC2FW
音箱类型
全频,低音反射式
全频,低音反射式
全频,低音反射式
频率范围 (-10dB)
60 Hz – 20 kHz (Half-space:2π)
71 Hz – 20 kHz (Half-space:2π)
67 Hz - 20 kHz (Half-space 2π)
覆盖角度
130° conical (Half-space :2π)
140° conical (Half-space :2π)
160゜conical (Half-space 2π)
部件
LF-HF
4.5” Full range unit
3.5” Full range unit
2.5” Full range unit
电功率
噪音
40 W
20 W
15 W
PGM
80 W
40 W
30 W
PEAK
160 W
80 W
60 W
标称阻抗
8 Ω
8 Ω
8 Ω
转换器标签
100V
30 W, 15W, 7.5 W
15W, 7.5 W, 3.8 W
15W, 7.5W, 3.8W, 1.9W
70V
30 W, 15 W, 7.5 W, 3.8 W
15 W, 7.5 W, 3.8 W, 1.9 W
15 W, 7.5 W, 3.8 W, 1.9 W, 1 W
SPL
灵敏度 (1W; 1m on axis)
89 dB SPL (Half-space:2π)
87 dB SPL (Half-space:2π)
86 dB SPL (Half-space:2π)
大 SPL (计算所得)
111 dB SPL (Calculated, 1m)
106 dB SPL (Calculated, 1m)
104 dB SPL (Calculated, 1m)
接口
Euroblock (4 pin) × 1 (input: +/-, loop-thru: +/-)
Euroblock (4 pin) × 1 (input: +/-, loop-thru: +/-)
Euroblock (4 pin) × 1 (input: +/-, loop-thru: +/-)
Protection circuit
过载保护
全方位功率限制以保护网络和变频器
全方位功率限制以保护网络和变频器
全方位功率限制以保护网络和变频器
颜色
VXC5F: Black (approx. Munsell N3), VXC5FW: White (approx. Munsell N9.3)
VXC3F: Black (approx. Munsell N3), VXC3FW: White (approx. Munsell N9.3)
VXC2FB: Black (approx. Munsell N3), VXC2FW: White (approx. Munsell N9.3)
尺寸
Diameter
324 mm (12-13/16")
285 (11-1/4")
225 mm (8-7/8")
D
143 mm (5-11/16")
112 mm (4-7/16")
89 mm (3-1/2")
重量
3.1 kg (6.8 lbs)
2.5 kg (5.5 lbs)
1.7 kg (3.7 lbs)
Cutout size
Ø285 mm (Ø11-1/4")
Ø247 mm (Ø9-3/4")
Ø186 mm (Ø7-5/16")
Required ceiling board thickness
5 mm – 37 mm
5 mm – 37 mm
5 mm – 37 mm
附件
O-ring, Tile Rail, Cutout Template, Euro Block (4pin), Terminal Cover
O-ring, Tile Rail, Cutout Template, Euro Block (4pin), Terminal Cover
Cutout Template
包装
一对装
一对装
单个装
Certificate
UL1480, NFPA70, CE, EAC, RoHS
UL1480, NFPA70, CE, EAC, RoHS
UL1480, UL2043, NFPA70, CE, EAC, RoHS
EN54-24 compliance
-
-
-
Others
Conduit tube: Ø15.4 mm - Ø21.3 mm
Conduit tube: Ø15.4 mm - Ø21.3 mm
Conduit tube: Ø15.4 mm - Ø21.3 mm
Options
-
-
PK-C4B / PK-C4W: Pendant-mount kit, AB-C2: C-ring + Tile Rail kit
声学建模数据
Name
English
English
CLF Data for VXC Series F model Speakers (V1.0)
—
[10KB]
EASE GLL Data for VXC Series Speakers (V3.0) - EASE Focus / EASE Address enabled
—
[229KB]
产品手册
Commercial Installation Solutions
中文
English
Speakers for Commercial Installations
中文
English
System Examples Catalog
English
固件及软件
Name
OS
Size
Last Update
CISSCA V3.00 for Win 10/8.1/8/7
Win
42.6MB
2019-06-10
NS-1
NS-1
NS-1 是一个功能强大且直观的系统配置和模拟工具,使NEXO和Yamaha用户能够配置和优化广泛的NEXO和Yamaha系统性能。
更多
产品说明书
Name
中文
English
English
VXC5F VXC5FW VXC3F VXC3FW Owner's Manual
—
[492KB]
[308KB]
VXC5F VXC5FW VXC3F VXC3FW Technical Specifications
—
—
[3.4MB]
VXC5F-VA/VXC5F-VAW/VXC3F-VA/VXC3F-VAW Owner's Manual
—
—
[4.7MB]
Y-S3 V3.0 Compatible models for Distributed Speakers
—
—
[279KB]
Y-S3 V3.0 Manual
—
—
[1.9MB]
Y-S3 V3.1 Compatible models for Distributed Speakers
—
—
[15KB]
Y-S3 V3.1 Manual
—
—
[2.5MB]
其他(工程数据参数等)
Name
中文
English
English
CAD Data (VXC3F)
—
—
[443KB]
CAD Data (VXC5F)
—
—
[447KB]
Data Sheet (CISSCA)
—
—
[613KB]
Data Sheet (VXC Series "F model")
—
—
[3.3MB]
Data Sheet (VXC3F)
—
[1.9MB]
—
Data Sheet (VXC4)
—
[9.6MB]
—
Data Sheet (VXC5F)
—
[2.2MB]
—
General Speaker Data / CLF Data for VXC Series F model Speakers (V1.0)
—
—
[10KB]
General Speaker Data / EASE Data for VXC Series F model Speakers (V1.0)
—
—
[43KB]
VXC-F-VA Declaration of Performace
—
—
[737KB]
VXC-F-VA EN54-24 Certificate
—
—
[410KB]
Y-S3 Speaker System Design Guide
—
—
[337KB]
经销商查询
授权服务中心查询
说明书下载
产品注册
首页
产品
专业音响
扬声器
吸顶安装扬声器
VXC系列"F model"
×
产品
钢琴
电子键盘
吉他、贝斯和音箱
鼓乐器
管乐器 · 吹奏乐器
弦乐器
打击乐器
合成器及音乐制作产品
家庭音响
专业音响
会议系统
App应用程序
高尔夫
车载音响
音乐服务
雅马哈音乐中心
雅马哈流行音乐课程
雅马哈双排键电子琴教师俱乐部
雅马哈电子键盘专用教室
新闻活动
新闻活动首页
经销商查询
经销商查询首页
客户支持
常见问题(Q&A)
授权服务中心查询
雅马哈会员系统
雅马哈认证技师
下载与支持
经销商专区
雅马哈进口钢琴原产地信息查询
关于雅马哈
雅马哈集团
雅马哈中国
Global
联系我们
在线招聘
使用条款
隐私条款
Copyright© 2021 雅马哈乐器音响(中国)投资有限公司 版权所有 沪ICP备05040406号-1沪公网安备
31010602003422号
密度泛函理论学习笔记(2) - 知乎
密度泛函理论学习笔记(2) - 知乎切换模式写文章登录/注册密度泛函理论学习笔记(2)李小左拓扑超导/强关联/打工上节学习到K-S方程的求解方法,i.e.,自洽场方法,不过这里遗留了一个问题,就是Vxc如何选取或者说Exc泛函如何选取呢?交换关联势的定义能量泛函的组成人们对这个问题做了一些近似,寻找到精确的泛函是十分困难的,''Develop a functional that accurately represents nature‘s exact functional and implement it in a mathematical form that can be efficiently solved for large numbers of atoms will win you a Nobel prize . '' Vxc最简单的形式是:把观测位置看成均匀电子气,那么Vxc便只依赖于该点的电子密度,这称为局域密度近似(Local density approximation,LDA).更进一步,Vxc即依赖于电子密度,又依赖电子密度的梯度,那么Vxc中包含的物理信息就会更多一些,这种方法称为广义梯度近似(Generalized-gradient approximation,GGA).常见的GGA泛函有PBE,PW91;虽然GGA含有的物理信息更加丰富,但这不一定表示用GGA比用LDA一定准确。后来又发展了meta-GGA泛函,是指在GGA的基础上增加了电子密度的二阶导数的信息;典型代表是TPSS目前应用更广泛的是,Hyper-GGA是指在GGA的基础上,掺入准确的交换能。典型代表就是B3LYP。 有一张著名的Jocob's ladder梯子的高度是精度(一般来说),右侧是成分,n代表电子密度------------------------------------------分割线----------------------------------------量子化学中除了DFT,还有HF方法,半经验方法,后HF方法(微扰理论,耦合簇,组态相互作用方法等),有必要对量子化学有一个俯瞰,才能使得我们更加理解密度泛函理论的优势与劣势,以及适用范围,这也是我回过头来重新学习DFT比较大的感悟。先说一下在量子化学中的空间局域函数和空间扩展函数。 空间局域函数,顾名思义,函数局域在一定的区域,而当坐标趋近于无穷时候,函数趋于零。比如有限深方势阱里的波函数,局域在势阱内,而在势阱外,波函数随着坐标偏离势阱而迅速衰减。而对于分子体系,电子往往局域在分子中离子实附近,描述分子体系的波函数和电子密度往往用空间局域函数或者其线性叠加表示,而空间局域函数往往具有高斯函数的形式。这种方法在量子化学中描述分子体系广为采用,比如LCAO方法。 空间扩展函数,即函数在坐标趋于无穷时,并不趋于零,而是有一定的分布。对于块体(bulk)材料,原子排列长程有序,有一定的周期性,那么体系对应的波函数和电子密度也会体现出一定的周期性(Bloch 定理),这时可以采用具有周期性质的空间扩展函数描述(比如正弦)。当然描述块体材料的波函数并不一定采取空间扩展函数,也可以采用空间局域函数的线性叠加描述,采用前者只是处理起来更加方便。-------------------------------------------------------------------------------------编辑于 2020-04-30 22:51密度泛函理论量子化学计算物理学赞同 202 条评论分享喜欢收藏申请
如何评价水月雨耳机? - 知乎
如何评价水月雨耳机? - 知乎首页知乎知学堂发现等你来答切换模式登录/注册耳机耳机品牌入耳式耳机如何评价水月雨耳机?关注者250被浏览1,353,969关注问题写回答邀请回答好问题 191 条评论分享84 个回答默认排序虾扯蛋777随心而动 关注评价水月雨的耳机其实不用打多少字,要详细评价的其实是水月雨品牌。水月雨的耳机调音风格和方向相对统一,有较强的延续性,比如从KPE到KXXS,你不会觉得是两拨人做的两个完全不同的方案,而VXC等产品,你则依然可以找到大家玩的梗里说的“水式调音”,水月雨也乐于在宣传里披露自己耳机产品的频响图与主要设计思路,外观ID设计和命名风格则无疑是国产里的杠把子水平,偏向精致的日系风格。以前我听有个烧友说过,国产这些耳机和播放器的外观设计的上限是老板的文化和审美水平,我觉得确实是这么个道理,你看设计专业的学生都能拿出很惊艳的方案,为什么之前的国产产品设计大多数就这么土鳖呢?可不就是老板拍板方案的审美和水平露馅了。说完了简明扼要的对于水月雨耳机的评价,我要开启巨魔模式了。我并不算是一个水月雨的粉丝,实际上,我听的水月雨耳机产品也有好些了,但我个人并没有购入任何一个水月雨产品(笑),虽然我确实煽动和推荐了好些人去购买就是了。原因有不少,比如我并不喜欢KPE、KXXS 比较Bling Bling的外观设计风格,我自己持有的千元耳机是七彩虹的CH1,比较喜欢的外观设计也是这类源自IKKO OH1、OH10的风格,这个问题下有个用户说水月雨外观设计方面是低配版的Final,我不能再赞同,从水月、亚神对于日系ACG文化与审美的倾向就可以看出水月雨在外观设计方面的取向,而我个人并不是很喜欢这种精致的日系设计风格,我压根就不是一个Final产品的粉丝,如果偏粗粝和硬朗一点,比如使用一些磨砂和粗线条的元素的话,我可能会考虑购买的,事实上,我确实差点就下单KXXS了,在撺掇基友买了之后我白嫖了好几天,还是没能下得去这个手,外观是一方面,另一方面的原因是,在千元这个价位上,我更喜欢“有性格”一些的声音,KXXS及KPE的声音对于我都太过于“稳”了,至于水月雨更高阶的产品,我的评价又是不一样的,Blessing1代,我觉得这个曾是1999价位的圈铁耳机产品水平其实与奥斯特锐的1299的KC07相当,并不能让我有掏钱的兴致,但实际上这个产品也有受线材拖累的原因,而A8,我近来听了几天从朋友那白嫖的S8,具体看我文章的感受和吐槽。毫无疑问,S8的完成度比A8要更高,声音润得一逼(笑),我已经不太想评价A8了,A8这个产品同样换线也有很大潜力,水月雨也同样在做线材的生意,这方面的产品没实际接触过,但据朋友所说有些线确实算是比较良心的。我主要想说的,是水月雨的营销,及其粉丝。在有的极端水月雨粉丝,或者说极端龙人群体看来,我应该算是一个魔法师,而不是一个他们眼中的科学派/理性派HIFI用户,我发现这一点是因为当我用文字交流听感的时候,竟然被一些极端龙人给喷了,我当时觉得非常奇怪,国标IEC/TR 60268-13我也是知道的,我表达听感用的词汇也没有玄学难懂的二级词汇如什么“黄昏声”、“模拟味”、“厅堂感”,我用的表达相当克制,我本人也是比较鄙视那种满口上世纪音响杂志语汇和深受刘汉盛影响的“老烧”的,然而我还是被喷成“老烧”了,我觉得非常魔幻,因为在真正的那些听港台老歌满嘴hu话的“老烧”看来,我其实算是他们眼中的云烧友、极端数据党小白,我当时心想,这下我里外不是人?我知道数学是宇宙间最接近真理的东西,但是这帮人真想纯粹用数字来进行交流了?HIFI在他们眼中就是数0游戏?如果粗暴地将HIFI玩家与厂商划分成科学与魔法阵营,那毫无疑问水月雨是科学阵营,当我还是一个以创新Live!和飞利浦SHP9500入门的小白时,我就在知乎上关注了亚神与水月,知乎上的HIFI内容并不多,但在亚神强有力的影响下,总体来说是比较理性的,虽然量不多,但比下有余,质还是比现在的大家坛、2jb之流要能看得多,说是以一人之力掀起HIFI讨论的热潮也不为过,水月雨的营销也非常地现代、透明和高效,如果你是一个和我一样经历差不多的初烧玩家,你很难不被这种氛围所影响,大家可以畅所欲言地讨论自己的观点与好恶,产品的好坏,直接通过直观有效的测量数据进行交流,非常简单和高效,这比太多的充斥着文学作派的地方要好得多,但为什么我不能直接表达对这类龙人群体的认可呢?假如我是一个工程师,嗯,我看到仪器上显示这里有诡异的峰谷,那我就要把它弄好,这很自然,仪器比起人耳有一定的可靠性,必须参考这个,但是作为普通烧友,我认为,你听得出就是听得出,听不出,那即使测量数据对你有争议,那其实也是问题不大的,像歌德,没有错,测量看起来一塌糊涂,但毫无疑问它听一部分的音乐也真的挺好听(没有问题,它很好听——喵帕斯),那就有其存在价值,尽管高端歌德耳机的边际效应有点严重吧……这是经验主义跟科学作派的分歧,就不展开了。大多数龙人也是普通的年轻人初烧而已,其中大部分是空闲时间很多的有点闲钱的学生,空闲时间很多,加上学生身份,这两点结合起来,很自然的,这意味着表达欲就会比较旺盛,自我意识多多少少会过剩一点,而手里的金钱和自己的时间跟不上旺盛的表达欲会如何呢?我要说很难听的话了,那这部分龙人很可能就会“云“。无论是满嘴hu话(上世纪音响杂志语汇)的老烧,还是崇尚科学的理性派发烧友,大家对“云烧”的厌恶是共同的,我不是一点都不懂数据,而是我觉得,现在的测量数据,真的能百分百反映产品的性能吗?这是我一些比较理性的数码玩家朋友的疑惑,他们一直徘徊在HIFI发烧的门口,就因为他们对一些基本的东西比较执拗,比如一个显示器,确实可以通过产品的基本参数、真实理性评测和使用感受很轻松地进行选购了,但一个耳机,通过厂商披露的基本参数,通过瀑布图和频响曲线,通过贴吧论坛的听感分享,你是完全没法有效窥知这个产品的基本面貌的!比如说线材,明明换了有可闻的提升,但其实两根线的电气性能没有大差!像戴工的群,甚至非常滑稽地禁止讨论线材(不是戴工禁的),这在我的朋友看来就非常地奇怪和不可靠,真他妈玄学……所以他们一直没进这个门,在龙人看来,借助测量数据已经可以比较有效地筛选产品,但在我的那些圈外人数码爱好者朋友他们看来,水,还是太深了。科学派HIFI的兴起,确实滤干净了好大一部分水分,能筛去许多无谓的高溢价和智商税产品,使得我们可以更有效地区筛选产品,从中找到自己想要的产品,这是好事,然而,一部分极端龙人在我看来,完全不是这么想的,他们玩HIFI的方式,大概是手持亚神推崇的小4,时不时水个群吹个水,看看亚神又在吹什么新品种,好云一下测量数据,然后当作是自己听过一样到处大肆评价,打出各种廉价设备秒超平的神论,还带着水月雨的牌子出去招摇,使得本来对水月雨保有可笑成见和错误看法的人更加巩固了他们的观点,增加了隔阂,这能怪谁呢?我不知道郑老板的具体看法是怎么样的,对于我,我真的很鄙视很鄙视这部分龙人,这群极端龙人被戏称为HIFI警察是有其原因的。作为大部分手里没有AP也不会测量的普通发烧友来说,甚至你真的有仪器,你也真的会测量,听一下,听一下……也是在你评价产品之前绝对必要的,通过瀑布图和频响曲线,真的不能了解一个产品的实际面貌,比如说,亚神推崇的小4,没错,音色是比较正,但小4这耳机的动态表现实在是不咋地……音色确实比较正,设计思路比较科学,但是听起摇滚和金属真的不是很带感……肯定是有其局限性的,但有些龙人只是看亚神比较推崇就把这东西当作放之四海而皆准的东西到处吹上天了。你看,光是动态这一个东西,你就没法从瀑布图和频响曲线中实际感知了吧?更别提声音的表现是由多个子项构成的,这群极端龙人对如何联系测量数据和听感真的会有很多造诣么……用下面想想都知道,如果你不是手里有不少闲钱,不是有一群手里有钱的发烧友朋友,并不是居住在有可免费试听的代理商的发达城市,你是没什么太多机会听到很多产品的,但很多龙人怎么会有这么多奇怪而又言之凿凿的见解呢……我不想把话说得太难听了,我就这么说,身为一个普通的发烧友,如果你只是看了频响曲线,发现这里有峰那里有谷,或者发现这是深V(微笑)曲线,然后你就装模作样地表现出自己能听出来的样子,那我真的很诧异,你真的能保证,你在没看过测量图表数据的情况下能听出这个产品的不妥么?我觉得大部分人没有这个能力,专业的从业人员也要每天聆听一定的素材和量保证自己的审听能力和状态,那为什么不是专业的龙人却看着会有比肩亚神和戴工专业的审听能力呢?切实地提升自己的审听能力,比不知所谓地云一通强得多。说回水月雨本身,我知道上面这一大通带有个人情绪和抱怨,说得比较水,我知道这不是水月雨能控制的,从声学的比方来说,有信号的同时就一定会有噪声,从传播学意义上来说,这些也是难以避免的副产品,厂商也难以控制,我能理解,营销术语和实在话我也能分清,这个我能理解,HIFI这圈子的魅力之一确实就是它的多样性,如果HiFi这圈子真有什么“原教旨”的东西,那就是“多样性”,圈子里有相信自己的耳朵不看数据盘歌德的老烧,也有笃信测量数据的年轻发烧友,这些应该都去理解一下,不爽不要玩,不爽我就不会玩了呀,虽然确实有人对这些多样性确实是难以理解的,还把自己的偏见冠以原教旨HIFI之名……多样性非常重要,对某些以“我就是科学,听我的“的反”老烧“的姿态进入大家视野的KOL,请务必抱有警惕之心。我对水月雨是始终保有关注的,无他,诚恳,实在,以及产品力确实强大,在两三年内进步到如此地步,只能说一声敬佩,要知道水月、亚神其实也就是我的同龄人而已。我对水月雨的期待改进主要有以下几点:1、 切实改进品控,水月雨产品的性能一致性还不是一流水准,我听过不同的几个同一型号的水月雨耳机但音色有明显的不一样,这个有不少烧友反映过了;2、 切实改进质量,我之前推荐过别人购买KPE,结果不到半年(水月雨的保修期限)偏音了,此外滤网堵塞之类的小毛病也不少,我知道这是需要时间来沉淀和改进的,但是如果情况很长一段时间都是这样的话,就意味着我很难跟朋友推荐,因为他们万一出现问题,我就要当客服了;3、 能做出破圈的产品,之前在圈内名气比较大的银色飞船算是比较有这个方面潜力的,亲民的售价,以及在这个强大的声音表现……但是,品控和质量始终不过关,看一下后来者比如余音的一些产品,真的要加油了,像一些乐队,我都很欣赏他们破圈的表现,很欣赏他们能赢得核心乐迷以外更广大受众的表现,我也希望水月雨能做出这样的产品,以走量的破圈产品的利润反哺真正能代表自己风格的产品的研发,我算是一个飞傲的粉丝,说起来逼格尽丧,我喜欢飞傲的一点是虽然他们的产品并不极致,但却是实打实的破圈产品,是切实把市场做大的产品,比较想看到水月雨也有能破圈的产品,让大多数数码爱好者也能放心掏钱购买,把盘子做大;4、 走量产品的风格能更加地“大众化”,比如不要过分攀二刺螈这颗大树,即使是年轻人,真的也不都是都喜欢二刺螈的,产品的包装和配件希望能向国产里的大厂比如飞傲和达音科靠拢,飞傲的耳机虽然是随缘调音,但是开箱看到配件的琳琅满目和精美真的给人一种国际大厂的唬人感觉,外观设计方面,摆脱一些日系的桎梏,风格更加多样化一些,真的对于我这种审美的烧友来说挺好的,反正肯定不是坏事;5、 在我喜欢的播放器、直推/蓝牙头戴上希望能做出产品,声音上我对水月雨有信心,外观上我抱有更多的期待,比如播放器,现在的国砖播放器,多多少少真的还是摆脱不了艾利和/索尼Like的影子……水月雨的冉冉升起当然离不开这一代手里有些闲钱,并且手持廉价设备想跟“老烧”抢夺圈子内话语权的年轻人,这部分人群的数量还是挺多的,HIFI这圈子的多样性是非常丰富的,覆盖人群也极为广泛,而水月雨的针对受众是极其精准的,这是水月雨成功的一个原因,只是随着水月雨越做越大,受众的类型也会扩大,这部分受众比较极端的部分一定会有被背叛的感觉,水月雨伴随着这种营销的滋养和反噬不断壮大,这是已经发生的过去和还会继续发生的未来。虽然我大开地图炮,但也别觉得我有多么愤世嫉俗,我只是像阐述自己不太喜欢的音乐风格那样来说这些事情,我尊重HIFI生态圈的多样性,我就不像龙人那样习惯性催促REF3了,Stand By MOONDROP,支持水月和亚神,期待我购买第一个水月雨产品的那天尽早到来。编辑于 2020-04-10 22:09赞同 36910 条评论分享收藏喜欢收起不净猫Under the water 关注没听过早期产品,买过听过的加起来大概五六副左右吧。作为小透明有幸蹭过水月雨两位核心人物的饭,听过他们自身的一些关于业界和hifi的见解,很涨姿势。总的来说声音是有想法的,而且风格和方向比较统一,比起某些谜之调音和随缘出货的同行要高上不少,在大家还在强调老一套文学派宣传的时候率先引入曲线之类的理性因素和客观指标,这点值得尊敬。声价比在同行里我觉得算比较高的,比较有意思的一点就是他们出新品的话旧产品退市的十分干脆,其实是好事。可以押金试听这个好评,外观设计属于还不错的层次,虽然不一定符合我的审美,但是看上去没那么村炮又不那么杀马特。品控堪忧,品控堪忧,品控堪忧。今年感觉扭转了营销的方向,某种程度上更接近同行的操作了,可能做大了很多东西是要衡量的。老板的言论其实还是挺诚恳的,只是有些东西,在商言商,大家没必要太在意或者给他立人设。圈子不大,都要恰饭,还有些低头不见抬头见的人际交往问题。作为烧友,互相理解,作为消费者,有些话挑着听,完事了。他们是烧友,也是商人,这两个身份并不矛盾。编辑于 2019-12-12 18:22赞同 719 条评论分享收藏喜欢
VXC系列"S model" - 雅马哈(Yamaha)中国
VXC系列"S model" - 雅马哈(Yamaha)中国
My Account
global navigation
产品
钢琴
电子键盘
吉他、贝斯和音箱
鼓乐器
管乐器 · 吹奏乐器
弦乐器
打击乐器
合成器及音乐制作产品
家庭音响
专业音响
会议系统
App应用程序
高尔夫
车载音响
音乐服务
新闻活动
经销商查询
客户服务
企业用户
关于雅马哈
加入我们
产品
产品
钢琴
电子键盘
吉他、贝斯和音箱
鼓乐器
管乐器 · 吹奏乐器
弦乐器
打击乐器
合成器及音乐制作产品
家庭音响
专业音响
会议系统
App应用程序
高尔夫
车载音响
音乐服务
新闻活动
经销商查询
客户服务
企业用户
关于雅马哈
加入我们
Search this site
发送
搜索
专业音响
Toggle navigation
新闻活动
特别推荐
首页
产品
专业音响
扬声器
吸顶安装扬声器
VXC系列"S model"
VXC系列"S model"
概要
系列介绍
系统
产品参数
相关下载
更多服务
概要
概要
系列介绍
系统
产品参数
相关下载
更多服务
自然延伸的低音,把音乐带入生活
VXC系列的“S model”吸顶超低音扬声器是搭配VXS和VXC系列扬声器的理想之选,可在不破坏建筑室内设计的前提下,以卓越的音质平滑地扩展低频范围,实现更响、更真实的音乐在线。
VXC系列"S model"
VXC系列"S model"
[吸顶安装扬声器]
立即购买
VXC系列的“S model”吸顶超低音扬声器是搭配VXS和VXC系列扬声器的理想之选,可在不破坏建筑室内设计的前提下,以卓越的音质平滑地扩展低频范围,实现更响、更真实的音乐在线。
产品信息如有变动,恕不另行通知。网站上信息仅供参考,一切以具体实物为准。
产品信息
VXC8SB / VXC8SW
吸顶安装扬声器
VXC8SB / VXC8SW
吸顶安装扬声器
8" 吸顶超低音扬声器
与VXS和VXC系列理想匹配的声音和尺寸
带通设计确保平滑、无失真的低频延伸
直接支持低阻抗或高阻抗连接
内置便携带。提升安装过程中的安全性
防跌落拉环结构可在安装过程中提供安全的临时定位
双螺纹扬声器夹紧螺钉可用于快速拧紧
带磁铁锁扣的喷漆格栅
黑白双色可供选择
8.7kg(19.2lbs),Ø324 x D314 mm(Ø12-13/16" x D12-23/64")
需要AB-C8S(另售)以确保VXC8S的安全安装
AB-C8S
配件
AB-C8S
配件
用于VXC8S的O形环 + 导轨套件
需要AB-C8S(另售)以确保VXC8S的安全安装
相关产品
XMV系列
MA/PA 系列
VXC系列"F model"
MRX7-D
MTX系列
VXS系列
VXC系列
满足所有低频需求的型号选择
奢华的低音响应可以显著增强音乐的存在感和真实感。VXC系列S model的外壳采用带通设计,可减少不必要的振动和噪音,实现更高的声压级。
VXC8S的带通结构
智能设计,只为更安全、更快速的安装
VXC-S吸顶扬声器具有智能的机械功能,可显著提升安装的安全性和速度。由于这些型号同时支持低阻抗和高阻抗连接,可最大程度减小对额外库存的需求,使得系统设计能够理想化地满足任何应用的需求。
便携带
防跌落突耳
定压或定阻
定压或定阻
VXC-F系列同时支持定压和定阻两种系统连接,即使在安装完成后,您也可以轻松调节音箱的功率。
携带便捷
携带便捷
内置的手提带不仅便于您随身携带音箱,也提升了梯子作业时的安全性。
安全安装
安全安装
防摔落装置能够妥善地将音箱保持在正确位置,确保整个安装过程安全、高效。除此之外,另有释放杆设计,可帮助工程师顺利地从天花板上移除扬声器。
快速安装
快速安装
用于音箱夹紧装置的双螺纹螺钉能够使音箱得到双重夹紧,但安装速度丝毫不逊色于传统螺钉。
流线型
流线型
音箱的栅格面罩在强力磁铁的作用下被牢牢固定在恰当的位置。防摔落线亦可确保面罩的稳定性。
可喷涂
可喷涂
您可以根据室内的装饰风格,任意对音箱面罩进行喷涂。
VXS/VXC系列喷涂指南
系统示例咖啡厅
使用VXC2F扬声器和MA2030a功率放大器,可以创建一套流线型、高性能的系统,并可在播放背景音乐时使用麦克风。增加一台PA2030a功率放大器和一个VXC8S吸顶超低音扬声器便可营造丰富的音乐氛围。
VXC8SB / VXC8SW
一般规格
音箱类型
带通式超低音音箱
频率范围(-10dB)
44 Hz - 200 Hz(半空间 2π)
标称覆盖角度
-
单元
LF-HF
8" Cone
额定功率
NOISE
100 W
PGM
200 W
PEAK
400 W
标称阻抗
8 Ω
变压器分接头
100V
60 W, 30 W, 15 W, 7.5 W
70V
60 W, 30 W, 15 W, 7.5 W, 3.8 W
SPL
变压器分接头
88 dB SPL(半空间 2π)
峰值(计算值)
114 dB SPL(计算值,1m)
I/O接口
Euroblock(4针)× 1(输入:+/-,loop-thru:+/-)
保护电路
荷载保护
全频功率限制,保护网络和音箱单元
表面处理
VXC8SB:黑色(约Munsell N3),VXC8SW:白色(约Munsell N9.3)
外形尺寸
直径
324 mm (12-13/16")
D
314 mm (12-23/64")
净重
8.7 kg (19.2 lbs)
开孔尺寸
Ø285 mm (Ø11-7/32")
所需天花板厚度
5 mm - 37 mm
附件
开孔模板
包装
单个包装
认证
UL1480, UL2043, NFPA70, CE, EAC, RoHS
EN54-24符合性
-
其他
导线管:Ø15.4 mm - Ø21.3 mm
可选购
AB-C8S:O形环 + 导轨套件
Data Sheet
Name
English
English
Data Sheet (VXC Series "S model")
—
[1.1MB]
声学建模数据
Name
English
English
EASE GLL Data for VXC Series Speakers (V3.0) - EASE Focus / EASE Address enabled
—
[229KB]
产品手册
Speakers for Commercial Installations
中文
English
VXC-S model
日本語
桌面壁纸
Yamaha Speakers (FRAME_ALL)
[下载]
Yamaha Speakers (FRAME_9CAT)
[下载]
Yamaha Speakers (FRAME_EACH)
[下载]
产品说明书
名称
English
English
VXC8SB_VXC8SW_AB-C8S Owner's Manual
—
[2.1MB]
VXS/VXC系列喷涂指南
—
[357KB]
NS-1
NS-1
NS-1 是一个功能强大且直观的系统配置和模拟工具,使NEXO和Yamaha用户能够配置和优化广泛的NEXO和Yamaha系统性能。
更多
其他(工程数据参数等)
名称
English
English
BIM Data for Revit (VXC4/VXC6/VXC8/VXC2F/VXC3F/VXC5F/VXC8S)
—
[2.9MB]
CAD Data (VXC8S global)
—
[717KB]
CAD Data (VXC8S Japan)
—
[714KB]
DME Library Files for VXC Series Speakers (V1.1)
—
[50KB]
General Speaker Data / EASE and EASE Focus Data for VXC Series (V2.1)
—
[346KB]
MTX/MRX Library Files for VXC Series Speakers (V1.1)
—
[55KB]
Processor settings for VXC Series Speakers
—
[240KB]
经销商查询
授权服务中心查询
说明书下载
产品注册
首页
产品
专业音响
扬声器
吸顶安装扬声器
VXC系列"S model"
×
产品
钢琴
电子键盘
吉他、贝斯和音箱
鼓乐器
管乐器 · 吹奏乐器
弦乐器
打击乐器
合成器及音乐制作产品
家庭音响
专业音响
会议系统
App应用程序
高尔夫
车载音响
音乐服务
雅马哈音乐中心
雅马哈流行音乐课程
雅马哈双排键电子琴教师俱乐部
雅马哈电子键盘专用教室
新闻活动
新闻活动首页
经销商查询
经销商查询首页
客户支持
常见问题(Q&A)
授权服务中心查询
雅马哈会员系统
雅马哈认证技师
下载与支持
经销商专区
雅马哈进口钢琴原产地信息查询
关于雅马哈
雅马哈集团
雅马哈中国
Global
联系我们
在线招聘
使用条款
隐私条款
Copyright© 2021 雅马哈乐器音响(中国)投资有限公司 版权所有 沪ICP备05040406号-1沪公网安备
31010602003422号
VXC | Schneider Electric
VXC | Schneider Electric
跳至主要内容
China
我们的品牌
购物车中的产品数量为
0
我的产品
购物车中的产品数量为
0
文档收藏
我要注册
User name
我们的品牌
0
文档的数量为
Cancel
主菜单
产品
主菜单
服务
主菜单
解决方案
主菜单
乐享品质家居
主菜单
支持
主菜单
公司信息与招聘
China
我们的品牌
我的产品
购物车中的产品数量为
0
文档收藏
购物车中的产品数量为
0
我要注册
User name
欢迎访问施耐德电气网站
欢迎访问我们的网站。
留在此网站
选择您的所在地
VXC电弧炉主电路断路器 属于 PacT Series电弧炉主电路断路器 我要采购联系支持人员阅读更多arrow2_down我要采购联系支持人员
需要帮助?
从此处开始!
立即找到答案。自行搜索解决方案,或者联系我们的专家。
获取支持
我们的客户关爱团队可为您提供详细信息、技术支持、投诉帮助等服务,请联系他们。
浏览常见问题解答
通过浏览与主题相关的常见问题解答 (FAQ),获取您需要的答案。
我要采购
开始在线采购咨询,专家将会与您联系!
接收订阅的电子邮件地址:
即刻从收件箱中收到施耐德电气的每月更新。
我同意通过电子邮件、短信、电话等方式接收施耐德电气及其关联公司的产品新闻和商业广告信息,并同意收集邮件打开和点击信息以衡量和改善通信性能。
商业营销数据保护与隐私声明。
电子邮件
请输入有效的电子邮件地址
我是一名...
我是一名...
零售商/门店
总包商
设计院
电气分销商
家装/工装电工
IT渠道合作伙伴
机器制造商/OEM
成套厂/盘厂
服务及软件提供商
建筑系统集成商
工业系统集成商
电力系统集成商
中小型企业(<1000人)
大型企业(>1000人)
房屋建筑商/开发商
消费者/个人
学生/求职者
订阅
快速链接
所有产品
解决方案
软件
+全生命周期服务
合作伙伴
EcoStruxure架构与平台
客户成功案例
职位搜索 opens in new Window
博客 opens in new Window
关于我们
公司介绍
人才招聘与职业发展
可持续发展
多元化
数据隐私和Cookie政策
可访问性
服务
现场服务
数字化服务
咨询和培训
软件
能源管理软件
工业自动化软件
数据中心软件
支持
需要帮助?点击此处开始
产品选型工具
产品文档和软件下载
浏览常见问题解答
Green Premium产品
联系我们
联系中心
获取支持
获取报价 opens in new Window
销售网点
查找施耐德电气办事处 opens in new Window
查找培训中心 opens in new Window
解决方案
自动化与电动出行
云计算和服务供应商
商业建筑
数据中心
食品与饮料
医疗
酒店
生命科学
机械
海事
矿业、采矿与冶金
电机管理
电力电网
交通
水务及环保公用事业
支持中心热线 4008101315
使用条款
京ICP备05053940号-6 opens in new Window
更改您的 cookies 设置
opens in new Window
©2024, Schneider Electric
感谢您的订阅
现在,您将是第一个了解施耐德电气最新动态的用户。您很快将收到欢迎辞。希望您会喜欢!
VXC – Vanguard FTSE Global All Cap ex Can ETF – ETF Stock Quote | Morningstar
VXC – Vanguard FTSE Global All Cap ex Can ETF – ETF Stock Quote | Morningstar
Skip to Content
Morningstar brands and products
Company
Get 7 Days Free
Sign In
Sign In
Topics Investing Ideas MarketsStocksFundsETFsBondsPortfolio
Markets
Stocks
Funds
ETFs
Bonds
Investing Ideas
Best Investments
Christine Benz’s Portfolios
Best Companies to Own
Best ETFs
Guide to 529 Plans
Asset Management Companies
Topics
Portfolio Construction
Economy
Sustainable Investing
Personal Finance
Retirement
For Advisors
Alternative Investments
Media
Podcasts
Free Email Newsletters
Morningstar Magazine
Videos
Investing Definitions
Just For Investors
Morningstar Investor
Morningstar Investor Newsletters
Legacy Portfolio Manager
Vanguard FTSE Global All Cap ex Can ETF
VXC
Morningstar Medalist
Rating
Medalist Rating as of
Jan 19, 2024 |
See Vanguard Investment Hub
Quote
Chart
Fund Analysis
Performance
Sustainability
Risk
Price
Portfolio
People
Parent
Morningstar’s Analysis VXC
Will VXC outperform in future?
Get our overall rating based on a fundamental assessment of the pillars below.
Start a 7-Day Free Trial
Process Pillar
The Process Pillar is our assessment of how sensible, clearly defined, and repeatable VXC’s performance objective and investment process is for both security selection and portfolio construction.
People Pillar
The People Pillar is our evaluation of the VXC management team’s experience and ability. We find that high-quality management teams deliver superior performance relative to their benchmarks and/or peers.
Parent Pillar
The Parent Pillar is our rating of VXC’s parent organization’s priorities and whether they’re in line with investors’ interests.
Summary
Process
People
Parent
Performance
Price
Low-cost exposure to the entire foreign stock market.
Daniel Sotiroff
Senior Analyst
Summary Vanguard FTSE Global All-Cap ex Canada Index ETF is an excellent choice for exposure to stocks listed outside of Canada. Its extensive portfolio and rock-bottom management expense ratio should prove tough to beat. by Daniel Sotiroff
Rated on Jan 19, 2024
Published on Jan 19, 2024
Start a 7-Day Free Trial
Unlock our full analysis with Morningstar Investor
Portfolio Holdings VXC
More VXC Holdings
Current Portfolio Date Jan 31, 2024 Equity Holdings — Bond Holdings — Other Holdings — % Assets in Top 10 Holdings 100.0
Top 10 Holdings
% Portfolio Weight
Market Value USD
Sector
Vanguard Large-Cap ETF
56.36 923.2 Mil —
Vanguard FTSE Dev AC ex Nrth Amer ETF
26.98 442.0 Mil —
Vanguard FTSE Emerging Markets ETF
9.77 160.0 Mil —
Vanguard Small-Cap ETF
6.72 110.1 Mil —
Future on E-mini S&P 500 Futures
0.16 2.6 Mil —
All ETFs by Morningstar Ratings
Morningstar Medalist Rating
Gold Silver Bronze
Morningstar Rating
5-Star 4-Star 3-Star 2-Star 1-Star
All ETFs by Classification
Asset Class
U.S. Equity Asset Allocation International Equity Sector Equity Alternative Commodities Taxable Bond Municipal Bond
Equity
Large Value ETFs Large Blend ETFs Large Growth ETFs Mid-Cap Value ETFs Mid-Cap Blend ETFs Mid-Cap Growth ETFs Small Value ETFs Small Blend ETFs Small Growth ETFs Real Estate ETFs Foreign Large Blend ETFs Foreign Small/Mid Blend ETFs Diversified Emerging Markets ETFs
Fixed-Income
Intermediate-Term Core Bond ETFs Intermediate-Term Core-Plus Bond ETFs Corporate Bond ETFs High Yield Bond ETFs Muni National Short-Term Bond ETFs Muni National Intermediate-Term Bond ETFs Muni National Long-Term Bond ETFs Ultrashort Bond ETFs
Fund Type
Index Funds Active Funds Target Risk ETFs
Sponsor Center
Transparency is our policy. Learn how it impacts everything we do
Read More
Transparency is how we protect the integrity of our work and keep
empowering investors to achieve their goals and dreams. And we have
unwavering standards for how we keep that integrity intact, from our
research and data to our policies on content and your personal data.
We’d like to share more about how we work and what drives our day-to-day business.
How we make money
We sell different types of products and services to both investment professionals
and individual investors. These products and services are usually sold through
license agreements or subscriptions. Our investment management business generates
asset-based fees, which are calculated as a percentage of assets under management.
We also sell both admissions and sponsorship packages for our investment conferences
and advertising on our websites and newsletters.
How we use your personal data
How we use your information depends on the product and service that you use and your relationship with us. We may use it to: Verify your identity, personalize the content you receive, or create and administer your account. Provide specific products and services to you, such as portfolio management or data aggregation. Develop and improve features of our offerings.Gear advertisements and other marketing efforts towards your interests. To learn more about how we handle and protect your data, visit our privacy center.
How we approach editorial content
Maintaining independence and editorial freedom is essential to our mission of
empowering investor success. We provide a platform for our authors to report on
investments fairly, accurately, and from the investor’s point of view. We also
respect individual opinions––they represent the unvarnished thinking of our people
and exacting analysis of our research processes. Our authors can publish views that
we may or may not agree with, but they show their work, distinguish facts from
opinions, and make sure their analysis is clear and in no way misleading or deceptive.
To further protect the integrity of our editorial content, we keep a strict separation
between our sales teams and authors to remove any pressure or influence on our analyses
and research.
Read our editorial policy to learn more about our process. Site Index What We Do All Products & Services Our Signature Methodologies Morningstar Investment Conference Company About Us Careers Diversity, Equity, & Inclusion Corporate Sustainability Newsroom Investor Relations Get Help Advertising Opportunities Feedback Reprints Global Contacts Affiliate Program
United States
© Copyright 2024 Morningstar, Inc. All rights reserved.
Dow Jones Industrial Average, S&P 500, Nasdaq, and Morningstar Index (Market Barometer) quotes are real-time.
Terms and Conditions Privacy Center Disclosures Member User Agreement Corrections Do Not Sell or Share My Personal Information Accessibility
VXC Series - Overview - Speakers - Professional Audio - Products - Yamaha - Africa / Asia / CIS / Latin America / Middle East / Oceania
VXC Series - Overview - Speakers - Professional Audio - Products - Yamaha - Africa / Asia / CIS / Latin America / Middle East / Oceania
global navigationglobal navigation
Products
Pianos
Keyboard Instruments
Guitars, Basses, & Amps
Drums
Brass & Woodwinds
Strings
Percussion
Marching Instruments
Synthesizers & Music Production Tools
Electronic Entertainment Instruments
Headphones
Audio & Visual
Professional Audio
Unified Communications
Apps for iOS and Android™
Music Education
News & Events
Artists
Distributors
Support
About Yamaha
Products
Products
Pianos
Keyboard Instruments
Guitars, Basses, & Amps
Drums
Brass & Woodwinds
Strings
Percussion
Marching Instruments
Synthesizers & Music Production Tools
Electronic Entertainment Instruments
Headphones
Audio & Visual
Professional Audio
Unified Communications
Apps for iOS and Android™
Music Education
News & Events
Artists
Distributors
Support
About Yamaha
Search this sitesendSearch
**
login
Overview
Features
Specs
Downloads
FAQ
Professional Audio
Toggle navigation
Downloads
News & Events
Case Studies
Training & Support
Special Contents
About
HomeProductsProfessional AudioSpeakersVXC Series
VXC Series
Where to buy
Overview
Features
Specs
Downloads
FAQ
A versatile lineup for clear consistent sound
Yamaha designed the new VXC and VXS speakers to accommodate a growing list of applications in the installation market. While these speakers deliver quintessential Yamaha sound quality, they have also been carefully designed for safe and easy installation. Featuring both ceiling and surface mount options, these speaker series include a comprehensive range of models that are available in either black or white, or can be painted to match the interior of any application.
Product Information
VXC8 / VXC8W
Ceiling speaker
VXC8 / VXC8W
Ceiling speaker
8" cone woofer with a 1" soft dome tweeter
VXC6 / VXC6W
Ceiling speaker
VXC6 / VXC6W
Ceiling speaker
6.5" cone woofer with a 0.75" soft dome tweeter
VXC4 / VXC4W
Ceiling speaker
VXC4 / VXC4W
Ceiling speaker
Full-range loudspeaker with a 4" driver
VXC8-VA / VXC8-VAW
Ceiling speaker
VXC8-VA / VXC8-VAW
Ceiling speaker
8" cone woofer with a 1" soft dome tweeter
VXC6-VA / VXC6-VAW
Ceiling speaker
VXC6-VA / VXC6-VAW
Ceiling speaker
6.5" cone woofer with a 0.75" soft dome tweeter
VXC4-VA / VXC4-VAW
Ceiling speaker
VXC4-VA / VXC4-VAW
Ceiling speaker
Full-range loudspeaker with a 4" driver
PK-C4B / PK-C4W
Speaker accessory
PK-C4B / PK-C4W
Speaker accessory
Pendant-mount kit for VXC4/VXC2F
Black and white versions available
Paintable cosmetic cover
*VXC4 units produced after October 2019 are compatible with the pendant-mount kit. Compatible units are identified by “PK-C” on the package.
Related Products
MA/PA Series
Lo-Z/Hi-Z switchable Class-D amplifiers that provide a smart simple audio solutions for any small to mid-sized applications.
VXC Series "F model"
VXC series "F model" low-profile ceiling speakers can easily adapt to the strictest installation limitations, ensuring superb audio performance wherever they’re placed.
VXC Series "S model"
VXC series "S models" are ceiling subwoofers that ideally complement the expressive natural sound of VXS and VXC series speakers without spoiling interior design.
VXS Series
The VXS Series lineup features two full-range models and two subwoofers, allowing you to choose the optimal model for a particular application and, if necessary, combine it with a subwoofer for venues that require a stronger bottom end.
VXS Series "F model"
VXS-F compact surface-mount speakers feature attractive, discreet design and premium sound tuning for refined background music in elegant spaces.
VXS Series "M model"
VXS series “M models” combine sophisticated sound and design in compact surface-mount speakers that will make a significant contribution to the most refined, elegant spaces.
VXS Series "S model"
VXS series "S models" are subwoofers that ideally complement the expressive natural sound of VXS and VXC series speakers.
XMV Series
XMV Series multi-channel power amplifiers combine Class-D efficiency with features designed specifically to benefit commercial installation sound systems.
MTX Series
MTX Series matrix processors are equipped with flexible processing functions that are essential to a wide variety of applications.
MRX7-D
Simple, flexible control for complex, high-capacity sound systems
Related Software
Commercial Installation Solutions Speaker Calculator (CISSCA)
By following only a few steps, you can estimate the required number of speakers in an optimal way for your project.
The colours and finishes shown may vary from those on the actual products. Some models may not be available in some countries.
Downloads
News & Events
Case Studies
Training & Support
Special Contents
About
HomeProductsProfessional AudioSpeakersVXC Series
×
Products
Pianos
Keyboard Instruments
Guitars, Basses, & Amps
Drums
Brass & Woodwinds
Strings
Percussion
Marching Instruments
Synthesizers & Music Production Tools
Electronic Entertainment Instruments
Headphones
Audio & Visual
Professional Audio
Unified Communications
Apps
Music Education
Music Education Top
News & Events
News & Events Top
Artists
Artists Top
Support
Contact Us
About Yamaha Music ID Registration
Warranty Information
Brochures and Catalogs
Manual Library
Firmware / Software Updates
Documents and Data
FAQs
Distributors
Distributors Top
About Yamaha
Corporate Information
Corporate Profile Video
Brand Promise
Yamaha Philosophy
Promises to Stakeholders
Brand and History
Investor Relations
Sustainability
Global
Africa / Asia / CIS / Latin America / Middle East / Oceania
Yamaha has recently identified various fake E-Commerce sites which use our brand name.
You can check the list of E-Commerce sites which are operated by our company and also the names of our authorized dealers and distributors in your country / region at our official website (https://www.yamaha.com/2/countries/).
Please be careful not to visit or make an order on the E-Commerce sites which are operated by third parties which have no relationship with us, our authorized dealers and distributors.
X
Contact Us
Terms of Use
Privacy Policy
Cookie Policy
© Yamaha Corporation.
VXC ETF Review (2023): VXC vs XAW head to head - Genymoney.ca
C ETF Review (2023): VXC vs XAW head to head - Genymoney.ca Skip to content Genymoney.ca: Make the Most of your Money Menu Personal Finance Best Savings Accounts Cash Back Net worth Updates Credit Cards Saving Money Investing TFSA RRSP RESP RDSP Dividend Investing and Income Updates DIY Investing Robo Advisors Tax Minimization FIRE & Passive Income Passive Income Financial Independence Retirement All Posts Menu Personal Finance Best Savings Accounts Cash Back Net worth Updates Credit Cards Saving Money Investing TFSA RRSP RESP RDSP Dividend Investing and Income Updates DIY Investing Robo Advisors Tax Minimization FIRE & Passive Income Passive Income Financial Independence Retirement All Posts VXC ETF Review (2023): VXC vs XAW Compared October 23, 2023February 3, 2023 TweetSharePin2 Since the VXC ETF is by far the largest holding in my Questrade portfolio, I thought I should do a VXC ETF review. In this post, I’ll go over what the VXC ETF is, what the top 10 holdings in the VXC ETF are, and the most recent VXC returns. I’ll also compare the VXC vs XAW ETF (XAW is probably more popular that VXC but I like to support Vanguard and I have other reasons to stick with VXC that you’ll read about below- maybe one day I’ll get one of those Vanguard mugs, haha). Last updated: February 2023 Now, this is important to note, VXC is not one of the ‘one ticket ETFs’ where it automatically rebalances for you (for example, the one ticket ETF you might be thinking of is VGRO ETF). I added VXC to my portfolio because my portfolio was heavily weighted in Canada (and not performing very well with growth) and I needed an easy way to invest outside Canada without having to be at the mercy of currency conversion. This was before the ‘one ticket portfolios’ as they were not available back then, and because I feel comfortable doing my own asset allocation and rebalancing, I continue to add to my VXC holdings in addition to my VTI ETF holdings. Table of Contents ToggleWhat is VXC?VXC Top 10 HoldingsVXC Market AllocationVXC ReturnsVXC FeesVXC Foreign Withholding TaxVXC vs XAW ETF (XAW ETF Review)VXC vs XAW Market Allocation ExposureVXC vs XAW Sector WeightingVXC Vs XAW Top 10 HOldingsVXC vs XAW Foreign Withholding TaxvXC vs XAW FeesVXC vs XAW Distribution FrequencyVXC Vs XAW PerformanceHow to Buy VXC in QuestradeReview of VXC ETF What is VXC? The VXC ETF stands for Vanguard FTSE Global All Cap ex Canada Index ETF, it tries to track the broad global equity index with focus on developed and emerging markets, outside of Canada. The inception date for VXC is June 30, 2014. VXC Has over $1 billion in assets under management. The distribution is quarterly, and are paid in January, April, July, and October of each year. The current distribution yield is about 1.71% as of February 2023. VXC is traded on the Toronto Stock Exchange and the currency is in CAD (Canadian dollars). Therefore you don’t have to worry about using Norberts Gambit to buy more ex-Canada with VXC or transferring money to your brokerage from your US dollar accounts in Canada. VXC Top 10 Holdings As of writing, the number of stocks included within VXC are 10,095. Talk about diversification. This post main contain affiliate links. Please see genymoney.ca’s disclaimer for more information. The top 10 holdings of VXC are mainly big US corporations. Most of VXC (22%) is comprised of technology stocks. Here are the top 10 holdings in the VXC ETF: Apple Microsoft Amazon Alphabet Class A Alphabet Class C Berkshire Hathaway Class B Exxon Mobil Corp United Health Group Inc. Tesla NVIDIA VXC Market Allocation What’s the market allocation for VXC ETF? It’s not a straight 50/50 US and international. In fact, it is about 60.4% US and the rest is ex-US. 60.4% USA (North America, excluding Canada) Japan 6.3 % China 3.8 % (emerging markets) Europe (UK, France, Germany, Switzerland) about 11.8% Australia 2.4% Taiwan 1.8% (considered emerging market) India 1.7% In total, the allocation for VXC with regards to emerging markets is 10.6%, Europe is 17%, and Pacific is 11.6%. If you wanted to add more emerging markets, you could also add VEE (this is what I do). VXC Returns The 12 month return on VXC is pretty good. Here’s what it compares to for the S&P500 and VEQT (a one ticket all equity ETF from Vanguard). This image is from my Wealthica Performance Power Up tab where you can easily keep track of how your portfolio is performing compared to a specific ETF, index, or stock. Wealthica is free to use, you can see my Wealthica review here. Let’s compare VXC vs VEQT (not an apples to apples comparison though). As you can see the 12 month returns as of writing are -3.10% for VXC. The 12 months return as of writing for VEQT are -2.84% (Canada has been outperforming the S&P500 as of late). If you had invested $10,000 on the date of inception in 2014, you would have doubled your money by now. VXC Fees The management fee of VXC is 0.20% and the MER (management expense ratio) is 0.21%. They recently reduced it in spring 2021 from 0.26% to 0.21%. When you buy this ETF you don’t pay both the management fee and the MER. What you pay in fees is the MER and the management fee is embedded into that. Therefore the fees for VXC is 0.22%. As of November 2019, Vanguard reduced the management fee from 0.25% to 0.20% to match Blackrock’s XAW (another ex-Canada ETF). VXC’s MER was higher than XAW still. However, in spring 2021, Vanguard quietly lowered the MER to 0.21%, which makes VXC cheaper than XAW (0.22%) now in terms of fees! VXC Foreign Withholding Tax Because VXC is an “ETF of ETFs” like a Russian nesting doll, and it has US-listed ETFs, distributions from VXC will be subject to foreign withholding tax. The ETF structure of VXC is comprised of these Vanguard ETFs VV, VIU.TO, VWO, and VB. Vanguard Large Cap ETF (VV), this is US listed Vanguard FTSE Developed All Cap ex North America Idx ETF (VIU.TO), this is Canadian listed Vanguard FTSE Emerging Market ETF (VWO), this is US listed Vanguard Small Cap ETF (VB), this is Canadian listed Because of the switch to VIU within VXC, it is similarly tax efficient when compared to XAW. Here’s a more detailed comparison between VXC vs XAW. VXC vs XAW ETF (XAW ETF Review) Seems like more people in the Canadian dividend investing community prefer Blackrock’s XAW ETF to Vanguard’s VXC ETF (case in point, assets under management for XAW is $1.86 billion and VXC is $1.41 billion). Probably XAW vs VXC is more popular because of the reddit effect too. For a long time, this was because iShares XAW ETF was more tax efficient compared to VXC and it had a lower MER than Vanguard. XAW stands for iShares Core MSCI All Country ex Canada Index ETF. I initially bought VXC because XAW wasn’t available yet. The Inception Year for XAW is 2015 and VXC launched in 2014. However, as of November 2019, Vanguard reduced their management fee to 0.20% from 0.25%, which is the same as Blackrock’s XAW. However, the MER is still 0.26% compared to 0.22% for XAW. VXC vs XAW Market Allocation Exposure Here is the exposure for XAW: Here is the market allocation for VXC as of February 2023. As you can see they are similar but slightly different. XAW has more United States exposure than VXC. VXC vs XAW Sector Weighting Here’s a comparison of the sector weighting (as of February 2023) as a percentage of market value between the VXC ETF and the XAW ETF. As you can see there’s a bit of a difference, VXC has more tech. SectorVXCXAWTechnology19.9%20.3%Financials14.5%14.48%Consumer Discretionary14.2%11.55%Industrials14.1%11.11%Health Care12.1%12.2%Consumer Staples6.4%7.12%Energy5.0%4.67%Basic Materials4.4%5.15% VXC Vs XAW Top 10 HOldings There’s a bit of a difference between the two for the top 10 holdings too (as of February 2032) VXC Top 10 HoldingsXAW Top 10 HoldingsAppleAppleMicrosoftMicrosoftAmazonAmazonAlphabet Class AAlphabet Class AAlphabet Class CTeslaBerkshire Hathaway Class BBerkshire Hathaway B SharesExxon Mobil CorpNVIDIAUnited Health GroupAlphabet Class CTeslaUnited Health GroupNVIDIAExxon Mobil Corp VXC vs XAW Foreign Withholding Tax At the same time in late 2019 when Vanguard lowered the management fee, Vanguard also changed structure of VXC composition by switching to VIU.TO to remove a second layer of taxation (so that the foreign withholding tax is reduced), making it similarly tax efficient to Blackrock’s XAW. As you can see from Justin Bender’s Canadian Portfolio Manager Foreign Withholding Tax Calculator, when you hold VXC or XAW in your TFSA or RRSP, you will have a foreign withholding tax rate of 0.31% for both. And a rate of 0.04%/0.03% for XAW and VXC respectively if you hold it in a taxable account. I don’t think that the MER of 0.23% for VXC is accurate though on his calculator spreadsheet. As you can see it is better to hold VXC or XAW in a taxable account, as part of tax efficient investing. vXC vs XAW Fees As of Spring 2021, VXC is cheaper than XAW for the MER. VXC’s MER is now 0.21% compared to XAW’s MER of 0.22%. Even though the MER for VXC was more expensive, VXC is 0.26% compared to XAW’s 0.22%, this difference is 0.04% which isn’t very much in the grand scheme of things. On $250,000 value of XAW or VXC, this difference of 0.04% is $80. On $500,000 invested with XAW or VXC this is $200. VXC vs XAW Distribution Frequency VXC pays their distributions quarterly (four times a year in January, April, July, and October). XAW pays their distributions twice a year on a semi- annual basis in January and June of each year. Personally I prefer to get paid quarterly (you can more frequently look forward to a payment) but obviously you’ll get paid just less frequently with XAW but the same amount annually. I love my VXC distribution income. VXC Vs XAW Performance However, VXC has outperformed XAW consistently since January 2016 (I picked an arbitrary year to compared back to). Total return on investment of 70.18% for VXC and 54.72% for XAW. Of course, the tax efficient changes and Management fee reduction from Vanguard didn’t happen until recently, but still, the numbers are pretty impressive and outweigh the MER difference and tax inefficiency, in my opinion. Here’s a comparison between returns from Vanguard Canada’s fund comparison tool. You can input any fund and compare the two. The first column is VXC and second column is XAW, the returns are average annual returns since inception. From his comment in January 2021, even Justin Bender from Canadian Portfolio Manager would recommend VXC now instead of XAW in light of the recent changes to the structure and recent reduction in management fees. Justin Bender from PWL Capital has created a Youtube video in September 2021 explaining the similarities and differences between VXC vs XAW and why he would pick VXC over XAW today. I use a dollar cost averaging approach when adding VXC to my portfolio because buying ETFs is free in Questrade (there are a few pennies charged here and there). This is great for me in my accumulation phase of investing. Selling an ETF would be regular commission charge in Questrade. Selling for capital gains is going to be a big pain in the butt tax time though with all my ETF purchases outside of my TFSA/ RRSP. How to Buy VXC in Questrade I use Questrade as my discount online brokerage and have been using it since 2009. In recent years, Questrade reduced the commissions to buy ETFs and made them essentially free to buy (minus some ECN fees). When you log in to Questrade: Click “Trade” Under “Order Entry” put in your Ticker Symbol (e.g. VXC.TO) Under quantity put in how many you want to buy This is dependent on how much you have to invest or how much you want to buy at that time How much each share of ETF costs For example, VXC.TO is $45.85 (as of March 8 2021), and you have $500 you want to buy $500/45.85= 11 shares Under “Quantity” put in 11 You can choose to do a limit order if you want to make sure you don’t spend more than $45.85 per share. Put this (or whatever amount you want) in the limit order box GTD (Good To Date) and put in the date (or stick it to Day if you have time to put in an order when the market is open) Then press “Buy” (and review the fees charged on your order) Et Voila, you are done! Review of VXC ETF In summary, I think that if you are comfortable doing some rebalancing of your portfolio and are comfortable with some element of DIY investing (as compared to going the robo advisor route), holding VXC would be a great addition to your portfolio in order to easily stray away from having too much invested in Canada. If you are on the fence between investing in XAW or VXC and you want some ex-Canada exposure in your portfolio (and don’t want to go a one ticket route) VXC looks like it is a better choice returns wise even though there is a higher MER. If you need a bit of a reminder on how to rebalance your portfolio (including calculations of exact number of shares you need to purchase to rebalance), using Passiv for ETF rebalancing is a free for the first year for Questrade users. Here’s my Passiv review. Since Canada makes up around 2% of the world’s GDP global economy, holding less Canada in your portfolio is a good idea. Many Canadians have too much Canada in their portfolio. That being said, many things like favourable tax treatment towards Canadian dividends and higher yield dividends make investing in Canadian companies quite tempting, and I’m not ready myself to reduce my allocation of Canadian companies in my portfolio to 2%! Related: Tangerine Global ETFs Review (Much respect for those who have the discipline to do though!) Do you own VXC or XAW for your ex-Canada? If not, how to you invest outside of Canada? Get the Young Money Bootcamp PDF FREE Free Dividend Yield Spreadsheet Tracker Download and Blog Updates genymoneyGYM is a 40 something millennial writing about personal finance since 2009 and interested in achieving financial freedom through disciplined saving, dividend and ETF investing, and living a minimalist lifestyle. Before you go, check out my recommendations page of financial tools I use to save and invest money. Don’t forget to subscribe for a free dividend yield spreadsheet and the free Young Money Bootcamp PDF. You might also be interested in: TweetSharePin2 Post navigation High-Interest Savings vs GIC? Where to Park Your Cash?The Guide on Tax Efficient Investing in Canada 17 thoughts on “VXC ETF Review (2023): VXC vs XAW Compared” Mr. Dreamer @ VibrantDreamer.com March 15, 2021 at 6:54 am It is funny after you told me some changes in VXC, I did some digging yesterday and found out about VXC’s changes. I wrote a similar blog to yours with the same final conclusion. I declared VXC as the winner even versus holding 3 ETF solutions (XUU – VIU – ZEM) directly. Reply genymoney March 15, 2021 at 2:02 pm @Mr. Dreamer- Nice! Welcome to Team $VXC! Now let’s get another $500 million AUM for VXC to catch up to XAW. Reply Mr. Dreamer March 15, 2021 at 7:39 pm Need to celebrate haha. I think, won’t be long before funds move from XAW to VXC. So many still don’t know about the changes (Obviously I was one of them). Reply jimmbboe March 16, 2021 at 12:07 am Thinking VXC myself. Thanks for the writeup! Reply genymoney March 18, 2021 at 12:03 am @jimmbboe- Welcome, glad you enjoyed it! Reply Dividendes & FNB March 17, 2021 at 11:43 pm Great analysis ! ???? I have both VXC into my TFSA + XAW into my RRSP and into my taxable account. Agree with you, I prefer to get paid 4 times a year than 2 times! Maybe the time to switch from XAW to VXC into my taxable account with my Wealthsimple Trade. Reply genymoney March 18, 2021 at 12:04 am @Dividends&FNB- Yeah, free up that precious registered account space. I’m planning to move some out too but have yet to do it, it’s on the to do list Reply genymoney March 22, 2021 at 12:28 am @Dividends & FNB- Thanks, glad you liked the analysis Reply michelle March 28, 2021 at 8:44 pm nice work on the comparison! would be interesting to see what the drawdowns were for both Reply genymoney March 29, 2021 at 12:20 am @Michelle- Do you mean from trough to peak? March 23 2020 to March 23 2021= VXC returns were 50.05% and XAW returns were 48.25%. Not much difference if you have a smaller amount invested in either, but if you’re taking $500,000 invested, that’s $9000 or 1.8% difference. Reply VLW April 20, 2021 at 12:53 pm Thanks for all your work. I’ve owned VXC since Jan 2015 and have been very happy with it’s performance. It is around 10% of my total portfolio. Reply genymoney April 20, 2021 at 10:41 pm @VLW- Nice. VXC is a huge portion of mine too. Glad you enjoyed this analysis. Reply VLW April 21, 2021 at 9:01 am You might want to update the information as I notice the MER for VXC on the Vanguard web site is now shown as 0.21%. XAW is still at 0.22%. Reply genymoney April 24, 2021 at 11:11 pm @VLW- Thanks! Will have a look at update accordingly. Reply genymoney April 24, 2021 at 11:26 pm @VLW- Amazing, they must have quietly lowered it! VXC is cheaper than XAW now. Though, the trailing yield of XAW is 1.39% and 12 month trailing yield of VXC is 1.34%, though when you look at total return, VXC is still > XAW. Reply VLW January 19, 2023 at 2:40 pm A quick update on VXC (I love this ETF). Morningstar currently rates it as “GOLD”. Think it’s time to buy a little more as 2022 was a poor year so highly likely that 2023 will be better. Reply genymoney January 23, 2023 at 10:54 am @VLW- It’s treating me like gold so far YTD in 2023, lol! I need to update this post. Reply Leave a Comment Cancel replyCommentName Email Website Δ This site uses Akismet to reduce spam. Learn how your comment data is processed. Popular Offers 1 Year GIC: 5.50%* Interest Get Offer Get your Free Dividend Yield Spreadsheet Tracker & Young Money Bootcamp PDF Get free blog updates Popular Posts 10 Easy Ways to Earn Passive Income in Canada Borrowell Review: A Free Credit Score in Canada Wealthica Review: A Canadian Version of Personal Capital? Step-By-Step Guide on How to Invest your TFSA with Questrade Best Way to Invest Money in Canada Investing for Millennials: A How to Guide The 5 Best Canadian Dividend Stocks to Invest In Rakuten Canada Review: Get Cash Back on Amazon.ca EQ Bank Review: Is It Safe? genymoney.caAbout Contact DISCLAIMER PRIVACY POLICY CategoriesPersonal Finance Saving Money Investing Passive Income Credit Cards Real Estate © 2024 Genymoney.caVC开发指南--Visual C++/MFC入门教程_《visual c++ mfc基础教程》王凯-CSDN博客
>VC开发指南--Visual C++/MFC入门教程_《visual c++ mfc基础教程》王凯-CSDN博客
VC开发指南--Visual C++/MFC入门教程
最新推荐文章于 2023-06-03 11:11:37 发布
immortal_mcl
最新推荐文章于 2023-06-03 11:11:37 发布
阅读量2k
收藏
3
点赞数
分类专栏:
VC/MFC
文章标签:
c++
mfc
windows
文档
dialog
command
VC/MFC
专栏收录该内容
25 篇文章
0 订阅
订阅专栏
VC开发指南
1.1 如何学好VC
这个问题很多朋友都问过我,当然流汗是必须的,但同时如果按照某种思路进行有计划的学习就会起到更好的效果。万事开头难,为了帮助朋友们更快的掌握VC开发,下面我将自己的一点体会讲一下:
1、需要有好的C/C++基础。正所谓“磨刀不误砍柴工”,最开始接触VC时不要急于开始Windows程序开发,而是应该进行一些字符界面程序的编写。这样做的目的主要是增加对语言的熟悉程度,同时也训练自己的思维和熟悉一些在编程中常犯的错误。更重要的是理解并能运用C++的各种特性,这些在以后的开发中都会有很大的帮助,特别是利用MFC进行开发的朋友对C++一定要能熟练运用。
2、理解Windows的消息机制,窗口句柄和其他GUI句柄的含义和用途。了解和MFC各个类功能相近的API函数。
3、一定要理解MFC中消息映射的作用。
4、训练自己在编写代码时不使用参考书而是使用Help Online。
5、记住一些常用的消息名称和参数的意义。
6、学会看别人的代码。
7、多看书,少买书,买书前一定要慎重。
8、闲下来的时候就看参考书。
9、多来我的主页。^O^
后面几条是我个人的一点意见,你可以根据需要和自身的情况选用适用于自己的方法。
此外我将一些我在选择参考书时的原则:
对于初学者:应该选择一些内容比较全面的书籍,并且书籍中的内容应该以合理的方式安排,在使用该书时可以达到循序渐进的效果,书中的代码要有详细的讲解。尽量买翻译的书,因为这些书一般都比较易懂,而且语言比较轻松。买书前一定要慎重如果买到不好用的书可能会对自己的学习积极性产生打击。
对于已经掌握了VC的朋友:这种程度的开发者应该加深自己对系统原理,技术要点的认识。需要选择一些对原理讲解的比较透彻的书籍,这样一来才会对新技术有更多的了解,最好书中对技术的应用有一定的阐述。尽量选择示范代码必较精简的书,可以节约银子。
此外最好涉猎一些辅助性的书籍。 1.2 理解Windows消息机制
Windows系统是一个消息驱动的OS,什么是消息呢?我很难说得清楚,也很难下一个定义(谁在嘘我),我下面从不同的几个方面讲解一下,希望大家看了后有一点了解。
1、消息的组成:一个消息由一个消息名称(UINT),和两个参数(WPARAM,LPARAM)。当用户进行了输入或是窗口的状态发生改变时系统都会发送消息到某一个窗口。例如当菜单转中之后会有WM_COMMAND消息发送,WPARAM的高字中(HIWORD(wParam))是命令的ID号,对菜单来讲就是菜单ID。当然用户也可以定义自己的消息名称,也可以利用自定义消息来发送通知和传送数据。
2、谁将收到消息:一个消息必须由一个窗口接收。在窗口的过程(WNDPROC)中可以对消息进行分析,对自己感兴趣的消息进行处理。例如你希望对菜单选择进行处理那么你可以定义对WM_COMMAND进行处理的代码,如果希望在窗口中进行图形输出就必须对WM_PAINT进行处理。
3、未处理的消息到那里去了:M$为窗口编写了默认的窗口过程,这个窗口过程将负责处理那些你不处理消息。正因为有了这个默认窗口过程我们才可以利用Windows的窗口进行开发而不必过多关注窗口各种消息的处理。例如窗口在被拖动时会有很多消息发送,而我们都可以不予理睬让系统自己去处理。
4、窗口句柄:说到消息就不能不说窗口句柄,系统通过窗口句柄来在整个系统中唯一标识一个窗口,发送一个消息时必须指定一个窗口句柄表明该消息由那个窗口接收。而每个窗口都会有自己的窗口过程,所以用户的输入就会被正确的处理。例如有两个窗口共用一个窗口过程代码,你在窗口一上按下鼠标时消息就会通过窗口一的句柄被发送到窗口一而不是窗口二。
5、示例:下面有一段伪代码演示如何在窗口过程中处理消息
LONG yourWndProc(HWND hWnd,UINT uMessageType,WPARAM wP,LPARAM) { switch(uMessageType) {//使用SWITCH语句将各种消息分开 case(WM_PAINT): doYourWindow(...);//在窗口需要重新绘制时进行输出 break; case(WM_LBUTTONDOWN): doYourWork(...);//在鼠标左键被按下时进行处理 break; default: callDefaultWndProc(...);//对于其它情况就让系统自己处理 break; } }
接下来谈谈什么是消息机制:系统将会维护一个或多个消息队列,所有产生的消息都回被放入或是插入队列中。系统会在队列中取出每一条消息,根据消息的接收句柄而将该消息发送给拥有该窗口的程序的消息循环。每一个运行的程序都有自己的消息循环,在循环中得到属于自己的消息并根据接收窗口的句柄调用相应的窗口过程。而在没有消息时消息循环就将控制权交给系统所以Windows可以同时进行多个任务。下面的伪代码演示了消息循环的用法:
while(1) { id=getMessage(...); if(id == quit) break; translateMessage(...); }
当该程序没有消息通知时getMessage就不会返回,也就不会占用系统的CPU时间。 图示消息投递模式
在16位的系统中系统中只有一个消息队列,所以系统必须等待当前任务处理消息后才可以发送下一消息到相应程序,如果一个程序陷如死循环或是耗时操作时系统就会得不到控制权。这种多任务系统也就称为协同式的多任务系统。Windows3.X就是这种系统。
而32位的系统中每一运行的程序都会有一个消息队列,所以系统可以在多个消息队列中转换而不必等待当前程序完成消息处理就可以得到控制权。这种多任务系统就称为抢先式的多任务系统。Windows95/NT就是这种系统。
1.3 利用Visual C++/MFC开发Windows程序的优势
MFC借助C++的优势为Windows开发开辟了一片新天地,同时也借助ApplicationWizzard使开发者摆脱离了那些每次都必写基本代码,借助ClassWizard和消息映射使开发者摆脱了定义消息处理时那种混乱和冗长的代码段。更令人兴奋的是利用C++的封装功能使开发者摆脱Windows中各种句柄的困扰,只需要面对C++中的对象,这样一来使开发更接近开发语言而远离系统。(但我个人认为了解系统原理对开发很有帮助)
正因为MFC是建立在C++的基础上,所以我强调C/C++语言基础对开发的重要性。利用C++的封装性开发者可以更容易理解和操作各种窗口对象;利用C++的派生性开发者可以减少开发自定义窗口的时间和创造出可重用的代码;利用虚拟性可以在必要时更好的控制窗口的活动。而且C++本身所具备的超越C语言的特性都可以使开发者编写出更易用,更灵活的代码。
在MFC中对消息的处理利用了消息映射的方法,该方法的基础是宏定义实现,通过宏定义将消息分派到不同的成员函数进行处理。下面简单讲述一下这种方法的实现方法:
代码如下 BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd) //{{AFX_MSG_MAP(CMainFrame) ON_WM_CREATE() //}}AFX_MSG_MAP ON_COMMAND(ID_FONT_DROPDOWN, DoNothing) END_MESSAGE_MAP() 经过编译后,代码被替换为如下形式(这只是作讲解,实际情况比这复杂得多): //BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd) CMainFrame::newWndProc(...) { switch(...) { //{{AFX_MSG_MAP(CMainFrame) // ON_WM_CREATE() case(WM_CREATE): OnCreate(...); break; //}}AFX_MSG_MAP // ON_COMMAND(ID_FONT_DROPDOWN, DoNothing) case(WM_COMMAND): if(HIWORD(wP)==ID_FONT_DROPDOWN) { DoNothing(...); } break; //END_MESSAGE_MAP() } }
newWndProc就是窗口过程只要是该类的实例生成的窗口都使用该窗口过程。
所以了解了Windows的消息机制在加上对消息映射的理解就很容易了解MFC开发的基本思路了。
1.4 利用MFC进行开发的通用方法介绍
以下是我在最初学习VC时所常用的开发思路和方法,希望能对初学VC的朋友有所帮助和启发。
1、开发需要读写文件的应用程序并且有简单的输入和输出可以利用单文档视结构。
2、开发注重交互的简单应用程序可以使用对话框为基础的窗口,如果文件读写简单这可利用CFile进行。
3、开发注重交互并且文件读写复杂的的简单应用程序可以利用以CFormView为基础视的单文档视结构。
4、利用对话框得到用户输入的数据,在等级提高后可使用就地输入。
5、在对多文档要求不强烈时尽量避免多文档视结构,可以利用分隔条产生单文档多视结构。
6、在要求在多个文档间传递数据时使用多文档视结构。
7、学会利用子窗口,并在自定义的子窗口包含多个控件达到封装功能的目的。
8、尽量避免使用多文档多视结构。
9、不要使用多重继承并尽量减少一个类中封装过多的功能。
1.5 MFC中常用类,宏,函数介绍
常用类
CRect:用来表示矩形的类,拥有四个成员变量:top left bottom right。分别表是左上角和右下角的坐标。可以通过以下的方法构造:
CRect( int l, int t, int r, int b ); 指明四个坐标
CRect( const RECT& srcRect ); 由RECT结构构造
CRect( LPCRECT lpSrcRect ); 由RECT结构构造
CRect( POINT point, SIZE size ); 有左上角坐标和尺寸构造
CRect( POINT topLeft, POINT bottomRight ); 有两点坐标构造
下面介绍几个成员函数:
int Width( ) const; 得到宽度 int Height( ) const; 得到高度 CSize Size( ) const; 得到尺寸 CPoint& TopLeft( ); 得到左上角坐标 CPoint& BottomRight( ); 得到右下角坐标 CPoint CenterPoint( ) const; 得当中心坐标 此外矩形可以和点(CPoint)相加进行位移,和另一个矩形相加得到“并”操作后的矩形。
CPoint:用来表示一个点的坐标,有两个成员变量:x y。 可以和另一个点相加。
CString:用来表示可变长度的字符串。使用CString可不指明内存大小,CString会根据需要自行分配。下面介绍几个成员函数:
GetLength 得到字符串长度 GetAt 得到指定位置处的字符 operator + 相当于strcat void Format( LPCTSTR lpszFormat, ... ); 相当于sprintf Find 查找指定字符,字符串 Compare 比较 CompareNoCase 不区分大小写比较 MakeUpper 改为小写 MakeLower 改为大写
CStringArray:用来表示可变长度的字符串数组。数组中每一个元素为CString对象的实例。下面介绍几个成员函数:
Add 增加CString RemoveAt 删除指定位置CString对象 RemoveAll 删除数组中所有CString对象 GetAt 得到指定位置的CString对象 SetAt 修改指定位置的CString对象 InsertAt 在某一位置插入CString对象
常用宏
RGB
TRACE
ASSERT
VERIFY
常用函数
CWindApp* AfxGetApp();
HINSTANCE AfxGetInstanceHandle( );
HINSTANCE AfxGetResourceHandle( );
int AfxMessageBox( LPCTSTR lpszText, UINT nType = MB_OK, UINT nIDHelp = 0 );用于弹出一个消息框
2.1 和GUI有关的各种对象
在Windows中有各种GUI对象(不要和C++对象混淆),当你在进行绘图就需要利用这些对象。而各种对象都拥有各种属性,下面分别讲述各种GUI对象和拥有的属性。
字体对象CFont用于输出文字时选用不同风格和大小的字体。可选择的风格包括:是否为斜体,是否为粗体,字体名称,是否有下划线等。颜色和背景色不属于字体的属性。关于如何创建和使用字体在2.2 在窗口中输出文字中会详细讲解。
刷子CBrush对象决定填充区域时所采用的颜色或模板。对于一个固定色的刷子来讲它的属性为颜色,是否采用网格和网格的类型如水平的,垂直的,交叉的等。你也可以利用8*8的位图来创建一个自定义模板的刷子,在使用这种刷子填充时系统会利用位图逐步填充区域。关于如何创建和使用刷子在2.3 使用刷子,笔进行绘图中会详细讲解。
画笔CPen对象在画点和画线时有用。它的属性包括颜色,宽度,线的风格,如虚线,实线,点划线等。关于如何创建和使用画笔在2.3 使用刷子,笔进行绘图中会详细讲解。
位图CBitmap对象可以包含一幅图像,可以保存在资源中。关于如何使用位图在2.4 在窗口中绘制设备相关位图,图标,设备无关位图中会详细讲解。
还有一种特殊的GUI对象是多边形,利用多边形可以很好的限制作图区域或是改变窗口外型。关于如何创建和使用多边形在2.6 多边形和剪贴区域中会详细讲解。
在Windows中使用GUI对象必须遵守一定的规则。首先需要创建一个合法的对象,不同的对象创建方法不同。然后需要将该GUI对象选入DC中,同时保存DC中原来的GUI对象。如果选入一个非法的对象将会引起异常。在使用完后应该恢复原来的对象,这一点特别重要,如果保存一个临时对象在DC中,而在临时对象被销毁后可能引起异常。有一点必须注意,每一个对象在重新创建前必须销毁,下面的代码演示了这一种安全的使用方法:
OnDraw(CDC* pDC) { CPen pen1,pen2; pen1.CreatePen(PS_SOLID,2,RGB(128,128,128));//创建对象 pen2.CreatePen(PS_SOLID,2,RGB(128,128,0));//创建对象 CPen* pPenOld=(CPen*)pDC->SelectObject(&pen1);//选择对象进DC drawWithPen1... (CPen*)pDC->SelectObject(&pen2);//选择对象进DC drawWithPen2... pen1.DeleteObject();//再次创建前先销毁 pen1.CreatePen(PS_SOLID,2,RGB(0,0,0));//再次创建对象 (CPen*)pDC->SelectObject(&pen1);//选择对象进DC drawWithPen1... pDC->SelectObject(pOldPen);//恢复 }
此外系统中还拥有一些库存GUI对象,你可以利用CDC::SelectStockObject(SelectStockObject( int nIndex )选入这些对象,它们包括一些固定颜色的刷子,画笔和一些基本字体。
BLACK_BRUSH Black brush.
DKGRAY_BRUSH Dark gray brush.
GRAY_BRUSH Gray brush.
HOLLOW_BRUSH Hollow brush.
LTGRAY_BRUSH Light gray brush.
NULL_BRUSH Null brush.
WHITE_BRUSH White brush.
BLACK_PEN Black pen.
NULL_PEN Null pen.
WHITE_PEN White pen.
ANSI_FIXED_FONT ANSI fixed system font.
ANSI_VAR_FONT ANSI variable system font.
DEVICE_DEFAULT_FONT Device-dependent font.
OEM_FIXED_FONT OEM-dependent fixed font.
SYSTEM_FONT The system font. By default, Windows uses the system font to draw menus, dialog-box controls, and other text. In Windows versions 3.0 and later, the system font is proportional width; earlier versions of Windows use a fixed-width system font.
SYSTEM_FIXED_FONT The fixed-width system font used in Windows prior to version 3.0. This object is available for compatibility with earlier versions of Windows.
DEFAULT_PALETTE Default color palette. This palette consists of the 20 static colors in the system palette. 这些对象留在DC中是安全的,所以你可以利用选入库存对象来作为恢复DC中GUI对象。
大家可能都注意到了绘图时都需要一个DC对象,DC(Device Context设备环境)对象是一个抽象的作图环境,可能是对应屏幕,也可能是对应打印机或其它。这个环境是设备无关的,所以你在对不同的设备输出时只需要使用不同的设备环境就行了,而作图方式可以完全不变。这也就是Windows耀眼的一点设备无关性。如同你将对一幅画使用照相机或复印机将会产生不同的输出,而不需要对画进行任何调整。DC的使用会穿插在本章中进行介绍。
2.2 在窗口中输出文字
在这里我假定读者已经利用ApplicationWizard生成了一个SDI界面的程序代码。接下来的你只需要在CView派生类的OnDraw成员函数中加入绘图代码就可以了。在这里我需要解释一下OnDraw函数的作用,OnDraw函数会在窗口需要重绘时自动被调用,传入的参数CDC* pDC对应的就是DC环境。使用OnDraw的优点就在于在你使用打印功能的时候传入OnDraw的DC环境将会是打印机绘图环境,使用打印预览时传入的是一个称为CPreviewDC的绘图环境,所以你只需要一份代码就可以完成窗口/打印预览/打印机绘图三重功能。利用Windows的设备无关性和M$为打印预览所编写的上千行代码你可以很容易的完成一个具有所见即所得的软件。
输出文字一般使用CDC::BOOL TextOut( int x, int y, const CString& str )和CDC::int DrawText( const CString& str, LPRECT lpRect, UINT nFormat )两个函数,对TextOut来讲只能输出单行的文字,而DrawText可以指定在一个矩形中输出单行或多行文字,并且可以规定对齐方式和使用何种风格。nFormat可以是多种以下标记的组合(利用位或操作)以达到选择输出风格的目的。
DT_BOTTOM底部对齐 Specifies bottom-justified text. This value must be combined with DT_SINGLELINE.
DT_CALCRECT计算指定文字时所需要矩形尺寸 Determines the width and height of the rectangle. If there are multiple lines of text, DrawText will use the width of the rectangle pointed to by lpRect and extend the base of the rectangle to bound the last line of text. If there is only one line of text, DrawText will modify the right side of the rectangle so that it bounds the last character in the line. In either case, DrawText returns the height of the formatted text, but does not draw the text.
DT_CENTER中部对齐 Centers text horizontally.
DT_END_ELLIPSIS or DT_PATH_ELLIPSIS Replaces part of the given string with ellipses, if necessary, so that the result fits in the specified rectangle. The given string is not modified unless the DT_MODIFYSTRING flag is specified. You can specify DT_END_ELLIPSIS to replace characters at the end of the string, or DT_PATH_ELLIPSIS to replace characters in the middle of the string. If the string contains backslash (/) characters, DT_PATH_ELLIPSIS preserves as much as possible of the text after the last backslash.
DT_EXPANDTABS Expands tab characters. The default number of characters per tab is eight.
DT_EXTERNALLEADING Includes the font抯 external leading in the line height. Normally, external leading is not included in the height of a line of text.
DT_LEFT左对齐 Aligns text flush-left.
DT_MODIFYSTRING Modifies the given string to match the displayed text. This flag has no effect unless the DT_END_ELLIPSIS or DT_PATH_ELLIPSIS flag is specified. Note Some uFormat flag combinations can cause the passed string to be modified. Using DT_MODIFYSTRING with either DT_END_ELLIPSIS or DT_PATH_ELLIPSIS may cause the string to be modified, causing an assertion in the CString override.
DT_NOCLIP Draws without clipping. DrawText is somewhat faster when DT_NOCLIP is used.
DT_NOPREFIX禁止使用&前缀 Turns off processing of prefix characters. Normally, DrawText interprets the ampersand (&) mnemonic-prefix character as a directive to underscore the character that follows, and the two-ampersand (&&) mnemonic-prefix characters as a directive to print a single ampersand. By specifying DT_NOPREFIX, this processing is turned off.
DT_PATH_ELLIPSIS
DT_RIGHT右对齐 Aligns text flush-right.
DT_SINGLELINE单行输出 Specifies single line only. Carriage returns and linefeeds do not break the line.
DT_TABSTOP设置TAB字符所占宽度 Sets tab stops. The high-order byte of nFormat is the number of characters for each tab. The default number of characters per tab is eight.
DT_TOP定部对齐 Specifies top-justified text (single line only).
DT_VCENTER中部对齐 Specifies vertically centered text (single line only).
DT_WORDBREAK每行只在单词间被折行 Specifies word-breaking. Lines are automatically broken between words if a word would extend past the edge of the rectangle specified by lpRect. A carriage return杔inefeed sequence will also break the line.
在输出文字时如果希望改变文字的颜色,你可以利用CDC::SetTextColor( COLORREF crColor )进行设置,如果你希望改变背景色就利用CDC::SetBkColor( COLORREF crColor ),很多时候你可能需要透明的背景色你可以利用CDC::SetBkMode( int nBkMode )设置,可接受的参数有
OPAQUE Background is filled with the current background color before the text, hatched brush, or pen is drawn. This is the default background mode.
TRANSPARENT Background is not changed before drawing.
接下来讲讲如何创建字体,你可以创建的字体有两种:库存字体CDC::CreateStockObject( int nIndex )和自定义字体。在创建非库存字体时需要填充一个LOGFONT结构并使用CFont::CreateFontIndirect(const LOGFONT* lpLogFont )(可以参考文章在同一系统中显示GB字符和BIG5字符),或使用CFont::CreateFont( int nHeight, int nWidth, int nEscapement, int nOrientation, int nWeight, BYTE bItalic, BYTE bUnderline, BYTE cStrikeOut, BYTE nCharSet, BYTE nOutPrecision, BYTE nClipPrecision, BYTE nQuality, BYTE nPitchAndFamily, LPCTSTR lpszFacename )其中的参数和LOGFONT中的分量有一定的对应关系。下面分别讲解参数的意义:
nHeight 字体高度(逻辑单位)等于零为缺省高度,否则取绝对值并和可用的字体高度进行匹配。 nWidth 宽度(逻辑单位)如果为零则使用可用的横纵比进行匹配。 nEscapement 出口矢量与X轴间的角度 nOrientation 字体基线与X轴间的角度 nWeight 字体粗细,可取以下值 Constant Value FW_DONTCARE 0 FW_THIN 100 FW_EXTRALIGHT 200 FW_ULTRALIGHT 200 FW_LIGHT 300 FW_NORMAL 400 FW_REGULAR 400 FW_MEDIUM 500 FW_SEMIBOLD 600 FW_DEMIBOLD 600 FW_BOLD 700 FW_EXTRABOLD 800 FW_ULTRABOLD 800 FW_BLACK 900 FW_HEAVY 900
bItalic 是否为斜体 bUnderline 是否有下划线 cStrikeOut 是否带删除线 nCharSet 指定字符集合,可取以下值 Constant Value ANSI_CHARSET 0 DEFAULT_CHARSET 1 SYMBOL_CHARSET 2 SHIFTJIS_CHARSET 128 OEM_CHARSET 255
nOutPrecision 输出精度 OUT_CHARACTER_PRECIS OUT_STRING_PRECIS OUT_DEFAULT_PRECIS OUT_STROKE_PRECIS OUT_DEVICE_PRECIS OUT_TT_PRECIS OUT_RASTER_PRECIS
nClipPrecision 剪辑精度,可取以下值 CLIP_CHARACTER_PRECIS CLIP_MASK CLIP_DEFAULT_PRECIS CLIP_STROKE_PRECIS CLIP_ENCAPSULATE CLIP_TT_ALWAYS CLIP_LH_ANGLES
nQuality 输出质量,可取以下值
DEFAULT_QUALITY Appearance of the font does not matter.
DRAFT_QUALITY Appearance of the font is less important than when PROOF_QUALITY is used. For GDI raster fonts, scaling is enabled. Bold, italic, underline, and strikeout fonts are synthesized if necessary.
PROOF_QUALITY Character quality of the font is more important than exact matching of the logical-font attributes. For GDI raster fonts, scaling is disabled and the font closest in size is chosen. Bold, italic, underline, and strikeout fonts are synthesized if necessary. nPitchAndFamily 字体间的间距 lpszFacename 指定字体名称,为了得到系统所拥有的字体可以利用EmunFontFamiliesEx。(可以参考文章在同一系统中显示GB字符和BIG5字符)
此外可以利用CFontDialog来得到用户选择的字体的LOGFONT数据。
最后我讲一下文本坐标的计算,利用CDC::GetTextExtent( const CString& str )可以得到字符串的在输出时所占用的宽度和高度,这样就可以在手工输出多行文字时使用正确的行距。另外如果需要更精确的对字体高度和宽度进行计算就需要使用CDC::GetTextMetrics( LPTEXTMETRIC lpMetrics ) 该函数将会填充TEXTMETRIC结构,该结构中的分量可以非常精确的描述字体的各种属性。
2.3 使用点,刷子,笔进行绘图
在Windows中画点的方法很简单,只需要调用COLORREF CDC::SetPixel( int x, int y, COLORREF crColor )就可以在指定点画上指定颜色,同时返回原来的颜色。COLORREF CDC::GetPixel( int x, int y)可以得到指定点的颜色。在Windows中应该少使用画点的函数,因为这样做的执行效率比较低。
刷子和画笔在Windows作图中是使用最多的GUI对象,本节在讲解刷子和画笔使用方法的同时也讲述一写基本作图函数。
在画点或画线时系统使用当前DC中的画笔,所以在创建画笔后必须将其选入DC才会在绘图时产生效果。画笔可以通过CPen对象来产生,通过调用CPen::CreatePen( int nPenStyle, int nWidth, COLORREF crColor )来创建。其中nPenStyle指名画笔的风格,可取如下值:
PS_SOLID 实线 Creates a solid pen.
PS_DASH 虚线,宽度必须为一 Creates a dashed pen. Valid only when the pen width is 1 or less, in device units.
PS_DOT 点线,宽度必须为一 Creates a dotted pen. Valid only when the pen width is 1 or less, in device units.
PS_DASHDOT 点划线,宽度必须为一 Creates a pen with alternating dashes and dots. Valid only when the pen width is 1 or less, in device units.
PS_DASHDOTDOT 双点划线,宽度必须为一 Creates a pen with alternating dashes and double dots. Valid only when the pen width is 1 or less, in device units.
PS_NULL 空线,使用时什么也不会产生 Creates a null pen.
PS_ENDCAP_ROUND 结束处为圆形 End caps are round.
PS_ENDCAP_SQUARE 结束处为方形 End caps are square.
nWidth和crColor为线的宽度和颜色。
刷子是在画封闭曲线时用来填充的颜色,例如当你画圆形或方形时系统会用当前的刷子对内部进行填充。刷子可利用CBrush对象产生。通过以下几种函数创建刷子:
BOOL CreateSolidBrush( COLORREF crColor ); 创建一种固定颜色的刷子 BOOL CreateHatchBrush( int nIndex, COLORREF crColor ); 创建指定颜色和网格的刷子,nIndex可取以下值: HS_BDIAGONAL Downward hatch (left to right) at 45 degrees
HS_CROSS Horizontal and vertical crosshatch
HS_DIAGCROSS Crosshatch at 45 degrees
HS_FDIAGONAL Upward hatch (left to right) at 45 degrees
HS_HORIZONTAL Horizontal hatch
HS_VERTICAL Vertical hatch BOOL CreatePatternBrush( CBitmap* pBitmap ); 创建以8*8位图为模板的刷子
在选择了画笔和刷子后就可以利用Windows的作图函数进行作图了,基本的画线函数有以下几种
CDC::MoveTo( int x, int y ); 改变当前点的位置 CDC::LineTo( int x, int y ); 画一条由当前点到参数指定点的线 CDC::BOOL Arc( LPCRECT lpRect, POINT ptStart, POINT ptEnd ); 画弧线 CDC::BOOL Polyline( LPPOINT lpPoints, int nCount ); 将多条线依次序连接 基本的作图函数有以下几种: CDC::BOOL Rectangle( LPCRECT lpRect ); 矩形 CDC::RoundRect( LPCRECT lpRect, POINT point ); 圆角矩形 CDC::Draw3dRect( int x, int y, int cx, int cy, COLORREF clrTopLeft, COLORREF clrBottomRight ); 3D边框 CDC::Chord( LPCRECT lpRect, POINT ptStart, POINT ptEnd ); 扇形 CDC::Ellipse( LPCRECT lpRect ); 椭圆形 CDC::Pie( LPCRECT lpRect, POINT ptStart, POINT ptEnd ); CDC::Polygon( LPPOINT lpPoints, int nCount ); 多边形 对于矩形,圆形或类似的封闭曲线,系统会使用画笔绘制边缘,使用刷子填充内部。如果你不希望填充或是画出边缘,你可以选入空刷子(NULL_PEN)或是(NULL_BRUSH)空笔。
下面的代码创建一条两象素宽的实线并选入DC。并进行简单的作图: { ... CPen pen; pen.CreatePen(PS_SOLID,2,RGB(128,128,128)); CPen* pOldPen=(CPen*)dc.SelectObject(&pen); dc.SelectStockObject(NULL_BRUSH);//选入空刷子 dc.Rectangle(CRect(0,0,20,20));//画矩形 ...
2.4 在窗口中绘制设备相关位图,图标,设备无关位图
在Windows中可以将预先准备好的图像复制到显示区域中,这种内存拷贝执行起来是非常快的。在Windows中提供了两种使用图形拷贝的方法:通过设备相关位图(DDB)和设备无关位图(DIB)。
DDB可以用MFC中的CBitmap来表示,而DDB一般是存储在资源文件中,在加载时只需要通过资源ID号就可以将图形装入。BOOL CBitmap::LoadBitmap( UINT nIDResource )可以装入指定DDB,但是在绘制时必须借助另一个和当前绘图DC兼容的内存DC来进行。通过CDC::BitBlt( int x, int y, int nWidth, int nHeight, CDC* pSrcDC, int xSrc, int ySrc, DWORD dwRop )绘制图形,同时指定光栅操作的类型。BitBlt可以将源DC中位图复制到目的DC中,其中前四个参数为目的区域的坐标,接下来是源DC指针,然后是源DC中的起始坐标,由于BitBlt为等比例复制,所以不需要再次指定长宽,(StretchBlt可以进行缩放)最后一个参数为光栅操作的类型,可取以下值:
BLACKNESS 输出区域为黑色 Turns all output black.
DSTINVERT 反色输出区域 Inverts the destination bitmap.
MERGECOPY 在源和目的间使用AND操作 Combines the pattern and the source bitmap using the Boolean AND operator.
MERGEPAINT 在反色后的目的和源间使用OR操作 Combines the inverted source bitmap with the destination bitmap using the Boolean OR operator.
NOTSRCCOPY 将反色后的源拷贝到目的区 Copies the inverted source bitmap to the destination.
PATINVERT 源和目的间进行XOR操作 Combines the destination bitmap with the pattern using the Boolean XOR operator.
SRCAND 源和目的间进行AND操作 Combines pixels of the destination and source bitmaps using the Boolean AND operator.
SRCCOPY 复制源到目的区 Copies the source bitmap to the destination bitmap.
SRCINVERT 源和目的间进行XOR操作 Combines pixels of the destination and source bitmaps using the Boolean XOR operator.
SRCPAINT 源和目的间进行OR操作 Combines pixels of the destination and source bitmaps using the Boolean OR operator.
WHITENESS 输出区域为白色 Turns all output white. 下面用代码演示这种方法: CYourView::OnDraw(CDC* pDC) { CDC memDC;//定义一个兼容DC memDC.CreateCompatibleDC(pDC);//创建DC CBitmap bmpDraw; bmpDraw.LoadBitmap(ID_BMP);//装入DDB CBitmap* pbmpOld=memDC.SelectObject(&bmpDraw);//保存原有DDB,并选入新DDB入DC pDC->BitBlt(0,0,20,20,&memDC,0,0,SRCCOPY);//将源DC中(0,0,20,20) 复制到目的DC(0,0,20,20) pDC->BitBlt(20,20,40,40,&memDC,0,0,SRCAND);//将源DC中(0,0,20,20) 和目的DC(20,20,40,40)中区域进行AND操作 memDC.SelectObject(pbmpOld);//选入原DDB }
(图标并不是一个GDI对象,所以不需要选入DC)在MFC中没有一个专门的图标类,因为图标的操作比较简单,使用HICON CWinApp::LoadIcon( UINT nIDResource )或是HICON CWinApp::LoadStandardIcon( LPCTSTR lpszIconName ) 装入后就可以利用BOOL CDC::DrawIcon( int x, int y, HICON hIcon )绘制。由于在图标中可以指定透明区域,所以在某些需要使用非规则图形而且面积不大的时候使用图标会比较简单。下面给出简单的代码:
OnDraw(CDC* pDC) { HICON hIcon1=AfxGetApp()->LoadIcon(IDI_I1); HICON hIcon2=AfxGetApp()->LoadIcon(IDI_I2); pDC->DrawIcon(0,0,hIcon1); pDC->DrawIcon(0,40,hIcon2); DestroyIcon(hIcon1); DestroyIcon(hIcon2); }
同样在MFC也没有提供一个DIB的类,所以在使用DIB位图时我们需要自己读取位图文件中的头信息, 并读入数据,并利用API函数StretchDIBits绘制。位图文件以BITMAPFILEHEADER结构开始,然后是BITMAPINFOHEADER 结构和调色版信息和数据,其实位图格式是图形格式中最简单的一种,而且也是Windows可以理解的一种。我不详细 讲解DIB位图的结构,提供一个CDib类供大家使用,这个类包含了基本的功能如:Load,Save,Draw。
2.5 使用各种映射方式
所谓的映射方式简单点讲就是坐标的安排方式,系统默认的映射方式为MM_TEXT即X坐标向右增加,Y坐标向下增加,(0,0)在屏幕左上方,DC中的每一点就是屏幕上的一个象素。也许你会认为这种方式下是最好理解的,但是一个点和象素对应的关系在屏幕上看来是正常的,但到了打印机上就会很不正常。因为我们作图是以点为单位并且打印机的分辨率远远比显示器高(800DPI 800点每英寸)所以在打印机上图形看起来就会很小。这样就需要为打印另做一套代码而加大了工作量。如果每个点对应0.1毫米那么在屏幕上的图形就会和打印出来的图形一样大小。
通过int CDC::SetMapMode( int nMapMode )可以指定映射方式,可用的有以下几种:
MM_HIENGLISH 每点对应0.001英寸 Each logical unit is converted to 0.001 inch. Positive x is to the right; positive y is up.
MM_HIMETRIC 每点对应0.001毫米 Each logical unit is converted to 0.01 millimeter. Positive x is to the right; positive y is up.
MM_LOENGLISH 每点对应0.01英寸 Each logical unit is converted to 0.01 inch. Positive x is to the right; positive y is up.
MM_LOMETRIC 每点对应0.001毫米 Each logical unit is converted to 0.1 millimeter. Positive x is to the right; positive y is up.
MM_TEXT 象素对应 Each logical unit is converted to 1 device pixel. Positive x is to the right; positive y is down.
以上几种映射默认的原点在屏幕左上方。除MM_TEXT外都为X坐标向右增加,Y坐标向上增加,和自然坐标是一致的。所以在作图是要注意什么时候应该使用负坐标。而且以上的映射都是X-Y等比例的,即相同的长度在X,Y轴上显示的长度都是相同的。
另外的一种映射方式为MM_ANISOTROPIC,这种方式可以规定不同的长宽比例。在设置这中映射方式后必须调用CSize CDC::SetWindowExt( SIZE size )和CSize CDC::SetViewportExt( SIZE size )来设定长宽比例。系统会根据两次设定的长宽的比值来确定长宽比例。下面给出一段代码比较映射前后的长宽比例:
OnDraw(CDC* pDC) { CRect rcC1(200,0,400,200); pDC->FillSolidRect(rcC1,RGB(0,0,255)); pDC->SetMapMode(MM_ANISOTROPIC ); CSize sizeO; sizeO=pDC->SetWindowExt(5,5); TRACE("winExt %d %d/n",sizeO.cx,sizeO.cy); sizeO=pDC->SetViewportExt(5,10); TRACE("ViewExt %d %d/n",sizeO.cx,sizeO.cy); CRect rcC(0,0,200,200); pDC->FillSolidRect(rcC,RGB(0,128,0)); }
上面代码在映射后画出的图形将是一个长方形。
最后讲讲视原点(viewport origin),你可以通过调用CPoint CDC::SetViewportOrg( POINT point )重新设置原点的位置,这就相对于对坐标进行了位移。例如你将原点设置在(20,20)那么原来的(0,0)就变成了(-20,-20)。
2.6 多边形和剪贴区域
多边形也是一个GDI对象,同样遵守其他GDI对象的规则,只是通常都不将其选入DC中。在MFC中多边形有CRgn表示。多边形用来表示一个不同与矩形的区域,和矩形具有相似的操作。如:检测某点是否在内部,并操作等。此外还得到一个包含此多边形的最小矩形。下面介绍一下多边形类的成员函数:
CreateRectRgn 由矩形创建一个多边形 CreateEllipticRgn 由椭圆创建一个多边形 CreatePolygonRgn 创建一个有多个点围成的多边形 PtInRegion 某点是否在内部 CombineRgn 两个多边形相并 EqualRgn 两个多边形是否相等
在本节中讲演多边形的意义在于重新在窗口中作图时提高效率。因为引发窗口重绘的原因是某个区域失效,而失效的区域用多边形来表示。假设窗口大小为500*400当上方的另一个窗口从(0,0,10,10)移动到(20,20,30,30)这时(0,0,10,10)区域就失效了,而你只需要重绘这部分区域而不是所有区域,这样你程序的执行效率就会提高。
通过调用API函数int GetClipRgn( HDC hdc, HRGN hrgn)就可以得到失效区域,但是一般用不着那么精确而只需得到包含该区域的最小矩形就可以了,所以可以利用int CDC::GetClipBox( LPRECT lpRect )完成这一功能。
3.1 文档 视图 框架窗口间的关系和消息传送规律
在MFC中M$引入了文档-视结构的概念,文档相当于数据容器,视相当于查看数据的窗口或是和数据发生交互的窗口。(这一结构在MFC中的OLE,ODBC开发时又得到更多的拓展)因此一个完整的应用一般由四个类组成:CWinApp应用类,CFrameWnd窗口框架类,CDocument文档类,CView视类。(VC6中支持创建不带文档-视的应用)
在程序运行时CWinApp将创建一个CFrameWnd框架窗口实例,而框架窗口将创建文档模板,然后有文档模板创建文档实例和视实例,并将两者关联。一般来讲我们只需对文档和视进行操作,框架的各种行为已经被MFC安排好了而不需人为干预,这也是M$设计文档-视结构的本意,让我们将注意力放在完成任务上而从界面编写中解放出来。
在应用中一个视对应一个文档,但一个文档可以包含多个视。一个应用中只用一个框架窗口,对多文档界面来讲可能有多个MDI子窗口。每一个视都是一个子窗口,在单文档界面中父窗口即是框架窗口,在多文档界面中父窗口为MDI子窗口。一个多文档应用中可以包含多个文档模板,一个模板定义了一个文档和一个或多个视之间的对应关系。同一个文档可以属于多个模板,但一个模板中只允许定义一个文档。同样一个视也可以属于多个文档模板。(不知道我说清楚没有)
接下来看看如何在程序中得到各种对象的指针:
全局函数AfxGetApp可以得到CWinApp应用类指针 AfxGetApp()->m_pMainWnd为框架窗口指针 在框架窗口中:CFrameWnd::GetActiveDocument得到当前活动文档指针 在框架窗口中:CFrameWnd::GetActiveView得到当前活动视指针 在视中:CView::GetDocument得到对应的文档指针 在文档中:CDocument::GetFirstViewPosition,CDocument::GetNextView用来遍历所有和文档关联的视。 在文档中:CDocument::GetDocTemplate得到文档模板指针 在多文档界面中:CMDIFrameWnd::MDIGetActive得到当前活动的MDI子窗口
一般来讲用户输入消息(如菜单选择,鼠标,键盘等)会先发往视,如果视未处理则会发往框架窗口。所以定义消息映射时定义在视中就可以了,如果一个应用同时拥有多个视而当前活动视没有对消息进行处理则消息会发往框架窗口。
3.2 接收用户输入
在视中接收鼠标输入:
鼠标消息是我们常需要处理的消息,消息分为:鼠标移动,按钮按下/松开,双击。利用ClassWizard可以轻松的添加这几种消息映射,下面分别讲解每种消息的处理。
WM_MOUSEMOVE对应的函数为OnMouseMove( UINT nFlags, CPoint point ),nFlags表明了当前一些按键的消息,你可以通过“位与”操作进行检测。
MK_CONTROL Ctrl键是否被按下 Set if the CTRL key is down.
MK_LBUTTON 鼠标左键是否被按下 Set if the left mouse button is down.
MK_MBUTTON 鼠标中间键是否被按下 Set if the middle mouse button is down.
MK_RBUTTON 鼠标右键是否被按下 Set if the right mouse button is down.
MK_SHIFT Shift键是否被按下 Set if the SHIFT key is down. point表示当前鼠标的设备坐标,坐标原点对应视左上角。
WM_LBUTTONDOWN/WM_RBUTTONDOWN(鼠标左/右键按下)对应的函数为OnLButtonDown/OnRButtonDown( UINT nFlags, CPoint point )参数意义和OnMouseMove相同。
WM_LBUTTONUP/WM_RBUTTONUP(鼠标左/右键松开)对应的函数为OnLButtonUp/OnRButtonUp( UINT nFlags, CPoint point )参数意义和OnMouseMove相同。
WM_LBUTTONDBLCLK/WM_RBUTTONDBLCLK(鼠标左/右键双击)对应的函数为OnLButtonDblClk/OnRButtonDblClk( UINT nFlags, CPoint point )参数意义和OnMouseMove相同。
下面我用一段伪代码来讲解一下这些消息的用法:
代码的作用是用鼠标拉出一个矩形 global BOOL fDowned;//是否在拉动 global CPoint ptDown;//按下位置 global CPoint ptUp;//松开位置
OnLButtonDown(UINT nFlags, CPoint point) { fDowned=TRUE; ptUp=ptDown=point; DrawRect(); ... }
OnMouseMove(UINT nFlags, CPoint point) { if(fDowned) { DrawRect();//恢复上次所画的矩形 ptUp=point; DrawRect();//画新矩形 } } OnLButtonUp(UINT nFlags, CPoint point) { if(fDowned) { DrawRect();//恢复上次所画的矩形 ptUp=point; DrawRect();//画新矩形 fDowned=FALSE; } }
DrawRect() {//以反色屏幕的方法画出ptDown,ptUp标记的矩形 CClientDC dc(this); MakeRect(ptDown,ptUp); SetROP(NOT); Rect(); }
坐标间转换:在以上的函数中point参数对应的都是窗口的设备坐标,我们应该将设备坐标和逻辑坐标相区别,在图32_g1由于窗口使用了滚动条,所以传入的设备坐标是对应于当前窗口左上角的坐标,没有考虑是否滚动,而逻辑坐标必须考虑滚动后对应的坐标,所以我以黄线虚拟的表达一个逻辑坐标的区域。可以看得出同一点在滚动后的坐标值是不同的,这一规则同样适用于改变了映射方式的窗口,假设你将映射方式设置为每点为0.01毫米,那么设备坐标所对应的逻辑坐标也需要重新计算。进行这种转换需要写一段代码,所幸的是系统提供了进行转换的功能DC的DPtoLP,LPtoDP,下面给出代码完成由设备坐标到逻辑坐标的转换。
CPoint CYourView::FromDP(CPoint point) { CClientDC dc(this); CPoint ptRet=point; dc.PrepareDC();//必须先准备DC,这在使用滚动时让DC重新计算坐标
//如果你作图设置了不同的映射方式,则在下面需要设置 dc.SetMapMode(...) // dc.DPtoLP(&ptRet);//DP->LP进行转换 return ptRet; }
在图32_g1中以蓝线标记的是屏幕区域,红线标记的客户区域。利用ScreenToClient,ClientToScreen可以将坐标在这两个区域间转换。
在视中接收键盘输入:
键盘消息有三个:键盘被按下/松开,输入字符。其中输入字符相当于直接得到用户输入的字符这在不需要处理按键细节时使用,而键盘被按下/松开在按键状态改变时发送。
WM_CHAR对应的函数为OnChar( UINT nChar, UINT nRepCnt, UINT nFlags ),其中nChar为被按下的字符,nRepCnt表明在长时间为松开时相当于的按键次数,nFlags中的不同位代表不同的含义,在这里一般不使用。
WM_KEYDOWN/WM_KEYUP所对应的函数为OnKeyDown/OnKeyUp( UINT nChar, UINT nRepCnt, UINT nFlags )nChar代表按键的虚拟码值,如VK_ALT为ALT键,VK_CONTROL为Ctrl键。nFlags各位的含义如下: Value Description 0? Scan code (OEM-dependent value). 8 Extended key, such as a function key or a key on the numeric keypad (1 if it is an extended key). 9?0 Not used. 11?2 Used internally by Windows. 13 Context code (1 if the ALT key is held down while the key is pressed; otherwise 0). 14 Previous key state (1 if the key is down before the call, 0 if the key is up). 15 Transition state (1 if the key is being released, 0 if the key is being pressed).
3.3 使用菜单
利用菜单接受用户命令是一中很简单的交互方法,同时也是一种很有效的方法。通常菜单作为一中资源存储在文件中,因此我们可以在设计时就利用资源编辑器设计好一个菜单。关于使用VC设计菜单我就不再多讲了,但你在编写菜单时应该尽量在属性对话框的底部提示(Prompt)处输入文字,这虽然不是必要的,但MFC在有状态栏和工具条的情况下会使用该文字,文字的格式为“状态栏出说明/n工具条提示”。图33_g1
我们要面临的任务是如何知道用户何时选择了菜单,他选的是什么菜单项。当用户选择了一个有效的菜单项时系统会向应用发送一个WM_COMMAND消息,在消息的参数中表明来源。在MFC中我们只需要进行一次映射,将某一菜单ID映射到一处理函数,图33_g2。在这里我们在CView的派生类中处理菜单消息,同时我对同一ID设置两个消息映射,接下来将这两种映射的作用。
ON_COMMAND 映射的作用为在用户选择该菜单时调用指定的处理函数。如:ON_COMMAND(IDM_COMMAND1, OnCommand1)会使菜单被选择时调用OnCommand1成员函数。
ON_UPDATE_COMMAND_UI(IDM_COMMAND1, OnUpdateCommand1) 映射的作用是在菜单被显示时通过调用指定的函数来进行确定其状态。在这个处理函数中你可以设置菜单的允许/禁止状态,其显示字符串是什么,是否在前面打钩。函数的参数为CCmdUI* pCmdUI,CCmdUI是MFC专门为更新命令提供的一个类,你可以调用
Enable 设置允许/禁止状态 SetCheck 设置是否在前面打钩 SetText 设置文字
下面我讲解一个例子:我在CView派生类中有一个变量m_fSelected,并且在视中处理两个菜单的消息,当IDM_COMMAND1被选时,对m_fSelected进行逻辑非操作,当IDM_COMMAND2被选中时出一提示;同时IDM_COMMAND1根据m_fSelected决定菜单显示的文字和是否在前面打上检查符号,IDM_COMMAND2根据m_fSelected的值决定菜单的允许/禁止状态。下面是代码和说明:
void CMenuDView::OnCommand1() { m_fSelected=!m_fSelected; TRACE("command1 selected/n"); }
void CMenuDView::OnUpdateCommand1(CCmdUI* pCmdUI) { pCmdUI->SetCheck(m_fSelected);//决定检查状态 pCmdUI->SetText(m_fSelected?"当前被选中":"当前未被选中");//决定所显示的文字 }
void CMenuDView::OnUpdateCommand2(CCmdUI* pCmdUI) {//决定是否为允许 pCmdUI->Enable(m_fSelected); }
void CMenuDView::OnCommand2() {//选中时给出提示 AfxMessageBox("你选了command2"); }
接下来再讲一些通过代码操纵菜单的方法,在MFC中有一个类CMenu用来处理和菜单有关的功能。在生成一个CMenu对象时你需要从资源中装如菜单,通过调用BOOL CMenu::LoadMenu( UINT nIDResource )进行装入,然后你就可以对菜单进行动态的修改,所涉及到的函数有:
CMenu* GetSubMenu( int nPos ) 一位置得到子菜单的指针,因为一个CMenu对象只能表示一个弹出菜单,如果菜单中的某一项也为弹出菜单,就需要通过该函数获取指针。 BOOL AppendMenu( UINT nFlags, UINT nIDNewItem = 0, LPCTSTR lpszNewItem = NULL ) 在末尾添加一项,nFlag为MF_SEPARATOR表示增加一个分隔条,这样其他两个参数将会被忽略;为MF_STRING表示添加一个菜单项uIDNewItem为该菜单的ID命令值;为MF_POPUP表示添加一个弹出菜单项,这时uIDNewItem为另一菜单的句柄HMENU。lpszNewItem为菜单文字说明。 BOOL InsertMenu( UINT nPosition, UINT nFlags, UINT nIDNewItem = 0, LPCTSTR lpszNewItem = NULL )用于在指定位置插入一菜单,位置由变量nPosition指明。如果nFlags包含MF_BYPOSITION则表明插入在nPosition位置,如果包含MF_BYCOMMAND表示插入在命令ID为nPosition的菜单处。 BOOL ModifyMenu( UINT nPosition, UINT nFlags, UINT nIDNewItem = 0, LPCTSTR lpszNewItem = NULL )用于修改某一位置的菜单,如果nFlags包含MF_BYPOSITION则表明修改nPosition位置的菜单,如果包含MF_BYCOMMAND表示修改命令ID为nPosition处的菜单。 BOOL RemoveMenu( UINT nPosition, UINT nFlags )用于删除某一位置的菜单。如果nFlags包含MF_BYPOSITION则表明删除nPosition位置的菜单,如果包含MF_BYCOMMAND表示删除命令ID为nPosition处的菜单。 BOOL AppendMenu( UINT nFlags, UINT nIDNewItem, const CBitmap* pBmp ) 和 BOOL InsertMenu( UINT nPosition, UINT nFlags, UINT nIDNewItem, const CBitmap* pBmp )可以添加一位图菜单,但这样的菜单在选中时只是反色显示,并不美观。(关于使用自绘OwnerDraw菜单请参考我翻译的一篇文章自绘菜单类)
视图中是没有菜单的,在框架窗口中才有,所以只有用AfxGetApp()->m_pMainWnd->GetMenu()才能得到应用的菜单指针。
最后我讲一下如何在程序中弹出一个菜单,你必须先装入一个菜单资源,你必需得到一个弹出菜单的指针然后调用BOOL TrackPopupMenu( UINT nFlags, int x, int y, CWnd* pWnd, LPCRECT lpRect = NULL )弹出菜单,你需要指定(x,y)为菜单弹出的位置,pWnd为接收命令消息的窗口指针。下面有一段代码说明方法,当然为了处理消息你应该在pWnd指明的窗口中对菜单命令消息进行映射。
CMenu menu; menu.LoadMenu(IDR_POPUP); CMenu* pM=menu.GetSubMenu(0); CPoint pt; GetCursorPos(&pt); pM->TrackPopupMenu(TPM_LEFTALIGN,pt.x,pt.y,this);
另一种做法是通过CMenu::CreatePopupMenu()建立一个弹出菜单,然后使用TrackPopupMenu弹出菜单。使用CreatePopupMenu创建的菜单也可以将其作为一个弹出项添加另一个菜单中。下面的伪代码演示了如何创建一个弹出菜单并进行修改后弹出:
CMenu menu1,menu2; menu1.CreatePopupMenu menu1.InsertMenu(1) menu1.InsertMenu(2) menu1.InsertMenu(3)
menu2.CreatePopupMenu menu2.AppendMenu(MF_POPUP,1,menu1.Detach()) 将弹出菜单加入 or InsertMenu... menu2.InsertMenu("string desc"); menu.TrackPopupMenu(...)
3.4 文档,视,框架之间相互作用
一般来说用户的输入/输出基本都是通过视进行,但一些例外的情况下可能需要和框架直接发生作用,而在多视的情况下如何在视之间传递数据。
在使用菜单时大家会发现当一个菜单没有进行映射处理时为禁止状态,在多视的情况下菜单的状态和处理映射是和当前活动视相联系的,这样MFC可以保证视能正确的接收到各种消息,但有时候也会产生不便。有一个解决办法就是在框架中对消息进行处理,这样也可以保证当前文档可以通过框架得到当前消息。
在用户进行输入后如何使视的状态得到更新?这个问题在一个文档对应一个视图时是不存在的,但是现在有一个文档对应了两个视图,当在一个视上进行了输入时如何保证另一个视也得到通知呢?MFC的做法是利用文档来处理的,因为文档管理着当前和它联系的视,由它来通知各个视是最合适的。让我们同时看两个函数:
void CView::OnUpdate( CView* pSender, LPARAM lHint, CObject* pHint ) void CDocument::UpdateAllViews( CView* pSender, LPARAM lHint = 0L, CObject* pHint = NULL ) 当文档的UpdateAllViews被调用时和此文档相关的所有视的OnUpdate都会被调用,而参数lHint和pHint都会被传递。这样一来发生改变视就可以通知其他的兄弟了。那么还有一个问题:如何在OnUpdate中知道是那个视图发生了改变呢,这就可以利用pHint参数,只要调用者将this指针赋值给参数就可以了,当然完全可以利用该参数传递更复杂的结构。
视的初始化,当一个文档被打开或是新建一个文档时视图的CView::OnInitialUpdate()会被调用,你可以通过重载该函数对视进行初始化,并在结束前调用父类的OnInitialUpdate,因为这样可以保证OnUpdate会被调用。
文档中内容的清除,当文档被关闭时(比如退出或是新建前上一个文档清除)void CDocument::DeleteContents ()会被调用,你可以通过重载该函数来进行清理工作。
在单文档结构中上面两点尤其重要,因为软件运行文档对象和视对象只会被产生并删除一次。所以应该将上面两点和C++对象构造和构析分清楚。
最后将一下文档模板(DocTemplate)的作用,文档模板分为两类单文档模板和多文档模板,分别由CSingleDocTemplate和CMultiDocTemplate表示,模板的作用在于记录文档,视,框架之间的对应关系。还有一点就是模板可以记录应用程序可以打开的文件的类型,当打开文件时会根据文档模板中的信息选择正确的文档和视。模板是一个比较抽想的概念,一般来说是不需要我们直接进行操作的。
当使用者通过视修改了数据时,应该调用GetDocument()->SetModifiedFlag(TRUE)通知文档数据已经被更新,这样在关闭文档时会自动询问用户是否保存数据。
3.5 利用序列化进行文件读写
在很多应用中我们需要对数据进行保存,或是从介质上读取数据,这就涉及到文件的操作。我们可以利用各种文件存取方法完成这些工作,但MFC中也提供了一种读写文件的简单方法——“序列化”。序列化机制通过更高层次的接口功能向开发者提供了更利于使用和透明于字节流的文件操纵方法,举一个例来讲你可以将一个字串写入文件而不需要理会具体长度,读出时也是一样。你甚至可以对字符串数组进行操作。在MFC提供的可自动分配内存的类的支持下你可以更轻松的读/写数据。你也可以根据需要编写你自己的具有序列化功能的类。
序列化在最低的层次上应该被需要序列化的类支持,也就是说如果你需要对一个类进行序列化,那么这个类必须支持序列化。当通过序列化进行文件读写时你只需要该类的序列化函数就可以了。
怎样使类具有序列化功能呢?你需要以下的工作:
该类从CObject派生。 在类声明中包括DECLARE_SERIAL宏定义。 提供一个缺省的构造函数。 在类中实现Serialze函数 使用IMPLEMENT_SERIAL指明类名和版本号
下面的代码建立了一个简单身份证记录的类,同时也能够支持序列化。
in H struct strPID { char szName[10]; char szID[16]; struct strPID* pNext; }; class CAllPID : public CObject { public: DECLARE_SERIAL(CAllPID) CAllPID(); ~CAllPID();
public:// 序列化相关 struct strPID* pHead; //其他的成员函数 void Serialize(CArchive& ar); };
in CPP IMPLEMENT_SERIAL(CAllPID,CObject,1) // version is 1,版本用于读数据时的检测 void CAllPID::Serialize(CArchive& ar) { int iTotal; if(ar.IsStoring()) {//保存数据 iTotal=GetTotalID();//得到链表中的记录数量 arr<26;i++) ar<<&(((BYTE*)pItem)+i);//写一个strPID中所有的数据 } } else {//读数据 ar>>iTotal; for(int i=0;i26;j++) ar>>*(((BYTE*)pID)+j);//读一个strPID中所有的数据 //修改链表 } } }
当然上面的代码很不完整,但已经可以说明问题。这样CAllPID就是一个可以支持序列化的类,并且可以根据记录的数量动态分配内存。在序列化中我们使用了CArchive类,该类用于在序列化时提供读写支持,它重载了<<和>>运算符号,并且提供Read和Write函数对数据进行读写。
下面看看如何在文档中使用序列化功能,你只需要修改文档类的Serialize(CArchive& ar)函数,并调用各个进行序列化的类的Serial进行数据读写就可以了。当然你也可以在文档类的内部进行数据读写,下面的代码利用序列化功能读写数据:
class CYourDoc : public CDocument { void Serialize(CArchive& ar); CString m_szDesc; CAllPID m_allPID; ...... }
void CYourDoc::Serialize(CArchive& ar) { if (ar.IsStoring()) {//由于CString对CArchive定义了<<和>>操作符号,所以可以直接利用>>和<< ar<>m_szDesc; } m_allPID.Serialize(ar);//调用数据类的序列化函数
} 3.6 MFC中所提供的各种视类介绍
MFC中提供了丰富的视类供开发者使用,下面对各个类进行介绍:
CView类是最基本的视类只支持最基本的操作。
CScrollView类提供了滚动的功能,你可以利用void CScrollView::SetScrollSizes( int nMapMode, SIZE sizeTotal, const SIZE& sizePage = sizeDefault, const SIZE& sizeLine = sizeDefault )设置滚动尺寸,和坐标映射模式。但是在绘图和接收用户输入时需要对坐标进行转换。请参见3.2 接收用户输入。
CFormView类提供用户在资源文件中定义界面的能力,并可以将子窗口和变量进行绑定。通过UpdateData函数让数据在变量和子窗口间交换。
CTreeView类利用TreeCtrl界面作为视界面,通过调用CTreeCtrl& CTreeView::GetTreeCtrl( ) const得到CTreeCtrl的引用。
CListView类利用ListCtrl界面作为视界面,通过调用CTreeCtrl& CTreeView::GetTreeCtrl( ) const得到CListCtrl的引用。
CEditView类利用Edit接收用户输入,它具有输入框的一切功能。通过调用CEdit& CEditView::GetEditCtrl( ) const得到Edit&的引用。void CEditView::SetPrinterFont( CFont* pFont )可以设置打印字体。
CRichEditView类作为Rich Text Edit(富文本输入)的视类,提供了可以按照格式显示文本的能力,在使用时需要CRichEditDoc的支持。
4.1 Button
按钮窗口(控件)在MFC中使用CButton表示,CButton包含了三种样式的按钮,Push Button,Check Box,Radio Box。所以在利用CButton对象生成按钮窗口时需要指明按钮的风格。
创建按钮:BOOL CButton::Create( LPCTSTR lpszCaption, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID );其中lpszCaption是按钮上显示的文字,dwStyle为按钮风格,除了Windows风格可以使用外(如WS_CHILD|WS_VISUBLE|WS_BORDER)还有按钮专用的一些风格。
BS_AUTOCHECKBOX 检查框,按钮的状态会自动改变 Same as a check box, except that a check mark appears in the check box when the user selects the box; the check mark disappears the next time the user selects the box.
BS_AUTORADIOBUTTON 圆形选择按钮,按钮的状态会自动改变 Same as a radio button, except that when the user selects it, the button automatically highlights itself and removes the selection from any other radio buttons with the same style in the same group.
BS_AUTO3STATE 允许按钮有三种状态即:选中,未选中,未定 Same as a three-state check box, except that the box changes its state when the user selects it.
BS_CHECKBOX 检查框 Creates a small square that has text displayed to its right (unless this style is combined with the BS_LEFTTEXT style).
BS_DEFPUSHBUTTON 默认普通按钮 Creates a button that has a heavy black border. The user can select this button by pressing the ENTER key. This style enables the user to quickly select the most likely option (the default option).
BS_LEFTTEXT 左对齐文字 When combined with a radio-button or check-box style, the text appears on the left side of the radio button or check box.
BS_OWNERDRAW 自绘按钮 Creates an owner-drawn button. The framework calls the DrawItem member function when a visual aspect of the button has changed. This style must be set when using the CBitmapButton class.
BS_PUSHBUTTON 普通按钮 Creates a pushbutton that posts a WM_COMMAND message to the owner window when the user selects the button.
BS_RADIOBUTTON 圆形选择按钮 Creates a small circle that has text displayed to its right (unless this style is combined with the BS_LEFTTEXT style). Radio buttons are usually used in groups of related but mutually exclusive choices.
BS_3STATE 允许按钮有三种状态即:选中,未选中,未定 Same as a check box, except that the box can be dimmed as well as checked. The dimmed state typically is used to show that a check box has been disabled. rect为窗口所占据的矩形区域,pParentWnd为父窗口指针,nID为该窗口的ID值。
获取/改变按钮状态:对于检查按钮和圆形按钮可能有两种状态,选中和未选中,如果设置了BS_3STATE或BS_AUTO3STATE风格就可能出现第三种状态:未定,这时按钮显示灰色。通过调用int CButton::GetCheck( ) 得到当前是否被选中,返回0:未选中,1:选中,2:未定。调用void CButton::SetCheck( int nCheck );设置当前选中状态。
处理按钮消息:要处理按钮消息需要在父窗口中进行消息映射,映射宏为ON_BN_CLICKED( id, memberFxn )id为按钮的ID值,就是创建时指定的nID值。处理函数原型为afx_msg void memberFxn( );
4.2 Static Box
静态文本控件的功能比较简单,可作为显示字符串,图标,位图用。创建一个窗口可以使用成员函数: BOOL CStatic::Create( LPCTSTR lpszText, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID = 0xffff ); 其中dwStyle将指明该窗口的风格,除了子窗口常用的风格WS_CHILD,WS_VISIBLE外,你可以针对静态控件指明专门的风格。
SS_CENTER,SS_LEFT,SS_RIGHT 指明字符显示的对齐方式。 SS_GRAYRECT 显示一个灰色的矩形 SS_NOPREFIX 如果指明该风格,对于字符&将直接显示,否则&将作为转义符,&将不显示而在其后的字符将有下划线,如果需要直接显示&必须使用&&表示。 SS_BITMAP 显示位图 SS_ICON 显示图标 SS_CENTERIMAGE 图象居中显示
控制显示的文本利用成员函数SetWindowText/GetWindowText用于设置/得到当前显示的文本。
控制显示的图标利用成员函数SetIcon/GetIcon用于设置/得到当前显示的图标。
控制显示的位图利用成员函数SetBitmap/GetBitmap用于设置/得到当前显示的位图。下面一段代码演示如何创建一个显示位图的静态窗口并设置位图
CStatic* pstaDis=new CStatic; pstaDis->Create("",WS_CHILD|WS_VISIBLE|SS_BITMAP|SSCENTERIMAGE, CRect(0,0,40,40),pWnd,1); CBitmap bmpLoad; bmpLoad.LoadBitmap(IDB_TEST); pstaDis->SetBitmap(bmpLoad.Detach());
4.3 Edit Box
Edit窗口是用来接收用户输入最常用的一个控件。创建一个输入窗口可以使用成员函数: BOOL CEdit::Create( LPCTSTR lpszText, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID = 0xffff ); 其中dwStyle将指明该窗口的风格,除了子窗口常用的风格WS_CHILD,WS_VISIBLE外,你可以针对输入控件指明专门的风格。
ES_AUTOHSCROLL,ES_AUTOVSCROLL 指明输入文字超出显示范围时自动滚动。 ES_CENTER,ES_LEFT,ES_RIGHT 指定对齐方式 ES_MULTILINE 是否允许多行输入 ES_PASSWORD 是否为密码输入框,如果指明该风格则输入的文字显示为* ES_READONLY 是否为只读 ES_UPPERCASE,ES_LOWERCASE 显示大写/小写字符
控制显示的文本利用成员函数SetWindowText/GetWindowText用于设置/得到当前显示的文本。
通过GetLimitText/SetLimitText可以得到/设置在输入框中输入的字符数量。
由于在输入时用户可能选择某一段文本,所以通过void CEdit::GetSel( int& nStartChar, int& nEndChar )得到用户选择的字符范围,通过调用void CEdit::SetSel( int nStartChar, int nEndChar, BOOL bNoScroll = FALSE )可以设置当前选择的文本范围,如果指定nStartChar=0 nEndChar=-1则表示选中所有的文本。void ReplaceSel( LPCTSTR lpszNewText, BOOL bCanUndo = FALSE )可以将选中的文本替换为指定的文字。
此外输入框还有一些和剪贴板有关的功能,void Clear( );删除选中的文本,void Copy( );可将选中的文本送入剪贴板,void Paste( );将剪贴板中内容插入到当前输入框中光标位置,void Cut( );相当于Copy和Clear结合使用。
最后介绍一下输入框几种常用的消息映射宏:
ON_EN_CHANGE 输入框中文字更新后产生 ON_EN_ERRSPACE 输入框无法分配内存时产生 ON_EN_KILLFOCUS / ON_EN_SETFOCUS 在输入框失去/得到输入焦点时产生 使用以上几种消息映射的方法为定义原型如:afx_msg void memberFxn( );的函数,并且定义形式如ON_Notification( id, memberFxn )的消息映射。如果在对话框中使用输入框,Class Wizard会自动列出相关的消息,并能自动产生消息映射代码。
4.5 List Box/Check List Box
ListBox窗口用来列出一系列的文本,每条文本占一行。创建一个列表窗口可以使用成员函数: BOOL CListBox::Create( LPCTSTR lpszText, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID = 0xffff ); 其中dwStyle将指明该窗口的风格,除了子窗口常用的风格WS_CHILD,WS_VISIBLE外,你可以针对列表控件指明专门的风格。
LBS_MULTIPLESEL 指明列表框可以同时选择多行 LBS_EXTENDEDSEL 可以通过按下Shift/Ctrl键选择多行 LBS_SORT 所有的行按照字母顺序进行排序
在列表框生成后需要向其中加入或是删除行,可以利用: int AddString( LPCTSTR lpszItem )添加行, int DeleteString( UINT nIndex )删除指定行, int InsertString( int nIndex, LPCTSTR lpszItem )将行插入到指定位置。 void ResetContent( )可以删除列表框中所有行。 通过调用int GetCount( )得到当前列表框中行的数量。
如果需要得到/设置当前被选中的行,可以调用int GetCurSel( )/int SetCurSel(int iIndex)。如果你指明了选择多行的风格,你就需要先调用int GetSelCount( )得到被选中的行的数量,然后int GetSelItems( int nMaxItems, LPINT rgIndex )得到所有选中的行,参数rgIndex为存放被选中行的数组。通过调用int GetLBText( int nIndex, LPTSTR lpszText )得到列表框内指定行的字符串。
此外通过调用int FindString( int nStartAfter, LPCTSTR lpszItem )可以在当前所有行中查找指定的字符传的位置,nStartAfter指明从那一行开始进行查找。 int SelectString( int nStartAfter, LPCTSTR lpszItem )可以选中包含指定字符串的行。
在MFC 4.2版本中添加了CCheckListBox类,该类是由CListBox派生并拥有CListBox的所有功能,不同的是可以在每行前加上一个检查框。必须注意的是在创建时必须指明LBS_OWNERDRAWFIXED或LBS_OWNERDRAWVARIABLE风格。
通过void SetCheckStyle( UINT nStyle )/UINT GetCheckStyle( )可以设置/得到检查框的风格,关于检查框风格可以参考4.1 Button中介绍。通过void SetCheck( int nIndex, int nCheck )/int GetCheck( int nIndex )可以设置和得到某行的检查状态,关于检查框状态可以参考4.1 Button中介绍。
最后介绍一下列表框几种常用的消息映射宏:
ON_LBN_DBLCLK 鼠标双击 ON_EN_ERRSPACE 输入框无法分配内存时产生 ON_EN_KILLFOCUS / ON_EN_SETFOCUS 在输入框失去/得到输入焦点时产生 ON_LBN_SELCHANGE 选择的行发生改变 使用以上几种消息映射的方法为定义原型如:afx_msg void memberFxn( );的函数,并且定义形式如ON_Notification( id, memberFxn )的消息映射。如果在对话框中使用列表框,Class Wizard会自动列出相关的消息,并能自动产生消息映射代码。
4.6 Combo Box
组合窗口是由一个输入框和一个列表框组成。创建一个组合窗口可以使用成员函数: BOOL CListBox::Create( LPCTSTR lpszText, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID = 0xffff ); 其中dwStyle将指明该窗口的风格,除了子窗口常用的风格WS_CHILD,WS_VISIBLE外,你可以针对列表控件指明专门的风格。
CBS_DROPDOWN 下拉式组合框 CBS_DROPDOWNLIST 下拉式组合框,但是输入框内不能进行输入 CBS_SIMPLE 输入框和列表框同时被显示 LBS_SORT 所有的行按照字母顺序进行排序
由于组合框内包含了列表框,所以列表框的功能都能够使用,如可以利用: int AddString( LPCTSTR lpszItem )添加行, int DeleteString( UINT nIndex )删除指定行, int InsertString( int nIndex, LPCTSTR lpszItem )将行插入到指定位置。 void ResetContent( )可以删除列表框中所有行。 通过调用int GetCount( )得到当前列表框中行的数量。
如果需要得到/设置当前被选中的行的位置,可以调用int GetCurSel( )/int SetCurSel(int iIndex)。通过调用int GetLBText( int nIndex, LPTSTR lpszText )得到列表框内指定行的字符串。
此外通过调用int FindString( int nStartAfter, LPCTSTR lpszItem )可以在当前所有行中查找指定的字符传的位置,nStartAfter指明从那一行开始进行查找。 int SelectString( int nStartAfter, LPCTSTR lpszItem )可以选中包含指定字符串的行。
此外输入框的功能都能够使用,如可以利用: DWORD GetEditSel( ) /BOOL SetEditSel( int nStartChar, int nEndChar )得到或设置输入框中被选中的字符位置。 BOOL LimitText( int nMaxChars )设置输入框中可输入的最大字符数。 输入框的剪贴板功能Copy,Clear,Cut,Paste动可以使用。
最后介绍一下列表框几种常用的消息映射宏:
ON_CBN_DBLCLK 鼠标双击 ON_CBN_DROPDOWN 列表框被弹出 ON_CBN_KILLFOCUS / ON_CBN_SETFOCUS 在输入框失去/得到输入焦点时产生 ON_CBN_SELCHANGE 列表框中选择的行发生改变 ON_CBN_EDITUPDATE 输入框中内容被更新 使用以上几种消息映射的方法为定义原型如:afx_msg void memberFxn( );的函数,并且定义形式如ON_Notification( id, memberFxn )的消息映射。如果在对话框中使用组合框,Class Wizard会自动列出相关的消息,并能自动产生消息映射代码。
4.7 Tree Ctrl
树形控件TreeCtrl和下节要讲的列表控件 ListCtrl在系统中大量被使用,例如Windows资源管理器就是一个典型的例子。
树形控件可以用于树形的结构,其中有一个根接点(Root)然后下面有许多子结点,而每个子结点上有允许有一个或多个或没有子结点。MFC中使用CTreeCtrl类来封装树形控件的各种操作。通过调用 BOOL Create( DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID );创建一个窗口,dwStyle中可以使用以下一些树形控件的专用风格:
TVS_HASLINES 在父/子结点之间绘制连线 TVS_LINESATROOT 在根/子结点之间绘制连线 TVS_HASBUTTONS 在每一个结点前添加一个按钮,用于表示当前结点是否已被展开 TVS_EDITLABELS 结点的显示字符可以被编辑 TVS_SHOWSELALWAYS 在失去焦点时也显示当前选中的结点 TVS_DISABLEDRAGDROP 不允许Drag/Drop TVS_NOTOOLTIPS 不使用ToolTip显示结点的显示字符 在树形控件中每一个结点都有一个句柄(HTREEITEM),同时添加结点时必须提供的参数是该结点的父结点句柄,(其中根Root结点只有一个,既不可以添加也不可以删除)利用 HTREEITEM InsertItem( LPCTSTR lpszItem, HTREEITEM hParent = TVI_ROOT, HTREEITEM hInsertAfter = TVI_LAST );可以添加一个结点,pszItem为显示的字符,hParent代表父结点的句柄,当前添加的结点会排在hInsertAfter表示的结点的后面,返回值为当前创建的结点的句柄。下面的代码会建立一个如下形式的树形结构: +--- Parent1 +--- Child1_1 +--- Child1_2 +--- Child1_3 +--- Parent2 +--- Parent3 /*假设m_tree为一个CTreeCtrl对象,而且该窗口已经创建*/ HTREEITEM hItem,hSubItem; hItem = m_tree.InsertItem("Parent1",TVI_ROOT); 在根结点上添加Parent1 hSubItem = m_tree.InsertItem("Child1_1",hItem); //在Parent1上添加一个子结点 hSubItem = m_tree.InsertItem("Child1_2",hItem,hSubItem);//在Parent1上添加一个子结点,排在Child1_1后面 hSubItem = m_tree.InsertItem("Child1_3",hItem,hSubItem); hItem = m_tree.InsertItem("Parent2",TVI_ROOT,hItem); hItem = m_tree.InsertItem("Parent3",TVI_ROOT,hItem); 如果你希望在每个结点前添加一个小图标,就必需先调用CImageList* SetImageList( CImageList * pImageList, int nImageListType );指明当前所使用的ImageList,nImageListType为TVSIL_NORMAL。在调用完成后控件中使用图片以设置的ImageList中图片为准。然后调用 HTREEITEM InsertItem( LPCTSTR lpszItem, int nImage, int nSelectedImage, HTREEITEM hParent = TVI_ROOT, HTREEITEM hInsertAfter = TVI_LAST);添加结点,nImage为结点没被选中时所使用图片序号,nSelectedImage为结点被选中时所使用图片序号。下面的代码演示了ImageList的设置。 /*m_list 为CImageList对象 IDB_TREE 为16*(16*4)的位图,每个图片为16*16共4个图标*/ m_list.Create(IDB_TREE,16,4,RGB(0,0,0)); m_tree.SetImageList(&m_list,TVSIL_NORMAL); m_tree.InsertItem("Parent1",0,1);//添加, 选中时显示图标1,未选中时显示图标0
此外CTreeCtrl还提供了一些函数用于得到/修改控件的状态。 HTREEITEM GetSelectedItem( );将返回当前选中的结点的句柄。BOOL SelectItem( HTREEITEM hItem );将选中指明结点。 BOOL GetItemImage( HTREEITEM hItem, int& nImage, int& nSelectedImage ) / BOOL SetItemImage( HTREEITEM hItem, int nImage, int nSelectedImage )用于得到/修改某结点所使用图标索引。 CString GetItemText( HTREEITEM hItem ) /BOOL SetItemText( HTREEITEM hItem, LPCTSTR lpszItem );用于得到/修改某一结点的显示字符。 BOOL DeleteItem( HTREEITEM hItem );用于删除某一结点,BOOL DeleteAllItems( );将删除所有结点。
此外如果想遍历树可以使用下面的函数: HTREEITEM GetRootItem( );得到根结点。 HTREEITEM GetChildItem( HTREEITEM hItem );得到子结点。 HTREEITEM GetPrevSiblingItem/GetNextSiblingItem( HTREEITEM hItem );得到指明结点的上/下一个兄弟结点。 HTREEITEM GetParentItem( HTREEITEM hItem );得到父结点。
树形控件的消息映射使用ON_NOTIFY宏,形式如同:ON_NOTIFY( wNotifyCode, id, memberFxn ),wNotifyCode为通知代码,id为产生该消息的窗口ID,memberFxn为处理函数,函数的原型如同void OnXXXTree(NMHDR* pNMHDR, LRESULT* pResult),其中pNMHDR为一数据结构,在具体使用时需要转换成其他类型的结构。对于树形控件可能取值和对应的数据结构为:
TVN_SELCHANGED 在所选中的结点发生改变后发送,所用结构:NMTREEVIEW TVN_ITEMEXPANDED 在某结点被展开后发送,所用结构:NMTREEVIEW TVN_BEGINLABELEDIT 在开始编辑结点字符时发送,所用结构:NMTVDISPINFO TVN_ENDLABELEDIT 在结束编辑结点字符时发送,所用结构:NMTVDISPINFO TVN_GETDISPINFO 在需要得到某结点信息时发送,(如得到结点的显示字符)所用结构:NMTVDISPINFO 关于ON_NOTIFY有很多内容,将在以后的内容中进行详细讲解。
关于动态提供结点所显示的字符:首先你在添加结点时需要指明lpszItem参数为:LPSTR_TEXTCALLBACK。在控件显示该结点时会通过发送TVN_GETDISPINFO来取得所需要的字符,在处理该消息时先将参数pNMHDR转换为LPNMTVDISPINFO,然后填充其中item.pszText。但是我们通过什么来知道该结点所对应的信息呢,我的做法是在添加结点后设置其lParam参数,然后在提供信息时利用该参数来查找所对应的信息。下面的代码说明了这种方法: char szOut[8][3]={"No.1","No.2","No.3"}; //添加结点 HTREEITEM hItem = m_tree.InsertItem(LPSTR_TEXTCALLBACK,...) m_tree.SetItemData(hItem, 0 ); hItem = m_tree.InsertItem(LPSTR_TEXTCALLBACK,...) m_tree.SetItemData(hItem, 1 ); //处理消息 void CParentWnd::OnGetDispInfoTree(NMHDR* pNMHDR, LRESULT* pResult) { TV_DISPINFO* pTVDI = (TV_DISPINFO*)pNMHDR; pTVDI->item.pszText=szOut[pTVDI->item.lParam];//通过lParam得到 需要显示的字符在数组中的位置 *pResult = 0; }
关于编辑结点的显示字符:首先需要设置树形控件的TVS_EDITLABELS风格,在开始编辑时该控件将会发送TVN_BEGINLABELEDIT,你可以通过在处理函数中返回TRUE来取消接下来的编辑,在编辑完成后会发送TVN_ENDLABELEDIT,在处理该消息时需要将参数pNMHDR转换为LPNMTVDISPINFO,然后通过其中的item.pszText得到编辑后的字符,并重置显示字符。如果编辑在中途中取消该变量为NULL。下面的代码说明如何处理这些消息: //处理消息 TVN_BEGINLABELEDIT void CParentWnd::OnBeginEditTree(NMHDR* pNMHDR, LRESULT* pResult) { TV_DISPINFO* pTVDI = (TV_DISPINFO*)pNMHDR; if(pTVDI->item.lParam==0);//判断是否取消该操作 *pResult = 1; else *pResult = 0; } //处理消息 TVN_BEGINLABELEDIT void CParentWnd::OnBeginEditTree(NMHDR* pNMHDR, LRESULT* pResult) { TV_DISPINFO* pTVDI = (TV_DISPINFO*)pNMHDR; if(pTVDI->item.pszText==NULL);//判断是否已经取消取消编辑 m_tree.SetItemText(pTVDI->item.hItem,pTVDI->pszText);//重置显示字符 *pResult = 0; } 上面讲述的方法所进行的消息映射必须在父窗口中进行(同样WM_NOTIFY的所有消息都需要在父窗口中处理)。
4.8 List Ctrl
列表控件可以看作是功能增强的ListBox,它提供了四种风格,而且可以同时显示一列的多中属性值。MFC中使用CListCtrl类来封装列表控件的各种操作。通过调用 BOOL Create( DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID );创建一个窗口,dwStyle中可以使用以下一些列表控件的专用风格:
LVS_ICON LVS_SMALLICON LVS_LIST LVS_REPORT 这四种风格决定控件的外观,同时只可以选择其中一种,分别对应:大图标显示,小图标显示,列表显示,详细报表显示 LVS_EDITLABELS 结点的显示字符可以被编辑,对于报表风格来讲可编辑的只为第一列。 LVS_SHOWSELALWAYS 在失去焦点时也显示当前选中的结点 LVS_SINGLESEL 同时只能选中列表中一项 首先你需要设置列表控件所使用的ImageList,如果你使用大图标显示风格,你就需要以如下形式调用: CImageList* SetImageList( CImageList* pImageList, LVSIL_NORMAL); 如果使用其它三种风格显示而不想显示图标你可以不进行任何设置,否则需要以如下形式调用: CImageList* SetImageList( CImageList* pImageList, LVSIL_SMALL);
通过调用int InsertItem( int nItem, LPCTSTR lpszItem );可以在列表控件中nItem指明位置插入一项,lpszItem为显示字符。除LVS_REPORT风格外其他三种风格都只需要直接调用InsertItem就可以了,但如果使用报表风格就必须先设置列表控件中的列信息。
通过调用int InsertColumn( int nCol, LPCTSTR lpszColumnHeading, int nFormat , int nWidth, int nSubItem);可以插入列。iCol为列的位置,从零开始,lpszColumnHeading为显示的列名,nFormat为显示对齐方式,nWidth为显示宽度,nSubItem为分配给该列的列索引。
在有多列的列表控件中就需要为每一项指明其在每一列中的显示字符,通过调用 BOOL SetItemText( int nItem, int nSubItem, LPTSTR lpszText );可以设置每列的显示字符。nItem为设置的项的位置,nSubItem为列位置,lpszText为显示字符。下面的代码演示了如何设置多列并插入数据: m_list.SetImageList(&m_listSmall,LVSIL_SMALL);//设置ImageList m_list.InsertColumn(0,"Col 1",LVCFMT_LEFT,300,0);//设置列 m_list.InsertColumn(1,"Col 2",LVCFMT_LEFT,300,1); m_list.InsertColumn(2,"Col 3",LVCFMT_LEFT,300,2); m_list.InsertItem(0,"Item 1_1");//插入行 m_list.SetItemText(0,1,"Item 1_2");//设置该行的不同列的显示字符 m_list.SetItemText(0,2,"Item 1_3");
此外CListCtrl还提供了一些函数用于得到/修改控件的状态。 COLORREF GetTextColor( )/BOOL SetTextColor( COLORREF cr );用于得到/设置显示的字符颜色。 COLORREF GetTextBkColor( )/BOOL SetTextBkColor( COLORREF cr );用于得到/设置显示的背景颜色。 void SetItemCount( int iCount );用于得到添加进列表中项的数量。 BOOL DeleteItem(int nItem);用于删除某一项,BOOL DeleteAllItems( );将删除所有项。 BOOL SetBkImage(HBITMAP hbm, BOOL fTile , int xOffsetPercent, int yOffsetPercent);用于设置背景位图。 CString GetItemText( int nItem, int nSubItem );用于得到某项的显示字符。
列表控件的消息映射同样使用ON_NOTIFY宏,形式如同:ON_NOTIFY( wNotifyCode, id, memberFxn ),wNotifyCode为通知代码,id为产生该消息的窗口ID,memberFxn为处理函数,函数的原型如同void OnXXXList(NMHDR* pNMHDR, LRESULT* pResult),其中pNMHDR为一数据结构,在具体使用时需要转换成其他类型的结构。对于列表控件可能取值和对应的数据结构为:
LVN_BEGINLABELEDIT 在开始某项编辑字符时发送,所用结构:NMLVDISPINFO LVN_ENDLABELEDIT 在结束某项编辑字符时发送,所用结构:NMLVDISPINFO LVN_GETDISPINFO 在需要得到某项信息时发送,(如得到某项的显示字符)所用结构:NMLVDISPINFO 关于ON_NOTIFY有很多内容,将在以后的内容中进行详细讲解。
关于动态提供结点所显示的字符:首先你在项时需要指明lpszItem参数为:LPSTR_TEXTCALLBACK。在控件显示该结点时会通过发送TVN_GETDISPINFO来取得所需要的字符,在处理该消息时先将参数pNMHDR转换为LPNMLVDISPINFO,然后填充其中item.pszText。通过item中的iItem,iSubItem可以知道当前显示的为那一项。下面的代码演示了这种方法: char szOut[8][3]={"No.1","No.2","No.3"}; //添加结点 m_list.InsertItem(LPSTR_TEXTCALLBACK,...) m_list.InsertItem(LPSTR_TEXTCALLBACK,...) //处理消息 void CParentWnd::OnGetDispInfoList(NMHDR* pNMHDR, LRESULT* pResult) { LV_DISPINFO* pLVDI = (LV_DISPINFO*)pNMHDR; pLVDI->item.pszText=szOut[pTVDI->item.iItem];//通过iItem得到需要 显示的字符在数组中的位置 *pResult = 0; }
关于编辑某项的显示字符:(在报表风格中只对第一列有效)首先需要设置列表控件的LVS_EDITLABELS风格,在开始编辑时该控件将会发送LVN_BEGINLABELEDIT,你可以通过在处理函数中返回TRUE来取消接下来的编辑,在编辑完成后会发送LVN_ENDLABELEDIT,在处理该消息时需要将参数pNMHDR转换为LPNMLVDISPINFO,然后通过其中的item.pszText得到编辑后的字符,并重置显示字符。如果编辑在中途中取消该变量为NULL。下面的代码说明如何处理这些消息: //处理消息 LVN_BEGINLABELEDIT void CParentWnd::OnBeginEditList(NMHDR* pNMHDR, LRESULT* pResult) { LV_DISPINFO* pLVDI = (LV_DISPINFO*)pNMHDR; if(pLVDI->item.iItem==0);//判断是否取消该操作 *pResult = 1; else *pResult = 0; } //处理消息 LVN_BEGINLABELEDIT void CParentWnd::OnBeginEditList(NMHDR* pNMHDR, LRESULT* pResult) { LV_DISPINFO* pLVDI = (LV_DISPINFO*)pNMHDR; if(pLVDI->item.pszText==NULL);//判断是否已经取消取消编辑 m_list.SetItemText(pLVDI->item.iItem,0,pLVDI->pszText);//重置显示字符 *pResult = 0; } 上面讲述的方法所进行的消息映射必须在父窗口中进行(同样WM_NOTIFY的所有消息都需要在父窗口中处理)。
如何得到当前选中项位置:在列表控件中没有一个类似于ListBox中GetCurSel()的函数,但是可以通过调用GetNextItem( -1, LVNI_ALL | LVNI_SELECTED);得到选中项位置。
4.9 Tab Ctrl
Tab属性页控件可以在一个窗口中添加不同的页面,然后在页选择发生改变时得到通知。MFC中使用CTabCtrl类来封装属性页控件的各种操作。通过调用 BOOL Create( DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID );创建一个窗口,dwStyle中可以使用以下一些属性页控件的专用风格:
TCS_BUTTONS 使用按钮来表示页选择位置 TCS_MULTILINE 分行显示页选择位置 TCS_SINGLELINE 只使用一行显示页选择位置 在控件创建后必需向其中添加页面才可以使用,添加页面的函数为: BOOL InsertItem( int nItem, LPCTSTR lpszItem );nItem为位置,从零开始,lpszItem为页选择位置上显示的文字。如果你希望在页选择位置处显示一个图标,你可以调用 BOOL InsertItem( int nItem, LPCTSTR lpszItem, int nImage );nImage指明所使用的图片位置。(在此之前必须调用CImageList * SetImageList( CImageList * pImageList );设置正确的ImageList)
此外CTabCtrl还提供了一些函数用于得到/修改控件的状态。 int GetCurSel( )/int SetCurSel( int nItem );用于得到/设置当前被选中的页位置。 BOOL DeleteItem( int nItem )/BOOL DeleteAllItems( );用于删除指定/所有页面。 void RemoveImage( int nImage );用于删除某页选择位置上的图标。
属性页控件的消息映射同样使用ON_NOTIFY宏,形式如同:ON_NOTIFY( wNotifyCode, id, memberFxn ),wNotifyCode为通知代码,id为产生该消息的窗口ID,memberFxn为处理函数,函数的原型如同void OnXXXTab(NMHDR* pNMHDR, LRESULT* pResult),其中pNMHDR为一数据结构,在具体使用时需要转换成其他类型的结构。对于列表控件可能取值和对应的数据结构为:
TCN_SELCHANGE 在当前页改变后发送,所用结构:NMHDR TCN_SELCHANGING 在当前页改变时发送可以通过返回TRUE来禁止页面的改变,所用结构:NMHDR
一般来讲在当前页发生改变时需要隐藏当前的一些子窗口,并显示其它的子窗口。下面的伪代码演示了如何使用属性页控件:
CParentWnd::OnCreate(...) { m_tab.Create(...); m_tab.InsertItem(0,"Option 1"); m_tab.InsertItem(1,"Option 2"); Create a edit box as the m_tab's Child Create a static box as the m_tab's Child edit_box.ShowWindow(SW_SHOW); // edit box在属性页的第一页 static_box.ShowWindow(SW_HIDE); // static box在属性页的第二页 } void CParentWnd::OnSelectChangeTab(NMHDR* pNMHDR, LRESULT* pResult) {//处理页选择改变后的消息 if(m_tab.GetCurSel()==0) {//根据当前页显示/隐藏不同的子窗口 edit_box.ShowWindow(SW_SHOW); static_box.ShowWindow(SW_HIDE); } else {// edit_box.ShowWindow(SW_HIDE); static_box.ShowWindow(SW_SHOW); } }
4.A Tool Bar
工具条也是常用的控件。MFC中使用CToolBar类来封装工具条控件的各种操作。通过调用 BOOL Create( CWnd* pParentWnd, DWORD dwStyle = WS_CHILD | WS_VISIBLE | CBRS_TOP, UINT nID = AFX_IDW_TOOLBAR );创建一个窗口,dwStyle中可以使用以下一些工具条控件的专用风格:
CBRS_TOP 工具条在父窗口的顶部 TCBRS_BOTTOM 工具条在父窗口的底部 CBRS_FLOATING 工具条是浮动的 创建一个工具条的步骤如下:先使用Create创建窗口,然后使用BOOL LoadToolBar( LPCTSTR lpszResourceName );直接从资源中装入工具条,或者通过装入位图并指明每个按钮的ID,具体代码如下:
UINT uID[5]={IDM_1,IDM_2,IDM_3,IDM_4,IDM_5}; m_toolbar.Create(pParentWnd); m_toolbar.LoadBitmap(IDB_TOOLBAR); m_toolbar.SetSizes(CSize(20,20),CSize(16,16));//设置按钮大尺寸和按钮上位图的尺寸 m_toolbar.SetButtons(uID,5);
AppWizard在生成代码时也会同时生成工具条的代码,同时还可以支持停靠功能。所以一般是不需要直接操作工具条对象。
工具条上的按钮被按下时发送给父窗口的消息和菜单消息相同,所以可以使用ON_COMMAND宏进行映射,同样工具条中的按钮也支持ON_UPDATE_COMMAND_UI的相关操作,如SetCheck,Enable,你可以将按钮的当作菜单上的一个具有相同ID菜单项。
在以后的章节4.D 利用AppWizard创建并使用ToolBar StatusBar Dialog Bar会给出使用的方法。
4.B Status Bar
状态条用于显示一些提示字符。MFC中使用CStatusBar类来封装状态条控件的各种操作。通过调用 BOOL Create( CWnd* pParentWnd, DWORD dwStyle = WS_CHILD | WS_VISIBLE | CBRS_BOTTOM, UINT nID = AFX_IDW_STATUS_BAR );创建一个窗口,dwStyle中可以使用以下一些状态条控件的专用风格:
CBRS_TOP 状态条在父窗口的顶部 TCBRS_BOTTOM 状态条在父窗口的底部 创建一个状态条的步骤如下:先使用Create创建窗口,然后调用BOOL SetIndicators( const UINT* lpIDArray, int nIDCount );设置状态条上各部分的ID,具体代码如下:
UINT uID[2]={ID_SEPARATOR,ID_INDICATOR_CAPS}; m_stabar.Create(pParentWnd); m_stabar.SetIndicators(uID,2);
通过CString GetPaneText( int nIndex )/BOOL SetPaneText( int nIndex, LPCTSTR lpszNewText, BOOL bUpdate = TRUE )可以得到/设置状态条上显示的文字。
Tip:在创建状态条时最好将状态条中所有的部分ID(除MFC自定义的几个用于状态条的ID外)都设置为ID_SEPARATOR,在生成后调用 void SetPaneInfo( int nIndex, UINT nID, UINT nStyle, int cxWidth );改变其风格,ID和宽度。
AppWizard在生成代码时也会同时生成状态条的代码。所以一般是不需要直接创建状态条对象。此外状态条上会自动显示菜单上的命令提示(必须先在资源中定义),所以也不需要人为设置显示文字。
状态条支持ON_UPDATE_COMMAND_UI的相关操作,如SetText,Enable。
在以后的章节4.D 利用AppWizard创建并使用ToolBar StatusBar Dialog Bar会给出使用的方法。
4.C Dialog Bar
Dialog Bar类似一个静态的附在框架窗口上的对话框,由于Dialog Bar可以使用资源编辑器进行编辑所以使用起来就很方便,在设计时就可以对Dialog Bar上的子窗口进行定位。用于显示一些提示字符。MFC中使用CDialogBar类来Dialog Bar控件的各种操作。通过调用 BOOL Create( CWnd* pParentWnd, UINT nIDTemplate, UINT nStyle, UINT nID );创建一个窗口,nIDTemplate为对话框资源,nID为该Dialog Bar对应的窗口ID,nStyle中可以使用以下一些状态条控件的专用风格:
CBRS_TOP Dialog Bar在父窗口的顶部 TCBRS_BOTTOM Dialog Bar在父窗口的底部 CBRS_LEFT Dialog Bar在父窗口的左部 CBRS_RIGHT Dialog Bar在父窗口的右部 对于Dialog Bar的所产生消息需要在父窗口中进行映射和处理,例如Dialog Bar上的按钮,需要在父窗口中进行ON_BN_CLICKED或ON_COMMAND映射,Dialog Bar上的输入框可以在父窗口中进行ON_EN_CHANGE,ON_EN_MAXTEXT等输入框对应的映射。
Dialog Bar支持ON_UPDATE_COMMAND_UI的相关操作,如SetText,Enable。
在以后的章节4.D 利用AppWizard创建并使用ToolBar StatusBar Dialog Bar会给出使用的方法。
4.D 利用AppWizard创建并使用ToolBar StatusBar Dialog Bar
运行时程序界面如界面图,该程序拥有一个工具条用于显示两个命令按钮,一个用于演示如何使按钮处于检查状态,另一个根据第一个按钮的状态来禁止/允许自身。(设置检查状态和允许状态都通过OnUpdateCommand实现)此外Dialog Bar上有一个输入框和按钮,这两个子窗口的禁止/允许同样是根据工具条上的按钮状态来确定,当按下Dialog Bar上的按钮时将显示输入框中的文字内容。状态条的第一部分用于显示各种提示,第二部分用于利用OnUpdateCommand显示当前时间。同时在程序中演示了如何设置菜单项的命令解释字符(将在状态条的第一部分显示)和如何设置工具条的提示字符(利用一个小的ToolTip窗口显示)。
生成应用:利用AppWizard生成一个MFC工程,图例,并设置为单文档界面图例,最后选择工具条,状态条和ReBar支持,图例
修改菜单:利用资源编辑器删除多余的菜单并添加一个新的弹出菜单和三个子菜单,图例,分别是: 名称 ID 说明字符 Check IDM_CHECK SetCheck Demo/nSetCheck Demo Disable IDM_DISABLE Disable Demo/nDisable Demo ShowText on DialogBar IDM_SHOW_TXT ShowText on DialogBar Demo/nShowText on DialogBar
/n前的字符串将显示在状态条中作为命令解释,/n后的部分将作为具有相同ID的工具条按钮的提示显示在ToolTip窗口中。
修改Dialog Bar:在Dialog Bar中添加一个输入框和按钮,按钮的ID为IDM_SHOW_TXT与一个菜单项具有相同的ID,这样可以利用映射菜单消息来处理按钮消息(当然使用不同ID值也可以利用ON_COMMAND来映射Dialog Bar上的按钮消息,但是ClassWizard没有提供为Dialog Bar上按钮进行映射的途径,只能手工添加消息映射代码)。图例
修改工具条:在工具条中添加两个按钮,ID值为IDM_CHECK和IDM_DISABLE和其中两个菜单项具有相同的ID值。图例
利用ClassWizard为三个菜单项添加消息映射和更新命令。图例
修改MainFrm.h文件
//添加一个成员变量来记录工具条上Check按钮的检查状态。 protected: BOOL m_fCheck; //手工添加状态条第二部分用于显示时间的更新命令,和用于禁止/允许输入框的更新命令 //{{AFX_MSG(CMainFrame) afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); afx_msg void OnCheck(); afx_msg void OnUpdateCheck(CCmdUI* pCmdUI); afx_msg void OnDisable(); afx_msg void OnUpdateDisable(CCmdUI* pCmdUI); afx_msg void OnShowTxt(); afx_msg void OnUpdateShowTxt(CCmdUI* pCmdUI); //}}AFX_MSG //上面的部分为ClassWizard自动产生的代码 afx_msg void OnUpdateTime(CCmdUI* pCmdUI); //显示时间 afx_msg void OnUpdateInput(CCmdUI* pCmdUI); //禁止/允许输入框
修改MainFrm.cpp文件
//修改状态条上各部分ID #define ID_TIME 0x705 //作为状态条上第二部分ID static UINT indicators[] = { ID_SEPARATOR, // status line indicator ID_SEPARATOR, //先设置为ID_SEPARATOR,在状态条创建后再进行修改 }; //修改消息映射 //{{AFX_MSG_MAP(CMainFrame) ON_WM_CREATE() ON_COMMAND(IDM_CHECK, OnCheck) ON_UPDATE_COMMAND_UI(IDM_CHECK, OnUpdateCheck) ON_COMMAND(IDM_DISABLE, OnDisable) ON_UPDATE_COMMAND_UI(IDM_DISABLE, OnUpdateDisable) ON_COMMAND(IDM_SHOW_TXT, OnShowTxt) ON_UPDATE_COMMAND_UI(IDM_SHOW_TXT, OnUpdateShowTxt) //}}AFX_MSG_MAP //以上部分为ClassWizard自动生成代码 ON_UPDATE_COMMAND_UI(ID_TIME, OnUpdateTime) 显示时间 ON_UPDATE_COMMAND_UI(IDC_INPUT_TEST, OnUpdateInput) //禁止/允许输入框 //修改OnCreate函数,重新设置状态条第二部分ID值 int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) { .... // by wenyy 修改状态条上第二部分信息 m_wndStatusBar.SetPaneInfo(1,ID_TIME,SBPS_NORMAL,60); //set the width return 0; } //修改经过映射的消息处理函数代码 void CMainFrame::OnCheck() { //在Check按钮被按下时改变并保存状态 m_fCheck=!m_fCheck; }
void CMainFrame::OnUpdateCheck(CCmdUI* pCmdUI) { //Check按钮是否设置为检查状态 pCmdUI->SetCheck(m_fCheck); }
void CMainFrame::OnDisable() { //Disable按钮被按下 AfxMessageBox("you press disable test"); }
void CMainFrame::OnUpdateDisable(CCmdUI* pCmdUI) { //根据Check状态决定自身禁止/允许状态 pCmdUI->Enable(m_fCheck); }
void CMainFrame::OnShowTxt() { //得到Dialog Bar上输入框中文字并显示 CEdit* pE=(CEdit*)m_wndDlgBar.GetDlgItem(IDC_INPUT_TEST); CString szO; pE->GetWindowText(szO); AfxMessageBox(szO); }
void CMainFrame::OnUpdateShowTxt(CCmdUI* pCmdUI) { //Dialog Bar上按钮根据Check状态决定自身禁止/允许状态 pCmdUI->Enable(m_fCheck); }
void CMainFrame::OnUpdateInput(CCmdUI* pCmdUI) { //Dialog Bar上输入框根据Check状态决定自身禁止/允许状态 pCmdUI->Enable(m_fCheck); }
void CMainFrame::OnUpdateTime(CCmdUI* pCmdUI) { //根据当前时间设置状态条上第二部分文字 CTime timeCur=CTime::GetCurrentTime(); char szOut[20]; sprintf( szOut, "%02d:%02d:%02d", timeCur.GetHour(), timeCur.GetMinute(),timeCur.GetSecond()); pCmdUI->SetText(szOut); }
4.E General Window
从VC提供的MFC类派生图中我们可以看出窗口的派生关系,派生图,所有的窗口类都是由CWnd派生。所有CWnd的成员函数在其派生类中都可以使用。本节介绍一些常用的功能给大家。
改变窗口状态: BOOL EnableWindow( BOOL bEnable = TRUE );可以设置窗口的禁止/允许状态。BOOL IsWindowEnabled( );可以查询窗口的禁止/允许状态。 BOOL ModifyStyle( DWORD dwRemove, DWORD dwAdd, UINT nFlags = 0 )/BOOL ModifyStyleEx( DWORD dwRemove, DWORD dwAdd, UINT nFlags = 0 );可以修改窗口的风格,而不需要调用SetWindowLong BOOL IsWindowVisible( ) 可以检查窗口是否被显示。 BOOL ShowWindow( int nCmdShow );将改变窗口的显示状态,nCmdShow可取如下值:
SW_HIDE 隐藏窗口 SW_MINIMIZE SW_SHOWMAXIMIZED 最小化窗口 SW_RESTORE 恢复窗口 SW_SHOW 显示窗口 SW_SHOWMINIMIZED 最大化窗口
改变窗口位置: void MoveWindow( LPCRECT lpRect, BOOL bRepaint = TRUE );可以移动窗口。 void GetWindowRect( LPRECT lpRect ) ;可以得到窗口的矩形位置。 BOOL IsIconic( ) ;可以检测窗口是否已经缩为图标。 BOOL SetWindowPos( const CWnd* pWndInsertAfter, int x, int y, int cx, int cy, UINT nFlags );可以改变窗口的Z次序,此外还可以移动窗口位置。
使窗口失效,印发重绘: void Invalidate( BOOL bErase = TRUE );使整个窗口失效,bErase将决定窗口是否产生重绘。 void InvalidateRect( LPCRECT lpRect, BOOL bErase = TRUE )/void InvalidateRgn( CRgn* pRgn, BOOL bErase = TRUE );将使指定的矩形/多边形区域失效。
窗口查找: static CWnd* PASCAL FindWindow( LPCTSTR lpszClassName, LPCTSTR lpszWindowName );可以以窗口的类名和窗口名查找窗口。任一参数设置为NULL表对该参数代表的数据进行任意匹配。如FindWindow("MyWnd",NULL)表明查找类名为MyWnd的所有窗口。 BOOL IsChild( const CWnd* pWnd ) 检测窗口是否为子窗口。 CWnd* GetParent( ) 得到父窗口指针。 CWnd* GetDlgItem( int nID ) 通过子窗口ID得到窗口指针。 int GetDlgCtrlID( ) 得到窗口ID值。 static CWnd* PASCAL WindowFromPoint( POINT point );将从屏幕上某点坐标得到包含该点的窗口指针。 static CWnd* PASCAL FromHandle( HWND hWnd );通过HWND构造一个CWnd*指针,但该指针在空闲时会被删除,所以不能保存供以后使用。
时钟: UINT SetTimer( UINT nIDEvent, UINT nElapse, void (CALLBACK EXPORT* lpfnTimer)(HWND, UINT, UINT, DWORD) );可以创建一个时钟,如果lpfnTimer回调函数为NULL,窗口将会收到WM_TIMER消息,并可以在afx_msg void OnTimer( UINT nIDEvent );中安排处理代码 BOOL KillTimer( int nIDEvent );删除一个指定时钟。
可以利用重载来添加消息处理的虚函数: afx_msg int OnCreate( LPCREATESTRUCT lpCreateStruct );窗口被创建时被调用 afx_msg void OnDestroy( );窗口被销毁时被调用 afx_msg void OnGetMinMaxInfo( MINMAXINFO FAR* lpMMI );需要得到窗口尺寸时被调用 afx_msg void OnSize( UINT nType, int cx, int cy );窗口改变大小后被调用 afx_msg void OnMove( int x, int y );窗口被移动后时被调用 afx_msg void OnPaint( );窗口需要重绘时时被调用,你可以填如绘图代码,对于视图类不需要重载OnPaint,所有绘图代码应该在OnDraw中进行 afx_msg void OnChar( UINT nChar, UINT nRepCnt, UINT nFlags );接收到字符输入时被调用 afx_msg void OnKeyDown/OnKeyUp( UINT nChar, UINT nRepCnt, UINT nFlags );键盘上键被按下/放开时被调用 afx_msg void OnLButtonDown/OnRButtonDown( UINT nFlags, CPoint point );鼠标左/右键按下时被调用 afx_msg void OnLButtonUp/OnRButtonUp( UINT nFlags, CPoint point );鼠标左/右键放开时被调用 afx_msg void OnLButtonDblClk/OnRButtonDblClk( UINT nFlags, CPoint point );鼠标左/右键双击时被调用 afx_msg void OnMouseMove( UINT nFlags, CPoint point );鼠标在窗口上移动时被调用
5.1 使用资源编辑器编辑对话框
在Windows开发中弹出对话框是一种常用的输入/输出手段,同时编辑好的对话框可以保存在资源文件中。Visual C++提供了对话框编辑工具,利用编辑工具可以方便的添加各种控件到对话框中,而且利用ClassWizard可以方便的生成新的对话框类和映射消息。
首先资源列表中按下右键,可以在弹出菜单中选择“插入对话框”,如图1。然后再打开该对话框进行编辑,你会在屏幕上看到一个控件板,如图2。你可以将所需要添加的控件拖到对话框上,或是先选中后再在对话框上用鼠标画出所占的区域。
接下来我们在对话框上产生一个输入框,和一个用于显示图标的图片框。之后我们使用鼠标右键单击产生的控件并选择其属性,如图3。我们可以在属性对话框中编辑控件的属性同时也需要指定控件ID,如图4,如果在选择对话框本身的属性那么你可以选择对话框的一些属性,包括字体,外观,是否有系统菜单等等。最后我们编辑图片控件的属性,如图5,我们设置控件的属性为显示图标并指明一个图标ID。
接下来我们添加一些其他的控件,最后的效果如图6。按下Ctrl-T可以测试该对话框。此外在对话框中还有一个有用的特性,就是可以利用Tab键让输入焦点在各个控件间移动,要达到这一点首先需要为控件设置在Tab键按下时可以接受焦点移动的属性Tab Stop,如果某一个控件不打算利用这一特性,你需要清除这一属性。然后从菜单“Layout”选择Tab Order来确定焦点移动顺序,如图7。使用鼠标依此点击控件就可以重新规定焦点移动次序。最后按下Ctrl-T进行测试。
最后我们需要为对话框产生新的类,ClassWizard可以替我们完成大部分的工作,我们只需要填写几个参数就可以了。在编辑好的对话框上双击,然后系统回询问是否添加新的对话框,选择是并在接下来的对话框中输入类名就可以了。ClassWizard会为你产生所需要的头文件和CPP文件。然后在需要使用的地方包含相应的头文件,对于有模式对话框使用DoModal()产生,对于无模式对话框使用Create()产生。相关代码如下;
void CMy51_s1View::OnCreateDlg() {//产生无模式对话框 CTestDlg *dlg=new CTestDlg; dlg->Create(IDD_TEST_DLG); dlg->ShowWindow(SW_SHOW); }
void CMy51_s1View::OnDoModal() {//产生有模式对话框 CTestDlg dlg; int iRet=dlg.DoModal(); TRACE("dlg return %d/n",iRet); }
下载例子。如果你在调试这个程序时你会发现程序在退出后会有内存泄漏,这是因为我没有释放无模式对话框所使用的内存,这一问题会在以后的章节5.3 创建无模式对话框中专门讲述。
关于在使用对话框时Enter键和Escape键的处理:在使用对话框是你会发现当你按下Enter键或Escape键都会退出对话框,这是因为Enter键会引起CDialog::OnOK()的调用,而Escape键会引起CDialog::OnCancel()的调用。而这两个调用都会引起对话框的退出。在MFC中这两个成员函数都是虚拟函数,所以我们需要进行重载,如果我们不希望退出对话框那么我们可以在函数中什么都不做,如果需要进行检查则可以添加检查代码,然后调用父类的OnOK()或OnCancel()。相关代码如下;
void CTestDlg::OnOK() { AfxMessageBox("你选择确定"); CDialog::OnOK(); }
void CTestDlg::OnCancel() { AfxMessageBox("你选择取消"); CDialog::OnCancel(); }
5.2 创建有模式对话框
使用有模式对话框时在对话框弹出后调用函数不会立即返回,而是等到对话框销毁后才会返回(请注意在对话框弹出后其他窗口的消息依然会被传递)。所以在使用对话框时其他窗口都不能接收用户输入。创建有模式对话框的方法是调用CDialog::DoModal()。下面的代码演示了这种用法:
CYourView::OnOpenDlg() { CYourDlg dlg; int iRet=dlg.DoModal(); }
CDialog::DoModal()的返回值为IDOK,IDCANCEL。表明操作者在对话框上选择“确认”或是“取消”。由于在对话框销毁前DoModal不会返回,所以可以使用局部变量来引用对象。在退出函数体后对象同时也会被销毁。而对于无模式对话框则不能这样使用,下节5.3 创建无模式对话框中会详细讲解。
你需要根据DoModal()的返回值来决定你下一步的动作,而得到返回值也是使用有模式对话框的一个很大原因。
使用有模式对话框需要注意一些问题,比如说不要在一些反复出现的事件处理过程中生成有模式对话框,比如说在定时器中产生有模式对话框,因为在上一个对话框还未退出时,定时器消息又会引起下一个对话框的弹出。
同样的在你的对话框类中为了向调用者返回不同的值可以调用CDialog::OnOK()或是CDialog::OnCancel()以返回IDOK或IDCANCEL,如果你希望返回其他的值,你需要调用 CDialog::EndDialog( int nResult );其中nResult会作为DoModal()调用的返回值。
下面的代码演示了如何使用自己的函数来退出对话框:
void CMy52_s1View::OnLButtonDown(UINT nFlags, CPoint point) {//创建对话框并得到返回值 CView::OnLButtonDown(nFlags, point); CTestDlg dlg; int iRet=dlg.DoModal(); CString szOut; szOut.Format("return value %d",iRet); AfxMessageBox(szOut); } //重载OnOK,OnCancel void CTestDlg::OnOK() {//什么也不做 } void CTestDlg::OnCancel() {//什么也不做 } //在对话框中对三个按钮消息进行映射 void CTestDlg::OnExit1() { CDialog::OnOK(); } void CTestDlg::OnExit2() { CDialog::OnCancel(); } void CTestDlg::OnExit3() { CDialog::EndDialog(0XFF); }
由于重载了OnOK和OnCancel所以在对话框中按下Enter键或Escape键时都不会退出,只有按下三个按钮中的其中一个才会返回。
此外在对话框被生成是会自动调用BOOL CDialog::OnInitDialog(),你如果需要在对话框显示前对其中的控件进行初始化,你需要重载这个函数,并在其中填入相关的初始化代码。利用ClassWizard可以方便的产生一些默认代码,首先打开ClassWizard,选择相应的对话框类,在右边的消息列表中选择WM_INITDIALOG并双击,如图,ClassWizard会自动产生相关代码,代码如下:
BOOL CTestDlg::OnInitDialog() { /*先调用父类的同名函数*/ CDialog::OnInitDialog(); /*填写你的初始化代码*/ return TRUE; }
VC小知识总结:
(1) 如何通过代码获得应用程序主窗口的 指针? 主窗口的 指针保存在CWinThread::m_pMainWnd中,调用AfxGetMainWnd实现。 AfxGetMainWnd() ->ShowWindow(SW_SHOWMAXMIZED) //使程序最大化.
(2) 确定应用程序的路径 Use GetModuleFileName 获得应用程序的路径,然后去掉可执行文件名。 Example: TCHAR exeFullPath[MAX_PATH] // MAX_PATH在API中定义了吧,好象是 128 GetModuleFileName(NULL,exeFullPath,MAX_PATH)
(3) 如何在程序中获得其他程序的 图标? 两种方法: (1) SDK函数 SHGetFileInfo 或使用 ExtractIcon获得图标资源的 handle, (2) SDK函数 SHGetFileInfo 获得有关文件的很多信息,如大小图标,属性, 类型等. Example(1): 在程序窗口左上角显示 NotePad图标. void CSampleView: OnDraw(CDC * pDC) { if( :: SHGetFileInfo(_T("c://pwin95//notepad.exe"),0, &stFileInfo,sizeof(stFileInfo),SHGFI_ICON)) { pDC ->DrawIcon(10,10,stFileInfo.hIcon) } } Example(2):同样功能,Use ExtractIcon Function void CSampleView:: OnDraw(CDC *pDC) { HICON hIcon=:: ExtractIcon(AfxGetInstanceHandle(),_T ("NotePad.exe"),0) if (hIcon &&hIcon!=(HICON)-1) pDC->DrawIcon(10,10,hIcon) } 说明: 获得notepad.exe的路径正规上来说用GetWindowsDirectory函数得到, 如果是调用 win95下的画笔,应该用访问注册表的方法获得其路径,要作成一个比较考究的程序,考虑应该全面点.
(4) 获得各种目录信息 Windows目录: Use "GetWindowsDirectory" Windows下的system目录: Use "GetSystemDirectory" temp目录: Use "GetTempPath" 当前目录: Use "GetCurrentDirectory" 请注意前两个函数的第一个参数为目录变量名,后一个为缓冲区后两个相反.
(5) 如何自定义消息 1) 手工定义消息,可以这么写 #define WM_MY_MESSAGE(WM_USER+100), MS 推荐的至少是 WM_USER+100 (2)写消息处理函数,用 WPARAM,LPARAM返回LRESULT. LRESULT CMainFrame::OnMyMessage(WPARAM wparam,LPARAM lParam) { temp目录: Use "GetTempPath" //加入你的处理函数 irectory" }
(6) 如何改变窗口的图标? 向窗口发送 WM_SECTION消息。 Example: HICON hIcon=AfxGetApp() ->LoadIcon(IDI_ICON) ASSERT(hIcon) AfxGetMainWnd() ->SendMessage(WM_SECTION,TRUE,(LPARAM)hIcon)
(7) 如何改变窗口的缺省风格? 重载 CWnd:: PreCreateWindow 并修改CREATESTRUCT结构来指定窗口风格和其他创建信息. Example: Delete "Max" Button and Set Original Window's Position and Size BOOL CMainFrame:: PreCreateWindow (CREATESTRUCT &cs) { cs.style &=~WS_MAXINIZEMOX cs.x=cs.y=0 cs.cx=GetSystemMetrics(SM_CXSCREEN/2) cs.cy=GetSystemMetrics(SM_CYSCREEN/2) return CMDIFramewnd ::PreCreateWindow(cs) }
(8) 如何将窗口居中显示? Call Function CWnd:: Center Windows Example(1): Center Window( ) //Relative to it's parent // Relative to Screen Example(2): Center Window(CWnd:: GetDesktopWindow( )) //Relative to Application's MainWindow AfxGetMainWnd( ) -> Center Window( )
(9) 如何让窗口和 MDI窗口一启动就最大化和最小化? 先说窗口。在 InitStance 函数中设定 m_nCmdShow的取值. m_nCmdShow=SW_SHOWMAXMIZED //最大化 m_nCmdShow=SW_SHOWMINMIZED //最小化 m_nCmdShow=SW_SHOWNORMAL //正常方式 MDI窗口: 如果是创建新的应用程序,可以用MFC AppWizard 的Advanced 按钮并在MDI子窗口风格组中检测最大化或最小化还可以重载 MDI Window 的PreCreateWindow函数,设置WS_MAXMIZE or WS_MINMIZE 如果从 CMDIChildWnd派生,调用 OnInitialUpdate函数中的 CWnd::Show Window来指定 MDI Child Window的风格。
(10) 如何限制窗口的大小? 也就是 FixedDialog形式。 Windows发送 WM_GETMAXMININFO消息来跟踪, 响应它,在 OnGetMAXMININFO 中写代码:
(11) 如何使窗口不可见? 很简单,用SW_HIDE 隐藏窗口,可以结合 FindWindow,ShowWindow控制.
(12) 如何创建一个字回绕的CEditView 重载CWnd : : PreCreateWindow和修改CREATESTRUCT结构,关闭CEditView对象的ES_AUTOHSCROLL和WS_HSCROLL风格位, 由于CEditView : : PreCreateWindow显示设置cs. style,调用基类函数后要修改cs . style。 BOOL CSampleEDitView : : PreCreateWindow (CREATESTRUCT&cs) { //First call basse class function . BOOL bResutl =CEditView : : PreCreateWindow (cs) // Now specify the new window style . cs.style &= ~ (ES_AUTOHSCROLL |WS_HSCROLL) return bResult }
(13) 如何使程序保持极小状态? 这么办: 在恢复程序窗体大小时,Windows会发送WM_QUERY-OPEN消息,用 ClassWizard设置成员函数 OnQueryOpen() ,add following code: Bool CMainFrame:: OnQueryOpen( ) { Return false }
(14) 移动窗口 调用CWnd : : SetWindowPos并指定SWP_NOSIZE标志。目的位置与父窗口有关(顶层窗口与屏幕有关)。调用CWnd : : MoveWindow时必须要指定窗口的大小。 //Move window to positoin 100 , 100 of its parent window . SetWindowPos (NULL, 100 , 100 , 0 , 0 , SWP_NOSIZE |SWP_NOAORDER)
(15) 通用控件的显示窗口 MFC提供了几个CView派生的视窗类, 封装了通用控件的功能,但仍然使用工作框文档显示窗口体系结构:CEditView封装了编辑控件,CTreeView保持了树列表控件,CListView封装了列表显示窗口控件,CRichEditView可以处理多种编辑控件。
(16) 重置窗口的大小 调用CWnd: : SetWindowPos并指定SWP_NOMOVE标志, 也可调用CWnd : : MoveWindow 但必须指定窗口的位置。 // Get the size of the window . Crect reWindow GetWindowRect (reWindow ) //Make the window twice as wide and twice as tall . SetWindowPos (NULL , 0 , 0 , reWindow . Width ( ) *2, reWindow . Height () * 2, SWP_NOMOVE |SWP_NOZORDER )
(17) 如何单击除了窗口标题栏以外的区域使窗口移动 当窗口需要确定鼠标位置时Windows向窗口发送WM_NCHITTEST信息,可以处理该信息使Windows认为鼠标在窗口标题上。对于对话框和基于对话的应用程序,可以使用ClassWizard处理该信息并调用基类函数, 如果函数返回HTCLIENT 则表明鼠标在客房区域,返回HTCAPTION表明鼠标在Windows的标题栏中。 UINT CSampleDialog : : OnNcHitTest (Cpoint point ) { UINT nHitTest =Cdialog: : OnNcHitTest (point ) return (nHitTest = =HTCLIENT)? HTCAPTION : nHitTest } 上述技术有两点不利之处,其一是在窗口的客户区域双击时,窗口将极大;其二, 它不适合包含几个视窗的主框窗口。还有一种方法,当用户按下鼠标左键使主框窗口认为鼠标在其窗口标题上,使用ClassWizard在视窗中处理WM_LBUTTODOWN信息并向主框窗口发送一个WM_NCLBUTTONDOWN信息和一个单击测试HTCAPTION。 void CSampleView : : OnLButtonDown (UINT nFlags , Cpoint point ) { CView : : OnLButtonDow (nFlags , pont ) //Fool frame window into thinking somene clicked on its caption bar . GetParentFrame ( ) —> PostMessage ( WM_NCLBUTTONDOWN , HTCAPTION , MAKELPARAM (poitn .x , point .y) ) } 该技术也适用于对话框和基于对的应用程序,只是不必调用 CWnd: :GetParentFrame 。 void CSampleDialog : : OnLbuttonDown (UINT nFlags, Cpoint point ) { Cdialog : : OnLButtonDow (nFlags, goint ) //Fool dialog into thinking simeone clicked on its caption bar . PostMessage (WM_NCLBUTTONDOWN , HTCAPTION , MAKELPARM (point.x , point. y ) ) }
(18) 如何改变视窗的背景颜色 Windows向窗口发送一个WM_ERASEBKGND消息通知该窗口擦除背景,可以使用ClassWizard重载该消息的缺省处理程序来擦除背景(实际是画),并返回TRUE以防止Windows擦除窗口。 //Paint area that needs to be erased. BOOL CSampleView : : OnEraseBkgnd (CDC* pDC) { // Create a pruple brush. CBrush Brush (RGB (128 , 0 , 128) ) // Select the brush into the device context . CBrush* pOldBrush = pDC—>SelcetObject (&brush) // Get the area that needs to be erased . CRect reClip pDC—>GetCilpBox (&rcClip) //Paint the area. pDC—> PatBlt (rcClip.left , rcClip.top , rcClip.Width ( ) , rcClip.Height( ) , PATCOPY ) //Unselect brush out of device context . pDC—>SelectObject (pOldBrush ) // Return nonzero to half fruther processing . return TRUE }
(19) 如何改变窗口标题 调用CWnd : : SetWindowText可以改变任何窗口(包括控件)的标题。 //Set title for application's main frame window . AfxGetMainWnd ( ) —> SetWindowText (_T("Application title") ) //Set title for View's MDI child frame window . GetParentFrame ( ) —> SetWindowText ("_T ("MDI Child Frame new title") ) //Set title for dialog's push button control. GetDigitem (IDC_BUTTON) —> SetWindowText (_T ("Button new title ") ) 如果需要经常修改窗口的标题(注:控件也是窗口),应该考虑使用半文档化的函数AfxSetWindowText。该函数在AFXPRIV.H中说明,在WINUTIL.CPP中实现,在联机帮助中找不到它,它在AFXPRIV.H中半文档化, 在以后发行的MFC中将文档化。 AfxSetWindowText的实现如下: voik AFXAPI AfxSetWindowText (HWND hWndCtrl , LPCTSTR IpszNew ) { itn nNewLen= Istrlen (Ipaznew) TCHAR szOld [256] //fast check to see if text really changes (reduces flash in the controls ) if (nNewLen >_contof (szOld) || : : GetWindowText (hWndCrtl, szOld , _countof (szOld) !=nNewLen || Istrcmp (szOld , IpszNew)! = 0 { //change it : : SetWindowText(hWndCtrl , IpszNew ) } }
(20) 如何防止主框窗口在其说明中显示活动的文档名 创建主框窗口和MDI子窗口进通常具有FWS_ADDTOTITLE风格位,如果不希望在说明中自动添加文档名, 必须禁止该风格位, 可以使用ClassWizard重置 CWnd: : PreCreateWindow并关闭FWS_ADDTOTITLE风格。 BOOL CMainFrame : : PreCreateWindow (CREATESTRUCT&cs) { //Turn off FWS_ADDTOTITLE in main frame . cs.styel & = ~FWS_ADDTOTITLE return CMDIFrameWnd : : PreCreateWindow (cs ) } 关闭MDI子窗口的FWS _ADDTOTITLE风格将创建一个具有空标题的窗口,可以调用CWnd: : SetWindowText来设置标题。记住自己设置标题时要遵循接口风格指南。
(21) 如何获取有关窗口正在处理的当前消息的信息 调用CWnd: : GetCurrentMessage可以获取一个MSG指针。例如,可以使用ClassWizard将几个菜单项处理程序映射到一个函数中,然后调用GetCurrentMessage来确定所选中的菜单项。 viod CMainFrame : : OnCommmonMenuHandler ( ) { //Display selected menu item in debug window . TRACE ("Menu item %u was selected . /n" ,
(22) 如何在代码中获取工具条和状态条的指针 缺省时, 工作框创建状态条和工具条时将它们作为主框窗口的子窗口,状态条有一个AFX_IDW_STATUS_BAR标识符,工具条有一个AFX_IDW_TOOLBAR标识符,下例说明了如何通过一起调用CWnd: : GetDescendantWindow和AfxGetMainWnd来获取这些子窗口的指针: //Get pointer to status bar . CStatusBar * pStatusBar = (CStatusBar *) AfxGetMainWnd ( ) —> GetDescendantWindow(AFX_IDW_STUTUS_BAR) //Get pointer to toolbar . CToolBar * pToolBar = (CToolBar * ) AfxGetMainWnd ( ) —> GetDescendantWindow(AFX_IDW_TOOLBAR)
(23) 如何使能和禁止工具条的工具提示 如果设置了CBRS_TOOLTIPS风格位,工具条将显示工具提示,要使能或者禁止工具提示,需要设置或者清除该风格位。下例通过调用CControlBar : : GetBarStyle和CControlBar : : SetBarStyle建立一个完成此功能的成员函数: void CMainFrame : : EnableToolTips ( BOOL bDisplayTips ) { ASSERT_VALID (m_wndToolBar) DWORD dwStyle = m _wndToolBar.GetBarStyle ( ) if (bDisplayTips) dwStyle |=CBRS_TOOLTIPS else dwStyle & = ~CBRS_TOOLTIPS m_wndToolBar.SetBarStyle (dwStyle ) }
(24) 如何创建一个不规则形状的窗口 可以使用新的SDK函数SetWindowRgn。该函数将绘画和鼠标消息限定在窗口的一个指定的区域,实际上使窗口成为指定的不规则形状。 使用AppWizard创建一个基于对的应用程序并使用资源编辑器从主对话资源中删除所在的缺省控件、标题以及边界。给对话类增加一个CRgn数据成员,以后要使用该数据成员建立窗口区域。 Class CRoundDlg : public CDialog { … private : Crgn m_rgn : // window region … } 修改OnInitDialog函数建立一个椭圆区域并调用SetWindowRgn将该区域分配给窗口: BOOL CRoundDlg : : OnInitDialog ( ) { CDialog : : OnInitDialog ( ) //Get size of dialog . CRect rcDialog GetClientRect (rcDialog ) // Create region and assign to window . m_rgn . CreateEllipticRgn (0 , 0 , rcDialog.Width( ) , rcDialog.Height ( ) ) SetWindowRgn (GetSafeHwnd ( ) , (HRGN) m_ rgn ,TRUE ) return TRUE } 通过建立区域和调用SetWindowRgn,已经建立一个不规则形状的窗口,下面的例子程序是修改OnPaint函数使窗口形状看起来象一个球形体。 voik CRoundDlg : : OnPaint ( ) { CPaintDC de (this) // device context for painting . //draw ellipse with out any border dc. SelecStockObject (NULL_PEN) //get the RGB colour components of the sphere color COLORREF color= RGB( 0 , 0 , 255) BYTE byRed =GetRValue (color) BYTE byGreen = GetGValue (color) BYTE byBlue = GetBValue (color) // get the size of the view window Crect rect GetClientRect (rect) // get minimun number of units int nUnits =min (rect.right , rect.bottom ) //calculate he horiaontal and vertical step size float fltStepHorz = (float) rect.right /nUnits float fltStepVert = (float) rect.bottom /nUnits int nEllipse = nUnits/3 // calculate how many to draw int nIndex // current ellipse that is being draw CBrush brush // bursh used for ellipse fill color CBrush *pBrushOld // previous brush that was selected into dc //draw ellipse , gradually moving towards upper-right corner for (nIndex = 0 nIndes < + nEllipse nIndes++) { //creat solid brush brush . CreatSolidBrush (RGB ( ( (nIndex*byRed ) /nEllipse ). ( ( nIndex * byGreen ) /nEllipse ), ( (nIndex * byBlue) /nEllipse ) ) ) //select brush into dc pBrushOld= dc .SelectObject (&brhsh) //draw ellipse dc .Ellipse ( (int) fltStepHorz * 2, (int) fltStepVert * nIndex , rect. right -( (int) fltStepHorz * nIndex )+ 1, rect . bottom -( (int) fltStepVert * (nIndex *2) ) +1) //delete the brush brush.DelecteObject ( ) } } 最后,处理WM_NCHITTEST消息,使当击打窗口的任何位置时能移动窗口。 UINT CRoundDlg : : OnNchitTest (Cpoint point ) { //Let user move window by clickign anywhere on thewindow . UINT nHitTest = CDialog : : OnNcHitTest (point) rerurn (nHitTest = = HTCLIENT)? HTCAPTION: nHitTest }
(25) 如何获取应用程序的 实例句柄? 应用程序的实例句柄保存在CWinApp m_hInstance 中,可以这么调用AfxGetInstancdHandle获得句柄. Example: HANDLE hInstance=AfxGetInstanceHandle()
(26) 如何编程结束应用程序? 这是个很简单又是编程中经常要遇到的问题. 向窗口发送 WM_CLOSE消息,调用 CWnd::OnClose成员函数.允许对用户提示是否保存修改过的数据. Example: AfxGetMainWindow()->SendMessage(WM_CLOSE) 还可以创建一个自定义的函数 Terminate Window void Terminate Window(LPCSTR pCaption) { CWnd *pWnd=Cwnd::FindWindow(NULL,pCaption) if (pWnd) pWnd ->SendMessage(WM_CLOSE) } 说明: FindWindow函数不是提倡的做法,因为它无法处理标题栏自动改变,比如我们要检测 Notepad是不是已运行而事先不知道Notepad的标题栏,这时FindWindow就无能为力了,可以通过枚举 windows任务列表的办法来实现。在机械出版社"Windows 95 API开发人员指南"一书有比较详细的介绍,这里就不再多说乐。
(27) 如何创建和使用无模式对话框 MFC将模式和无模式对话封装在同一个类中,但是使用无模式对话需要几个对话需要几个额处的步骤。首先,使用资源编辑器建立对话资源并使用ClassWizard创建一个CDialog的派生类。模式和无模式对话的中止是不一样的:模式对话通过调用CDialog : : EndDialog 来中止,无模式对话则是调用CWnd: : DestroyWindow来中止的,函数CDialog : : OnOK和CDialog : : OnCancel调用EndDialog ,所以需要调用DestroyWindow并重置无模式对话的函数。 void CSampleDialog : : OnOK ( ) { // Retrieve and validate dialog data . if (! UpdateData (TRUE) ) { // the UpdateData rountine will set focus to correct item TRACEO (" UpdateData failed during dialog termination ./n") return } //Call DestroyWindow instead of EndDialog . DestroyWindow ( ) } void CSampleDialog : : OnCancel ( ) { //Call DestroyWindow instead of EndDialog . DestroyWindow ( ) } 其次,需要正确删除表示对话的C++对象。对于模式对来说,这很容易,需要创建函数返回后即可删除C++对象;无模式对话不是同步的,创建函数调用后立即返回,因而用户不知道何时删除C++对象。撤销窗口时工作框调用CWnd : : PostNcDestroy,可以重置该函数并执行清除操作,诸如删除this指针。 void CSampleDialog : : PostNcDestroy ( ) { // Declete the C++ object that represents this dialog. delete this 最后,要创建无模式对话。可以调用CDialog : : DoModal创建一个模式对放,要创建一个无模式对话则要调用CDialog: : Create。下面的例子说明 了应用程序是如何创建无模式对话的: 象;无模式对话不是同步的,创建函数调用后立即返回, void CMainFrame : : OnSampleDialog ( ) { //Allocate a modeless dialog object . CSampleDilog * pDialog =new CSampleDialog ASSERT_VALID (pDialog) Destroy ( ) //Create the modeless dialog . represents this dialog. BOOL bResult = pDialog —> Creste (IDD_IDALOG) ASSERT (bResult ) }
(28) 如何防止主框窗口在其说明中显示活动的文档名 创建主框窗口和MDI子窗口进通常具有FWS_ADDTOTITLE风格位,如果不希望在说明中自动添加文档名, 必须禁止该风格位, 可以使用ClassWizard重置 CWnd: : PreCreateWindow并关闭FWS_ADDTOTITLE风格。 BOOL CMainFrame : : PreCreateWindow (CREATESTRUCT&cs) { //Turn off FWS_ADDTOTITLE in main frame . cs.styel & = ~FWS_ADDTOTITLE return CMDIFrameWnd : : PreCreateWindow (cs ) } 关闭MDI子窗口的FWS _ADDTOTITLE风格将创建一个具有空标题的窗口,可以调用CWnd: : SetWindowText来设置标题。记住自己设置标题时要遵循接口风格指南。
(29) 如何在代码中获取工具条和状态条的指针 缺省时, 工作框创建状态条和工具条时将它们作为主框窗口的子窗口,状态条有一个AFX_IDW_STATUS_BAR标识符,工具条有一个AFX_IDW_TOOLBAR标识符,下例说明了如何通过一起调用CWnd: : GetDescendantWindow和AfxGetMainWnd来获取这些子窗口的指针: //Get pointer to status bar . CStatusBar * pStatusBar = (CStatusBar *) AfxGetMainWnd ( ) —> GetDescendantWindow(AFX_IDW_STUTUS_BAR) //Get pointer to toolbar . CToolBar * pToolBar = (CToolBar * ) AfxGetMainWnd ( ) —> GetDescendantWindow(AFX_IDW_TOOLBAR)
(30) 怎样加载其他的应用程序? 三个SDK函数 winexec, shellexecute,createprocess可以使用。 WinExec最简单,两个参数,前一个指定路径,后一个指定显示方式.后一个参数值得说一下,比如泥用 SW_SHOWMAXMIZED方式去加载一个无最大化按钮的程序,就是Neterm,calc等等,就不会出现正常的窗体,但是已经被加到任务列表里了。 ShellExecute较 WinExex灵活一点,可以指定工作目录,下面的Example就是直接打开 c:/temp/1.txt,而不用加载与 txt文件关联的应用程序,很多安装程序完成后都会打开一个窗口,来显示Readme or Faq,我猜就是这么作的啦. ShellExecute(NULL,NULL,_T("1.txt"),NULL,_T("c://temp"),SW_SHOWMAXMIZED) CreateProcess最复杂,一共有十个参数,不过大部分都可以用NULL代替,它可以指定进程的安全属性,继承信息,类的优先级等等.来看个很简单的Example: STARTUPINFO stinfo //启动窗口的信息 PROCESSINFO procinfo //进程的信息 CreateProcess(NULL,_T("notepad.exe"),NULL,NULL.FALSE, NORMAL_PRIORITY_ CLASS,NULL,NULL, &stinfo,&procinfo)
(31) 如何在代码中获取工具条和状态条的指针 缺省时, 工作框创建状态条和工具条时将它们作为主框窗口的子窗口,状态条有一个AFX_IDW_STATUS_BAR标识符,工具条有一个AFX_IDW_TOOLBAR标识符,下例说明了如何通过一起调用CWnd: : GetDescendantWindow和AfxGetMainWnd来获取这些子窗口的指针: //Get pointer to status bar . CStatusBar * pStatusBar = (CStatusBar *) AfxGetMainWnd ( ) —> GetDescendantWindow(AFX_IDW_STUTUS_BAR)
(32) 如何使能和禁止工具条的工具提示 如果设置了CBRS_TOOLTIPS风格位,工具条将显示工具提示,要使能或者禁止工具提示,需要设置或者清除该风格位。下例通过调用CControlBar : : GetBarStyle和CControlBar : : SetBarStyle建立一个完成此功能的成员函数: void CMainFrame : : EnableToolTips ( BOOL bDisplayTips ) { ASSERT_VALID (m_wndToolBar) DWORD dwStyle = m _wndToolBar.GetBarStyle ( ) if (bDisplayTips) dwStyle |=CBRS_TOOLTIPS else dwStyle & = ~CBRS_TOOLTIPS m_wndToolBar.SetBarStyle (dwStyle ) } //Get pointer to toolbar . CToolBar * pToolBar = (CToolBar * ) AfxGetMainWnd ( ) —> GetDescendantWindow(AFX_IDW_TOOLBAR)
(33) 如何设置工具条标题 工具条是一个窗口,所以可以在调用CWnd : : SetWindowText来设置标题,例子如下: int CMainFrame : : OnCreate (LPCREATESTRUCT lpCreateStruct ) { … // Set the caption of the toolbar . m_wndToolBar.SetWindowText (_T "Standdard")
(34) 如何使窗口始终在最前方? BringWindowToTop(Handle) SetWindowPos函数,指定窗口的 最顶风格,用WS_EX_TOPMOST扩展窗口的风格 Example: void ToggleTopMost( CWnd *pWnd) { ASSERT_VALID(pWnd) pWnd ->SetWindowPos(pWnd-> GetStyle( ) &WS_EX_TOPMOST)? &wndNoTopMOST: &wndTopMost,0,0,0,0,SSP_NOSIZE|WSP_NOMOVE) }
(35) 如何在对话框中显示一个位图 这要归功于Win 32先进的静态控件和Microsoft的资源编辑器,在对话框中显示位图是很容易的, 只需将图形控件拖到对话中并选择适当属性即可,用户也可以显示图标、位图以及增强型元文件。
(36) 如何改变对话或窗体视窗的背景颜色 调用CWinApp : : SetDialogBkColor可以改变所有应用程序的背景颜色。第一个参数指定了背景颜色,第二个参数指定了文本颜色。下例将应用程序对话设置为蓝色背景和黄色文本。 BOOL CSampleApp : : InitInstance ( ) { … //use blue dialog with yellow text . SetDialogBkColor (RGB (0, 0, 255 ), RGB ( 255 ,255 , 0 ) ) … } 需要重画对话(或对话的子控件)时,Windows向对话发送消息WM_CTLCOLOR,通常用户可以让Windows选择绘画背景的刷子,也可重置该消息指定刷子。下例说明了创建一个红色背景对话的步骤。 首先,给对话基类增加一人成员变量 CBursh :class CMyFormView : public CFormView { … private : CBrush m_ brush // background brush … } 其次, 在类的构造函数中将刷子初始化为所需要的背景颜色。 CMyFormView : : CMyFormView ( ) { // Initialize background brush . m_brush .CreateSolidBrush (RGB ( 0, 0, 255) ) } 最后,使用ClassWizard处理WM_CTLCOLOR消息并返回一个用来绘画对话背景的刷子句柄。注意:由于当重画对话控件时也要调用该函数,所以要检测nCtlColor参量。 HBRUSH CMyFormView : : OnCtlColor (CDC* pDC , CWnd*pWnd , UINT nCtlColor ) { // Determine if drawing a dialog box . If we are, return +handle to //our own background brush . Otherwise let windows handle it . if (nCtlColor = = CTLCOLOR _ DLG ) return (HBRUSH) m_brush.GetSafeHandle ( ) return CFormView : : OnCtlColor (pDC, pWnd , nCtlColor ) }
(37) 如何获取一个对话控件的指针 有两种方法。其一,调用CWnd: : GetDlgItem,获取一个CWnd*指针调用成员函数。下例调用GetDlgItem,将返回值传给一个CSpinButtonCtrl*以便调用CSpinButtonCtrl : : SetPos 函数: BOOL CSampleDialog : : OnInitDialog ( ) { CDialog : : OnInitDialog ( ) //Get pointer to spin button . CSpinButtonCtrl * pSpin - ( CSpinButtonCtrl *) GetDlgItem(IDC_SPIN) ASSERT _ VALID (pSpin) //Set spin button's default position . pSpin —> SetPos (10) return TRUE } 其二, 可以使用ClassWizard将控件和成员变量联系起来。在ClassWizard中简单地选择Member Variables标签,然后选择Add Variable …按钮。如果在对话资源编辑器中,按下Ctrl键并双击控件即可转到Add Member Variable对话。
(38) 如何禁止和使能控件 控件也是窗口,所以可以调用CWnd : : EnableWindow使能和禁止控件。 //Disable button controls . m_wndOK.EnableWindow (FALSE ) m_wndApply.EnableWindow (FALSE )
(39) 如何改变控件的字体 由于控件是也是窗口,用户可以调用CWnd: : SetFont指定新字体。该函数用一个Cfont指针,要保证在控件撤消之前不能撤消字体对象。下例将下压按钮的字体改为8点Arial字体: //Declare font object in class declaration (.H file ). private : Cfont m_font // Set font in class implementation (.Cpp file ). Note m_wndButton is a //member variable added by ClassWizard.DDX routines hook the member //variable to a dialog button contrlo. BOOL CSampleDialog : : OnInitDialog ( ) { … //Create an 8-point Arial font m_font . CreateFont (MulDiv (8 , -pDC —> GetDeviceCaps(LOGPIXELSY) ,72). 0 , 0 , 0 , FW_NORMAL , 0 , 0,0, ANSI_CHARSER, OUT_STROKE_PRECIS , CLIP_STROKE _PRECIS , DRAFT _QUALITY VARIABLE_PITCH |FF_SWISS, _T("Arial") ) //Set font for push button . m_wndButton . SetFont (&m _font ) … }
(40) 如何在OLE控件中使用OLE_COLOR数据类型 诸如COleControl : : GetFortColor和COleControl : : GetBackColor等函数返回OLE _COLOR数据类型的颜色,而GDI对象诸如笔和刷子使用的是COLORREF数据类型,调用COleControl : : TranslateColor可以很容易地将OLE_COLOR类型改为COLORREF类型。下例创建了一个当前背景颜色的刷子: void CSampleControl : : OnDraw (CDC* pdc const Crect& rcBounds , const Crect& rcInvalid ) { //Create a brush of the cuttent background color. CBrush brushBack (TranslateColor (GetBackColor () ) ) //Paint the background using the current backgroundcolor . pdc—> FilllRect (rcBounds , &brushBack) //other drawign commands … }
(41) 在不使用通用文件打开对话的情况下如何显示一个文件列表 调用CWnd: : DlgDirList或者CWnd: : DlgDirListComboBox,Windows 将自动地向列表框或组合框填充可用的驱动器名或者指定目录中的文件,下例将Windows目录中的文件填充在组合框中: BOOL CSampleDig : : OnInitDialog ( ) { CDialog : : OnInitDialog ( ) TCHAR szPath [MAX_PATH] = {"c://windows"} int nReslt = DlgDirListComboBox (szPath, IDC_COMBO , IDC_CURIDIR, DDL_READWRITE |DDL_READONLY|DDL_HIDDEN| DDL_SYSTEM|DDL_ARCHIVE) return TRUE }
(42) 为什么旋转按钮控件看起来倒转 需要调用CSpinCtrl : : SetRange 设置旋转按钮控件的范围,旋转按钮控件的缺省上限为0,缺省下限为100,这意味着增加时旋转按控件的值由100变为0。下例将旋转按钮控件的范围设置为0到100: BOOL CAboutDlg : : OnInitDialog ( ) { CDialog : : OnInitDialog ( ) //set the lower and upper limit of the spin button m_wndSpin . SetRange ( 0 ,100 ) return TRUE } Visual C++ 4.0 Print对话中的Copise旋转按钮控件也有同样的问题:按下Up按钮时拷贝的数目减少,而按下Down 按钮时拷贝的数目增加。
(43) 为什么旋转按钮控件不能自动地更新它下面的编辑控件 如果使用旋转按钮的autu buddy特性, 则必须保证在对话的标记顺序中buddy窗口优先于旋转按钮控件。从Layout菜单中选择Tab Order菜单项(或者按下Crtl+D)可以设置对话的标签顺序。
(44) 如何用位图显示下压按钮 Windows 95按钮有几处新的创建风格,尤其是BS_BITMAP和BS_ICON,要想具有位图按钮,创建按钮和调用CButton : : SetBitmap或CButton : : SetIcon时要指定BS_BITMAP或BS_ICON风格。 首先,设置按钮的图标属性。然后,当对话初始化时调用CButton: : SetIcon。注意:下例用图标代替位图,使用位图时要小心,因为不知道背景所有的颜色——并非每个人都使用浅灰色。 BOOL CSampleDlg : : OnInitDialog ( ) { CDialog : : OnInitDialog ( ) //set the images for the push buttons . BOOL CSampleDlg : : OnInitDialog ( ) { CDialog : : OnInitDialog ( ) //set the images for the push buttons . m_wndButton1.SetIcon (AfxGetApp ( ) —> LoadIcon (IDI _ IPTION1)) m_wndButton2.SetIcon (AfxGetApp ( ) —> LoadIcon (IDI _ IPTION2)) m_wndButton3.SetIcon (AfxGetApp ( ) —> LoadIcon (IDI _ IPTION3)) return TRUE }
(45) 如何一个创建三态下压按钮 可以使用新的BS_PUSHBUTTON 风格位和检测框以及按钮来创建一个三态下压按钮。这很容易,只需将检测框和按钮拖拉到对话中并指定属性Push—like即可。不用任何附加程序就可以成为三态下压按钮。
(46) 如何动态创建控件 分配一个控件对象的实例并调用其Create成员函数。开发者最容易忽略两件事:忘记指定WS_VISBLE标签和在栈中分配控件对象。下例动态地创建一个下压按钮控件: //In class declaration (.H file ). private : CButton* m _pButton //In class implementation (.cpp file ) . m_pButton =new CButton ASSERT_VALID (m_pButton) m_pButton —>Create (_T ("Button Title ") , WS_CHILD |WS_VISIBLE |BS_PUSHBUTTON. Crect ( 0, 0, 100 , 24) , this , IDC _MYBUTTON )
(47) 如何限制编辑框中的准许字符 如果用户在编辑控件中只允许接收数字,可以使用一个标准的编辑控件并指定新的创建标志ES_NUMBERS,它是Windows 95新增加的标志,该标志限制 编辑控件只按收数字字符。如果用户需要复杂的编辑控件,可以使用Microsoft 的屏蔽编辑控件,它是一个很有用的OLE定制控件。如果希望不使用OLE 定制控件自己处理字符,可以派生一个CEdit类并处理WM_CHAR消息,然后从编辑控件中过滤出特定的字符。首先,使用ClassWizard建立一个 CEdit的派生类,其次,在对话类中指定一个成员变量将编辑控件分类在OnInitdialog 中调用CWnd: : SubclassDlgItem . //In your dialog class declaration (.H file ) private : CMyEdit m_wndEdit // Instance of your new edit control . //In you dialog class implementation (.CPP file ) BOOL CSampleDialog : : OnInitDialog ( ) { … //Subclass the edit lontrod . m_wndEdit .SubclassDlgItem (IDC_EDIT,this) … } 使用ClassWizard处理WM_CHAR消息,计算nChar参量并决定所执行的操作,用户可以确定是否修改、传送字符。下例说明了如何显示字母字符,如果字符是字母字符,则调用CWnd OnChar,否则不调用OnChar. //Only display alphabetic dharacters . void CMyEdit : : OnChar (UINT nChar , UINT nRepCnt , UITN nFlags ) { //Determine if nChar is an alphabetic character. if (: : IsCharAlpha ( ( TCHAR) nChar ) ) CEdit : : OnChar (nChar, nRepCnt , nFlags ) } 如果要修改字符,则不能仅仅简单地用修改过的nChar调用CEdit: : OnChar,然后CEdit: : OnChar调用CWnd: : Default获取原来的wParam 和lParam 的值,这样是不行的。要修改一个字符,需要首先修改nChar,然后用修改过的nChar调用CWnd: : DefWindowProc。下例说明了如何将字符转变为大写: //Make all characters uppercase void CMyEdit : : OnChar (UINT nChar , UINT nRepCnt , UINT nFlags ) { //Make sure character is uppercase . if (: : IsCharAlpha ( .( TCHAR) nChar) nChar=: : CharUpper(nChar ) //Bypass default OnChar processing and directly call //default window proc. DefWindProc (WM_CHAR, nChar , MAKELPARAM (nRepCnt, nFlags )) }
(48) 如何改变控件的颜色 有两种方法。其一,可以在父类中指定控件的颜色,或者利用MFC4.0新的消息反射在控件类中指定颜色。 当控件需要重新着色时,工作框调用父窗口(通常是对话框)的CWnd: : OnCrtlColor,可以在父窗口类中重置该函数并指定控件的新的绘画属性。例如,下述代码将对话中的所有编辑控件文本颜色改为红色: HBRUSH CAboutDig : : OnCtlColor (CDC * pDCM , CWnd * pWnd , UINT nCtlColor) { HBRUSH hbr = CDialog : : OnCtlColor (pDC, pWnd , nCtlColor ) //Draw red text for all edit controls . if (nCtlColor= = CTLCOLOR_EDIT ) pDC —> SetTextColor (RGB (255, 0 , 0 , ) ) return hbr } 然而,由于每个父窗口必须处理通知消息并指定每个控件的绘画属性,所以,这种方法不是完全的面向对象的方法。控件处理该消息并指定绘画属性更合情合理。消息反射允许用户这样做。通知消息首先发送给父窗口,如果父窗口没有处理则发送给控件。创建一个定制彩色列表框控件必须遵循下述步骤。 首先,使用ClassWizard 创建一个CListBox 的派生类并为该类添加下述数据成员。 class CMyListBox publilc CListBox { … private COLORREF m_clrFor // foreground color COLORREF m_clrBack //background color Cbrush m_brush //background brush … } 其次,在类的构造函数中,初始化数据中。 CMyListBox : : CMyListBox () { //Initialize data members . m_clrFore =RGB (255 , 255 , 0) //yellow text m_clrBack=RGB (0 , 0 , 255) // blue background m_brush . CreateSolidBrush (m _clrBack ) } 最后,使用ClassWizard处理反射的WM_CTLCOLOR(=WM_CTLCOLOR)消息并指定新的绘画属性。 HBRUSH CMyListBox : : CtlColor (CDC* pDC, UINT nCtlColor ) { pDC—>SetTextColor (m_clrFore) pDC—>SetBkColor (m_clrBack) return (HBRUSH) m_brush.GetSafeHandle () } 现在,控件可以自己决定如何绘画,与父窗口无关。
(49) 当向列表框中添加多个项时如何防止闪烁 调用CWnd::SetRedraw 清除重画标志可以禁止CListBox(或者窗口)重画。当向列表框添加几个项时,用户可以清除重画标志,然后添加项,最后恢复重画标志。为确保重画列表框的新项,调用SetRedraw (TRUE) 之后调用CWnd::Invalidate。 //Disable redrawing. pListBox->SetRedraw (FALSE) //Fill in the list box gere //Enable drwing and make sure list box is redrawn. pListBox->SetRedraw (TRUE) pListBox->Invalidate ()
(50) 如何向编辑控件中添加文本 由于没有CEdit:: AppendText函数,用户只好自己做此项工作。调用CEdit:: SetSel移动到编辑控件末尾,然后调用CEdit:: ReplaceSel添加文本。下例是AppendText 的一种实现方法: void CMyEdit:: AppendText (LPCSTR pText) { int nLen=GetWindowTextLength () SetFocus () SetSel (nLen, nLen) ReplaceSel (pText) }
(51) 如何访问预定义的GDI对象 可以通过调用CDC:: SlectStockObject使用Windows的几个预定义的对象,诸如刷子、笔以及字体。下例使用了Windows预定义的笔和刷子GDI对象在视窗中画一个椭圆。 //Draw ellipse using stock black pen and gray brush. void CSampleView:: OnDraw (CDC* pDC) { //Determine size of view. CRect rcView GetClientRect (rcView) //Use stock black pen and stock gray brush to draw ellipse. pDC->SelectStockObject (BLACK_PEN) pDC->SelectStockObject (GRAY_BRUSH) //Draw the ellipse. pDC->Ellipse (reView) } 也可以调用新的SDK函数GetSysColorBrush获取一个系统颜色刷子,下例用背景色在视窗中画一个椭圆: void CsampleView:: OnDraw (CDC* pDC) { //Determine size of view. CRect rcView GetClientRect (rcView) //Use background color for tooltips brush. CBrush * pOrgBrush=pDC->SelectObject ( CBrush ::FromHandle( ::GetSysColorBrush (COLOR_INFOBK))) //Draw the ellipse. pDC->Ellipse (rcView) //Restore original brush. pDC->SelectObject (pOrgBrush) }
(52) 如何获取GDI对象的属性信息 可以调用GDIObject:: GetObject。这个函数将指定图表设备的消息写入到缓冲区。下例创建了几个有用的辅助函数。 //Determine if font is bold. BOOL IsFontBold (const CFont&font) { LOGFONT stFont font.GetObject (sizeof (LOGFONT), &stFont) return (stFont.lfBold)? TRUE: FALSE } //Return the size of a bitmap. CSize GetBitmapSize (const CBitmap&bitmap) { BITMAP stBitmap bitmap.GetObject (sizeof (BITMAP), &stBitmap) return CSize (stBitmap.bmWidth, stBitmap.bmHeight) } //Create a pen with the same color as a brush. BOOL CreatePenFromBrush (Cpen&pen, cost Cbrush&brush) { LOGBRUSH stBrush brush.Getobject (sizeof (LOGBRUSH), &stBrush) return pen. Createpen (PS_SOLID, 0, stBrush.ibColor) }
(53) 如何实现一个橡皮区矩形 CRectTracker是一个很有用的类,可以通过调用CRectTracker::TrackRubberBand 响应WM_LBUTTONDOWN消息来创建一个橡皮区矩形。下例表明使用CRectTracker移动和重置视窗中的蓝色椭圆的大小是很容易的事情。 首先,在文件档中声明一个CRectTracker数据成员: class CSampleView : Public CView { … public : CrectTracker m_tracker … } 其次,在文档类的构造函数中初始化CRectTracker 对象: CSampleDoc:: CSampleDOC () { //Initialize tracker position, size and style. m_tracker.m_rect.SetRect (0, 0, 10, 10) m_tracker.m_nStyle=CRectTracker:: resizeInside | CRectTracker ::dottedLine } 然后,在OnDraw函数中画椭圆和踪迹矩形: void CSampleView:: OnDraw (CDC* pDC) { CSampleDoc* pDoc=GetDocument () ASSERT_VALID (pDoc) //Select blue brush into device context. CBrush brush (RGB (0, 0, 255)) CBrush* pOldBrush=pDC->SelectObject (&brush) //draw ellipse in tracking rectangle. Crect rcEllipse pDoc->m_tracker.GetTrueRect (rcEllipse) pDC->Ellipse (rcEllipse) //Draw tracking rectangle. pDoc->m_tracker.Draw (pDC) //Select blue brush out of device context. pDC->Selectobject (pOldBrush) } 最后,使用ClassWizard处理WM_LBUTTONDOWN消息,并增加下述代码。该段代码根据鼠标击键情况可以拖放、移动或者重置椭圆的大小。 void CSampleView::OnLButtonDown (UINT nFlags, CPoint point) { //Get pointer to document. CSampleDoc* pDoc=GetDocument () ASSERT_VALID (pDoc) //If clicked on ellipse, drag or resize it.Otherwise create a //rubber-band rectangle nd create a new ellipse. BOOL bResult=pDoc->m_tracker.HitTest (point)!= CRectTracker::hitNothing //Tracker rectangle changed so update views. if (bResult) { pDoc->m_tracker.Track (this,point,TRue) pDoc->SetModifiedFlag () pDoc->UpdateAllViews (NULL) } else pDoc->m-tracker.TrackRubberBand(this,point,TRUE) CView:: onLButtonDown (nFlags,point) }
(54) 如何更新翻转背景颜色的文本 调用CDC:: SetBkmode并传送OPAQUE用当前的背景颜色填充背景,或者调用CDC::SetBkMode并传送TRANSPAARENT使背景保持不变,这两种方法都可以设置背景模式。下例设置背景模式为TRANSPARENT,可以两次更新串,用花色带黑阴影更新文本。黑色串在红色串之后,但由于设置了背景模式仍然可见。 void CSampleView:: OnDraw (CDC* pDC) { //Determint size of view. CRect rcView GetClientRect (rcVieew) //Create sample string to display. CString str (_T ("Awesome Shadow Text...")) //Set the background mode to transparent. pDC->SetBKMode (TRANSPARENT) //Draw black shadow text. rcView.OffsetRect (1, 1) pDc->SetTextColor (RGB (0, 0, 0)) pDC->DrawText (str, str.GetLength (), rcView, DT_SINGLELINE | DT_CENTER | DT_VCENTER) //Draw red text. rcView.OffsetRect (-1,-1) pDc->SetTextColor (RGB (255, 0, 0)) pDC->DrawText (str, str.GetLength (), rcView, DT_SINGLELINE | DT_CENTER | DT_VCENTER) }
(55) 如何创建一个具有特定点大小的字体 可以指定字体逻辑单位的大小,但有时指定字体的点的大小可能会更方便一些。可以如下将字体的点转换为字体的高度: int nHeigth=mulDiv (nPointSize, -dc.GetDeviceCaps (LOGPIXELSY), 72) 下例创建了一个8点的Apial字体: … CClientDC dc (AqfxGetMainWnd ()) m_font. CreateFont (MulDiv (8, -dc.GetDeviceCaps (LOGPIXELSY), 72), 0, 0, 0, FW_NORMAL, 0, 0, 0, ANSI_CHARSET, OUT_STROKE_PRECIS, CLIP_STROKE_PRECIS, DRAFT_QUALITY, VARIABLE_PITCH | FF-SWISS,_T("Arial"))
(56) 如何计算一个串的大小 函数CDC:: Det text Extent 根据当前选择的字体计算一个串的高度和宽度。如果使用的不是系统字体而是其他字体,则在调用GetTextExtent之前将字体选进设备上下文中是很重要的,否则计算高度和宽度时将依据系统字体,由此得出的结果当然是不正确的。下述样板程序当改变下压按钮的标题时动态调整按钮的大小,按钮的大小由按钮的字体和标题的大小而定。响应消息WM_SETTEXT时调用OnSetText,该消息使用ON_MESSAE宏指令定义的用户自定义消息。 LRESULT CMyButton:: OnSettext (WPARAM wParam, LPARAM lParam) { //Pass message to window procedure. LRESULT bResult=CallWindowProc (*GetSuperWndProcAddr(), m_hWnd, GetCurrentMessage() ->message,wParam,lParam) //Get title of push button. CString strTitle GetWindowText (strTitle) //Select current font into device context. CDC* pDC=GetDc () CFont*pFont=GetFont () CFont*pOldFont=pDC->SelectObject (pFont) //Calculate size of title. CSize size=pDC->GetTextExent (strTitle,strTitle.GetLength()) //Adjust the button's size based on its title. //Add a 5-pixel border around the button. SetWindowPos (NULL, 0, 0, size.cx+10, size.cy+10, SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE) //Clean up. pDC->SelectFont (pOldFont) ReleaseDC (pDC) return bResult }
(57) 如何显示旋转文本 只要用户使用TrueType或者GDI笔或字体就可以显示旋转文本(有些硬件设备也支持旋转光栅字体)。LOGFONT结构中的ifEscapement成员指定了文本行和x轴的角度,角度的单位是十分之一度而不是度,例如,ifEscapement为450表示字体旋转45度。为确保所有的字体沿坐标系统的同一方向旋转,一定要设置ifEscapement成员的CLIP_LH_ANGLES位,否则,有些字体可能反向旋转。下例使用了14点Arial字体每间隔15度画一个串。 void CSampleView:: OnDraw (CDC* pDC) { //Determine the size of the window. CRect rcClient GetClientRect (rcClient) //Create sample string. CString str (_T ("Wheeee...I am rotating!")) //Draw transparent, red text. pDC->SetBkMode (TRANSPARENT) pDC->SetTextColor (RGB (255,0,0)) CFont font //font object LOGFONT stFont //font definition //Set font attributes that will not change. memset (&stFont, 0, sizeof (LOGFONT)) stFont.ifheight=MulDiv (14, -pDC->GetDeviceCaps(LOGPIXELSY), 72) stFont.ifWeight=FW_NORMAL stFont.ifClipPrecision=LCIP_LH_ANGLES strcpy (stFont.lfFaceName, "Arial") //Draw text at 15degree intervals. for (int nAngle=0 nAngle<3600 nAngle+=150) { //Specify new angle. stFont.lfEscapement=nAngle //Create and select font into dc. font.CreateFontIndirect(&stfont) CFont* pOldFont=pDC ->SelectObject(&font) //Draw the text. pDC->SelectObject(pOldFont) font.DelectObjext() } }
(58) 如何正确显示包含标签字符的串 调用GDI文本绘画函数时需要展开标签字符,这可以通过调用CDC:: TabbedTextOut或者CDC:: DrawText并指定DT_EXPANDTABS标志来完成。TabbedTextOut函数允许指定标签位的数组,下例指定每20设备单位展开一个标签: void CSampleView:: OnDraw (CDC* pDC) { CTestDoc* pDoc=GetDocument () ASSERT_VALID (pDoC) CString str str.Format (_T ("Cathy/tNorman/tOliver")) int nTabStop=20 //tabs are every 20 pixels pDC->TabbedtextOut (10, 10, str, 1, &nTabStop, 10) }
(59) 如何快速地格式化一个CString对象 调用CString:: Format,该函数和printf函数具有相同的参数,下例说明了如何使用Format函数: //Get size of window. CRect rcWindow GetWindowRect (rcWindow) //Format message string. CString strMessage strMessage.Format (_T ("Window Size (%d, %d)"), rcWindow.Width (), rcWindow.Height ()) //Display the message. MessageBox (strmessage)
(60) 串太长时如何在其末尾显示一个省略号 调用CDC:: DrawText并指定DT_END_ELLIPSIS标志,这样就可以用小略号取代串末尾的字符使其适合于指定的边界矩形。如果要显示路径信息,指定DT_END_ELLIPSIS标志并省略号取代串中间的字符。 void CSampleView:: OnDraw (CDC* pDC) { CTestDoc* pDoc=GetDocument () ASSERT_VALID (pDoc) //Add ellpsis to end of string if it does not fit pDC->Drawtext (CString ("This is a long string"), CRect (10, 10, 80, 30), DT_LEFT | DT_END_ELLIPSIS) //Add ellpsis to middle of string if it does not fit pDC->DrawText (AfxgetApp () ->m_pszhelpfilePath, CRect (10, 40, 200, 60), DT_LEFT | DT_PATH_ELLIPSIS) }
(61) 为什么即使调用EnableMenuItem菜单项后,菜单项还处于禁止状态 需要将CFrameWnd:: m_bAutomenuEnable设置为FALSE,如果该数据成员为TRUE(缺省值),工作框将自动地禁止没有ON_UPDATE_COMMAND_UI或者ON_COMMAND的菜单项。 //Disable MFC from automatically disabling menu items. m_bAuoMenuEnable=FALSE //Now enable the menu item. CMenu* pMenu=GetMenu () ASSERT_VALID (pMenu) pMenu->EnableMenuItem (ID_MENU_ITEM,MF_BYCOMMAND | MF_ENABLED)
(62) 如何给系统菜单添加一个菜单项 给系统菜单添加一个菜单项需要进行下述三个步骤:首先,使用Resource Symbols对话(在View菜单中选择Resource Symbols...可以显示该对话)定义菜单项ID,该ID应大于0x0F而小于0xF000;其次,调用CWnd::GetSystemMenu获取系统菜单的指针并调用CWnd:: Appendmenu将菜单项添加到菜单中。下例给系统菜单添加两个新的 int CMainFrame:: OnCreate (LPCREATESTRUCT lpCreateStruct) { … //Make sure system menu item is in the right range. ASSERT (IDM_MYSYSITEM &0xFFF0)==IDM_MYSYSITEM) ASSERT (IDM-MYSYSITEM<0xF000) //Get pointer to system menu. CMenu* pSysmenu=GetSystemmenu (FALSE) ASSERT_VALID (pSysMenu) //Add a separator and our menu item to system menu. CString StrMenuItem (_T ("New menu item")) pSysMenu->Appendmenu (MF_SEPARATOR) pSysMenu->AppendMenu (MF_STRING, IDM_MYSYSITEM, strMenuitem) … } 现在,选择系统菜单项时用户应进行检测。使用ClassWizard处理WM_SYSCOMMAND消息并检测用户菜单的nID参数: void CMainFrame:: OnSysCommand (UINT nID,LPARAM lParam) { //Determine if our system menu item was selected. if ( (nID & 0xFFF0)==IDM_MYSYSITEM) { //TODO-process system menu item } else CMDIFrameWnd ::OnSysCommand (nID, lParam) } 最后,一个设计良好的UI应用程序应当在系统菜单项加亮时在状态条显示一个帮助信息,这可以通过增加一个包含系统菜单基ID的串表的入口来实现。
(63) 如何确定顶层菜单所占据的菜单行数 这可以通过简单的减法和除法来实现。首先,用户需要计算主框窗口的高度和客户区;其次,从主框窗口的高度中减去客户区、框边界以及标题的高度;最后,除以菜单栏的高度。下例成员函数是一个计算主框菜单所占据的行数的代码实现。 int CMainFrame:: GetMenuRows () { CRect rcFrame,rcClient GetWindowRect (rcFrame) GetClientRect (rcClient) return (rcFrame.Height () -rcClient.Height () - :: GetSystemMetrics(SM_CYCAPTION) - (:: getSystemMetrics(SM_CYFRAME) *2)) / :: GetSystemMetrics(SM_CYMENU) }
(64) 在用户环境中如何确定系统显示元素的颜色 调用SDK函数GetSysColor可以获取一个特定显示元素的颜色。下例说明了如何在MFC函数CMainFrameWnd:: OnNcPaint中调用该函数设置窗口标题颜色。 void CMiniFrameWnd:: OnNcPaint () { … dc.SetTextColor (:: GetSysColor (m_bActive ? COLOR_CAPTIONTEXT : COLOR_INACTIVECAPTIONTEXT)) …
(65) 如何查询和设置系统参数 在Windows 3.1 SDK中介绍过SDK函数SystemParametersInfo,调用该函数可以查询和设置系统参数,诸如按键的重复速率设置、鼠标双击延迟时间、图标字体以及桌面覆盖位图等等。 //Create a font that is used for icon titles. LOGFONT stFont ∶: SystemParametersInfo (SPIF_GETICONTITLELOGFONT, sizeof (LOGFONT), &stFont, SPIF_SENDWININICHANGE) m_font.CreateFontIndirect (&stFont) //Change the wallpaper to leaves.bmp. ∶ : SystemParametersInfo (SPI_SETDESKWALLPAPER, 0, _T (" forest.bmp"), SPIF_UPDATEINIFILE)
(66) 如何确定当前屏幕分辨率 调用SDK函数GetSystemMetrics,该函数可以检索有关windows显示信息,诸如标题大小、边界大小以及滚动条大小等等。 //Initialize CSize object with screen size. CSize sizeScreen (GetSystemMetrics (SM_CXSCREEN), GetSystemMetrics (SM_CYSCREEN))
(67) 如何使用一个预定义的Windows光标 调用CWinApp:: LoadStandardCursor并传送光标标识符。 BOOL CSampleDialog:: OnSetCursor (CWnd* pWnd, UINT nHitTest, UINT message) { //Display wait cursor if busy. if (m_bBusy) { SetCursor (AfxGetApp () ->LoadStandardCursor (IDC_WAIT)) return TRUE } return CDialog:: OnSetCursor (pWnd. nHitTest,message) }
(68) 如何检索原先的Task Manager应用程序使用的任务列表 原先的Task Manager应用程序显示顶层窗口的列表。为了显示该列表,窗口必须可见、包含一个标题以及不能被其他窗口拥有。调用CWnd:: GetWindow可以检索顶层窗口的列表,调用IsWindowVisible、GetWindowTextLength以及GetOwner可以确定窗口是否应该在列表中。下例将把TaskManager窗口的标题填充到列表中。 void GetTadkList (CListBox&list) { CString strCaption //Caption of window. list.ResetContent () //Clear list box. //Get first Window in window list. ASSERT_VALID (AfxGetMainWnd ()) CWnd* pWnd=AfxGetMainWnd () ->GetWindow (GW_HWNDFIRST) //Walk window list. while (pWnd) { // I window visible, has a caption, and does not have an owner? if (pWnd ->IsWindowVisible() && pWnd ->GetWindowTextLength () &&! pWnd ->GetOwner ()) { //Add caption o window to list box. pWnd ->GetWindowText (strCaption) list.AddString (strCaption) } //Get next window in window list. pWnd=pWnd ->GetWindow(GW_HWNDNEXT) } }
(69) 如何确定Windows和Windows系统目录 有两个SDK函数可以完成该功能。GetWindowsDirectory和GetSystemDirectory,下例说明了如何使用这两个函数: TCHAR szDir [MAX_PATH] //Get the full path of the windows directory. ∶ : GetWindowsDirectory (szDir, MAX_PATH) TRACE ("Windows directory %s/n", szDir) //Get the full path of the windows system directory. ∶ : GetSystemDirectory (szDir, MAX_PATH) TRACE ("Windows system directory %s/n", szDir)
(70) 在哪儿创建临文件 调用SDK函数GetTemPath可以确定临时文件的目录,该函数首先为临时路径检测TMP环境变量:如果没有指定TMP,检测TMP环境变量,然后返回到当前目录。下例说明了如何创建一个临时文件。 … //get unique temporary file. CString strFile GetUniqueTempName (strFile) TRY { //Create file and write data.Note that file is closed //in the destructor of the CFile object. CFile file (strFile,CFile ::modeCreate | CFile:: modeWrite) //write data } CATCH (CFileException, e) { //error opening file } END_CATCH … Void GetuniqueTempName (CString& strTempName) { //Get the temporary files directory. TCHAR szTempPath [MAX_PATH] DWORD dwResult=:: GetTempPath (MAX_PATH, szTempPath) ASSERT (dwResult) //Create a unique temporary file. TCHAR szTempFile [MAX_PATH] UINT nResult=GetTempFileName (szTempPath, _T ("~ex"),0,szTempfile) ASSERT (nResult) strTempName=szTempFile }
(71) 我怎样才能建立一个等待光标? 调 用 BeginWaitCursor 函 数 来 启 动 等 待 光 标,调 用 EndWaitCursor 函 数 来 结 束 等 待 光 标。要 注 意,二 者 都 要 调 用 app 的 成 员 函 数,如 下 所 示: AfxGetApp()->BeginWaitCursor(); // 要做的事 AfxGetApp()->EndWaitCursor();
(72) 我在MDI框架中有个 form 视窗。它有个取消按钮,我需要当用户按取消按钮时可关闭form视窗。我应该如何关闭该文档? 调 用 OnCloseDocument 函 数。
(73) 如何访问桌面窗口 静态函数CWnd:: GetDesktopWindow 返回桌面窗口的指针。下例说明了MFC函数CFrameWnd::BeginModalStae是如何使用该函数进入内部窗口列表的。 void CFrameWnd::BeginModalState () { … //first count all windows that need to be disabled UINT nCount=0 HWND hWnd= :: GetWindow (:: GetDesktopWindow(), GW_CHILD) while (hWnd!=NULL) { if (:: IsWindowEnabled (hwnd) && CWnd::FromHandlePermanent (hWnd)!=NULL && AfxIsDescendant (pParent->m_hWnd, hWnd) && :: SendMessage (hWnd, WM_DISABLEMODAL, 0, 0)==0) { ++nCount } hWnd=:: GetWindow (hWnd, GW_HWNDNEXT) } …
(74) 什么是COLORREF? 我该怎样用它? COLORREF 是 一 个 32-bit 整 型 数 值,它 代 表 了 一 种 颜 色。你 可 以 使 用 RGB 函 数 来 初 始 化 COLORREF。例 如: COLORREF color = RGB(0, 255, 0); RGB 函 数 接 收 三 个 0-255 数 值,一 个 代 表 红 色, 一 个 代 表 绿 色, 一 个 代 表 蓝 色。在 上 面的 例 子 中, 红 色 和 蓝 色 值 都 为 0,所 以 在 该 颜 色 中 没 有 红 色 和 蓝 色。绿 色 为 最 大 值 255。所 以 该 颜 色 为 绿 色。0,0,0 为 黑 色,255,255,255 为 白 色。 另 一 种 初 始 化 COLORREF 的 方 法 如 下 所 示: CColorDialog colorDialog; COLORREF color; if( colorDialog.DoModal() == IDOK ) { color = colorDialog.GetColor(); } 这 段 代 码 使 用 了 MFC 中 的 颜 色 对 话 框,它 需 要 文 件。
(75) AppWizard所产生的STDAFX文件是干什么用的? 它 主 要 是 协 助 产 生 预 编 译 头 文 件 的。通 常 你 是 不 需 要 修 改 它 的。
(76) 我在我的程序中是了CDWordArray。我向它添加了约10,000个整数,这使得它变得非常非常慢。为什么会这么糟? CDWordArray 是 很 好 用 的,只 是 因 为 你 没 有 指 定 数 组 的最大尺寸。因 此,当 你 添 加 新 元 素 时,该 类 会 从 堆 中 重 新 分 配 空 间。不 幸 的 是,该 类 会 在 每 次 插 入 新 元 素 时 都 为 数 组 重 新 分 配 空 间。如 果 你 向 它 添 加 了 很 多 新 元 素,所 有 这 些 分 配 和 复 制 数 组 的 操 作 会 就 会 使 它 变 慢。解 决 该 问 题 的 方 法 是,你 可 以 使 用 SetSize 函 数 的 第 二 个 参 数 来 改 变 这 种 重 新 分 配 的 频 率。例 如,如 果 你 把 该 参 数 设 置 为 500,则 每 次 数 组 空 间 超 出 时 它 才 重 新 分 配 并 添 加 500 个 新 空 间,而 不 是 1 个。这 样 一 来,你 就 可 以 不 用 重 新 分 配 而 添 加 了 另 外 499 个 元 素 空 间,这 也 会 大 大 提 高 程 序 的 运 行 速 度。
(77) 我该如何改变MDI框架窗口的子窗口的大小以使在窗口以一定的大小打开? 在 视 中 的 OnInitialUpdate 函 数 中 调 用 GetParentFrame 函 数。GetParentFrame 会 返 回 一 指 向 一 保 存 有 该 视 的 框 架 窗 口 的 指 针。然 后 调 用 在 框 架 窗 口 上 调 用 MoveWindow。
(78) 在我的程序的某些部分,我可以调用 MessageBox 函数来建立一个信息对话框,例如在视类中。但是,在其它部分我却不能,如文档类中。为什么?我怎样才能在我的应用程序类中建立一个信息对话框? MessageBox 函 数 来 自 CWnd 类,所 以 你 只 能 在 从 CWnd 继 承 的 类 ( 如 CView ) 中 调 用 它。但 是,MFC 也 提 供 了 AfxMessageBox 函 数,你 可 以 在 任 何 地 方 调 用 它。
(79) 我需要在我的程序中设置全局变量,以使文档中的所有类都能访问。我应该吧它放到哪儿? 把 该 变 量 放 到 该 应 用 程 序 类 的 头 文 件 中 的 attribute 处。然 后,在 程 序 的 任 何 地 方,你 都 可 以 用 下 面 的 方 法 来 访 问 该 变 量: CMyApp *app = (CMyApp *)AfxGetApp(); app->MyGlobalVariable = ...
(80) 我听说MFC可以发现内存漏洞,我怎样使用该特性? 如 果 你 在 Debug 菜 单 中 的 Go 选 项 ( 不 是 Project 菜 单 中 的 Execute 选 项 ) 来 运 行 你 的 应 用 程 序,MFC 应 该 在 程 序 终 止 时 报 告 内 存 漏 洞。如 果 没 有,那 么 试 试 运 行 MFC Tracer 工 具 程 序 ( 在 VC++ 程 序 组 中 ),并 启 动 跟 踪。然 后 返 回 应 用 程 序。
(81) 我怎样才能在我的应用程序中循环浏览已经打开的文档? 使用CDocTemplate中未公开的GetFirstDocPosition()和GetNextDoc()函数。
(82)才能在我的应用程序中循环浏览已经打开的视? 使 用 CDocument 中 未 公 开 的 GetFirstViewPosition() 和 GetNextView() 函 数。
(83)数PreCreateWindow是干什么用的? PreCreateWindow 允 许 你 在 调 用 CreateWindow 之 前 来 改 变 窗 口 属 性。
(84)该怎样防止MFC在窗口标题栏上把文档名预置成应用程序名? 在 PreCreateWindow 函 数 中 删 除 FWS_PREFIXTITLE 标 志 的 窗 口 样 式: cs.style &= ~FWS_PREFIXTITLE;
(85) 我应该怎样防止MFC在窗口标题栏上添加文档名? 在 PreCreateWindow 函 数 中 删 除 FWS_ADDTOTITLE 标 志 的 窗 口 样 式: cs.style &= ~FWS_ADDTOTITLE ;
(86) 我应该如何改变视窗口的大小? 因 为 视 窗 口 实 际 上 是 框 架 窗 口 的 子 窗 口,所 以 你 必 须 改 变 框 架 窗 口 的 大 小,而 不 是 改 变 视 窗 口。使 用 CView 类 中 的 GetParentFrame() 函 数 获 得 指 向 框 架 窗 口 的 指 针,然 后 调 用 MoveWindow() 函 数 来 改 变 框 架 的 大 小。这 会 使 变 尺 寸 的 视 充 满 框 架 窗 口。
(87) 我有一无模式对话框。我怎样才能在窗口退出时删除CDialog对象? 把“delete this”加 到 PostNcDestroy 中。这 主 要 用 在 需 要 自 动 删 除 对 象 的 场 合。
(88) 为什么把“delete this”放在PostNcDestroy中而不是OnNcDestroy? OnNcDestroy 只 被 已 建 立 的 窗 口 调 用。如 果 建 立 窗 口 失 败 ( 如 PreCreateWindow ),则 没 有 窗 口 处 来 发 送 WM_NCDESTROY 消 息。PostNcDestroy 是 在 对 象 窗 口 被 完 全 删 除,在 OnNcDestroy 后,甚 至 在 窗 口 建 立 失 败 之 后 调 用 的。
(89) File菜单中的MRU列表是从哪儿来的?列表中的名字放在哪儿了?我怎样才能改变列表中项目的最大值? 在 应 用 程 序 类 的 InitInstance 函 数 中 对 LoadStdProfileSettings 的 调 用 中。该 调 用 接 受 一 个 参 数 ( 在 缺 省 情 况 下 如 果 没 有 传 递 值 则 为 4 )。MRU 文 件 名 是 从 INI 文 件 中 调 用 的。如 果 你 有 带 有 ID_FILE_MRU_FILE1 的 ID 的 菜 单 选 项,它 会 为 调 入 的 MRU 列 表 所 替 换。如 果 你 改 变 传 递 给 LoadStdProfileSettings 的 数 值 ( 最 大 为 16 ),则 你 就 改 变 了 所 装 如 文 件 名 的 最 大 值。
(90) 我在菜单中添加了新的项。但是,当我选该项时,在状态栏上没有出现任何提示信息。为什么? 打 开 资 源 文 件 中 的 菜 单 模 板。打 开 新 菜 单 选 项 的 属 性 对 话 框。在 对 话 框 的 底 部 的 Prompt 编 辑 框 中 ,你 可 以 如 下 指 定 状 态 栏 上 的 提 示 信 息 和 工 具 栏 上 的 提 示 信 息 ( 如 果 你 已 经 建 立 的 工 具 栏 按 钮 ): Status bar string/nFlying tag
(91) 我怎样才能在应用程序的缺省系统菜单中加上一些东西? 系 统 菜 单 与 其 它 菜 单 类 似,你 可 以 添 加 或 删 除 项 目,这 需 要 使 用 CMenu 类 的 成 员 函 数。下 面 的 代 码 在 你 的 系 统 菜 单 后 面 添 加 一 个 新 菜 单 项: CMenu *sysmenu; sysmenu = m_pMainWnd->GetSystemMenu(FALSE); sysmenu->AppendMenu(MF_STRING, 1000, "xxx"); 参 见 MFC 帮 助 文 件 中 的 CMenu 类。
(92) 我建立了一个对话框。但是当我显示该对话框时,第一个编辑框总是不能获得焦点,我必须单击它来使它获得焦点。我怎样才能使第一个编辑框在对话框打开时就获得焦点? 打 开 资 源 编 辑 器 中 的 对 话 框 模 板。在 Layout 菜单 中 选 择 Tab Order 选 项。按 你 的 需 求 单 击 对 话 框 中 的 控 制 来 重 新 排 列 这 些 控 制 的 tab 顺 序。
(93) 我怎样才能使一个窗口具有“always on top”特性? 在 调 用 OnFileNew 后,在 你 的 InitInstance 函 数 中 加 上 下 面 的 代 码: m_pMainWnd->SetWindowPos(&CWnd::wndTopMost,0,0,0,0, SWP_NOMOVE | SWP_NOSIZE);
(94) 我要为我的form view添加文档模板。我先建立了对话框模板,然后使用ClassWizard建立了基于CFormView的新类,它也是从CDocument继承来的。我还建立了相应的资源并在InitInstance中添加了新的文档模板。但是,当我试图运行该程序时,出现了Assertion信息。为什么?
form 的 对 话 框 模 板 需 要 些 特 殊 设 置 以 便 可 用 于 CFromView。确 保 这 些 设 置 的 最 简 单 方 法 是 使 用 AppWizard 来 建 立 CFormView 应 用 程 序,并 查 看 AppWizard 所 建 立 的 对 话 框 模 板 所 选 择 的Styles Properties。你 会 发 现 该 对 话 框 模 板 具 有 下 列 样 式:没 有 标 题 栏、不 可 见 和“Child”。把 你 的 form view 的 对 话 框 属 性 变 成 这 样 就 可 以 了。 (95) 我在一对话框中有一列表框,我需要tabbed列表框中的项目。但是,当我处理含有tab字符(用AddString添加的)的列表项时,tab被显示成小黑块而没有展开。哪儿出错了?
在 对 话 框 模 版 中,打 开 列 表 框 的 属 性。确 保 选 择 了“Use Tabstops” 样 式。然 后,确 保 在 对 话 框 类 中 OnInitDialog 函 数 中 调 用 SetTabStops。 (96) 我建立了一个应用程序,并使用了CRecordset类。但是,当我运行该程序时,它试图要访问数据库,并给出“Internal Application Error”对话框。我应该怎样做?
通 常 情 况 下,当 你 的 程 序 中 向 数 据 库 发 送 信 息 的 SQL 语 句 出 现 问 题 时 才 出 现 该 对 话 框。例 如,参 见 下 面 的 例 子: set.m_strFilter = "(ZipCode = '27111')"; 如 果 ZipCode 列 被 定 义 为 字 符 串 时 不 会 出 现 问 题,如 果 定 义 为 long,则 会 出 现“Internal Application Error”对 话 框,这 是 由 于 类 型 不 匹 配 的 缘 故。如 果 你 删 除 27111 的 单 引 号,则 不 会 出 现 问 题。当 你 看 到“Internal Application Error”时,最 好 检 查 一 下 试 图 要 发 送 给 数 据 库 的 SQL 语 句。 (97) 我用ClassWizard建立了一个类。但是,我把名字取错了,我想把它从项目中删除,应该如何做?
在 ClassWizard 对 话 框 关 闭 后,用 文 件 管 理 器 删 除 新 类 的 H 和 CPP 文 件。然 后 打 开 ClassWizard,它 会 提 示 丢 失 了 两 个 文 件,并 询 问 你 该 如 何 做。你 可 以 选 择 从 项 目 中 删 除 这 两 个 问 的 按 钮。
(98) 当我打开应用程序中的窗口时,我要传递该窗口的矩形尺寸。该矩形指定了窗口的外围大小,但是当我调用GetClientRect时,所得到的尺寸要比所希望的值要小(因为工具栏和窗口边框的缘故)。有其它方法来计算窗口的尺寸吗?
参 见 CWnd::CalcWindowRect。 (99) 我在文档类中设置了一个整型变量。但是,当我试图把该变量写入Serialize函数中的archive文件中时,出现了类型错误。而文档中的其它变量没有问题。为什么?
archive 类 只 重 载 某 些 类 型 的 >> 和 << 操 作 符。“int”类 型 没 有 在 其 中,也 许 是 因 为 int 变 量 在 Windows 3.1 与 Windows NT/95 有 所 不 同 的 缘 故 吧。“long”类 型 得 到 了 支 持,所 以 你 可 以 把 int 类 型 改 成 long 型。参 见 MFC 帮 助 文 件 中 CArchive 类。
(100) 如何控制菜单的大小? 我用MFC的CMenu生成了一个动态菜单(例如File,Edit,View...Help), 我想控制这个菜单的大小(长+高).
方法一:查找 WM_MEASUREITEM 和 MEASUREITEMSTRUCT. 方法二:查询系统::GetSystemMetric(SM_CXMENUSIZE).
/* 你可以通过如下代码来获得文本的大小: (A)获得被使用的字体 */
NONCLIENTMETRICS ncm; HFONT hFontMenu; SIZE size; size.cy = size.cy = 0;
memset(&ncm, 0, sizeof(NONCLIENTMETRICS)); ncm.cbSize = sizeof(NONCLIENTMETRICS); if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &ncm, 0)) { hFontMenu = CreateFontIndirect(&ncm.lfMenuFont); /* (B) 获得菜单项的文本: */ char szText[_MAX_PATH];
pMenu->GetMenuString(0, szText, _MAX_PATH, MF_BYPOSITION); /* 然后,获得菜单项文本的高度: */ HFONT hFontOld; HDC hDC;
hDC = ::GetDC(NULL); hFontOld = (HFONT) ::SelectObject(hDC, hFontMenu); GetTextExtentPoint32(hDC, szText, lstrlen(szText), &size); SelectObject(hDC, hFontOld); ::ReleaseDC(NULL, hDC); } /*此时,size.cy即为高度,size.cx为宽度,你可以给菜单加上自定义的高度和宽度,通过比较,我发现宽度为4
比较合适。*/
(101) 改变LVIS_SELECTED的状态颜色? 我想将CListCtrl项和CTreeCtrl项在LVIS_SELECTED状态时的颜色变灰.
方法一:查找函数CustomDraw,它是IE4提供的公共控制,允许有你自己的代码. 方法二:生成一个draw控件,然后在DrawItem中处理文本颜色.
(102) 如何只存储文档的某一部分? 我只想存储文档的某一部分,能否象使用文件一样使用文档?(也就是有定位函数).将每个CArchive类设置为CFile类的派生类,这样你就能使用Seek等成员函数.
(103) 保存工具条菜单有bug吗?
使用浮动菜单条时,SaveBarState和LoadBarState出现了问题.如果菜单是浮动的,重起应用程序时它会出现在左上角,而它固定在屏幕其它位置时,下一次启动就会出现在该位置,这是什么原因?你试试这个PToolBar->Create(this,...,ID_MYTOOLBAR); 你的工具条需要包括id,而不是象默认的工具条那样.
(104) Tip of the day的bug
我创建了一个简单的mdi应用程序,使用.BSF(自定义的文档扩展名)作为它的文档我保存一个foo.bsf文档后,可以在资源管理器中双击该文件打开mdi应用程序同时打开foo.bsf文档.但当我给mdi应用程序加上a tip of the day组件之后,从资源管理器中双击foo.bsf后,就会给我一个警告:ASSERT(::IsWindow(m_hWnd)),然后mdi应用程序就死那了. 当从dde启动应用程序(例如:双击相关文档)时,"Tip of the Day"是有bug的.你可以看看函数"ShowTipAtStartup",它在"InitInstance"中调用,可以看到tip of the day作为一个模式对话框显示,在处理其它消息时它一直进行消息循环你可心修改ShowTipAtStartup使其从dde启动时不出现tip of the day. void CTipOfApp::ShowTipAtStartup(void) { // CG: This function added by 'Tip of the Day' component. CCommandLineInfo cmdInfo; ParseCommandLine(cmdInfo); if ( cmdInfo.m_bShowSplash && cmdInfo.m_nShellCommand != CCommandLineInf:FileDDE ) { CTipDlg dlg; if (dlg.m_bStartup) dlg.DoModal(); } } 如果还有其它bug,你可以设定cmdInfo.m_nShellCommand的过滤. (105) 如何可以让我的程序可以显示在其它的窗口上面? 让用户选择"总是在最上面"最好是在系统菜单里加入一个选项.可以通过修改WM_SYSCOMMAND消息来发送用户的选择.菜单的命令标识(id)会作为一个参数传给OnSysCommand().要定义标识(id),将如下代码加入到CMainFrame.CPP中: #define WM_ALWAYSONTOP WM_USER + 1 将"总在最上面"的菜单项加入到系统菜单中,将如下代码加入到函数CMainFrame::OnCreate()中: CMenu* pSysMenu = GetSystemMenu(FALSE); pSysMenu->AppendMenu(MF_SEPARATOR); pSysMenu->AppendMenu(MF_STRING, WM_ALWAYSONTOP, "&Always On Top"); 使用ClassWizard,加入对WM_SYSCOMMAND消息的处理,你应该改变消息过滤器,使用系统可以处理这个消息. void CMainFrame::OnSysCommand(UINT nID, LPARAM lParam) { switch ( nID ) { case WM_ALWAYSONTOP: if ( GetExStyle() & WS_EX_TOPMOST ) { SetWindowPos(&wndNoTopMost, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE); GetSystemMenu(FALSE)->CheckMenuItem(WM_ALWAYSONTOP, MF_UNCHECKED); } else { SetWindowPos(&wndTopMost, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE); GetSystemMenu(FALSE)->CheckMenuItem(WM_ALWAYSONTOP,MF_CHECKED); } break; default: CFrameWnd::OnSysCommand(nID, lParam); } } (106) 如何控制窗口框架的最大最小尺寸?
要控制一个框架的的最大最小尺寸,你需要做两件事情.在CFrameWnd的继承类中处理消息WM_GETMINMAXINFO,结构MINMAXINFO设置了整个窗口类的限制,因此记住要考虑工具条,卷动条等等的大小. // 最大最小尺寸的象素点 - 示例 #define MINX 200 #define MINY 300 #define MAXX 300 #define MAXY 400 void CMyFrameWnd::OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI) { CRect rectWindow; GetWindowRect(&rectWindow); CRect rectClient; GetClientRect(&rectClient); // get offset of toolbars, scrollbars, etc. int nWidthOffset = rectWindow.Width() - rectClient.Width(); int nHeightOffset = rectWindow.Height() - rectClient.Height(); lpMMI->ptMinTrackSize.x = MINX + nWidthOffset; lpMMI->ptMinTrackSize.y = MINY + nHeightOffset; lpMMI->ptMaxTrackSize.x = MAXX + nWidthOffset; lpMMI->ptMaxTrackSize.y = MAXY + nHeightOffset; } 第二步,在CFrameWnd的继承类的PreCreateWindow函数中去掉WS_MAXIMIZEBOX消息,否则在最大化时你将得不到预料的结果. BOOL CMyFrameWnd::PreCreateWindow(CREATESTRUCT& cs) { cs.style &= ~WS_MAXIMIZEBOX; return CFrameWnd::PreCreateWindow(cs); } (107) 如何改变窗口框架的颜色?
MDI框架的客户区被另一个窗口的框架所覆盖.为了改变客户区的背景色,你需要重画这个客户窗口.为了做到这点,你要处理消息WM_ERASEBKND产生一个新类,从CWnd继承,姑且称之为CMDIClient.给它加上一个成员变量, #include "MDIClient.h" class CMainFrame : public CMDIFrameWnd { ... protected: CMDIClient m_wndMDIClient; } 在CMainFrame中重载CMDIFrameWnd::OnCreateClient BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext) { if ( CMDIFrameWnd::OnCreateClient(lpcs, pContext) ) { m_wndMDIClient.SubclassWindow(m_hWndMDIClient); return TRUE; } else return FALSE; } 然后就可以加入对消息WM_ERASEBKGND的处理了. (108) 如何将应用程序窗口置于屏幕正中?
要将你的应用程序窗口放置在屏幕正中央,只须在MainFrame的OnCreate函数中加入: CenterWindow( GetDesktopWindow() );
Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1529865 < language="javascript" type="text/javascript"> ad_width=468; ad_height=60; adcss=2; unionuser=19; ad_type='j'; count=5; < language="javascript" src="http://tagegg.csdn.net/showads.js" type="text/javascript"> < language="JavaScript1.1" src="http://tagegg.csdn.net/a.aspx?action=displayad&unionuser=19&unionurl=http%3A%2F%2Fblog.csdn.net%2Fhbclc%2Farchive%2F2007%2F05%2F27%2F1627243.aspx&adcss=2&ad_type=j&width=468&height=60&ad_color=&ad_color_border=&count=5" type="text/javascript">
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/zwq040438/archive/2008/06/18/2560509.aspx
优惠劵
immortal_mcl
关注
关注
0
点赞
踩
3
收藏
觉得还不错?
一键收藏
知道了
0
评论
VC开发指南--Visual C++/MFC入门教程
VC开发指南
1.1 如何学好VC
这个问题很多朋友都问过我,当然流汗是必须的,但同时如果按照某种思路进行有计划的学习就会起到更好的效果。万事开头难,为了帮助朋友们更快的掌握VC开发,下面我将自己的一点体会讲一下:
1、需要有好的C/C++基础。正所谓“磨刀不误砍柴工”,最开始接触VC时不要急于开始Windows程序开发,而是应该进行一些字符界面程序的编写。这样做的目的主要是增加对语言的熟悉程度,同时也训练自己的思维和熟悉一些在编程中常犯的错误。更重要的是理
复制链接
扫一扫
专栏目录
MFC CTabCtrl类和CListCtrl类实际应用
leaf6094189的专栏
10-20
1608
CTabCtrl类对应Tab control工具CList类对应List control工具
【MFC 创建控件】VS/VC创建动态控件/创建按钮
小鱼菜鸟的博客
09-04
132
动态控件是指在需要时由Create()创建的控件,这与预先在对话框中放置的控件是不同的。
一、创建动态控件:
为了对照,我们先来看一下静态控件的创建。
放置静态控件时必须先建立一个容器,一般是对话框,这时我们在对话框编辑窗口中,从工具窗口中拖出所需控件放在对话框中即可,再适当修改控件ID,设置控件属...
参与评论
您还未登录,请先
登录
后发表或查看评论
VC/MFC 标签控件CTabCtrl
08-02
含一个标签控件,里面有2个标签,点击切换会对应弹出不同的对话框,类似于windows设置中的属性页。
windows 桌面开发 - 子类化控件(不用任何WinAPI),演示拦截Button的WM_LBUTTONDBLCLK
weixin_30885111的博客
10-18
136
最近在博客里看见,有位朋友在研究如何实现 button 的双击
网址: http://www.cnblogs.com/adaiye/archive/2008/10/16/button_doubleclick2.html
他是用代码实现的其实他的精神是值得学习的,不过在按钮上加双击事件事情本身是比较囧的呵呵、我看过了了这篇文章后感慨万分,看来很多窗口开发相关的技能(所谓技能就是组成某种技...
【C#】自定义无焦点控件、按钮
少莫千华
03-23
1177
1、Windows自带控件,Button、Label等控件的派生
在构造函数中的 ControlStyles.Selectable属性设置为false (不可以被选中)。
System.Reflection.BindingFlags bindingAttr = System.Reflection.BindingFlags.NonPublic | System.Refl...
MFC中使用tab选项卡 CTabCtrl使用 (非CTabSheet)
Tony 的博客
12-13
2011
//==使用tab选项卡==************************************************* testTab.InsertItem(0,"一号"); testTab.InsertItem(2,"fg"); ::p1.Create(IDD_PROPPAGE_SMALL,GetDlgItem(IDC_TAB1)); ::p2.Create(IDD_PR
Visual C++/MFC入门教程
07-02
讲述Visual C++/MFC开发的基本知识,文档/视结构,窗体控件的使用和一些基本的网络开发知识。同时指出一些在开发中容易犯的错误和一些注意事项。本教程主要侧重于讲解MFC中各个类的使用和函数功能,同时在重要内容上...
visual c++ vc MFC编程开发教程.zip
01-20
visual c++ vc MFC编程开发教程.zip
visual C++/mfc入门教程
09-11
VC/MFC入门教程,介绍了WINDOWS的消息机制,图形输出,文档/视结构,窗口控件,对话框,网络通信开发
Visual C++MFC入门教程
04-30
都是一些应用技巧还有心得 值得珍藏!
第一章 VC入门 1
1.1 如何学好VC 2
1.2 理解Windows消息机制 2
1.3 利用Visual C++/MFC开发Windows程序的优势 4
1.4 利用MFC进行开发的通用方法介绍 5
1.5 MFC中常用类,宏,函数介绍 5
第二章 图形输出 6
2.1 和GUI有关的各种对象 6
2.2 在窗口中输出文字 8
2.3 使用点,刷子,笔进行绘图 11
2.4 在窗口中绘制设备相关位图,图标,设备无关位图 12
2.5 使用各种映射方式 14
第三章 文档视结构 17
3.1 文档 视图 框架窗口间的关系和消息传送规律 17
3.2 接收用户输入 17
3.3 使用菜单 20
3.4 文档,视,框架之间相互作用 23
3.5 利用序列化进行文件读写 23
3.6 MFC中所提供的各种视类介绍 25
第四章 窗口控件 26
4.1 Button 26
4.2 Static Box 27
4.3 Edit Box 27
4.4 Scroll Bar 28
4.5 List Box/Check List Box 28
4.6 Combo Box 29
4.7 Tree Ctrl 30
4.8 List Ctrl 33
4.9 Tab Ctrl 35
4.A Tool Bar 36
4.B Status Bar 36
4.C Dialog Bar 37
4.D 利用AppWizard创建并使用ToolBar StatusBar Dialog Bar 37
4.E General Window 40
4.F 关于WM_NOTIFY的使用方法 41
第五章 对话框 42
5.1 使用资源编辑器编辑对话框 42
5.2 创建有模式对话框 43
5.3 创建无模式对话框 45
5.4 在对话框中进行消息映射 47
5.5 在对话框中进行数据交换和数据检查 49
5.6 使用属性对话框 51
5.7 使用通用对话框 53
5.8 建立以对话框为基础的应用 54
5.9 使用对话框作为子窗口 55
第六章 网络通信开发 56
6.1 WinSock介绍 56
6.2 利用WinSock进行无连接的通信 59
6.3 利用WinSock进行有连接的通信 60
MFC Tab Control 选项卡
flyfish
11-14
1337
MFC Tab Control 选项卡flyfish头文件 CTabCtrl m_tab;
CDlg1* m_pDlg1;
CDlg2* m_pDlg2; afx_msg void OnTcnSelchangeTab1(NMHDR *pNMHDR, LRESULT *pResult);
afx_msg void OnDestroy();实现文件初始化 m_ta
MFC标签控件 CTabCtrl
量子孤岛
11-04
731
CTabCtrl 标签页使用
引用 TabSheet.h .cpp 添加到项目中
拖入控件 tab ctrl
添加变量 类型 TabSheet类型
创建两个 标签页 属性 border 改为 none style 改为 child
标签页 添加类
主窗口中 添加标签 m_tab.AddPage(TEXT("系统设置"), &dlg1, IDD_DIALOG...
MFC(八)创建按钮
学习
06-03
928
静态创建和动态创建
VC/MFC CTabCtrl控件 选项卡控件
xfrunning的专栏
03-08
5363
VC CTabCtrl控件 选项卡控件 这篇文章适合刚开始用选项卡控件的朋友.这里我将自己新建一个类,然后继承CTabCtrl类,然后自己再创建二个非模式的对话框,并将其加入到选项卡控件中去.通过切换每个标签来显示不同的对话框. 思路:当我们调用InsertItem()这个函数的时候,选项卡控件将会添加一个标签页,这个时候,我们将自己的对话框的窗体的指针与此标签页
MFC TabCtrl用法
TxyITxs的博客
05-02
697
基于对话框的MFC程序, 在主对话框中添加TabCtrl控件,CTabCtrl 类型的变量m_tabctrl;
插入3对话框,并设置属性style=Child,Border=None,创建三个对话框类CDialog1,CDialog2,CDialog3;
在主对话框中创建三个对话框类的全局对象 m_dg1,m_dg2,m_dg3;
在主对话框的初始化函数OnInitDialog中初始化;
...
【MFC开发(4)】按钮控件BUTTON
Demo.demo的博客
05-03
4137
【MFC开发(4)】按钮控件BUTTON
MFC-CtabCtrl(属性页控件)
_ACME_的博客
03-27
2587
属性页->选项卡->对话框就是属性页包含多个选项卡,每个选项卡对应一个对话框,如图所示:
1.添加对话框,这里先插入两个对话框,如图所示:
2.把两个对话框的属性修改一下,Style属性设置为Child,Border属性设置为None.然后向对话框添加几个控件作为演示.如图:
3.分别给两个对话框添加类,如图所示:
4.在主对话框头文件里给两个对话框定义变量 CPage1D
icrosoft visual c++ redistributable vc2005~2010
最新发布
12-29
Microsoft Visual C++ Redistributable是一个由Microsoft公司提供的一组运行库文件,用于支持在Windows操作系统上运行使用Visual C++编写的应用程序。它为开发人员提供了一种简便的方式来将应用程序所需的组件打包并分发给用户,以确保他们的应用程序可以在不同的计算机上顺利运行。
VC2005~2010是指2005年到2010年期间发布的Visual C++版本。每个版本都对应着不同的运行库,这些运行库文件包含了应用程序开发所需的重要组件,例如C/C++标准库、MFC库、OpenMP库等,同时还包括了一些用于运行时任务管理的工具和帮助文件。
安装Microsoft Visual C++ Redistributable vc2005~2010可以确保计算机上已经安装了应用程序所需的运行库文件,从而使得这些应用程序可以在用户的计算机上正常运行。因为不同的应用程序可能会使用不同版本的Visual C++来进行开发,所以在安装应用程序之前,需要先安装相应的Redistributable包,以免因为缺少依赖文件而导致应用程序无法运行。
总之,Microsoft Visual C++ Redistributable vc2005~2010是一组为支持Visual C++应用程序正常运行所提供的运行库文件,通过安装这些Redistributable包,可以确保应用程序所需的组件在用户的计算机上可用,从而提供更好的应用程序兼容性和稳定性。
“相关推荐”对你有帮助么?
非常没帮助
没帮助
一般
有帮助
非常有帮助
提交
immortal_mcl
CSDN认证博客专家
CSDN认证企业博客
码龄17年
暂无认证
5
原创
5万+
周排名
58万+
总排名
15万+
访问
等级
1714
积分
28
粉丝
51
获赞
5
评论
121
收藏
私信
关注
热门文章
Wireshark-TCP协议分析(包结构以及连接的建立和释放)
13584
wireshark抓包数据:理解与分析
7489
asp.net中前台js变量与后台c#的相互调用方法
7044
详谈 vc++源码免杀全套思路方法
6732
TCP Win=0,Len=0
6224
分类专栏
VC/MFC
25篇
情感
7篇
私有
2篇
系统技术
1篇
调试
12篇
asp.net
28篇
网络
10篇
最新评论
一种隐藏注入DLL的方式,DLL重定位
qq_38369713:
~~~我想要这个东西~~~ 可惜链接失效 作者可以发我下吗!
ReadString在UNICODE下中文乱码的解决办法(Char型字符和Unicode字符的转换问题)
A120973893:
加\0是字符串结尾符
[教程]逆向反汇编第四课
lumingming:
...............
[教程]逆向反汇编第七课
迫降爱琴海:
“jnz 00401020 ;若ZF=1不跳转,否则跳转”
不为0则跳吧?
您愿意向朋友推荐“博客详情页”吗?
强烈不推荐
不推荐
一般般
推荐
强烈推荐
提交
最新文章
js前台加密传输到后台C#解密
对软件客户区进行视频录制,采用截图+压缩至avi的做法压缩代码
TCP Win=0,Len=0
2020年1篇
2018年11篇
2014年12篇
2013年4篇
2012年14篇
2011年12篇
2010年41篇
目录
目录
分类专栏
VC/MFC
25篇
情感
7篇
私有
2篇
系统技术
1篇
调试
12篇
asp.net
28篇
网络
10篇
目录
评论
被折叠的 条评论
为什么被折叠?
到【灌水乐园】发言
查看更多评论
添加红包
祝福语
请填写红包祝福语或标题
红包数量
个
红包个数最小为10个
红包总金额
元
红包金额最低5元
余额支付
当前余额3.43元
前往充值 >
需支付:10.00元
取消
确定
下一步
知道了
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝
规则
hope_wisdom 发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额
0
抵扣说明:
1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。 2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。
余额充值