手机游戏开发hoteditw3mm地图编辑器下载怎么安装

孔夫子旧书网该图书“【浓诚二手】手机游戏开发全书:J2ME完整实例精解 李晓洁 王晓龙”已经找不到了, 还有其他店铺销售此图书。Copyright(C)
孔夫子旧书网
京ICP证041501号
海淀分局备案编号地图编辑器设计文档_百度文库
两大类热门资源免费畅读
续费一年阅读会员,立省24元!
地图编辑器设计文档
阅读已结束,下载文档到电脑
想免费下载本文?
定制HR最喜欢的简历
下载文档到电脑,方便使用
还剩3页未读,继续阅读
定制HR最喜欢的简历
你可能喜欢升级到游戏设计师攻略之—— 用游戏编辑器制作MOD脱颖而出 - CSDN博客
升级到游戏设计师攻略之—— 用游戏编辑器制作MOD脱颖而出
立志成为的你,和千千万万的游戏玩家的不同之处在哪? 是你玩过很多的游戏?别人也玩过 是你游戏打得比别人好?也许电子竞技更适合你 是你对游戏的理解比别人深,知道如何设计出更好玩的游戏?嗯,是的,可是怎么证明呢? Action speaks louder than words! 最好的证明就是拿出你自己制作的游戏MOD,这胜过一万字的文字简历。可做mod难吗?不难,需要的只是你的一刻红心(立志成为师的决心),两手准备(选对工具,找对方法),假以时日,你就能做出自己的第一个mod!
本文将向大家介绍并推荐几款市面上主流的游戏编辑器,并结合一些作者的关卡制作经验,帮助新手在制作mod的过程中少走弯路。
本文分为三部分:
一、什么是MOD与编辑器;
二、常用编辑器简介;
三、制作MOD步骤。
一、什么是MOD与编辑器
什么是MOD?
MOD,全称为modification,直译为“修改,改进”,但对于游戏来说,MOD指的是玩家使用独立游戏引擎或已发售游戏中自带的编辑器,利用游戏引擎或编辑器自带的,或自己制作并导入到游戏引擎或编辑器中的游戏资源,做出新的游戏地图,甚至新的游戏模式。 早期的MOD可以追溯到FC时代的坦克大战,摩托飞车等,功能非常简单,只能利用游戏提供的资源,而且缺少了MOD的另外一大特征——分享性,所以也只局限于玩家的自娱自乐。MOD真正开始兴起是在PC游戏上,比如大家最熟悉的CS就是玩家利用《半条命》所带的编辑器做的,现在提到MOD也一般是指PC游戏,虽然现在的次时代主机也有一些MOD,并且可以利用网络分享,比如PS3的《小小大星球》,但受限于工具使用的不便性和局限性,也难成为主流。而就游戏类型来说,虽然基本各种类型的游戏都可以制作出MOD,但最成熟和最流行的是FPS和RTS,其余的像RAC和RPG虽然也有不少,但仍显小众向。
什么是编辑器?——制作MOD的工具
就像上面提到的,MOD是在独立游戏引擎或编辑器中制作的,那么我们先来对他们有点了解。
游戏编辑器的定义和概念
游戏地图编辑器,顾名思义,就是用来编辑游戏地图的工具,如果你玩过魔兽争霸或是帝国时代2,英雄无敌的话,应该会知道这几款游戏都附有地图编辑工具,可提供给玩家自行编辑地图关卡,地图编辑器就具有类似的功能。
1.游戏引擎和游戏编辑器的区别
虽然这两个词常常被混用,但它们是不一样的,游戏编辑器只是游戏引擎中用于整合资源的可视化工具,两者是从属关系。编辑器能制作什么类型的游戏,能实现什么功能,能在哪些平台上运行等等都是游戏引擎所决定的。举个最直观的例子,利用《战争机器》PC版附带的unreal编辑器,你只能制作出在PC上运行的类似《战争机器》的游戏,而不可能做出360版的《生化奇兵》(Bioshock)或《暗影帝国》(Shadow Complex),虽然他们都是通过unreal3引擎开发的。而虽然像魔兽3的编辑器能制作出塔防,Dota等跟原游戏有很大区别的新模式,而且能导入新的模型,但这些都是停留在脚本修改级别的,而不是真正的代码级别,所以只是算魔兽3的编辑器功能更开放而已。
所以两者的大致区别是:
1) 游戏附带的都只能叫编辑器,不能修改游戏底层代码,不能创建完全脱离原游戏的内容,使用某游戏编辑器制作出的MOD只能在该游戏中运行;
2) 游戏引擎一般需要购买以获得授权,可以修改游戏代码,从而开发出各种类型的游戏,运行游戏不需要安装该引擎。
2.工具的选择
游戏引擎和游戏编辑器都可以实现制作MOD的功能,那么如何选择呢?
除了是“成功游戏”的编辑器外,一个好的编辑器在我看来还应该有以下特点:
1) 流行广,这意味着你更容易获得这个编辑器,接触到更多“同道中人”,而做出的MOD也有让更多玩家玩到的空间
2) 技术新,对于想通过制作MOD,进而有机会进入游戏行业的同学们来说,在一步步制作MOD的过程中,更宝贵的收获是对当今游戏的制作方法有所了解,所以请尽量避免使用年代过于久远的编辑器,以免学到的是火星技术
3) 教程多,大部分的MOD制作者都是靠自学掌握编辑器的使用,所以有丰富教程资源的编辑器能让制作者更容易上手,遇到问题也能马上找到解决方法;当然,以上几点是在广义的层面来定义一个我认为“好”的编辑器,但对于个体来说,最重要的是你自己的兴趣和动机,假如你是一个星际的死忠,梦想是加入暴雪或制作出超越Lost Temple那样的经典地图,那么星际的编辑器一定是你的最先考虑对象;假如你的梦想加入Epic,那么不管什么游戏类型,Unreal的重要性对你也就不言而喻。
二、常用编辑器简介
基于以上几点,我不会向大家介绍太多编辑器,除了求精不求多的原则外,很多编辑器我本人也没有用过,不会做无责任推荐
UDK是于2009年11月正式对外发布的免费开发套件(下载地址:/download UDK;UDK开发案例:),拥有Unreal
Engine3的绝大部分功能,可以制作出次时代品质的MOD。
与其他编辑器最大的不同之处在于UDK是代码开放,所以它相当于是个引擎,而不只是编辑器,只要你有时间和精力,完全可以用其开发出全新的游戏,初期公布的几个游戏也都提供源代码学习。
Unreal是笔者用过的最方便的编辑器,如果只是利用UDK提供的资源,那么利用它搭建关卡就像搭积木一样简单,相信只要通过一天的学习,你就能搭出自己的第一个关卡,当然这只是说工具易用性方面,如何搭建结构合理而充满乐趣的关卡是件非常不容易的事。本文最后会分享一些笔者的关卡制作经验给大家,希望能有所帮助。
在UDK中搭建关卡
另外,对于大部分没学过程序的同学们来说,也许比较怕听到“脚本”二字,可脚本对于实现关卡内互动元素又是必不可少的(比如开关门,触发机关等)。早期的脚本都是“脚本语言”,而UDK的脚本很简单,因为它是“可视化脚本”,在脚本编辑器Kismet中提供了很多功能模块的接口,你只需要想清楚逻辑,找到自己想要的接口,并通过一条条的线把这些接口连起来就可以了。
可视化脚本编辑器Kismet
教程方面网上非常多,想要深入学习的话,我推荐3D Buzz制作的视频教程,这是和官方合作的,对UDK的几大功能都有非常详细的讲解。下载地址为:/Three/VideoTutorials.html。听力不好的同学可以下载英文字幕:/Three/rsrc/Three/VideoTutorials/3DBuzz_EN_SRT.zip。
如果追求最短的时间了解最多的话,EA洛杉矶的美术师Waylon Brinck制作的视频教程很不错,在电驴上搜“[UDK-顶级教材].gnomonunreal-CGFRIEND.iso”就能找到
用UDK除了能制作出精美的MOD外,另外很重要的一点是UE3是游戏业内使用最广的商业引擎,不光国外,现在很多国内公司都购买了UE3,所以UDK是相当值得花功夫学习的,不夸张的说,学会UDK就相当于半只脚迈进了游戏公司。
Bounty Arms
Dungeon Defense
注:以上游戏虽都是利用开发的,但美术物件和游戏逻辑都是新增的,而UDK初始所带的资源来自于《虚幻竞技场3》,利用它们只能做出《虚幻竞技场3》的新图。
CryEngine2
CryEngine2
CryEngine是德国Crytek公司开发的一款商业引擎,最初是为Nvidia的显卡演示而制作的,因为反响热烈转而全面开发,并希望能像Unreal一样打入商业引擎授权市场。该引擎所开发的游戏Crysis系列,因其“照片级”的画面一度被称为“最强的引擎”。目前该引擎发展到CryEngine3,但对应游戏Crysis2还未发售,所以我们还是只讨论CryEngine2(以下简称CE2)
CE2并没有像UDK那样提供代码开放的版本,要获得CE2的编辑器Sandbox2,可以在:/index.php/Mod_SDK_Information下载官方认可的MODSDK,或者是使用通过已发售的Crysis系列游戏中自带的编辑器Sandbox。
相比Unreal,CE2出彩的地方是其对自然环境的模拟,地形(Terrain)编辑器异常强大,能够轻松制作出非常逼真的地形,另外它的道路制作工具(RoadTool),天气如云,雾等模拟也很强大。此外CE2的光照系统也很不错,当初演示时就是以其逼真的即时光影吸引了大家的眼球,对阳光的模拟(LightShaft),时间流逝的模拟(TimeOfDay)都很逼真。所以如果你想制作的关卡使用到大量户外地形,那么CryEngine2是非常好的选择。
道路制作工具
脚本编辑方面,CE倡导的理念是WYSIWYP(What You See Is What You Play,所见即所玩),大部分互动物体(SmartObject)都是在3D视窗内直接编辑的,也有类似Unreal的Kismet那样直观的编辑器(Flow Graph)
编辑SmartObject
教程方面的话CE2并没有UDK那么多,特别是像UDK那样成熟的视频教程,主要教程来自网上,中文的话可以去http://oldbbs.ali213.net/viewthread.php?tid=1723210,英文好的推荐去,这里聚集着很多CE的MOD爱好者,资源很多,也可以利用论坛相互学习。
虽然CE系列引擎并没有像Unreal那样广泛应用,但它本身无疑是非常优秀的,学习的过程就是一个接触世界一流引擎工作方式的过程,另外Crytek也抓紧了CE的推广工作,近年的CGDC(中国游戏开发者展)也常看到CE的身影,他们也将中国市场看得很重,说不定哪天国内也会有公司购买,先学习CE的同学说不定能成为国内第一批使用CE的开发者的。
StarCraft2
对于暴雪和《星际争霸2》,我想已不用介绍。 因为当年《魔兽争霸3》的编辑器(WorldEditor,下简称WE)受到广大MOD爱好者的狂热支持,制作出了类似Dota,3C,各种塔防等经典游戏模式,成为了魔兽3的宝贵附加资源,延长了该游戏的可玩性。所以,在SC2中推出编辑器也是顺理成章的事。(SC2的编辑器目前还没有正式名,官方目前称Scumedit,以下简称SE)。 由于SC2有中文版,所以SE也对应的是中文版的,下载地址网上很多,自己可百度之。
SE可以说是WE的全面升级强化版,是一款深入贯彻MOD精神的编辑器,功能的开放程度很高,除了做出WE所能做的任何模式外,在自定义camera,UI,操作和大量的脚本功能下,SE还可以制作出横版动作游戏和2D射击游戏等。功能强大得让人开玩笑说SC2其实是SE的一个MOD。
利用SE制作的横版动作游戏
如果你用过WE,对SE应该上手很快,连界面都很相似。SE包含了很多的子编辑器,包括地形编辑器(Terrain),数据编辑器(Data),触发器(Trigger)等。地形编辑器的上手度也很简单直观,只需简单的教学就可搭出关卡来。
SE的地型编辑器界面
当然,就像WE一样,SE的核心也是触发器和数据编辑器,但两者都比WE强大很多。 触发器是负责游戏逻辑的,数据编辑器是创建和修改各种参数的,这是SE中最难掌握的,用好这两个东西也是菜鸟和高手的区别,可以先了解基本功能,然后打开别人做好的图来慢慢学习。
触发器中设置复杂的游戏逻辑面
数据编辑器中几乎可以修改任何参数
脚本方面,据说是基于C语言的,这个我还没研究过。 教程方面的话,由于SE刚公布不久,现在大家都是初级研究阶段,所以各种论坛的研究帖都很多,网站我推荐/, 国内的话没有找到很好的,不过.cn/thread--1.html有不错的教学贴
其它编辑器
以上介绍的都是3D的编辑器,其实也有很多不错的2D编辑器,MM们估计会比较喜欢2D的,而且用一下2D编辑器也能补充一下自己对2D游戏制作的知识,下面就简单介绍两款比较流行的
RPG Maker XP
RPG MakerXP是日本的Enterbrain发行的2D RPG制作工具RPG Maker的最新版,支持 640×480像素分辨率,32色真彩色图像,功能比较齐全,使用比较简单,可以导入自定义的图片,动画和BGM,脚本使用Ruby语言编写,可以制作出非常有趣的游戏内容。网上有非常多的对应资源可以下载。
RPG Maker XP界面
Action Game Maker
同样是EB社的作品,在RPGMaker大获成功后推出的ActionGameMaker更加强大,它不仅支持制作的游戏类型扩大到ACT,ARPG和STG三大类,而且支持包含Window平台和XNA,所以可以制作出在360Arcade平台上运行的游戏。
在使用上和RPGMaker比较相似,都是面向所有人的,所以界面相当的简单直观,不需任何编程知识都可以制作出有趣的游戏。而且内建的范例游戏Simple系列也可以帮助你最快的制作出自己第一款的游戏。
AGM中制作ARPG的界面
AGM中制作ACT的界面
三、制作MOD步骤
可为与不可为
首先你得清楚你选的编辑器能做什么,而在你有限的时间和能力下又能掌握多少,然后再开始构思你的MOD的复杂度和规模。当然你也可以和几个人一起合作制作一个MOD,这样不仅大大增加了效率,还能培养团队合作意识,对将来的工作也很有帮助。
学习MOD的方法
除了教程外,学习MOD最好的方法就是打开别人做好的图,点开各种编辑器看别人怎么用的,然后试着自己改改看产生的效果;如果可以复制的话,复制一些已设置好的复杂功能,然后再自己修改也是一个很方便的方法(比如WE中的塔防敌人波数配置,自己配的话非常麻烦,但在别人的基础上改的话就很简单了)
以策划的思维与流程来进行
对于策划来说,制作MOD主要体现的是你的创意能否实现,你的关卡是否好玩,而不是你的MOD好不好看—那是美术的事。所以,制作策划的MOD就应该是以策划的思维和步骤来做,下面8条是我以自己的经验所列出的关卡制作大致步骤,希望能给准备开始动手的同学做点参考:1. 研究同类游戏 2. 搜集参考资料,获得灵感 3. 绘制2D关卡图 4. 搭建最简单的可玩关卡 5. 反复测试和修改 6. 美化关卡 7. 获取别人的反馈 8. 根据反馈优化关卡
1. 研究同类游戏&当你脑中对即将制作的MOD有了大概轮廓,比如游戏类型,镜头表现,操作方式,核心玩法,地图尺寸等,是不是马上就可以开始动工了呢?别急,先看看市面上有没有和你的游戏相似的,看看哪些成功了,哪些失败了,然后总结哪些是可以借鉴的,哪些是应该避免的。
2. 搜集参考资料,获得灵感 灵感不光是靠想的,很多时候是需要激发的。当我们开始构思自己的关卡时,可以充分利用各种各样的资料获取灵感,游戏当然是非常重要的一项参考,但千万别局限于游戏,我们还可以从电影,动漫,图片,建筑,地图,甚至机械构造,解剖学等中受到启发,如果某一刻突然获得什么灵感了,记得要把它记下来,以免睡一觉又忘了。
3. 绘制2D关卡图&当你对关卡有想法的时候,别急着就开始用编辑器做,先动手把它画下来,因为2D的总比3D的快,先在2D上验证你的关卡结构,流程,节奏,尺寸等合不合适,以免在3D中做到一半发现不对时又重新返工。绘图的工具我建议以最快和最简单的纸和笔开始,注意标明图示和比例,在不需解释的前提下让别人也看得懂的2D关卡图才是合格的。如果想作为简历发送,可以利用Visio,Photoshop或Google Sketchup等重新绘制一下。
4. 搭建最简单的可玩关卡(沙盒关卡)&2D的关卡图验证完毕后,接下来就可以用编辑器搭建你的关卡了,这个阶段的目的是在可玩的游戏环境下验证你的关卡是否达到你画2D图时的构思,比如关卡的尺寸是不是合适,大体结构是不是合理,流程是不是紧凑等。“最简单”的目的是为了省时间和方便修改,利用编辑器提供的最基本的模型,贴图和物件就行了。
5. 反复测试和修改&在编辑器里搭建完关卡的雏形后,就自己试着玩玩,把自己不满意的都记下来,然后一条条的修改,改完后再继续测试,然后再修改,直到自己满意为止才开始下一步。
6. 美化关卡&如果你觉得自己的关卡尺寸,结构和流程都差不多了,玩起来也基本实现自己的初步构想了,那么就可以美化关卡了:利用编辑器提供的各种模型,贴图,特效,动画等使你的关卡漂亮起来。如果你有美术的合作同学,而且编辑器可以导入美术资源的话,你们还可以制作出全新的美术风格来。
7. 获取别人反馈&获取别人反馈是使自己关卡不断提升品质的最好方法。一个关卡自己玩久了难免会失去判断力,自己在怎么测也不可能发现所有问题,而别人可能一下就能指出你从没想到过的不足之处,所以获得别人反馈是非常重要的。你可以邀请自己的朋友来玩,先静静的观察他们玩的过程,记录下他们对关卡感到迷惑或经常会死的地方,然后再询问他们对你的关卡的意见。另外关卡也可以发布到网上,让更多的人玩到,获得更多的反馈。
8. 根据反馈优化关卡&收集到玩家们的反馈后,你可能会发现玩家的反馈有时候是非常主观的,所以不可以全听,但如果大部分玩家都反映出某一个问题,那么就是共性的不足,值得引起你的重视并该思考如何可以改进了。改进之后有时间和条件的话,再重复第7步和第8步,理论上这是一个无止境的循环,就看自己什么时候觉得满意了。
记录并展示你的关卡
如果你想把你的关卡作为简历投递的话,你要知道收到简历的人会真正去玩你的关卡的几率是相当低的,一是因为不一定能运行(没有对应的编辑器或游戏),二是也没有时间。所以最好的办法就是视频录制,并将录制的视频发到网上,然后在简历中附上该视频的链接。在录制视频时要展示你关卡的亮点,最好有配音讲解,时间最好不超过3分钟。对方如果感兴趣的话再想办法能让他玩到你的游戏。
另外,简历中最好能附上你所制作的2D关卡图,并附上关卡的说明,有时这比视频还有效。
作者简介:
snowinter 自我简介:毕业于某师范大学生物学专业,04年末以好奇的心态在育碧(Ubisoft)做了三个月的tester,预谋转职Level Designer失败后回去了老家,沦落为一名人民教师,“误人子弟”长达近两年,因对转职事件一直耿耿于怀,07年毅然辞职杀回上海滩,在GA策划班学习后有幸进入了维塔士(Virtuos),成为了一名“业内人士”,现就职于英佩(Epic Games China),担任某未公开项目的关卡设计师 参与过的项目平台有NDS, PSP, Wii, PC,类型包含FPS,ACT,RAC等
联系方式:
本文已收录于以下专栏:
相关文章推荐
立志成为游戏策划的你,和千千万万的游戏玩家的不同之处在哪? 是你玩过很多的游戏?别人也玩过 是你游戏打得比别人好?也许电子竞技更适合你 是你对游戏的理解比别人深,知道如何设计出更好玩的游戏...
这是一本游戏设计方面的好书
转自天:天之虹的博客:.cn/jackiechueng
感谢天之虹的无私奉献
Word版可到本人的资源中下载
我是游戏设计师
不对,你不是
我是游戏设计师
你是哪种设计师?
我是游戏设计师
你是说你会玩游戏
我是游戏设计师
这是一本游戏设计方面的好书
转自天:天之虹的博客:.cn/jackiechueng
感谢天之虹的无私奉献
Word版可到本人的资源中下载
第七章响应...
这是一本游戏设计方面的好书
转自天:天之虹的博客:.cn/jackiechueng
感谢天之虹的无私奉献
Word版可到本人的资源中下载
第九章润色...
这是一本游戏设计方面的好书
转自天:天之虹的博客:.cn/jackiechueng
感谢天之虹的无私奉献
Word版可到本人的资源中下载
第一章定...
他的最新文章
讲师:何宇健
讲师:董岩
您举报文章:
举报原因:
原文地址:
原因补充:
(最多只允许输入30个字)拥有1个小站,订阅2个话题,关注36个小站
我的两个&学生&Eva和Fong(译注:Eva是博主的姐姐,Fong是博主的女友)来到旧金山跟我学编程。在这篇博文中,我将记录下我教她们的方式,我构建这种学习过程的理由,以及这种学习方式奏效的原因。虽然以时间顺序列出她们在这段时间做的或学习的每一件事再容易不过,但是这毫无用处,而且读者们也会遗漏重点。了解学习过程中的细节并且明白它起作用的原因至关重要。所以我...&
& & 我的两个&学生&和(译注:Eva是博主的姐姐,Fong是博主的女友)来到旧金山跟我学编程。在这篇博文中,我将记录下我教她们的方式,我构建这种学习过程的理由,以及这种学习方式奏效的原因。虽然以时间顺序列出她们在这段时间做的或学习的每一件事再容易不过,但是这毫无用处,而且读者们也会遗漏重点。了解学习过程中的细节并且明白它起作用的原因至关重要。所以我会从基本原则开始讲。本文较长,请做好准备。
请在编程过程中始终牢记这些基本原则。
&1、交流沟通
在Eva和Fong开始学习之前,我为她们申请了博客,并请她们记录下她们的编程之旅和学到的东西。万事开头难,你可以问问她们。我大概花了一周的时间跟她们唠叨才让她们写了第一篇博客。但是现在,她们不在博客上写点儿自己投入了大量时间的项目就觉得不对劲。
& &如果你在项目中使用了API(译者注:Application&Programming&Interface,应用程序编程接口),发推文或者是邮件给这家公司告诉他们你关于他们的API的想法。当你在黑客马拉松中赢得奖项时,发个不错的推文@他们表示谢意,或写篇相关的博文。每写一篇博文都使它成为一直以来最好的,并怀着它会被放上黑客新闻版首页的期望将它提交(尽管大部分时候这种期望都不能实现)。
健康交流的最大好处就是,它使你对你的项目负责,&由此也引出我的下个要点。
& & Fong和Eva都知道,完成一个项目困难,却重要。我声明:除非她们写了一篇关于手头项目的博文,在推特上@了API公司,并且将它发布在黑客新闻网版上,我们是不会开始一个新项目的。尽管她们的第一个项目只是井字棋游戏,但这是她们做过的最好的井字棋游戏。从来就没有人想写一个蹩脚的项目,所以不管这个项目有多简单或者不相关,如果你要着手做个项目,那它必须是你能拿到的最好的那个。我已经见过太多开发者为毫无前景的次要项目工作。如果你在学习编程,你必须从一开始就认识到要珍惜你的时间和精力,完成你的项目证明它的价值。
& & 完成整个项目的最后20%需要花费全部努力的80%。开发者可以在1、2天之内实现一个项目的概念。而测试每种情况并且解决每一种边际情况从而成就一个&完美&的产品则需要两倍的时间。在项目最后的20%花费那80%的精力,将会在许多许多访问中传为佳话。
& & 如果你卡住了,不要紧盯住你的代码。出去散个步,呼吸点新鲜空气,再考虑一下。你卡住了是因为你的逻辑中有错误,而修正它最好的方法就是在脑海中或是在纸上一步一步地彻底想通它。程序员靠思考赚钱,问题在你的思考中被解决,编程是个蛋疼的工作。伟大的项目经理通常都有广博的编程背景,并且在思考和问题解决方面接受过出色的训练。
& &有一种说法:当你被卡住20多分钟时,并且你仍然茫然无绪,请教别人吧。如果在20分钟内没有任何头绪,那么在接下来的一个小时,你也不会有任何进展的。相信Eva。她有一天就浪费了5个小时,因为一个愚蠢的错误&&血的教训啊。散个步,做个其他事。然后再回到项目上来。能将自己与问题切断并转移注意力,是个技术活。
& & 也许你现在已经明白了,思考,在一个程序员的生活中是至关重要的。不要去复制-粘贴代码,尤其当你在学习如何去编程的时候。如果你想学习怎么编程,复制,粘贴&&&看,有用诶!&不会使你有任何成就。相反,无论何时你看到代码,你必须在企图去试运行它之前想清楚它在干什么。当你能轻易看懂别人的代码了,将其简化到你刚好需要的程度,然后写出来。如果从一开始就定期这么做,你会在几个月内成长为一个非凡的开发者。
& & 学会独立解决问题。除非至少被卡住20分钟,不要问编程问题。程序员们必须是独立的。他们是伟大的思想者和伟大的交流者。为了成为他们中的一员,你必须逻辑地思考,想出问题出现的原因。许多年轻开发者面对的问题是,写出他们真正需要的代码对他们来说很困难。我们中的许多人也是这样,明知道问题是什么,但就是不知道要去找什么去解决它。这是个你必须从一开始就培养的技能,它漂亮地联系了第一点,&成为一个交流者&。
& & 现在,有了这五点牢记于心,以下是Eva和Fong学到的东西,以时间顺序排列。
第1-3天:通过Ruby语言学习编程基础
& & 我选择Ruby语言,因为它用来上手是最好的。在Ruby语言中,有很少语法限制(space键与tab键,类型声明,等等),所以Eva和Fong能够关注编程的思考过程而不是解决语法问题。她们学习了if型语句、循环体、数据结构,解决了一些编程题目,比如说FizzBuzz(编程初级问题,即满足a条件时输出Fizz,满足b条件时输出Buzz,同时满足a、b条件时输出FizzBuzz),替换字符串中的字符,转换一个数组,找出最大值。关于类别和对象的学习也是重要的。
另外,我没有教她们特定的ruby语法,而是让她们对参数都使用括号,并且以返回空结束每个函数。&这样的话,她们下次学一种新的语言时就能更快上手。
第4天:HTML &
& & HTML或CSS严格上来说不能算是编程语言,所以没必要在这里花上太多时间。Eva和Fong在HTML上花了一天时间,编了几个标签玩儿,快速完成了表单、信息页等内容。这样,对CSS的兴奋感就建立起来了。在这里重点要学的是区分块HTML与内联HTML、标识与分类。
第5天:CSS
& & 在摆弄过HTML后,&如何在那里表达这个,怎样使这个丑陋的HTML页面看起来更漂亮&的问题浮出了水面。CSS就是那个完美的答案。花上一天的时间尽情设计网页(所有HTML页面都已经在前一天建好)。这一块的重点是,相对/绝对/固定定位,HTML浮动元素,以及如何用绝对、固定定位来控制正常的浮动。&
第6-7天:通过jQuery来学习javascript
& & jQuery需要花点时间来适应,而且因为涉及到编程,学习jQuery框架需要占用点时间。她们花了几天时间将HTML页面做成交互式页面。
第8-15天:第一个项目-&井字棋
& & 这时,Eva和Fong已经了解了HTML/CSS/Javascript,但不是特别习惯。这正是让她们开始第一个项目(井字棋)的绝佳时机。虽然她们花了两天的时间来完成这个项目,又用了几天时间来对其进行润色修饰。项目的最后20%要花费精力的80%是个金科玉律。作为一个初学者,学着去完成你的项目是很重要的。
第16-20天:Sinatra框架
& & 在那个看起来永远都不能结束的井字棋项目之后,Fong和Eva迫不及待地想学点新东西。学点服务终端代码对她们已经在做的事来说是个激动人心的全新体验。我选择Sinatra,是因为它是我使用过最整洁、最简单的网络框架,而且这种简洁性让解释网络的工作原理变成小菜一碟。
第20-22天:Photoshop
& & Photoshop对非凡的设计非常重要。对那些从没用过它的人来说,它有点儿吓人(至少对我来说是这样),但是用Photoshop做出来的网站比典型的bootstrap(译者注:由Twitter推出的一款开源前端框架)站点要高端一个档次。而你真正要知道的只是混合、协调功能就够了。任何一个相当成功的开发者都会需要Photoshop,所以学会它并且在你所有的项目中使用它非常重要。
第20-27天:项目2-Dragpic(通过拖动图片实现从网页上方便地保存图片的软件)
& & &项目2涉及到Javascript的大量使用。这个项目涉及到使用ajax(译者注:一种用于创建更好更快以及交互性更强的&Web&应用程序的技术)的需要,facebook的API,以及cookies。这是个将所有网络编程基础联系起来的绝佳项目。这个项目所需要的技术范围比第一个要更广,我觉得这也向更多更复杂的项目迈进了一步。在这段时间里,她们凭借GIT(译者注:分布式文件管理工具)通力合作。这可是一个开源项目啊!&
第28-30天:RSpec
& & 这时,Fong和Eva已经能相当自如地构造网络应用了。也正是这时,她们意识到,代码是多么地脆弱,一个细微的改动,就能导致满盘皆输。现在,测试驱动开发就显得有重要意义。我们花了几天时间重温了rspec,Eva和Fong则写出测试案例作为每天早晨的编程练习。我之前提过她们每天早晨都要解决一个技术问题吗?从第28天开始,她们就必须为这些技术问题写出rspec,在她们开始编程之前也不例外。
第30-35天:BackboneJS(一个开发网络应用的框架,提供了强大的对模型、视图和交互的抽象)
& & 通过负责一个设计技术范围广泛的项目(比如Dragpic),你能学到很多,遇到很多你希望能有更优解的问题。只有这样,你才能这正意识到那些帮助你的框架的价值。我还没有找到任何一个优秀的backboneJS教程,所有教程都一下子提供了太多信息。以下是我教授它的方法:
第一步:学习模型。仅为一个数据库数据库条目创建一个模型。学会如何去修改和保存。
第二步:学习视图。为你已经在做的模型创建一个视图。添加事件接听程式,体会视图如何能够隐蔽地与模型连接,以及这一切组装为一体是如此地合适。
第三步:集合的意义现在就明确了。&你不可能手动打印输出每一个模型,尤其是当你不知道模型具体数量的时候。
我们没有学过常规课程,到现在为止,我也不认为这有什么要紧。
第35-40天:Android
& & 假如你现在还没怎么注意,我们已经在短时间内涵盖了大量的材料了。伟大的程序员适应变化,因此我们最后一个计划就是学习Android系统。在编程中你不能忽视移动设备,这块实在是太重要了。我教她们Android编程,这不是特别难,Android编程与web编程非常类似。在视图上你有XML(译者注:extensive&makeup&language,用于标记电子文件使其具有结构性的标记语言),同时也有足以和web控制器相媲美的Java代码。模型-视图-控制!通过用Ruby语言和Java语言工作,Fong和Eva开始寻找编程语言之前的共同点,成为了编程语言不可知论者。对她们来说,编程语言仅仅在语法上有所不同,但工作起来却是一个道理(其实不是这样,稍后我会对其进行辨析,厘清混淆)。
女孩们在编程上天赋异禀。
没有获得计算机科学的学位不是个不学编程的借口。
在快乐中编程,人人都能学。
& & & & & & & & & & & & & & & & & & & & & & ##5## &小木&
转自 &极客网
class="hot-view"孙鑫VC学习笔记完整篇下载地址:/s/mUoPh...&
class="hot-view"孙鑫VC学习笔记完整篇下载地址:/s/mUoPh
Using WinForms controls in an MFC dialog转自codeproject上的文章,查看原文这是全英文的文章,如果有看不懂的,可以留言,我之后有时间再翻译一下。程序效果图:
IntroductionA few days ago, someone asked on the Code Project VC++ forum w...&
Using WinForms controls in an MFC dialog转自codeproject上的文章,这是全英文的文章,如果有看不懂的,可以留言,我之后有时间再翻译一下。&程序效果图:
IntroductionA few days ago, someone asked on the Code Project VC++ forum whether he can use the Dundas WinForms controls on his&MFC&dialogs. The answer is - yes, that's entirely possible, and pretty easy to do with VC++ 2005.This article is a simple introduction to using the&CWinFormsControl&MFC&class to put a Windows Forms control on anMFC&dialog. The article demonstrates this using a small dialog based application that has a .NET&MaskedTextBoxcontrol placed on it. The&MaskInputRejected&event is handled through a function declared in the&MFC&dialog class.&Steps to put the .NET control in the&MFC&dialog
Create a fresh&MFC&dialog based application using VC++ 2005. And turn on /clr compilation.
Add the following header file include to your stdafx.h
afxwinforms.h&
Modify your dialog resource so it has the controls shown in the screenshot above, with one change. Where you see the&MaskedTextBox&control in the screenshot, put a static control. You should end up with the following controls.
IDC_MASKED_EDIT1We'll map this to the&MaskedTextBox&control
IDC_EDITMASKCEdit m_Mask
IDC_BUTTONMASKON_BN_CLICKED&-&&OnBnSetMask
IDC_EDIT_STATUSCEdit m_StatusEdit (DDX)
IDC_STATIC"Set Mask"
IDC_STATIC"Enter Text"
Table 1 : The controls that you need to add to the dialog resource
Add the&CWinFormsControl&variable to your dialog header file :
CWinFormsControl&System::Windows::Forms::MaskedTextBox& m_MaskedE
The&CWinFormsControl&class provides the functionality to host a .NET control in an&MFC&application.
In your dialog class's&DoDataExchange, add a call to&DDX_ManagedControl&:
void CDialogFormsDlg::DoDataExchange(CDataExchange* pDX){
CDialog::DoDataExchange(pDX);
DDX_ManagedControl(pDX, IDC_MASKED_EDIT1, m_MaskedEdit);. . .}
This creates the .NET control and associates it with that resource ID.
Add the event handler declaration your header file.
void OnMaskInputRejected(System::Object^,
System::Windows::Forms::MaskInputRejectedEventArgs^);
Setup the delegate map in a public section of your dialog class declaration.
BEGIN_DELEGATE_MAP( CDialogFormsDlg )
EVENT_DELEGATE_ENTRY( OnMaskInputRejected, System::Object^,
System::Windows::Forms::MaskInputRejectedEventArgs^ )END_DELEGATE_MAP()
The delegate map allows us to use an&MFC&class function as a delegate by calling&MAKE_DELEGATE&on it.
Setup the&OnBnSetMask&function.
void CDialogFormsDlg::OnBnSetMask(){
CString strM
m_Mask.GetWindowText(strMask);
m_MaskedEdit-&Clear();
m_MaskedEdit-&Mask = gcnew System::String(strMask);}
Setup the&MaskedTextBox&control in&OnInitDialog.
m_MaskedEdit-&PromptChar = L' ';m_Mask.SetWindowText(L"00/00/0000");OnBnSetMask();m_MaskedEdit-&MaskInputRejected +=
MAKE_DELEGATE( System::Windows::Forms::MaskInputRejectedEventHandler,
OnMaskInputRejected);
Add the&OnMaskInputRejected&function to the dialog class.
void CDialogFormsDlg::OnMaskInputRejected(System::Object^,
System::Windows::Forms::MaskInputRejectedEventArgs^ args){
if(m_MaskedEdit-&MaskFull)
m_StatusEdit.SetWindowText(L"You've hit the max length of the mask.");
else if(args-&Position == m_MaskedEdit-&Mask-&Length)
m_StatusEdit.SetWindowText(L"You are at the end of the mask.");
m_StatusEdit.SetWindowText(L"Bad entry. Check your input!");
That's it. We are all done. Build and run the application. What you see is an&MFC&dialog that contains a WinForms control.
ConclusionThis should help you reuse your existing&MFC&applications and at the same time use new hyper looking .NET UI controls that are released in the market. Please use the article forum to provide feedback about the article or to post any questions you may have.&&原作者是,谢谢提供例子。
[转]VC去掉单文档中的菜单,工具栏,状态栏http://blog.csdn.net/kong5090041/article/details/8261913
一、去掉菜单栏
在单文档程序CMainFrame类中找到PreCreateWindow(CREATESTRUCT& cs)函数,按下面加入代码。
BOOL CMainFrame::Pr...&
[转]http://blog.csdn.net/kong5090041/article/details/8261913
一、去掉菜单栏
在单文档程序CMainFrame类中找到PreCreateWindow(CREATESTRUCT& cs)函数,按下面加入代码。
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs){if( !CFrameWnd::PreCreateWindow(cs) )&&&return FALSE;// TODO: Modify the Window class or styles here by modifying// the CREATESTRUCT cs
&cs.hMenu =&NULL;//加上这句即可去掉菜单
return TRUE;}
二、去掉工具栏:
在单文档程序CMainFrame类中找到OnCreate(LPCREATESTRUCT lpCreateStruct)函数,按下面代码进行注释。
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct){if (CFrameWnd::OnCreate(lpCreateStruct) == -1)&&&return -1;
if (!m_wndStatusBar.Create(this) ||&&&!m_wndStatusBar.SetIndicators(indicators,&&&&sizeof(indicators)/sizeof(UINT))){&&&TRACE0("Failed to create status bar/n");&&&return -1;&&&&&&// fail to create}
// TODO: Delete these three lines if you don't want the toolbar to// be dockable
return 0;}
三、去掉状态栏:
在单文档程序CMainFrame类中找到OnCreate(LPCREATESTRUCT lpCreateStruct)函数,按下面代码进行注释。
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct){if (CFrameWnd::OnCreate(lpCreateStruct) == -1)&&&return -1;if (!m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP&&&| CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) ||&&&!m_wndToolBar.LoadToolBar(IDR_MAINFRAME)){&&&TRACE0("Failed to create toolbar/n");&&&return -1;&&&&&&// fail to create}// TODO: Delete these three lines if you don't want the toolbar to// be dockablem_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);EnableDocking(CBRS_ALIGN_ANY);DockControlBar(&m_wndToolBar);
return 0;}作者:kong5090041 发表于 19:14:48
Stand Back or Your Hard Drive Is Going to Get It
First they came for our floppy drives. Then, they came for our CDs and our DVD drives. It won't be too long until the co...&
Stand Back or Your Hard Drive Is Going to Get It
First they came for our floppy drives. Then, they came for our CDs and our DVD drives. It won't be too long until the concept of a hard drive, or any local storage, beyond that needed for temporary offline use, is itself antiquated. After decades of dramatically increasing PC hard disks, from megabytes to terabytes, saving local data is more likely to put you at risk of loss, relative to remote backup, than it is to keep your data safe, helped along by many trends pushing toward cloud storage and applications.&
In April of last year, I talked about how&, disavowing books, CDs, DVDs and other printed materials, when digital would do, and I haven't looked back - getting to my media from any device that recognized my signed-in identity. Meanwhile, as chronicled,&starting in early 2010, when I first got a MacBook Air, and accelerated as I've turned toward ChromeOS as my primary device, I have almost entirely stopped the use of desktop applications. If it can't be reached via web browser, it's probably not worth having.&&
Goodbye Desktop Applications. Your Time Is Past
May's introduction of the latest Samsung Chromebooks (see my review) left me using my Mac only once per day, for a specific task - synchronizing my&FitBit.&Until recently, FitBit didn't have a completely cloud-capable service, so&each night around midnight, after a full day's neglect, I open the Mac, sync the FitBit in the cradle, confirm the data's gone through, and close the Mac again, until the next day. With the&&promising wireless syncing to iOS or Android, I'm just one device away from being done.&
For the rest of the day, without exception, I am on my Chromebook, or my Android devices. All my music, emails, photos, documents and other web services can be accessed and managed on the cloud through the browser.&
Knocking Down Lagging Apps One By One
The evolution of software and its intersection with platforms is an intriguing one. We Mac users in the 1990s and early 2000s occasionally had to make sacrifices, not having access to apps available only on Windows. Similarly, as iOS and Android increased in market presence, there was the occasional app missing from one platform or the other. But over time, practically all applications, or their equivalents, make their way to the top platforms, and while&&came with some apps missing, all the ones I needed quickly followed me there.
Now the web itself has proven capable enough for almost any task, and reasons why not to go all Web are dramatically reduced, especially the improved capabilities of documents, spreadsheets and presentations in Google Drive, the release of&, and promises that popular desktop&&now, to stream music in addition that which you can purchase from&.
Time to Move on From the Desktop and File Mentality
With solid reasons to not go all Web rapidly eliminated, this evolution also brings up the opportunity to revisit old paradigms we've always taken for granted, as how we use our computers and mobile devices has changed.&
Consider, for example, the desktop and files metaphor. Decades ago, we adapted our PCs to be similar to those environments we knew offline. The desktop, folders and files all hearken back to this original model. Even the hyperlinks of today's Web follow similar structures with directories and files owned by top level domains, and today's leading cloud storage vendors, including&&and&, mimic a traditional desktop environment to bring ease of adoption to users migrating from local storage. But this shouldn't always be the case.
While clean directory structures once were&&over a decade-plus ago, machine-generated links to content are good enough, and it's possible we just need to know how content relates to one another, or what you're searching - for example, email, and tags that generate metadata, providing you with what you need even if you don't know exactly where to look.
All Your Computers Are Mine. Seriously.
The notion of this being "my laptop" or "your PC" doesn't even make sense any more if you think about it. All I need is access to my "stuff", and that stuff is tagged to my identity, be it one that is affiliated with Apple, Google, Microsoft, Facebook or any other provider. While Chromebooks have made it most clear that you can sign out of one account and sign in as another and retain access to all your things, the truth is that so long as you are using a leading provider of identity, you should be able to get to all your files, bookmarks, and media from any device with a modern browser. Go ahead, steal my laptop. I'll just get another one that will do the same things and be up and running in minutes.
Kids These Days... They Don't Need Hard Drives
Consider also that my children should never need to use or know about local storage. At ages 4 and 2, my children will enter elementary school in 1 to 3 years. They have been raised with web-connected TVs, tablets and smartphones, have an expectation of anytime access to data, and shouldn't be trained to store data that is tied to any single device. To them, every device has&. To them, every device can get to&, and anything they want to see, hear or watch can be found by asking Google for the right image or video, instantly - no buffering allowed.
Just two to three years is enough for us to see how rapidly USB thumb drives went from being the hot tradeshow giveaway to now seeming almost completely useless, with online sharing being the norm. Just two to three years was all I needed as a student attending Berkeley in the late 1990s to move from carting a floppy disk across campus to the computer lab for printing my freshman year, to instead email the document to myself as an attachment my junior year.
Oh. So You Don't Have Pervasive High Speed Wireless?
It's easy to sit in Silicon Valley's ivory tower and say that with pervasive high speed Internet, eliminating any dependency on local storage is a brilliant idea. It's easy to overlook potential power outages, cloud disruptions, dependence on third party services, and spotty web. Nobody likes being out of range for phone calls, let alone all your data, and nobody truly wants to be helpless if their account is compromised. Those are not minor and trivial concerns. But neither is ensuring data compatibility as the data is stored on multiple local machines, and backed up to temporary local storage which may or may not be less reliable than a service provider that serves millions or more.
Years ago, it may have seemed silly to move to web-based email instead of desktop applications, and the same could be said for other apps that have now become default on the web - including calendaring, address books, event planning and more. Digital media for entertainment, once the province of physical media delivered to your home or picked up at a retailer, is now accessible anywhere on any device. So too will be your photos, music, documents, and more. I even moved all my family's photos off spinning disk on an array of Macs from the last 4 years and put them on Drive.
The key to staying prepared for the next evolution of computing is to be willing to take a leap of faith - knowledge that you don't need desktop devices when a laptop will do, knowledge that you don't need to have DVDs in your living room when Netflix or iTunes have all you need, and that what you've been used to and taught over decades just might not be entirely the same any more.
Disclosures:&I work for Google and yes, Google makes many services that provide for cloud storage and computing, as well as those nice Chromebooks, one of which I gained for free earlier this year and am using right now to make this post (as well as all the screenshots and images in the post, edited in Pixlr).
#include &iostream&#include &typeinfo&class base{public:virtual void vf() = 0;};class A1 : public base{public:void vf(){cout && &A1& &&}virtual void vf_a(...&
#include &iostream&#include &typeinfo&&&class base{public:virtual void vf() = 0;};&class A1 : public base{public:void vf(){cout && "A1" &&}virtual void vf_a(){cout && "the second vf of A1" &&}};&class A2 : public base{public:void vf(){cout && "A2" &&}&virtual void vf_a(){cout && "the second vf of A2" &&}};&class B : public A1, public A2{public:void vf(){cout && "B" &&}};&int _tmain(int argc, _TCHAR* argv[]){B * pB = new B();A1 * pA1 = (A1 *)pB;A2 * pA2 = (A2 *)pB;&cout && "the address of pB is " && pB &&cout && "the address of pA1 is " && pA1 &&cout && "the address of pA2 is " && pA2 &&&//pB-&vf_a();pB-&vf();pA2-&vf_a();pA2 = (A2 *) pA1;pA2-&vf_a();//pBase-&vf();return 0;}&从这个实验中得到的结论是:1、多继承时,向上转型时,pA2会自动加一个值以跳过A1的实例。2、只要参数类型正确,也就是函数的声明相符。是可以使用pA2-&vf_a去调去pA1-&vf_a的。&继承的规则是这样:1、派生类最多只可以访问父类的protected成员,却不能访问private成员。无论是private继承还是protected继承。2、当使用继承时,可以把父类的实例看做是子类的成员变量。而这个成员变量的访问控制由继承类型(public, private, protected)来决定。3、使用向上映射时,私有的或者保护的父类是不能成功的。因为这样做相当于直接访问了这个父类的实例,而这个实例是不能访问的。&friend 的用法:1、父类可以以子类为友元吗?答案是可以,不过要使用不完全定义。也就是声明。例如:class B;&class A{friend B;};&class B : private A{};2、嵌套友元。嵌套定义不能与friend写在一起。如果写了friend,会被认为不是成员结构,也就不是嵌套了。应该分开写。&&const 的用法:1、不能把一个 const 对象的地址赋给一个非 const 指针,因为这样做可能通过被赋值指针改变这个 const 指针。当然,总能用类型转换强制进行这样的赋值,但是,这不是一个好的程序设计习惯,因为这样就打破了对象的 const 属性以及由 const 提供的安全性。2、用const限定成员函数时。这个函数可以被const对象调用。&指向成员的指针:1、声明一个指针,希望它指向一个类的某一个成员的时候。要使用范围分解操作符。例如 int A::*p = &A:: 或者 void (A::*pFunc)(int n) = &A::func_a;2、静态成员变量定义必须出现在类的外部(不允许内联)而且只能定义一次,因此它通常放在一个类的实现文件中。而指向类的静态成员的指针是不需要加上类的范围限定的。通常,它应该这么写:int * pInt = &A::i;&static 的用法:1、指定存储位置。在程序的静态数据区。2、控制连接。static 的全局变量是内部连接的。所以可以放在头文件里。不会造成命名冲突。&运算符重载:1、运算符被定义为全局函数(对于一元是一个参数,对于二元是两个参数)还是成员函数(对于一元没有参数,对于二元是一个参数&&对象变为左侧参数)2、后缀式要这样写:const integer operator--(integer& a, int); 可以这样去记,后缀式要产生临时变量,所以可以视为二元操作符,所以需要两个参数。&
如果没有读过这本书,就别往下看了,这篇文章纯粹是瞎胡扯。
1、消息处理。
/*doccore.cpp这儿是CDocument要响应的三个消息,也就是说每一个Doc的关闭应该由自己负责。*/
BEGIN_MESSAGE_MAP(CDocument,CCmdTarget)
如果没有读过这本书,就别往下看了,这篇文章纯粹是瞎胡扯。
要响应的三个消息,也就是说每一个的关闭应该由自己负责。&
消息,而这个消息通常是在自己的文件中定义,例如:
的生成确实应该由更上一级的&实例来负责。
3、在中有如下定义:
void&CWinApp::OnFileNew()
if&(m_pDocManager&!=&NULL)
m_pDocManager-&OnFileNew();
而这个就是在刚开始的时候,程序会发出一个ID_FILE_NEW消息,由负责处理。
4、在中有函数的入口。
int&AFXAPI&AfxWinMain(HINSTANCE&hInstance,&HINSTANCE&hPrevInstance,
_In_&LPTSTR&lpCmdLine,&int&nCmdShow)
在这里,的这两个还是虚函数)和被按顺序分别调用。
SetWindowLong(this-&GetSafeHwnd(),GWL_EXSTYLE,GetWindowLong(this-&GetSafeHwnd(),GWL_EXSTYLE)^0x80000);HINSTANCE hInst = LoadLibrary(&User32.DLL&);if (hInst){ typedef BOOL (WINAPI *...&
&SetWindowLong(this-&GetSafeHwnd(),GWL_EXSTYLE,GetWindowLong(this-&GetSafeHwnd(),GWL_EXSTYLE)^0x80000);HINSTANCE hInst = LoadLibrary("User32.DLL");if (hInst){&& typedef BOOL (WINAPI * MYFUNC)(HWND,COLORREF,BYTE,DWORD);&& MYFUNC fun = NULL;&& fun = (MYFUNC)GetProcAddress(hInst,"SetLayeredWindowAttributes");&& if (fun)&&& fun(this-&GetSafeHwnd(),0,128,2);&& FreeLibrary(hInst);& }加在OnInitDialog()中~试试看~效果不错~~~
这个算是一次API的小hack了。呵呵。&&转自&
原文:/p/85281.html
Ubuntu发布Android版系统,使用户可以在Android系统中运行一个全功能的桌面操作系统,同时不影响手机功能的正常使用。在安装Ubuntu for Android后,用户可正常使用Google应用、应用市场、联系人以及打电话等,对手机的日常功能没有任何影响。在需要的时候,...&
Ubuntu发布Android版系统,使用户可以在Android系统中运行一个全功能的桌面操作系统,同时不影响手机功能的正常使用。在安装Ubuntu for Android后,用户可正常使用Google应用、应用市场、联系人以及打电话等,对手机的日常功能没有任何影响。在需要的时候,你可以使用支持HDMI接口的配件与显示器连接,这样就可以获得完整的Unity大屏体验。当手机与显示器连接后,并不会影响信息的收发等手机正常功能的使用。但是你可以通过它进行图片编辑或展示,并且可以播放存储在手机中的视频等。不过目前该应用的外接硬件是个问题,同时只能通过HDMI输出也限制了其应用范围。另外还对手机本身的处理能力提出更高的要求。但是如果巨头都能参与其中,或是运营得当,或许这也将开辟出一片新的市场。目前该系统暂不支持消费者直接安装,更多详情可到Ubuntu官方页面了解。
滑动条控制(Slider
Control)也叫轨道条控制,其主要是用一个带有轨道和滑标的小窗口以及窗口上的刻度,来让用户选择一个离散数据或一个连续的数值区间。通过鼠标或键盘来进行数据的选择操作,这在WIN98/95中的很多应用程序中都可以看到,如控制面板中的鼠标等,滑动条既可以是水平方式的也可以是垂直方式的。滑动条控制的风格如下:
TBS_HORZ...&
滑动条控制(Slider & Control)也叫轨道条控制,其主要是用一个带有轨道和滑标的小窗口以及窗口上的刻度,来让用户选择一个离散数据或一个连续的数值区间。通过鼠标或键盘来进行数据的选择操作,这在WIN98/95中的很多应用程序中都可以看到,如控制面板中的鼠标等,滑动条既可以是水平方式的也可以是垂直方式的。滑动条控制的风格如下:
TBS_HORZ & 滑动条是水平方向的
TBS_VERT & 滑动条是垂直方向的
TBS_LEFT & 滑动条位于窗口左侧
TBS_RIGHT & 滑动条位于窗口右侧
TBS_TOP & 滑动条位于窗口顶部
TBS_BOTTOM & 滑动条位于窗口底部
TBS_BOTH & 滑动条位于窗口两侧
TBS_AUTOTICKS滑动条具有刻度,默认
TBS_NOTICKS & 滑动条不具有刻度
滑动条的刻度条在每一个数值位置显示一个刻度标记,如果在滑动条上显示某一数值选择区间,则应使用风格TBS_ENABLESELRANGE,此时选择区间两个不再是刻度标记,而是一个小的三角形符号。另外,使用风格TBS_NOTHUMB会使滑标消隐起来。
滑动条控制在MFC类库中被封装为CSliderCtrl控制,其主要操作是设置刻度范围、绘制刻度标记、设置选择范围和当前滑标位置等。当用户进行交互操作时,滑动条控制将向其父窗口发送消息WM_HSCROLL,所以在应用程序中应重载父窗口的OnHScroll()成员函数,以便对消息进行正确处理系统发送的通知代码、滑标位置和指向CSliderCtrl对象的指针等。由于考虑到和水平卷动杆公用同一个成员函数,OnHScroll()函数参数表中的指针变量被定义为CScrollBar*类型,由于实际上消息是由滑动条产生的,所以在程序中必须把这个指针变量强制转换为CSliderCtrl*类型。滑动条和卷动杆的消息代码和含义都非常类似如TB_BOTTOM等,所以这种处理方法比较合理。SetRange()函数用来设置范围,SetPos()函数用来设置当前位置。
(二)滑动条控制的对象结构
滑动条控制的建立方法
CsliderCtrl & &SliderCtrl & 建立滑动条控制对象结构
Create & 建立滑动条控制对象并绑定对象
滑动条控制类CSliderCtrl::Create的调用格式如下:
BOOL & Create( & DWORD & dwStyle, & const & RECT& & rect, & CWnd* & pParentWnd, & UINT & nID & );
其中参数dwStyle用来确定滑动条控制风格;参数rect用来确定滑动条控制的大小和位置;参数pParentWnd用来确定滑动条控制的父窗口指针;参数nID用来确定滑动条控制的控制符ID值。
2、滑动条控制的类属性
滑动条控制对象的类属性包括取得滑动条大小GetLineSize、设置滑动条大小SetLineSize、取得滑动条页大小GetPageSize、设置滑动条页大小SetPageSize、取得滑动条最大位置GetRangeMax、取得滑动条最小位置GetRangeMin、取得滑动条范围GetRange、设置滑块最小位置SetRangeMin、设置滑块最大位置SetRangeMax、设置滑动条范围SetRange、取得滑块当前位置GetSelection、设置滑块当前位置SetSelection、取得滑动条当前位置GetPos和设置滑动条当前位置SetPos等。
3、滑动条控制的操作方法
滑动条控制的操作方法包括清除滑动条当前选择ClearSel、验证滑动条当前位置是否在最大最小位置之间VerifyPos和清除当前刻度标志ClearTics。
滑动条控制的应用技巧示例
1、利用应用程序向导AppWizard生成基于对象框的应用程序CSlidDlg;
2、在对话框中设置滑动条控制,其ID为IDC_SLIDER;
3、在对话框初始代码中增加控制的范围和位置:
(1)在SlidDlg.h中设置数据成员,用来表示滑动条的当前值:
//SlidDlg.h
class & CSlidDlg:public & Cdialog
{ & ......//其它代码
int & m_nC
......//其它代码
(2)在SlidDlg.cpp中设置初始状态
BOOL & CSlidDlg::OnInitDialog()
{ & Cdialog::OnInitDialog();
......//其它代码
//TODO:Add & extra & initialization & here
CSliderCtrl & *pSlidCtrl=(CSliderCtrl*)GetDlgItem(IDC_SLLIDER);
pSlidCtrl-& SetRange(1,5,TRUE);//设置滑动条范围
pSlidCtrl-& SetPos(2);//设置滑动条位置
......//其它代码
return & TRUE;
(3)完善滑动条的消息处理,利用类向导ClassWizard增加对话框窗口的WM_HSCROLL消息处理函数,并取得滑标所指位置值:
void & CSlidDlg::OnHScroll(UINT & nSBCode,UINT & nPos,CScrollBar & *pScrollBar)
{ & //TODO:Add & your & message & handler?
Cdialog::OnHScroll(nSBCode,nPos,pScrollBar);
CSliderCtrl & *pSlidCtrl=(CSliderCtrl*)GetDlgItem(IDC_SLLIDER);
m_nCur=pSlidCtrl-& GetPos();//取得当前位置值
ListCtrl在工作中,常常用到,也常常看到大家发帖问怎么用这个控件,故总结了一下自己的使用经验,以供参考使用。
先注明一下,这里,我们用m_listctrl来表示一个CListCtrl的类对象,然后这里我们的ListCtrl都是report形式,至于其他的如什么大图标,小图标的暂时不讲,毕竟report是大众话的使用。其次,我们这里用条款一,条款二...&
ListCtrl在工作中,常常用到,也常常看到大家发帖问怎么用这个控件,故总结了一下自己的使用经验,以供参考使用。
先注明一下,这里,我们用m_listctrl来表示一个CListCtrl的类对象,然后这里我们的ListCtrl都是report形式,至于其他的如什么大图标,小图标的暂时不讲,毕竟report是大众话的使用。其次,我们这里用条款一,条款二来描述第一点,第二点,这个是参照《Effective C++》的叫法,俺觉得这么叫比较COOL :)
条款一:设置ListCtrl的风格
在CSDN上常常看到有人问怎么设置风格的,他们ListCtrl的样子是一个列表,有横条和竖条分界线,然后选中一行,要整一行都选中,而不是只有某一列被选中,等等,这里给一个比较全面的设置方法。
//获得原有风格DWORD dwStyle = ::GetWindowLong(m_listctrl.m_hWnd, GWL_STYLE); dwStyle &= ~(LVS_TYPEMASK);dwStyle &= ~(LVS_EDITLABELS);//设置新风格SetWindowLong(m_listctrl.m_hWnd, GWL_STYLE,dwStyle, |LVS_REPORT | LVS_NOLABELWRAP | LVS_SHOWSELALWAYS);//设置扩展风格DWORD styles = LVS_EX_FULLROWSELECT|LVS_EX_GRIDLINES|LVS_EX_CHECKBOXES;ListView_SetExtendedListViewStyleEx(m_listctrl.m_hWnd, styles, styles );
其中LVS_EX_FULLROWSELECT 就是前面说得整行选中LVS_EX_GRIDLINES 网格线(只适用与report风格的listctrl)LVS_EX_CHECKBOXES 前面加个checkboxpListCtrl-&SetExtendedStyle( m_listctrl.GetExtendedStyle() | LVS_EX_SUBITEMIMAGES);
这也是一个很重要的属性,这样的话,可以在列表中加ICON,记得windows的任务管理器吗,你想做得那样,这个属性也要加哦,这个我以后会讲的~
条款二:加入列头
这是一个比较实质的东西,给列表框分列,然后加上列头,代码说话,来了
TCHAR rgtsz[2][10] = {_T("列头1"), _T("列头2")};LV_COLUMNCRm_listctrl.GetWindowRect(&rect);for(int i=0;i&2;i++){ lvcolumn.mask = LVCF_FMT | LVCF_SUBITEM | LVCF_TEXT | LVCF_WIDTH | LVCF_ORDER; lvcolumn.fmt = LVCFMT_LEFT; lvcolumn.pszText = rgtsz[i]; lvcolumn.iSubItem = lvcolumn.iOrder = if(i==0) {&&&&&&&lvcolumn.cx = rect.Width()*3/5 ;  } else&&&&&&&lvcolumn.cx = rect.Width()*2/5;
&&& m_listctrl.InsertColumn(i, &lvcolumn);}
这是插入两列的做法,你要插入20列??随便你,依样画葫芦~~lvcolumn.mask 中那个mask可以有各种属性,具体去看msdn吧,
条款三:把记录,插入列表框中
int nIndex = m_listctrl.GetItemCount();LV_ITEM&& lvitemAdd = {0};lvitemAdd.mask = LVIF_TEXT;lvitemAdd.iItem = nIlvitemAdd.iSubItem = 0;lvitemAdd.pszText =_T("毛毛1");;
if (m_listctrl.InsertItem(&lvitemAdd) != -1){ && LV_ITEM lvitem = {0};&& lvitem.mask = LVIF_TEXT;&& lvitem.iItem = nI&& lvitem.iSubItem = 1;
&& lvitem.pszText =_T("毛毛2");&& m_listctrl.SetItem(&lvitem);&& }
nIndex 是当前的行数,然后把新的一行,插在最下面,
条款四:给列表中插入图标
在report格式中,也能插入图标继续代码说话
m_image是个CImageList对象m_image.Create(16,16, TRUE|ILC_COLOR24, 3, 1);m_listctrl.SetImageList(&m_image,LVSIL_SMALL);
然后调用CImageList的成员函数int CImageList::Add( HICON hIcon );把ICON插入到imagelist,然后在插入记录的时候
lvitemAdd.mask = LVIF_TEXT; lvitemAdd.mask = LVIF_TEXT|LVIF_IMAGE
然后添加一个lvitemAdd.iImage =这个n是imagelist中的序号,表示是具体的哪一个图标,list么,呵呵
条款五:插入记录时使用额外的信息,lParam 的使用
有时候,你想对于某一行,加入一些额外的信息,那么就可以使用这个lParammsdn是这么描述的Specifies the 32-bit value of the item我上次是为了在某一行加入一个信息,窗口句柄,然后是这么加的,
int nIndex = m_listctrl.GetItemCount();LV_ITEM&& lvitemAdd = {0};lvitemAdd.mask = LVIF_TEXT|LVIF_IMAGE|LVIF_PARAM;lvitemAdd.iItem = nIlvitemAdd.iSubItem = 0;lvitemAdd.pszText =_T("毛毛1");;lvitemAdd.iImage =lvitemAdd.lParam = (LPARAM)(某个窗口的窗口句柄)
if (m_listctrl.InsertItem(&lvitemAdd) != -1){ && LV_ITEM lvitem = {0};&& lvitem.mask = LVIF_TEXT;&& lvitem.iItem = nI&& lvitem.iSubItem = 1;
&& lvitem.pszText =_T("毛毛2");&& m_listctrl.SetItem(&lvitem);&& }
ok,这是一个比较全的例子的,又插ICON,又使用PARAM的
条款六 : 点击列表框,获取选中行信息
响应NM_CLICK消息,如果你有MSDN,可以看到,有专门关于listview的NM_CLICK的介绍
void CMyDlg::OnItemClick(NMHDR* pNMHDR, LRESULT* pResult) {&&&// TODO: Add your control notification handler code here&&&int nItem = -1;
&&&LPNMITEMACTIVATE lpNMItemActivate = (LPNMITEMACTIVATE)pNMHDR;&&&if(lpNMItemActivate != NULL)&& {&&&&&&nItem = lpNMItemActivate-&iI&&&}}
现在nItem就是点击选中那行的index了,有了index,获取那行的信息还难吗懒汉说:难,因为你还没讲,晕,那就继续说
条款七: 根据行的index,获取该行的信息
直接上代码吧
LV_ITEM lvitem = {0};lvitem.iItem = nIlvitem.iSubItem = 0;lvitem.mask = LVIF_TEXT|LVIF_IMAGE|LVIF_PARAM;m_listctrl.GetItem(&lvitem)
这样,就把nindex,第一列的信息取出来了,包括刚才我们加入的ICON,和那个额外信息(窗口句柄),比如我要获取窗口句柄,就可以hwnd = (HWND)lvitem.lPmask 用来指明你想获取那些信息具体可以查msdn中LVITEM Structure的定义和CListCtrl::GetItem
条款八:用程序选中某一行,使之选中
选中之 m_listctrl.SetItemState(nIndex,LVIS_SELECTED|LVIS_FOCUSED,LVIS_SELECTED|LVIS_FOCUSED);不选中,取消选中之m_listctrl.SetItemState(nIndex,0,LVIS_SELECTED|LVIS_FOCUSED);
条款九:获取当前所有选中的行(多选)
这个,俺就比较懒了,抄msdn的代码吧,反正很简单
// CListCtrl* pListCtrl = (CListCtrl*) GetDlgItem(IDC_YOURLISTCONTROL);ASSERT(pListCtrl != NULL);POSITION pos = pList-&GetFirstSelectedItemPosition();if (pos == NULL)&& TRACE0("No items were selected!\n");else{&&&while (pos)&&&{&&&&&&int nItem = pList-&GetNextSelectedItem(pos);&&&&&&TRACE1("Item %d was selected!\n", nItem);&&&&& // you could do your own processing on nItem here&&&}}
条款十:删除条款九中选中的行
这个相对前面九个条款是比较麻烦的,因为如果你要删除多行的话,往往要出错。比如,我现在要删除第0行和第1行(列表的行序列是从0开始的)那么好啊。我来删了
m_listctrl.DeleteItem(0)m_listctrl.DeleteItem(1)
恭喜你,错了,我好开心啊 :)因为你删除第0行以后,下面的行会往上移,那么原来的第1行就变成了第0行,那么你再 m_listctrl.DeleteItem(1),那么删除的是原来的第2行,真麻烦,所以,只有从下往上删,才是安全的,先删的,不会影响后面的操作,
m_listctrl.DeleteItem(1)m_listctrl.DeleteItem(0)
但有时候,我们也不知道要删除哪些行,只知道要删除选中的那些行,像条款九中的那些如果我们还是用
POSITION pos = m_listctrl.GetFirstSelectedItemPosition();if (pos == NULL)&& TRACE0("No items were selected!\n");else{&&&while (pos)&&&{&&&&&&int nItem = m_listctrl.GetNextSelectedItem(pos);&&&&&&m_listctrl.DeleteItem(nItem );&&&}}
你就等着收尸吧这时候我们就要B4微软了,为虾米木有GetLastselectedItemPosition 和GetPrevSelectedItem,多写一对成员函数会死啊 :(没办法,办法自己想,这里有个笨办法
POSITION sSelPos = NULL;while(sSelPos = m_listctrl.GetFirstSelectedItemPosition()){&&&int nSelItem = -1;&&&nSelItem = m_listctrl.GetNextSelectedItem(sSelPos);&&&if(nSelItem &= 0 && nSelItem&m_listctrl.GetItemCount())&&&{&&&&&&//好了,这个nSelItem 就是我们要的DD&&&}}
GetNextSelectedItem这个函数,看msdn的用法,其实是返回第一个的index,然后走到下一个选中的行去,所以这么做也是安全的,在实际中,俺也是这么做的,测试也通过,没问题的当然,还有个办法,先通过GetFirstSelectedItemPosition和GetNextSelectedItem来获取所有的选中行的index,然后把这些index放到一个数组里,然后再从下往上删唉真麻烦啊,还要不定数组,不说用new在堆上开吧,那么一个vector总是要的吧,麻烦啊,所以我暂时是用上述的办法来删除,也供大家参考,希望能找到更好的办法。
要控制一个框架的的最大最小尺寸,你需要做两件事情.1.在CFrameWnd的继承类中处理消息WM_GETMINMAXINFO,结构MINMAXINFO设置了整个窗口类的限制,因此记住要考虑工具条,卷动条等等的大小.//
最大最小尺寸的象素点
要控制一个框架的的最大最小尺寸,你需要做两件事情.1.在CFrameWnd的继承类中处理消息WM_GETMINMAXINFO,结构MINMAXINFO设置了整个窗口类的限制,因此记住要考虑工具条,卷动条等等的大小.// & 最大最小尺寸的象素点 & - & 示例 && #define & MINX & 200 && #define & MINY & 300 && #define & MAXX & 300 && #define & MAXY & 400 && && void & CMyFrameWnd::OnGetMinMaxInfo(MINMAXINFO & FAR* & lpMMI) && { && & & & & CRect & rectW && & & & & GetWindowRect(&rectWindow); && && & & & & CRect & rectC && & & & & GetClientRect(&rectClient); && && & & & & & & // & get & offset & of & toolbars, & scrollbars, & etc. && & & & & int & nWidthOffset & = & rectWindow.Width() & - & rectClient.Width(); && & & & & int & nHeightOffset & = & rectWindow.Height() & - & rectClient.Height(); && && & & & & lpMMI-&ptMinTrackSize.x & = & MINX & + & nWidthO && & & & & lpMMI-&ptMinTrackSize.y & = & MINY & + & nHeightO && & & & & lpMMI-&ptMaxTrackSize.x & = & MAXX & + & nWidthO && & & & & lpMMI-&ptMaxTrackSize.y & = & MAXY & + & nHeightO && } &&
2.在CFrameWnd的继承类的PreCreateWindow函数中去掉WS_MAXIMIZEBOX,否则在最大化时你将得不到预料的结果. && && BOOL & CMyFrameWnd::PreCreateWindow(CREATESTRUCT& & cs) && { && & & & & cs.style & &= & ~WS_MAXIMIZEBOX; && & & & & return & CFrameWnd::PreCreateWindow(cs); && } &
首先在介绍可变参数表函数的设计之前,我们先来介绍一下最经典的可变参数表printf函数的实现原理。
一、printf函数的实现原理
在C/C++中,对函数参数的扫描是从后向前的。C/C++的函数参数是通过压入堆栈的方式来给函数传参数的(堆栈是一种先进后出的数据结构),最先压入的参数最后出来,在计算机的内存中,数据有2块,一块是堆,...&
首先在介绍可变参数表函数的设计之前,我们先来介绍一下最经典的可变参数表printf函数的实现原理。
一、printf函数的实现原理
在C/C++中,对函数参数的扫描是从后向前的。C/C++的函数参数是通过压入堆栈的方式来给函数传参数的(堆栈是一种先进后出的数据结构),最先压入的参数最后出来,在计算机的内存中,数据有2块,一块是堆,一块是栈(函数参数及局部变量在这里),而栈是从内存的高地址向低地址生长的,控制生长的就是堆栈指针了,最先压入的参数是在最上面,就是说在所有参数的最后面,最后压入的参数在最下面,结构上看起来是第一个,所以最后压入的参数总是能够被函数找到,因为它就在堆栈指针的上方。printf的第一个被找到的参数就是那个字符指针,就是被双引号括起来的那一部分,函数通过判断字符串里控制参数的个数来判断参数个数及数据类型,通过这些就可算出数据需要的堆栈指针的偏移量了,下面给出printf("%d,%d",a,b);(其中a、b都是int型的)的汇编代码
string out = "%d,%d"
call printf
.section.datastring out = "%d,%d"push bpush apush $outcall printf你会看到,参数是最后的先压入栈中,最先的后压入栈中,参数控制的那个字符串常量是最后被压入的,所以这个常量总是能被找到的。
二、可变参数表函数的设计
标准库提供的一些参数的数目可以有变化的函数。例如我们很熟悉的printf,它需要有一个格式串,还应根据需要为它提供任意多个&其他参数&。这种函数被称作&具有变长度参数表的函数&,或简称为&变参数函数&。我们写程序中有时也可能需要定义这种函数。要定义这类函数,就必须使用标准头文件&stdarg.h&,使用该文件提供的一套机制,并需要按照规定的定义方式工作。本节介绍这个头文件提供的有关功能,它们的意义和使用,并用例子说明这类函数的定义方法。 C中变长实参头文件stdarg.h提供了一个数据类型va-list和三个宏(va-start、va-arg和va-end),用它们在被调用函数不知道参数个数和类型时对可变参数表进行测试,从而为访问可变参数提供了方便且有效的方法。va-list是一个char类型的指针,当被调用函数使用一个可变参数时,它声明一个类型为va-list的变量,该变量用来指向va-arg和va-end所需信息的位置。下面给出va_list在C中的源码:
typedefchar * va_list;
typedef char *
void va-start(va-list ap,lastfix)是一个宏,它使va-list类型变量ap指向被传递给函数的可变参数表中的第一个参数,在第一次调用va-arg和va-end之前,必须首先调用该宏。va-start的第二个参数lastfix是传递给被调用函数的最后一个固定参数的标识符。va-start使ap只指向lastfix之外的可变参数表中的第一个参数,很明显它先得到第一个参数内存地址,然后又加上这个参数的内存大小,就是下个参数的内存地址了。下面给出va_start在C中的源码:
#define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )
#define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) ) //得到可变参数中第一个参数的首地址
#define _INTSIZEOF(n)
( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )#define va_start(ap,v)
( ap = (va_list)&v + _INTSIZEOF(v) )
//得到可变参数中第一个参数的首地址 type va-arg(va-list ap,type)也是一个宏,其使用有双重目的,第一个是返回ap所指对象的值,第二个是修改参数指针ap使其增加以指向表中下一个参数。va-arg的第二个参数提供了修改参数指针所必需的信息。在第一次使用va-arg时,它返回可变参数表中的第一个参数,后续的调用都返回表中的下一个参数,下面给出va_arg在C中的源码:
#define va_arg(ap,type) ( *(type *)((ap += _INTSIZEOF(type)) - _INTSIZEOF(type)) ) //将参数转换成需要的类型,并使ap指向下一个参数
#define va_arg(ap,type)
( *(type *)((ap += _INTSIZEOF(type)) - _INTSIZEOF(type)) )
//将参数转换成需要的类型,并使ap指向下一个参数 在使用va-arg时,要注意第二个参数所用类型名应与传递到堆栈的参数的字节数对应,以保证能对不同类型的可变参数进行正确地寻址,比如实参依次为char型、char * 型、int型和float型时,在va-arg中它们的类型则应分别为int、char *、int和double. void va-end(va-list ap)也是一个宏,该宏用于被调用函数完成正常返回,功能就是把指针ap赋值为0,使它不指向内存的变量。下面给出va_end在C中的源码:
#define va_end(ap) ( ap = (va_list)0 )
#define va_end(ap)
( ap = (va_list)0 )
va-end必须在va-arg读完所有参数后再调用,否则会产生意想不到的后果。特别地,当可变参数表函数在程序执行过程中不止一次被调用时,在函数体每次处理完可变参数表之后必须调用一次va-end,以保证正确地恢复栈。 一个变参数函数至少需要有一个普通参数,其普通参数可以具有任何类型。在函数定义中,这种函数的最后一个普通参数除了一般的用途之外,还有其他特殊用途。下面从一个例子开始说明有关的问题。假设我们想定义一个函数sum,它可以用任意多个整数类型的表达式作为参数进行调用,希望sum能求出这些参数的和。这时我们应该将sum定义为一个只有一个普通参数,并具有变长度参数表的函数,这个函数的头部应该是(函数原型与此类似):int sum(int n, ...)
我们实际上要求在函数调用时,从第一个参数n得到被求和的表达式个数,从其余参数得到被求和的表达式。在参数表最后连续写三个圆点符号,说明这个函数具有可变数目的参数。凡参数表具有这种形式(最后写三个圆点),就表示定义的是一个变参数函数。注意,这样的三个圆点只能放在参数表最后,在所有普通参数之后。下面假设函数sum里所用的va_list类型的变量的名字是vap。在能够用vap访问实际参数之前,必须首先用宏a_start对这个变量进行初始化。宏va_start的类型特征可以大致描述为:
va_start(va_list vap, 最后一个普通参数)
在函数sum里对vap初始化的语句应当写为:
va_start(vap, n); 相当于 char *vap= (char *)&n + sizeof(int);
此时vap正好指向n后面的可变参数表中的第一个参数。
在完成这个初始化之后,我们就可以通过另一个宏va_arg访问函数调用的各个实际参数了。宏va_arg的类型特征可以大致地描述为:
类型 va_arg(va_list vap, 类型名)
在调用宏va_arg时必须提供有关实参的实际类型,这一类型也将成为这个宏调用的返回值类型。对va_arg的调用不仅返回了一个实际参数的值(&当前&实际参数的值),同时还完成了某种更新操作,使对这个宏va_arg的下次调用能得到下一个实际参数。对于我们的例子,其中对宏va_arg的一次调用应当写为:
v = va_arg(vap, int);
这里假定v是一个有定义的int类型变量。
在变参数函数的定义里,函数退出之前必须做一次结束动作。这个动作通过对局部的va_list变量调用宏va_end完成。这个宏的类型特征大致是:void va_end(va_list vap);
三、栈中参数分布以及宏使用后的指针变化说明如下:
下面是函数sum的完整定义,从中可以看到各有关部分的写法:
#include&iostream&
usingnamespace
#include&stdarg.h&
int sum(int n,...)
int i , sum = 0;
va_start(vap , n); //指向可变参数表中的第一个参数
for(i = 0 ; i & ++i)
sum += va_arg(vap , int); //取出可变参数表中的参数,并修改参数指针vap使其增加以指向表中下一个参数
va_end(vap); //把指针vap赋值为0
int main(void)
int m = sum(3 , 45 , 89 , 72);
#include&iostream&#include&stdarg.h&int sum(int n,...){ int i , sum = 0; va_ va_start(vap , n);
//指向可变参数表中的第一个参数 for(i = 0 ; i & ++i)
sum += va_arg(vap , int);
//取出可变参数表中的参数,并修改参数指针vap使其增加以指向表中下一个参数 va_end(vap);
//把指针vap赋值为0 }int main(void){ int m = sum(3 , 45 , 89 , 72); cout&&m&& return 0;}这里首先定义了va_list变量vap,而后对它初始化。循环中通过va_arg取得顺序的各个实参的值,并将它们加入总和。最后调用va_end结束。下面是调用这个函数的几个例子:k = sum(3, 5+8, 7, 26*4);m = sum(4, k, k*(k-15), 27, (k*k)/30);函数sum中首先定义了可变参数表指针vap,而后通过va_start ( vap, n )取得了参数表首地址(赋值给了vap),其后的for循环则用来遍历可变参数表。这种遍历方式与我们在数据结构教材中经常看到的遍历方式是类似的。  函数sum看起来简洁明了,但是实际上printf的实现却远比这复杂。sum函数之所以看起来简单,是因为:  1、sum函数可变参数表的长度是已知的,通过num参数传入;  2、sum函数可变参数表中参数的类型是已知的,都为int型。  而printf函数则没有这么幸运。首先,printf函数可变参数的个数不能轻易的得到,而可变参数的类型也不是固定的,需由格式字符串进行识别(由%f、%d、%s等确定),因此则涉及到可变参数表的更复杂应用。在这个函数中,需通过对传入的格式字符串(首地址为lpStr)进行识别来获知可变参数个数及各个可变参数的类型,具体实现体现在for循环中。譬如,在识别为%d后,做的是va_arg ( vap, int ),而获知为%l和%lf后则进行的是va_arg ( vap, long )、va_arg ( vap, double )。格式字符串识别完成后,可变参数也就处理完了。
在编写和使用具有可变数目参数的函数时,有几个问题值得注意。第一:调用va_arg将更新被操作的va_list变量(如在上例的vap),使下次调用可以得到下一个参数。在执行这个操作时,va_arg并不知道实际有几个参数,也不知道参数的实际类型,它只是按给定的类型完成工作。因此,写程序的人应在变参数函数的定义里注意控制对实际参数的处理过程。上例通过参数n提供了参数个数的信息,就是为了控制循环。标准库函数printf根据格式串中的转换描述的数目确定实际参数的个数。如果这方面信息有误,函数执行中就可能出现严重问题。编译程序无法检查这里的数据一致性问题,需要写程序的人自己负责。在前面章节里,我们一直强调对printf等函数调用时,要注意格式串与其他参数个数之间一致性,其原因就在这里。第二:编译系统无法对变参数函数中由三个圆点代表的那些实际参数做类型检查,因为函数的头部没有给出这些参数的类型信息。因此编译处理中既不会生成必要的类型转换,也不会提供类型错误信息。考虑标准库函数printf,在调用这个函数时,不但实际参数个数可能变化,各参数的类型也可能不同,因此不可能有统一方式来描述它们的类型。对于这种参数,C语言的处理方式就是不做类型检查,要求写程序的人保证函数调用的正确性。假设我们写出下面的函数调用:k = sum(6, 2.4, 4, 5.72, 6, 2);
编译程序不会发现这里参数类型不对,需要做类型转换,所有实参都将直接传给函数。函数里也会按照内部定义的方式把参数都当作整数使用。编译程序也不会发现参数个数与6不符。这一调用的结果完全由编译程序和执行环境决定,得到的结果肯定不会是正确的。
四、简单的练习&
问题1:可变长参数的获取
  有这样一个具有可变长参数的函数,其中有下列代码用来获取类型为float的实参:  va_arg (argp, float);  这样做可以吗?  答案与分析:  不可以。在可变长参数中,应用的是"加宽"原则。也就是float类型被扩展成double;char、 short类型被扩展成int。因此,如果你要去可变长参数列表中原来为float类型的参数,需要用va_arg(argp, double)。对char和short类型的则用va_arg(argp, int)。  问题2:定义可变长参数的一个限制
  为什么我的编译器不允许我定义如下的函数,也就是可变长参数,但是没有任何的固定参数?
int f(...)
int f(...){ ...... ...... ......}答案与分析:  不可以。这是ANSI C 所要求的,你至少得定义一个固定参数。这个参数将被传递给va_start(),然后用va_arg()和va_end()来确定所有实际调用时可变长参数的类型和值。
问题3:如何判别可变参数函数的参数类型?
函数形式如下:
void fun(char *str ,...)
void fun(char *str ,...){ ...... ...... ......}若传的参数个数大于1,如何判别第2个以后传参的参数类型???答案与分析:
这个是没有办法判断的,例如printf( "%d%c%s ", ....)是通过格式串中的%d, %c, %s来确定后面参数的类型,其实你也可以参考这种方法来判断不定参数的类型。
最后,奉献上自己写的一个printf函数
#include&stdio.h&
#include&stdarg.h&
void myitoa(int n, char str[], int radix)
int i , j ,
remain = n %
if(remain & 9)
str[i] = remain - 10 + 'A';
str[i] = remain + '0';
}while(n /= radix);
str[i] = '\0';
for(i-- , j = 0 ; j &= j++ , i--)
tmp = str[j];
str[j] = str[i];
void m

我要回帖

更多关于 android开发 edittext 的文章

 

随机推荐