数学建模社区-数学中国

标题: BCB教程 [打印本页]

作者: 韩冰    时间: 2005-1-26 01:02
标题: BCB教程
<><b><FONT face=宋体 size=6> </FONT></b></P>
% o( W" ]# b3 ]4 y! D2 K< align=center>第一讲<FONT face="宋体, MS Song" size=6> C++ Builder</FONT><FONT face=宋体 size=6>简介</P></FONT><FONT face=宋体 size=3>2 l2 v+ O" P7 w3 L- j
< align=justify>“工欲善其事,必先利其器”,对于程序员来说,选择和掌握一门好的编程语言及其开发工具是至关重要的,然而这也正是困扰很多朋友的一个问题,随着心铃讲座的陆续刊出,越来越多的初学编程的读者朋友来信问到,“请问心铃,这么多种编程工具,到底哪一种更好呢?”对于这个问题,心铃一直都觉得很难回答清楚,只能说它们各有优缺点。其实,编程工具的选择要与具体的开发项目联系起来,如果项目是面向最终用户的</FONT><FONT face="宋体, MS Song" size=3>Windows</FONT><FONT face=宋体 size=3>应用程序,并且开发周期很短,那么心铃就要为大家推荐一种优秀的快速应用程序开发(</FONT><FONT face="宋体, MS Song" size=3>Rapid Application Development</FONT><FONT face=宋体 size=3>,简称</FONT><FONT face="宋体, MS Song" size=3>RAD</FONT><FONT face=宋体 size=3>)工具——</FONT><FONT face="宋体, MS Song" size=3>Borland C++ Builder</FONT><FONT face=宋体 size=3>,这也是本次讲座所要介绍的对象。</P>) `5 n% O* J3 g# Y! p$ u7 N; g
<UL></FONT><B><FONT size=3>5 ]/ c3 |1 ]- W6 L' i2 U
< align=justify>
$ ~8 W. W/ l7 f" i  H9 P9 e<LI>C++ Builder</FONT><FONT face=宋体 size=3>的主要特点
1 o) h6 I' O8 b& F' ^- B' u2 @3 U* J+ U4 t
</LI></UL></B></FONT><FONT size=3>
7 O. J: Q7 C6 G! |1 b* q< align=justify>C++ Builder</FONT><FONT face=宋体 size=3>(以后简称</FONT><FONT size=3>CBuilder</FONT><FONT face=宋体 size=3>)是</FONT><FONT size=3>Borland</FONT><FONT face=宋体 size=3>公司在</FONT><FONT size=3>Delphi</FONT><FONT face=宋体 size=3>成功的基础上开发的可视化</FONT><FONT size=3>C++</FONT><FONT face=宋体 size=3>编程工具,什么?等等!也许有的朋友会问:</FONT><FONT size=3>Borland</FONT><FONT face=宋体 size=3>以前不是出了一个</FONT><FONT size=3>Borland C++</FONT><FONT face=宋体 size=3>吗,难道</FONT><FONT size=3>CBuilder</FONT><FONT face=宋体 size=3>不是从</FONT><FONT size=3>BC</FONT><FONT face=宋体 size=3>演变而来?不错,</FONT><FONT size=3>CBuilder</FONT><FONT face=宋体 size=3>确实也吸取了不少</FONT><FONT size=3>BC</FONT><FONT face=宋体 size=3>的好东西,但</FONT><FONT size=3>CBuilder</FONT><FONT face=宋体 size=3>可视化编程的关键——</FONT><FONT size=3>Visual Component Library</FONT><FONT face=宋体 size=3>(</FONT><FONT size=3>VCL</FONT><FONT face=宋体 size=3>,可视化元件库)却是从</FONT><FONT size=3>Delphi</FONT><FONT face=宋体 size=3>搬过来的,因此</FONT><FONT size=3>CBuilder</FONT><FONT face=宋体 size=3>象</FONT><FONT size=3>Delphi</FONT><FONT face=宋体 size=3>比象</FONT><FONT size=3>BC</FONT><FONT face=宋体 size=3>更多一些。</FONT><FONT size=3>CBuilder</FONT><FONT face=宋体 size=3>面世的时间虽然不长,但几乎是以最快速度成为最流行的</FONT><FONT size=3>C++</FONT><FONT face=宋体 size=3>编程工具之一,由于自身的优秀品质,它受到了越来越多的程序员的喜爱,目前最新版本已经出到了</FONT><FONT size=3>5.0</FONT><FONT face=宋体 size=3>。</P>
2 h3 f0 c& l1 w' p$ \, ?< align=justify>与其它的可视化编程工具(如</FONT><FONT face="宋体, MS Song" size=3>VC</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>VB</FONT><FONT face=宋体 size=3>)相比,</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>的最大特点就在于其可视化程度更高,因此在开发面向用户的应用程序时更方便、更快捷。</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>集成了十分丰富的可视化元件库,其中的元件数量在百个以上,这些元件基本上覆盖了应用程序开发的各个方面,如:基本应用程序主窗口、菜单、工具栏、对话框、数据库、</FONT><FONT face="宋体, MS Song" size=3>Internet</FONT><FONT face=宋体 size=3>等等,利用这些元件,设计和开发</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>程序就象搭积木一样简单有趣。相比之下,</FONT><FONT face="宋体, MS Song" size=3>VC</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>VB</FONT><FONT face=宋体 size=3>中提供的控件在数量和种类上都是非常有限的,</FONT><FONT face="宋体, MS Song" size=3>VC</FONT><FONT face=宋体 size=3>中除了</FONT><FONT face="宋体, MS Song" size=3>Windows</FONT><FONT face=宋体 size=3>基本控件之外,只提供了少数几个自有控件。在</FONT><FONT face="宋体, MS Song" size=3>VB</FONT><FONT face=宋体 size=3>中使用控件虽然也很方便,但由于</FONT><FONT face="宋体, MS Song" size=3>Basic</FONT><FONT face=宋体 size=3>语言的局限性(不支持指针、不是真正的编译型语言),使其底层控制能力大受影响,</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>则充分体现了面向对象编程工具的优势,即不仅具有传统</FONT><FONT face="宋体, MS Song" size=3>C++</FONT><FONT face=宋体 size=3>开发工具高效和强大的底层控制能力,而且大大提高了应用程序开发的速度和可视化程度。</P>
% B; t2 n& Y2 e2 r! i. e) [< align=justify>在</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>中,元件的应用不仅提高了程序的开发速度,其高可重用性也使程序员受益菲浅。</FONT><FONT face="宋体, MS Song" size=3>VCL</FONT><FONT face=宋体 size=3>兼容</FONT><FONT face="宋体, MS Song" size=3>ActiveX</FONT><FONT face=宋体 size=3>和</FONT><FONT face="宋体, MS Song" size=3>DCOM</FONT><FONT face=宋体 size=3>技术,并且是完全基于对象的,因此在代码重用方面非常容易,例如,对于设计好的窗体或者控件,只要将其保存到对象仓库(</FONT><FONT face="宋体, MS Song" size=3>Repository</FONT><FONT face=宋体 size=3>)中,就可以在其它应用程序中使用。而在</FONT><FONT face="宋体, MS Song" size=3>VC</FONT><FONT face=宋体 size=3>中,虽然也可以将自定义类添加到</FONT><FONT face="宋体, MS Song" size=3>VC</FONT><FONT face=宋体 size=3>的组件库中,但只能添加代码,要添加对话框模板等资源却还不太容易。</P></FONT><FONT size=3>
  N/ m. u1 N. [: K2 V< align=justify>Borland</FONT><FONT face=宋体 size=3>公司充分认识到数据库在应用软件中的重要性,在</FONT><FONT size=3>CBuilder</FONT><FONT face=宋体 size=3>中提供了大量的用于数据库操作的元件,可以实现从数据库访问、数据浏览到制作报表的各种功能,可以很方便地根据需要定制自己的数据库应用程序,改变了以往数据库应用程序编制过程的复杂和繁琐,使开发人员可以把更多的精心放在程序总体功能设计上来。</P>
0 n5 j9 T" E* |. {3 j. t9 v< align=justify>同样,面向</FONT><FONT face="宋体, MS Song" size=3>Internet</FONT><FONT face=宋体 size=3>的应用也是应用软件的发展趋势之一,因此,</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>中提供了</FONT><FONT face="宋体, MS Song" size=3>WebBroker</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>WebBridge</FONT><FONT face=宋体 size=3>等</FONT><FONT face="宋体, MS Song" size=3>25</FONT><FONT face=宋体 size=3>个</FONT><FONT face="宋体, MS Song" size=3>Internet</FONT><FONT face=宋体 size=3>元件,可以帮助用户方便地开发</FONT><FONT face="宋体, MS Song" size=3>Internet</FONT><FONT face=宋体 size=3>应用程序,如</FONT><FONT face="宋体, MS Song" size=3>Web</FONT><FONT face=宋体 size=3>浏览器、</FONT><FONT face="宋体, MS Song" size=3>Email</FONT><FONT face=宋体 size=3>管理器、</FONT><FONT face="宋体, MS Song" size=3>FTP</FONT><FONT face=宋体 size=3>及</FONT><FONT face="宋体, MS Song" size=3>BBS</FONT><FONT face=宋体 size=3>程序等。</P></FONT><FONT size=3>
4 Z9 ?* u8 |' @) _  Q$ k< align=justify>CBuilder</FONT><FONT face=宋体 size=3>兼容许多流行的</FONT><FONT size=3>Windows</FONT><FONT face=宋体 size=3>编程技术。例如</FONT><FONT size=3>Delphi</FONT><FONT face=宋体 size=3>和</FONT><FONT size=3>CBuilder</FONT><FONT face=宋体 size=3>是同一个公司的产品,又同样采用了</FONT><FONT size=3>VCL</FONT><FONT face=宋体 size=3>技术,</FONT><FONT size=3>CBuilder</FONT><FONT face=宋体 size=3>可以很好地兼容</FONT><FONT size=3>Delphi</FONT><FONT face=宋体 size=3>,它不仅可以直接使用由</FONT><FONT size=3>Delphi</FONT><FONT face=宋体 size=3>产生的窗体和</FONT><FONT size=3>.OBJ</FONT><FONT face=宋体 size=3>文件,还可在项目中包含</FONT><FONT size=3>Delphi</FONT><FONT face=宋体 size=3>的</FONT><FONT size=3>.PAS</FONT><FONT face=宋体 size=3>源文件,大大扩展了</FONT><FONT size=3>CBuilder</FONT><FONT face=宋体 size=3>程序员可利用的资源。除此之外,</FONT><FONT size=3>CBuilder</FONT><FONT face=宋体 size=3>还兼容</FONT><FONT size=3>VC</FONT><FONT face=宋体 size=3>开发的</FONT><FONT size=3>MFC</FONT><FONT face=宋体 size=3>程序代码,因此具有一定</FONT><FONT size=3>VC</FONT><FONT face=宋体 size=3>基础的朋友也不用担心学习</FONT><FONT size=3>CBuilder</FONT><FONT face=宋体 size=3>会荒废以前的手艺了。</P></FONT><FONT size=3>2 C( ]5 V0 O. c: R
< align=justify>CBuilder</FONT><FONT face=宋体 size=3>的</FONT><FONT size=3>IDE</FONT><FONT face=宋体 size=3>(集成开发环境的缩写,内含了编辑、编译、连接以及调试工具)提供了强大的编辑、编译和调试功能。与同类编程工具相比,</FONT><FONT size=3>CBuilder</FONT><FONT face=宋体 size=3>的编译连接速度是相当快的,它内建的调试功能不仅可以实现一般的设置断点、单步执行、运行时变量监视等功能,还提供有</FONT><FONT size=3>CodeGuard</FONT><FONT face=宋体 size=3>功能,该功能可以在运行时查找内存越界、资源未释放、句柄使用不正确等常见的一些编程错误。</P>$ Y6 l, o' _% r& ~- U* I8 d* F
< align=justify>上面为大家介绍了</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>的主要特点,相信这么棒的软件开发工具已经让你心动了吧?下面心铃就带领大家进入奇妙的</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>编程世界。</P>
7 h% S" ?5 s0 x7 ]2 c( n% n<UL><B>6 j; h+ e& w* W" Y9 b
< align=justify>
4 `& z: H) H; @- R# D4 Q# d<LI>所需的预备知识
9 J+ d7 g+ Q% y4 P<p></LI></UL></B>
+ j" \3 L* S6 w< align=justify>我们的讲座是介绍编程工具的使用方法,而不是介绍单纯的编程语言,虽然</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>具有易学易用的特点,但如果朋友们熟悉以下一些基础的编程知识,学习起来会事半功倍的:</FONT><FONT face="宋体, MS Song" size=3>C/C++</FONT><FONT face=宋体 size=3>语言、</FONT><FONT face="宋体, MS Song" size=3>Windows</FONT><FONT face=宋体 size=3>编程基本知识、面向对象编程基础以及一定的软件工程基础知识。不过,目前还不太了解这些知识的朋友也不用着急,俗话说“只要工夫深,铁杆磨成针”,只要在今后的学习中多花一些时间和精力,相信没有什么能够难倒聪明的你。</P>
' |' v# T, W0 ~: N# U0 ^5 x2 G<UL><B>  g, Q/ o, I) B( \0 G5 U
< align=justify>
2 d5 }9 d: q2 m<LI>安装</FONT><FONT size=3><FONT face="宋体, MS Song">C++ Builder </FONT>: o/ r/ F' G0 C# h2 G
<p></LI></UL></B></FONT><FONT face=宋体 size=3>7 s3 N, K; o, H6 w" _- @
< align=justify>下面以</FONT><FONT face="宋体, MS Song" size=3>CBuilder 5.0</FONT><FONT face=宋体 size=3>企业版为例来介绍一下安装过程。安装</FONT><FONT face="宋体, MS Song" size=3>CBuilder 5</FONT><FONT face=宋体 size=3>所需要的系统基本配置为:奔腾</FONT><FONT face="宋体, MS Song" size=3>90MHz</FONT><FONT face=宋体 size=3>以上</FONT><FONT face="宋体, MS Song" size=3>C</FONT><FONT face=宋体 size=3>机、至少</FONT><FONT face="宋体, MS Song" size=3>32MB</FONT><FONT face=宋体 size=3>内存、以及至少</FONT><FONT face="宋体, MS Song" size=3>250MB</FONT><FONT face=宋体 size=3>的磁盘空间。当然,这只是最低配置,但如果真的在这样的机器上运行</FONT><FONT face="宋体, MS Song" size=3>CBuilder 5</FONT><FONT face=宋体 size=3>,那种感觉,恐怕就只能用“等你等到我心痛”来形容了。因此,心铃还是推荐大家使用自己最快的机器,安装尽量多的内存以及留出大量的硬盘自由空间,这样方可提高</FONT><FONT face="宋体, MS Song" size=3>CBuilder 5</FONT><FONT face=宋体 size=3>的运行效率,节约宝贵的时间。另外,</FONT><FONT face="宋体, MS Song" size=3>CBuilder 5</FONT><FONT face=宋体 size=3>可运行在</FONT><FONT face="宋体, MS Song" size=3>Windows 2000</FONT><FONT face=宋体 size=3>,</FONT><FONT face="宋体, MS Song" size=3>Windows 9x</FONT><FONT face=宋体 size=3>以及</FONT><FONT face="宋体, MS Song" size=3>Windows NT4</FONT><FONT face=宋体 size=3>(至少安装了</FONT><FONT face="宋体, MS Song" size=3>SP3</FONT><FONT face=宋体 size=3>)上。</P>
2 b" N8 R) o* l6 D( `0 d< align=justify>安装前首先关闭系统中所有不需要的程序,特别是可能和</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>安装程序发生冲突的软件,例如</FONT><FONT face="宋体, MS Song" size=3>Outlook 98</FONT><FONT face=宋体 size=3>和一些实时病毒监测程序等。</P>
" U8 h& w+ G* o9 O6 B< align=justify>将安装盘放入光驱内,并启动</FONT><FONT face="宋体, MS Song" size=3>Install.exe</FONT><FONT face=宋体 size=3>程序。首先出现的是欢迎消息,第</FONT><FONT face="宋体, MS Song" size=3>2</FONT><FONT face=宋体 size=3>步要求输入序列号,第</FONT><FONT face="宋体, MS Song" size=3>3</FONT><FONT face=宋体 size=3>步显示软件使用许可协议,第</FONT><FONT face="宋体, MS Song" size=3>4</FONT><FONT face=宋体 size=3>步会出现安装信息对话框,仔细阅读该部分内容对解决安装过程中出现的问题会有所帮助。</P>
( ]4 m. h& r+ u! D  _$ R( H) k9 Q; K< align=justify>第</FONT><FONT face="宋体, MS Song" size=3>5</FONT><FONT face=宋体 size=3>步选择安装类型(图</FONT><FONT face="宋体, MS Song" size=3>1-1</FONT><FONT face=宋体 size=3>),所列的安装类型包括典型、简洁、自定义和完全安装四种类型。其中完全安装(</FONT><FONT face="宋体, MS Song" size=3>Full</FONT><FONT face=宋体 size=3>)的内容最完整,包括</FONT><FONT face="宋体, MS Song" size=3>CBuilder IDE</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>BDE</FONT><FONT face=宋体 size=3>(</FONT><FONT face="宋体, MS Song" size=3>Borland</FONT><FONT face=宋体 size=3>数据库引擎)、数据库桌面等,典型安装(</FONT><FONT face="宋体, MS Song" size=3>Typical</FONT><FONT face=宋体 size=3>)只比完全安装缺少</FONT><FONT face="宋体, MS Song" size=3>MFC</FONT><FONT face=宋体 size=3>支持和微软</FONT><FONT face="宋体, MS Song" size=3>SDK</FONT><FONT face=宋体 size=3>帮助文档,简洁安装(</FONT><FONT face="宋体, MS Song" size=3>Compact</FONT><FONT face=宋体 size=3>)则只包括</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>的主程序和</FONT><FONT face="宋体, MS Song" size=3>ITE</FONT><FONT face=宋体 size=3>(</FONT><FONT face="宋体, MS Song" size=3>Internet Translate Environment</FONT><FONT face=宋体 size=3>)、</FONT><FONT face="宋体, MS Song" size=3>CodeGuard</FONT><FONT face=宋体 size=3>等少数工具。自定义安装(</FONT><FONT face="宋体, MS Song" size=3>Custom</FONT><FONT face=宋体 size=3>)是由用户选择安装内容。另外还有一个“仅配置注册信息”的选项,用于修复以前的安装信息,如果选取了该选项,则仅仅对安装过程中搜集到的信息进行注册,安装过程中不拷贝或只拷贝很少的必需文件,在第一次安装时不要选中该选项。为了能够充分体验</FONT><FONT face="宋体, MS Song" size=3>CBuilder 5</FONT><FONT face=宋体 size=3>的强大功能,心铃建议大家在这一步选择完全安装,大约需要</FONT><FONT face="宋体, MS Song" size=3>388MB</FONT><FONT face=宋体 size=3>的硬盘空间。</P>
$ h# P3 e' o" t- \< align=justify>如果在第</FONT><FONT face="宋体, MS Song" size=3>5</FONT><FONT face=宋体 size=3>步中选择了完全安装,那么安装内容将包括</FONT><FONT face="宋体, MS Song" size=3>Office</FONT><FONT face=宋体 size=3>控件集,第</FONT><FONT face="宋体, MS Song" size=3>6</FONT><FONT face=宋体 size=3>步需要选择一种版本(</FONT><FONT face="宋体, MS Song" size=3>Office 97</FONT><FONT face=宋体 size=3>还是</FONT><FONT face="宋体, MS Song" size=3>Office 2000</FONT><FONT face=宋体 size=3>)的</FONT><FONT face="宋体, MS Song" size=3>Office</FONT><FONT face=宋体 size=3>控件集进行安装。</P>
* n7 W8 i* b* v6 f) H3 H9 |* A< align=justify>如果系统中以前曾安装过其它的</FONT><FONT face="宋体, MS Song" size=3>C++</FONT><FONT face=宋体 size=3>开发工具,如</FONT><FONT face="宋体, MS Song" size=3>VC</FONT><FONT face=宋体 size=3>或</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>的早期版本,第</FONT><FONT face="宋体, MS Song" size=3>7</FONT><FONT face=宋体 size=3>步会让你选择是否重新设置文件关联,该对话框中会列出</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>中常用的文件类型,如</FONT><FONT face="宋体, MS Song" size=3>.cpp</FONT><FONT face=宋体 size=3>(</FONT><FONT face="宋体, MS Song" size=3>C++</FONT><FONT face=宋体 size=3>源程序文件)、</FONT><FONT face="宋体, MS Song" size=3>.bpr</FONT><FONT face=宋体 size=3>(</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>工程文件)等等,如果选择关联某种文件类型,那么今后在资源管理器中双击该类型的文件时,就可以自动调用</FONT><FONT face="宋体, MS Song" size=3>CBuilder 5</FONT><FONT face=宋体 size=3>来打开该文件。心铃建议大家将所有的文件类型都选中,然后按下一步。</P>
% G9 W; ^# q7 Q6 o/ |< align=justify>第</FONT><FONT face="宋体, MS Song" size=3>8</FONT><FONT face=宋体 size=3>步是关于远程数据库应用的许可协议,接受它,进入第</FONT><FONT face="宋体, MS Song" size=3>9</FONT><FONT face=宋体 size=3>步。</P>" M. |, O" ^4 k0 o+ C4 C% \% ]
< align=justify>第</FONT><FONT face="宋体, MS Song" size=3>9</FONT><FONT face=宋体 size=3>步选择安装目录,如图</FONT><FONT face="宋体, MS Song" size=3>1-2</FONT><FONT face=宋体 size=3>所示。如果硬盘自由空间不多,你可以考虑将</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>的程序文件、共享文件、</FONT><FONT face="宋体, MS Song" size=3>BDE</FONT><FONT face=宋体 size=3>与</FONT><FONT face="宋体, MS Song" size=3>SQL</FONT><FONT face=宋体 size=3>连接、数据库桌面分别安装在不同的硬盘上。心铃建议在安装时选择一个足够大的硬盘,将上述四部分内容全部安装到该盘,并保持缺省的目录关系。另外在修改目录名时要注意,路径名中最好不要有中文或其它双字节字符(如全角字母),否则有可能出现问题。</P>
  w6 U$ e% i, o; b< align=justify>第</FONT><FONT face="宋体, MS Song" size=3>10</FONT><FONT face=宋体 size=3>步设置启动菜单名称。第</FONT><FONT face="宋体, MS Song" size=3>11</FONT><FONT face=宋体 size=3>步是开始拷贝文件对话框,其中显示了用户在前几步中选择的安装选项,如果你认为一切正确,则可以按下“</FONT><FONT face="宋体, MS Song" size=3>Install</FONT><FONT face=宋体 size=3>”按钮,开始文件拷贝、安装过程。</P>
. U) I2 Y- p) E9 R6 j$ a2 e< align=justify>整个文件拷贝过程大约需要</FONT><FONT face="宋体, MS Song" size=3>20</FONT><FONT face=宋体 size=3>分钟。拷贝完毕后,根据提示重新启动计算机。安装过程再进行最后的配置工作。如果一切顺利,配置完成后整个安装过程就结束了。</P>4 K7 w2 g. t; _$ m' _7 I0 M
<UL></FONT><B><FONT size=3>$ M, ?5 k3 g6 [( E% R5 t  m0 S
< align=justify>
7 R' I  \4 P* v" ]9 e<LI>C++ Builder</FONT><FONT face=宋体 size=3>的组成
8 e( o* ^, B# i9 j3 z/ A<p></LI></UL></B>
( _3 n# i1 o' l8 |5 @' L7 S% R< align=justify>了解和熟悉</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>的文件组织和程序组织对大家今后的学习会有不小的帮助。表</FONT><FONT face="宋体, MS Song" size=3>1-1</FONT><FONT face=宋体 size=3>是</FONT><FONT face="宋体, MS Song" size=3>CBuilder 5</FONT><FONT face=宋体 size=3>的文件组织关系。</P><B>0 \/ V8 c7 D" X; K
< align=center>表</FONT><FONT face="宋体, MS Song" size=3>1-1 C++ Builder 5.0</FONT><FONT face=宋体 size=3>的文件组织</P>" r) h; l, \8 L  z
<></B></FONT>
' Q' G. p% R: P1 `2 u6 p7 q; X$ }<TABLE borderColor=#000000 cellSpacing=2 cellPadding=7 width=568 border=1>
9 B3 B- F) m: m, F0 m$ A  ]
. ~' l& A- H8 y+ e& O<TR>
5 A$ y: ^+ f% S% w* L* {<TD vAlign=top width="32%"><B><FONT face=宋体 size=3>. U. a! y, N( G5 r5 p# K; ~
<P align=justify>路</FONT><FONT face="宋体, MS Song" size=3> </FONT><FONT face=宋体 size=3>径</B></FONT></P></TD>* c( V3 s# K- x# S8 M2 T
<TD vAlign=top width="68%"><B><FONT face=宋体 size=3>
+ H. W, y( G8 v  r  n<P align=justify>说</FONT><FONT face="宋体, MS Song" size=3> </FONT><FONT face=宋体 size=3>明</B></FONT></P></TD></TR>& F% r9 a+ H, S
<TR>1 ]! b+ U$ C4 T" C0 a. V
<TD vAlign=top width="32%"><FONT size=3>2 h/ Z+ P5 U( m+ b: Y. x3 Q( e
<P align=justify>Borland\CBuilder5\Bin</FONT></P></TD>  X; I# C% _5 }  J
<TD vAlign=top width="68%"><FONT size=3>
. c1 k- o( ]8 h/ v<P align=justify>IDE</FONT><FONT face=宋体 size=3>的主要工具软件,如编译器、连接器、资源编程器等</FONT></P></TD></TR>9 H' z6 H7 T/ j- w/ r1 o
<TR>
( e: x4 T9 I2 T' F, ~9 r% ~<TD vAlign=top width="32%"><FONT size=3>& l' v/ H' `6 n/ M$ n
<P align=justify>Borland\CBuilder5\Examples</FONT></P></TD>
# D- y% F3 c, }% J/ _2 k! `<TD vAlign=top width="68%"><FONT face=宋体 size=3>
" d' e- R$ h! @4 H<P align=justify>应用程序例程</FONT></P></TD></TR>
. B9 E9 p3 Q1 n- F<TR>+ G  V0 v5 Y$ Z
<TD vAlign=top width="32%"><FONT size=3>. A8 r# \1 X* K* f% p2 p( {1 {
<P align=justify>Borland\CBuilder5\Help</FONT></P></TD>! n/ a" P8 h4 M
<TD vAlign=top width="68%"><FONT face=宋体 size=3>
( n; V: h6 y8 g9 c<P align=justify>帮助文档</FONT></P></TD></TR>2 F) P. u! l; T. `
<TR>
2 a# Z9 f+ f: h  |+ K0 x<TD vAlign=top width="32%"><FONT size=3>2 P) T* b# }, `0 P- T2 K& D
<P align=justify>Borland\CBuilder5\Include</FONT></P></TD>9 K' o0 h) ~9 w6 f4 T9 A
<TD vAlign=top width="68%"><FONT size=3>& f9 d- Y" C# \- [2 b2 O
<P align=justify>C++ Builder</FONT><FONT face=宋体 size=3>标准头文件</FONT></P></TD></TR>" r9 R0 u! R& T# d
<TR>- p% E/ v3 b5 |$ f/ E
<TD vAlign=top width="32%"><FONT size=3>
: X: N. O+ o1 x# Q+ j: \<P align=justify>Borland\CBuilder5\Lib</FONT></P></TD>
2 t0 g$ R( k# F3 N' Q<TD vAlign=top width="68%"><FONT size=3>
0 M+ A$ J" J& Y1 [" \<P align=justify>C++ Builder</FONT><FONT face=宋体 size=3>标准库文件</FONT></P></TD></TR>
# r% G3 f" p5 X<TR>* L2 y% q: M# ]/ u- G7 L8 i0 a
<TD vAlign=top width="32%"><FONT size=3>
3 m/ _% D! m4 {" m$ b<P align=justify>Borland\CBuilder5\ObjRepos</FONT></P></TD>
5 S& B5 d  y5 p: g1 S) Y1 l<TD vAlign=top width="68%"><FONT face=宋体 size=3>
- a5 S8 d- x6 ~% b- ]' G! o5 i) ?<P align=justify>对象仓库</FONT></P></TD></TR>
  V" P" h4 A- @<TR>1 {5 v" z# R' K6 x5 t( C. R4 g
<TD vAlign=top width="32%"><FONT size=3>% R$ T8 q0 w2 h( v) Q% f
<P align=justify>Borland\CBuilder5\Ocx</FONT></P></TD>
' Y4 ~' N% d: U) K8 ^$ J<TD vAlign=top width="68%"><FONT size=3># w0 o! m+ k: n% t5 ^6 l
<P align=justify>OCX</FONT><FONT face=宋体 size=3>控件库</FONT></P></TD></TR>
# ]3 k$ j1 `2 x/ d3 X& V1 T: ?: C: E1 G+ ]<TR>/ L$ a6 C9 e: n: K
<TD vAlign=top width="32%"><FONT size=3>
, B/ i) e5 I+ ~6 C3 F$ _) q& ^<P align=justify>Borland\CBuilder5\Projects</FONT></P></TD>
; A" f7 d+ j5 D<TD vAlign=top width="68%"><FONT face=宋体 size=3>
9 n8 ]! ?" U7 g+ q+ |0 Y3 X<P align=justify>用户工程存放目录</FONT></P></TD></TR>' I3 K8 B0 _/ t1 I- y* R1 P
<TR>
5 P; V2 n* ^6 {+ _  n0 Q& J<TD vAlign=top width="32%"><FONT size=3>
0 ?$ O. Q9 y) P) |( S0 _<P align=justify>Borland\CBuilder5\Source</FONT></P></TD>! }9 P; C' B5 W
<TD vAlign=top width="68%"><FONT size=3>
4 o: F  c; c5 f3 A7 i9 }; ?<P align=justify>VCL</FONT><FONT face=宋体 size=3>类及其他标准的源代码</FONT></P></TD></TR># S! i* i; ?, N/ I1 Q$ i
<TR>" {, o: {- {3 ]3 C/ }# O% @) q1 B3 q
<TD vAlign=top width="32%"><FONT size=3>7 k7 k& u2 M1 r/ S7 ~5 T1 S
<P align=justify>Borland\Database Desktop</FONT></P></TD>
) n( l$ }& _  `( y3 f<TD vAlign=top width="68%"><FONT face=宋体 size=3>
1 G" A0 `/ }/ a+ L<P align=justify>数据桌面工具软件及其运行目录</FONT></P></TD></TR>5 J( G& B: ]! U) T' W* ^: j
<TR>
& }9 j: u& @/ Q0 ]8 ?<TD vAlign=top width="32%"><FONT size=3>3 j# S, ]8 ?* r% E6 U
<P align=justify>Borland Shared\Bde</FONT></P></TD>& T+ ]" I1 B! s; m
<TD vAlign=top width="68%"><FONT size=3>% d6 j% {5 M) C' U
<P align=justify>Borland</FONT><FONT face=宋体 size=3>数据库引擎驱动程序</FONT></P></TD></TR>
5 i6 B  L7 i2 g' t: Z9 z# M<TR># p2 \2 r6 O7 c: k' r. M1 J1 w
<TD vAlign=top width="32%"><FONT size=3># i( i0 h. m6 n4 o2 ^: |  \
<P align=justify>Borland Shared\Data</FONT></P></TD>
, J" v; M4 j; g( L! k. O<TD vAlign=top width="68%"><FONT face=宋体 size=3>
8 ]. h0 I& N' v$ U) r/ x0 _<P align=justify>样例数据库</FONT></P></TD></TR>  |$ d9 H6 Y0 i/ n% E% R( ~) o
<TR>0 I9 A1 Z/ P7 G
<TD vAlign=top width="32%"><FONT size=3>
/ ^' ]# B/ r4 Y, V' |+ {<P align=justify>Borland Shared\Images</FONT></P></TD>3 _2 ?8 c" v, E* @. @" G! s2 ^
<TD vAlign=top width="68%"><FONT face=宋体 size=3>
7 Q4 g% `' g& Z% p- x' ^" p: a<P align=justify>图象库</FONT></P></TD></TR>
& T. D) \. l# M- s' ^9 K# B<TR>
! l4 s6 q6 \2 @. C+ r<TD vAlign=top width="32%"><FONT size=3>3 |. j' x6 r( R1 v, C: A3 G
<P align=justify>Borland Shared\MSHelp</FONT></P></TD>4 M* w; I* e2 D' F, n
<TD vAlign=top width="68%"><FONT face=宋体 size=3>
6 f, t+ L) R( s6 G; G3 ?/ q<P align=justify>微软帮助文档</FONT></P></TD></TR></TABLE><FONT face=宋体 size=3></P>
. ~: R" H% ~0 T1 \- T8 H<P align=justify>开始菜单中</FONT><FONT face="宋体, MS Song" size=3>CBuilder 5</FONT><FONT face=宋体 size=3>程序组包括的工具软件如表</FONT><FONT face="宋体, MS Song" size=3>1-2</FONT><FONT face=宋体 size=3>所示:</P><B>- _! y; h6 t+ T) J$ T
<P align=center>表</FONT><FONT face="宋体, MS Song" size=3>1-2 C++ Builder 5</FONT><FONT face=宋体 size=3>包含的主要工具软件</P># c+ S0 @. E: C- \5 I: l
<P></B></FONT>+ g% n0 c8 Q3 }$ w, e
<TABLE borderColor=#000000 cellSpacing=2 cellPadding=7 width=568 border=1>
5 X8 \) Y7 B! t$ m
+ K- F7 e7 z+ M7 }* s# U. x& n. H<TR>
7 J- \/ b+ G! [<TD vAlign=top width="25%"><B><FONT face=宋体 size=3># C% c4 i7 N$ U6 a7 A9 }) a
<P align=justify>名</FONT><FONT face="宋体, MS Song" size=3> </FONT><FONT face=宋体 size=3>称</B></FONT></P></TD>0 u9 u7 g4 `3 p2 }5 V6 }
<TD vAlign=top width="75%"><B><FONT face=宋体 size=3>6 @; q& Z2 n' l- v$ e
<P align=justify>说</FONT><FONT face="宋体, MS Song" size=3> </FONT><FONT face=宋体 size=3>明</B></FONT></P></TD></TR>
( M/ Z$ b0 k8 i, \4 H<TR>9 Q2 U3 g( O6 T
<TD vAlign=top width="25%"><FONT size=3>
+ h; w8 B3 c* O7 l/ |) z. g<P align=justify>BDE Administrator</FONT></P></TD>7 ?/ A  V) D) V2 O4 x1 l- _
<TD vAlign=top width="75%"><FONT size=3>: C0 r+ B8 W% f( P
<P align=justify>Borland</FONT><FONT face=宋体 size=3>数据库引擎管理器</FONT></P></TD></TR>
/ I. f5 ~& p3 X3 `, [7 ?  m<TR>
8 Y1 {  t% ]  t* v4 l* d$ n9 p2 y<TD vAlign=top width="25%"><FONT size=3>6 l1 B3 w7 s4 F  c4 L) B( Y7 J
<P align=justify>C++ Builder 5</FONT></P></TD>+ V7 \& J. C% D3 y
<TD vAlign=top width="75%"><FONT size=3>6 I0 x9 G3 G3 [' d# y$ R/ m6 v
<P align=justify>C++ Builder 5</FONT><FONT face=宋体 size=3>主程序(集成开发环境及内含的工具软件)</FONT></P></TD></TR>
) Q' B" ~7 a& h0 u2 R6 C<TR>4 j" l4 G3 _7 g
<TD vAlign=top width="25%"><FONT size=3>
" z  E: E2 e# T& ~6 `! E: t<P align=justify>Data pump</FONT></P></TD>: a: K  {# c* C- B' _. t! ?* e
<TD vAlign=top width="75%"><FONT face=宋体 size=3>
1 f9 U1 }8 ~) R& u# ^0 N" ^5 @<P align=justify>在数据库之间移动和拷贝数据。</FONT></P></TD></TR>
. m) F) f! ?  E<TR>
6 s# z+ F$ |+ c  G<TD vAlign=top width="25%"><FONT size=3>; m" h4 a5 s/ t1 {2 q( Q
<P align=justify>Image Editor</FONT></P></TD>
( ^4 @2 Z7 t- y6 V8 ^& S<TD vAlign=top width="75%"><FONT face=宋体 size=3>1 K5 r! e* ^5 f1 w
<P align=justify>图象编辑器</FONT></P></TD></TR>$ t# @8 j: I: B8 _7 y) n* _
<TR>" r, O2 S- ]% z0 H) V4 S
<TD vAlign=top width="25%"><FONT size=3>
7 ]; F5 B. n; X6 x<P align=justify>SQL Explorer</FONT></P></TD>
4 }3 r. T( n8 a! B7 K<TD vAlign=top width="75%"><FONT face=宋体 size=3>
7 C; v) G& H2 P2 q$ a% h<P align=justify>数据库浏览器,可列出所有本地数据库、</FONT><FONT face="宋体, MS Song" size=3>ODBC</FONT><FONT face=宋体 size=3>数据库及建立了</FONT><FONT face="宋体, MS Song" size=3>SQL Link</FONT><FONT face=宋体 size=3>的远程</FONT><FONT face="宋体, MS Song" size=3>SQL</FONT><FONT face=宋体 size=3>数据库</FONT></P></TD></TR>
0 ~6 j0 i3 \% {9 W$ [' ~. _* F<TR>9 N8 y& E# q$ s+ Q. M3 P4 ^# l
<TD vAlign=top width="25%"><FONT size=3>
$ C+ f6 r0 z7 E) m" r+ @<P align=justify>SQL Monitor</FONT></P></TD>
) ~& q; ?( }/ m# U. G( x7 H<TD vAlign=top width="75%"><FONT face=宋体 size=3>
& ^  n7 J" d" }, U$ l) H6 V<P align=justify>监视对远程</FONT><FONT face="宋体, MS Song" size=3>SQL</FONT><FONT face=宋体 size=3>数据库的访问</FONT></P></TD></TR>
6 Q! a! X( j8 }! t) ~<TR>
3 t3 y$ g; y0 H' _<TD vAlign=top width="25%"><FONT size=3>4 H! v( V3 b0 Q# r7 k# ~8 a& P1 U9 T
<P align=justify>WinSight32</FONT></P></TD>
  L4 m. O3 @1 ]/ D( V; C  Q: s6 X<TD vAlign=top width="75%"><FONT face=宋体 size=3># A# ?- z  [8 h' c- F0 O
<P align=justify>监视系统中的所有进程、线程、窗口、消息传递的工具软件</FONT></P></TD></TR></TABLE><FONT face=宋体 size=3></P>* \4 Z, m5 Y3 ]7 z  R$ A1 n
<P align=justify> </P></FONT>
作者: 韩冰    时间: 2005-1-26 01:03
<b><FONT size=6> </FONT></b>< align=center>C++ Builder<FONT face=宋体 size=6>集成开发环境(上)</P></FONT><FONT face=宋体 size=3>< align=justify>介绍一个新软件,总免不了要介绍该软件的用户界面,如菜单、工具条等等的使用方法,也许有的朋友会说“我的</FONT><FONT face="宋体, MS Song" size=3>E</FONT><FONT face=宋体 size=3>文不错,又有过使用</FONT><FONT face="宋体, MS Song" size=3>IDE</FONT><FONT face=宋体 size=3>编程开发的经验,所以这一步可以省了。”,但所谓“磨刀不误砍柴功”,</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>集成开发环境具有相当丰富的功能,如果能够熟练掌握这些功能,势必会大大提高我们的工作效率。当然,仅仅通过短短的讲座没有办法在短时间内对</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>集成开发环境进行详细的介绍,但心铃仍然希望借此大家能对</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>的使用和操作有一个初步的了解,并为进一步学习打下一个良好的基础。</FONT><FONT size=3><FONT face="宋体, MS Song"> </FONT></P>< align=justify>CBuilder </FONT><FONT face=宋体 size=3>集成开发环境采用了浮动式窗口</FONT><FONT size=3>/</FONT><FONT face=宋体 size=3>工具条的界面风格,如图</FONT><FONT size=3>2-1</FONT><FONT face=宋体 size=3>所示。缺省的集成开发环境由主菜单、工具条、元件面板、对象浏览器、窗体编辑器、代码编辑器和类浏览器组成,用户还可以通过</FONT><FONT size=3>View</FONT><FONT face=宋体 size=3>菜单中的一系列命令来定制自己习惯的窗口布局。</P><UL><B>< align=justify><LI>菜单
; V! b( D. x; n  }9 Z6 }: g</LI></UL></B></FONT><FONT size=3>< align=justify>CBuilder</FONT><FONT face=宋体 size=3>的菜单命令非常多,主菜单就有</FONT><FONT size=3>10</FONT><FONT face=宋体 size=3>个菜单栏,上百个菜单项,另外还有众多右键关联菜单。主菜单和关联菜单一起涵盖了</FONT><FONT size=3>CBuilder</FONT><FONT face=宋体 size=3>集成开发环境支持的所有操作命令。许多常用菜单命令都有加速键,如</FONT><FONT size=3>F9</FONT><FONT face=宋体 size=3>(调试运行)、</FONT><FONT size=3>Ctrl+S</FONT><FONT face=宋体 size=3>(保存文件)等,熟练使用这些加速键可以提高编程时的工作效率。</P>< align=justify>主菜单按不同用途分为</FONT><FONT face="宋体, MS Song" size=3>10</FONT><FONT face=宋体 size=3>个菜单栏。</FONT><FONT face="宋体, MS Song" size=3>File</FONT><FONT face=宋体 size=3>菜单中主要包括与文件操作有关的命令,其中最常用的是新建工程(</FONT><FONT face="宋体, MS Song" size=3>New Application</FONT><FONT face=宋体 size=3>)、打开工程(</FONT><FONT face="宋体, MS Song" size=3>Open Project</FONT><FONT face=宋体 size=3>)、打开文件(</FONT><FONT face="宋体, MS Song" size=3>Open</FONT><FONT face=宋体 size=3>)和保存(</FONT><FONT face="宋体, MS Song" size=3>Save</FONT><FONT face=宋体 size=3>)。另外一个非常有用的命令是新建对象(</FONT><FONT face="宋体, MS Song" size=3>New</FONT><FONT face=宋体 size=3>),它会调出如图</FONT><FONT face="宋体, MS Song" size=3>2-2</FONT><FONT face=宋体 size=3>所示的对话框。</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>中有许多预先建立的对象模版和向导,如各种类型的工程、不同用途的窗体等等,从</FONT><FONT face="宋体, MS Song" size=3>New Items</FONT><FONT face=宋体 size=3>对话框中选择一种对象模版或向导,可以让你按照向导的指示生成一个新的对象,许多高级的功能都可以通过这种方式实现,从而避免了大量手工重复性的劳动。如图</FONT><FONT face="宋体, MS Song" size=3>2-2</FONT><FONT face=宋体 size=3>所示,</FONT><FONT face="宋体, MS Song" size=3>New Items</FONT><FONT face=宋体 size=3>对话框将对象模版和向导分成了多个页,除了少数几页外,大部分的对象模版都保存在对象仓库(</FONT><FONT face="宋体, MS Song" size=3>Object Repository</FONT><FONT face=宋体 size=3>)中,通过对象仓库保存和重用一些已建立的对象是</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>代码重用技术中的重要内容。在讲座的后面,心铃还要介绍如何向对象仓库中的添加、编辑和删除对象的方法。</P></FONT><FONT size=3>< align=justify>Edit</FONT><FONT face=宋体 size=3>菜单列出了与编辑有关的命令。在</FONT><FONT size=3>CBuilder</FONT><FONT face=宋体 size=3>中,编辑不仅仅指代码编辑,也包括窗体编辑。</FONT><FONT size=3>Edit</FONT><FONT face=宋体 size=3>菜单中常用命令有:撤消</FONT><FONT size=3>/</FONT><FONT face=宋体 size=3>重复操作(</FONT><FONT size=3>Undo/Redo</FONT><FONT face=宋体 size=3>)、剪贴板操作(</FONT><FONT size=3>Copy</FONT><FONT face=宋体 size=3>、</FONT><FONT size=3>aste</FONT><FONT face=宋体 size=3>、</FONT><FONT size=3>Cut</FONT><FONT face=宋体 size=3>等)、布局操作(</FONT><FONT size=3>Align</FONT><FONT face=宋体 size=3>、</FONT><FONT size=3>Scale</FONT><FONT face=宋体 size=3>、</FONT><FONT size=3>Size</FONT><FONT face=宋体 size=3>);根据心铃的一点点实际经验,如果要让程序的用户界面设计得整齐美观,用好布局操作命令是很重要的。</P></FONT><FONT size=3>< align=justify>Search</FONT><FONT face=宋体 size=3>菜单包括在代码中查找和定位的有关命令,其中常用的有查找(</FONT><FONT size=3>Find</FONT><FONT face=宋体 size=3>)、在多个文件中查找(</FONT><FONT size=3>Find in Files</FONT><FONT face=宋体 size=3>)、替换(</FONT><FONT size=3>Replace</FONT><FONT face=宋体 size=3>)和按行号定位(</FONT><FONT size=3>Go to Line Number</FONT><FONT face=宋体 size=3>)等命令。</P></FONT><FONT size=3>< align=justify>View</FONT><FONT face=宋体 size=3>菜单中的命令用来调整集成开发环境的窗口布局。</FONT><FONT size=3>CBuilder</FONT><FONT face=宋体 size=3>内含许多具有特殊用途的工具窗口,如果全部同时显示出来,集成开发环境中的窗口就太多了,而且显得十分混乱,因此可以通过</FONT><FONT size=3>View</FONT><FONT face=宋体 size=3>菜单调出或隐藏这些窗口。例如,我们可以用</FONT><FONT size=3>roject Manager</FONT><FONT face=宋体 size=3>命令打开工程管理器,查看当前所有打开的工程;在运行时,可以打开各种调试功能窗口,如变量监视窗口(</FONT><FONT size=3>Watches</FONT><FONT face=宋体 size=3>)、调用堆栈窗口(</FONT><FONT size=3>Call Stack</FONT><FONT face=宋体 size=3>),以方便调试和排错;通过</FONT><FONT size=3>Toggle Form/Unit</FONT><FONT face=宋体 size=3>命令可以在窗体和其代码之间进行切换。</FONT><FONT size=3>View</FONT><FONT face=宋体 size=3>系列菜单命令很有用,心铃建议大家自己动手试一试每一项命令,调出这些特殊工具窗口,仔细了解它们的用途和用法。</P></FONT><FONT size=3>< align=justify>roject</FONT><FONT face=宋体 size=3>菜单列出了与工程有关的命令,包括:向工程中添加文件(</FONT><FONT size=3>Add to Project</FONT><FONT face=宋体 size=3>)、从工程中删除文件(</FONT><FONT size=3>Remove from Project</FONT><FONT face=宋体 size=3>)、把当前工程添加到对象仓库中(</FONT><FONT size=3>Add to Repository</FONT><FONT face=宋体 size=3>)、编译源代码(</FONT><FONT size=3>Compile Unit</FONT><FONT face=宋体 size=3>)、生成可执行文件(</FONT><FONT size=3>Make</FONT><FONT face=宋体 size=3>)、修改工程的设置(</FONT><FONT size=3>Option</FONT><FONT face=宋体 size=3>)等等,其中</FONT><FONT size=3>Option</FONT><FONT face=宋体 size=3>命令可以调出工程设置对话框,修改编译连接参数、设置启动窗口等,具体使用还会在后面的讲座中介绍。另外,</FONT><FONT size=3>Add to Repository</FONT><FONT face=宋体 size=3>命令可以把当前工程的所有内容(包括所有的窗体和源程序文件)添加到对象仓库中,如图</FONT><FONT size=3>2-3</FONT><FONT face=宋体 size=3>所示,“</FONT><FONT size=3>Add to Repository</FONT><FONT face=宋体 size=3>”对话框中需要输入的参数有对象名称,对象描述,以及目标页。目标页可以为对象仓库中已有的页,也可以输入新名字来建立一个新的对象仓库页。除了工程之外,还可以把窗体添加到对象仓库中,添加方法是编辑状态下,在某一窗体上单击右键,在弹出的关联菜单中选择(</FONT><FONT size=3>Add to Repository</FONT><FONT face=宋体 size=3>)命令。</P></FONT><FONT size=3>< align=justify>Run</FONT><FONT face=宋体 size=3>菜单用于调试工程,其中常用的命令包括运行(</FONT><FONT size=3>Run</FONT><FONT face=宋体 size=3>)、设置命令行参数(</FONT><FONT size=3>arameter</FONT><FONT face=宋体 size=3>)、单步(</FONT><FONT size=3>Step</FONT><FONT face=宋体 size=3>)、添加变量监视(</FONT><FONT size=3>Add Watch</FONT><FONT face=宋体 size=3>)和添加断点(</FONT><FONT size=3>Add Breakpoint</FONT><FONT face=宋体 size=3>)等。</P></FONT><FONT size=3>< align=justify>Component</FONT><FONT face=宋体 size=3>菜单中是元件有关的命令,包括建立元件、引入一个</FONT><FONT size=3>ActiveX</FONT><FONT face=宋体 size=3>控件等。在</FONT><FONT size=3>CBuilder</FONT><FONT face=宋体 size=3>中,编译好的元件存在于包文件中。包文件是</FONT><FONT size=3>CBuilder</FONT><FONT face=宋体 size=3>特有的一种动态连接库,其文件扩展名为</FONT><FONT size=3>BPL</FONT><FONT face=宋体 size=3>,一个</FONT><FONT size=3>BPL</FONT><FONT face=宋体 size=3>库中可以包含许多元件,常用的</FONT><FONT size=3>CBuilder</FONT><FONT face=宋体 size=3>元件位于</FONT><FONT size=3>dclstd50.bpl</FONT><FONT face=宋体 size=3>中,新建的元件一般位于</FONT><FONT size=3>dclusr50.bpl</FONT><FONT face=宋体 size=3>中。建立元件的过程就是将元件的源代码编译成</FONT><FONT size=3>BPL</FONT><FONT face=宋体 size=3>库的过程,用来定义</FONT><FONT size=3>BPL</FONT><FONT face=宋体 size=3>库编译选项的文件为其工程文件</FONT><FONT size=3>.BPK</FONT><FONT face=宋体 size=3>文件。</P></FONT><FONT size=3>< align=justify>Database</FONT><FONT face=宋体 size=3>菜单为数据库有关的命令,包括数据库浏览器(</FONT><FONT size=3>Explorer</FONT><FONT face=宋体 size=3>)、</FONT><FONT size=3>SQL</FONT><FONT face=宋体 size=3>监视器(</FONT><FONT size=3>SQL Monitor</FONT><FONT face=宋体 size=3>)和数据窗生成向导(</FONT><FONT size=3>Form Wizard</FONT><FONT face=宋体 size=3>)等。</P>< align=justify>从</FONT><FONT face="宋体, MS Song" size=3>Tools</FONT><FONT face=宋体 size=3>菜单可以启动许多有用的工具,如图象编辑器(</FONT><FONT face="宋体, MS Song" size=3>Image Editor</FONT><FONT face=宋体 size=3>)、数据库桌面(</FONT><FONT face="宋体, MS Song" size=3>Database Desktop</FONT><FONT face=宋体 size=3>)等,还可以对</FONT><FONT face="宋体, MS Song" size=3>CBuilder IDE</FONT><FONT face=宋体 size=3>的各项设置进行调整。例如,你对白底黑字看厌吗?通过</FONT><FONT face="宋体, MS Song" size=3>Editor Option</FONT><FONT face=宋体 size=3>修改代码编辑器的颜色方案,就可以给你的</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>换上更个性的彩妆。又如,在缺省情况下,</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>在启动时会创建新的工程,如果我们希望它自动调入上次编辑的工程,并恢复以前的编程状态,可以通过</FONT><FONT face="宋体, MS Song" size=3>Environment Option</FONT><FONT face=宋体 size=3>命令调出环境设置对话框,并在其</FONT><FONT face="宋体, MS Song" size=3>reference</FONT><FONT face=宋体 size=3>选项页中将</FONT><FONT face="宋体, MS Song" size=3>Autosave Options-&gtroject Desktop</FONT><FONT face=宋体 size=3>设置为选中状态,这样</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>在退出时会自动保存编辑状态,并在下次打开时自动调入上次编辑的工程。另外,</FONT><FONT face="宋体, MS Song" size=3>Tools-&gt;Repository</FONT><FONT face=宋体 size=3>命令可以打开</FONT><FONT face="宋体, MS Song" size=3>Object Repository</FONT><FONT face=宋体 size=3>对话框(图</FONT><FONT face="宋体, MS Song" size=3>2-4</FONT><FONT face=宋体 size=3>),以便添加、删除和更名对象仓库中的页和对象,这些更改都会在</FONT><FONT face="宋体, MS Song" size=3>New Items</FONT><FONT face=宋体 size=3>对话框中反映出来。</P></FONT><FONT size=3>< align=justify>Help</FONT><FONT face=宋体 size=3>菜单列出了与获取帮助相关的命令,包括</FONT><FONT size=3>C++ Builder Help</FONT><FONT face=宋体 size=3>、</FONT><FONT size=3>C++ Builder Tools</FONT><FONT face=宋体 size=3>、</FONT><FONT size=3>Windows SDK Help</FONT><FONT face=宋体 size=3>以及</FONT><FONT size=3>Borland</FONT><FONT face=宋体 size=3>公司的</FONT><FONT size=3>CBuilder</FONT><FONT face=宋体 size=3>主页链接。其中</FONT><FONT size=3>C++ Builder Help</FONT><FONT face=宋体 size=3>包括了集成开发环境的使用方法、函数的语法规则、各种元件的使用说明等等相当丰富的帮助内容,这些都是我们在学习和使用</FONT><FONT size=3>CBuilder</FONT><FONT face=宋体 size=3>过程中最常用的好帮手。除了通过菜单获取帮助之外,</FONT><FONT size=3>CBuilder</FONT><FONT face=宋体 size=3>还支持</FONT><FONT size=3>F1</FONT><FONT face=宋体 size=3>快捷键激活帮助,</FONT><FONT size=3>F1</FONT><FONT face=宋体 size=3>帮助会根据用户当前进行的操作快速定位用户所需的内容。例如,在代码编辑器中,将光标插入点放在某个函数或关键字上,按下</FONT><FONT size=3>F1</FONT><FONT face=宋体 size=3>键就可以直接查阅到该函数的帮助;再如,选中某个元件后按下</FONT><FONT size=3>F1</FONT><FONT face=宋体 size=3>键可查阅该元件的帮助;又如,当某一菜单命令被高亮度选中时,</FONT><FONT size=3>F1</FONT><FONT face=宋体 size=3>键还可查该菜单命令的功能,十分方便快捷。除此之外,互联网上还有许多优秀的</FONT><FONT size=3>CBuilder</FONT><FONT face=宋体 size=3>编程站点和论坛,在那里有很多热心的高手可以帮助大家答疑解惑,当然,心铃的信箱也总是向大家开放,愿意和大家一起分享学习的烦恼与乐趣。</P><UL><B>< align=justify><LI>工具条 <p></LI></UL></B></FONT><FONT size=3>< align=justify>CBuilder</FONT><FONT face=宋体 size=3>工具条可浮动、可停靠、可以任意调整位置,另外,通过</FONT><FONT size=3>View-&gt;Toolbars</FONT><FONT face=宋体 size=3>菜单命令还可以调出或隐藏不同的工具条,或者自定义工具条上的功能按钮。工具条按钮是菜单命令的快捷方式,标准的工具条命令包括新建对象(对应</FONT><FONT size=3>File-&gt;New</FONT><FONT face=宋体 size=3>)、打开文件(</FONT><FONT size=3>File-&gt;Open</FONT><FONT face=宋体 size=3>)、存盘(</FONT><FONT size=3>File-&gt;Save</FONT><FONT face=宋体 size=3>)、向工程中添加文件(</FONT><FONT size=3>roject-&gt;Add to Project</FONT><FONT face=宋体 size=3>)、打开帮助(</FONT><FONT size=3>Help-&gt;C++ Builder Help</FONT><FONT face=宋体 size=3>)、运行(</FONT><FONT size=3>Run-&gt;Run</FONT><FONT face=宋体 size=3>)、单步运行(</FONT><FONT size=3>Run-&gt;Step Over</FONT><FONT face=宋体 size=3>)等等。另外,打开文件工具按钮的右侧有一个下拉箭头,打开该箭头,会出现最近操作的文件(或工程)的列表,利用该列表可以快速打开最近操作的文件(或工程)。工具条中各种按钮命令都是最常用的</FONT><FONT size=3>CBuilder</FONT><FONT face=宋体 size=3>操作命令。因此,心铃建议大家熟练掌握这些工具条的使用。</P><UL><B>< align=justify><LI>元件面板 <p></LI></UL></B>< align=justify>丰富的元件库可以说是</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>中最精彩的部分了,缺省的可视化控件有</FONT><FONT face="宋体, MS Song" size=3>130</FONT><FONT face=宋体 size=3>多个,通过</FONT><FONT face="宋体, MS Song" size=3>Component</FONT><FONT face=宋体 size=3>菜单中的命令还可以很容易地添加其它控件,可以利用的资源是非常丰富的。众多的可视化元件就象橱窗里精美的货品,分门别类摆放在元件面板中,使用时,只要用鼠标选中某个元件,将其放置在窗体的合适位置上即可,使用相当方便。根据不同的功能,元件面板又分为多个元件栏,用鼠标点取某个元件栏标签,可以调出该栏的所有元件。如果窗口比较小,可能会有一些元件栏标签不可见,这时可以通过元件面板右上角的一对箭头来滚动查看。同样,有些元件栏的元件数量比较多,栏内显示不下,则该栏的左右会各有一个箭头以供浏览。另外,每个元件栏的最左边为一个鼠标箭头符号,它不是元件,只是用于取消对某一元件的选中状态。</P>< align=justify>缺省的元件栏包括</FONT><FONT face="宋体, MS Song" size=3>Standard</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>Additional</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>Win32</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>System</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>Data Access</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>Data Controls</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>ADO</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>Internet</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>QReport</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>Dialogs</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>Win3.1</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>Samples</FONT><FONT face=宋体 size=3>和</FONT><FONT face="宋体, MS Song" size=3>ActiveX</FONT><FONT face=宋体 size=3>。通过</FONT><FONT face="宋体, MS Song" size=3>Component-&gt;Configure Pallete</FONT><FONT face=宋体 size=3>命令可以添加、删除或更改元件栏的标签名称,也可以隐藏元件栏中的元件。如果要增加新的元件,有三种方式,即新建元件(</FONT><FONT face="宋体, MS Song" size=3>Component-&gt;New Component</FONT><FONT face=宋体 size=3>)、建立元件(</FONT><FONT face="宋体, MS Song" size=3>Component-&gt;Install Component</FONT><FONT face=宋体 size=3>)和引入</FONT><FONT face="宋体, MS Song" size=3>ActiveX</FONT><FONT face=宋体 size=3>控件(</FONT><FONT face="宋体, MS Song" size=3>Import ActiveX Control</FONT><FONT face=宋体 size=3>)。</P>< align=justify>在今后的编程实践中,很大一部分编程工作都是使用元件来完成所需要的功能,从某种意义上来说,使用元件的熟练程度是</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>编程者水平高低的标志之一。由于</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>中的元件数量太多,不可能在讲座全部介绍,只有靠大家自己通过查阅资料和帮助文档,至少要做到了解各个元件的大致用途。另外,在互联网上有大量现成的</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>Delphi</FONT><FONT face=宋体 size=3>及</FONT><FONT face="宋体, MS Song" size=3>ActiveX</FONT><FONT face=宋体 size=3>控件(其中有不少是免费的!),都是可以利用的元件资源,心铃建议大家注意收集并加以利用。</P>< align=justify>通过本讲的学习,相信大家已经对</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>集成开发环境的组成和基本操作命令有了一个感性的认识,希望大家多动手实践,熟悉集成开发环境各部分的功能和使用方法。</P>< align=justify> </P><B><P align=justify>名词解释:</P><P align=justify>对象仓库(</FONT><FONT face="宋体, MS Song" size=3>Object Repository</FONT><FONT face=宋体 size=3>):</B>是许多预建的项目、窗体、对象模版与向导的集合,是</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>中共享和重用对象的工具。</P><B><P align=justify>包文件(</FONT><FONT face="宋体, MS Song" size=3>Package</FONT><FONT face=宋体 size=3>):</B>包文件是</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>特有的一种动态连接库,其后缀为</FONT><FONT face="宋体, MS Song" size=3>.bpl</FONT><FONT face=宋体 size=3>。包文件的工程文件定义了源代码文件的组成与的编译选项,其后缀为</FONT><FONT face="宋体, MS Song" size=3>.bpk</FONT><FONT face=宋体 size=3>。</P><B><P align=justify>元件(</FONT><FONT face="宋体, MS Song" size=3>Component</FONT><FONT face=宋体 size=3>):</B>元件是</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>可视化对象的基本元素,有时又翻译成组件或控件,在本讲座中使用“元件”的名称,而将</FONT><FONT face="宋体, MS Song" size=3>ActiveX</FONT><FONT face=宋体 size=3>控件仍称为“控件”,从可视化对象的角度来说,</FONT><FONT face="宋体, MS Song" size=3>ActiveX</FONT><FONT face=宋体 size=3>控件也属于元件,但较为特殊,因此保留其常用称法。</P></FONT>
作者: 韩冰    时间: 2005-1-26 01:04
<b><FONT size=6> </FONT></b>< align=center>C++ Builder<FONT face=宋体 size=6>集成开发环境(下)</P></FONT><FONT face=宋体 size=3>< align=justify>上一讲介绍了</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>集成开发环境中的菜单、工具条和元件面板,本讲心铃将继续为大家介绍</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>集成开发环境中几个主要工具的功能和使用方法,这些工具包括代码编辑器、窗体编辑器、对象浏览器、类浏览器、消息窗口和图象编辑器。</P><UL><B>< align=justify><LI>单元与窗体
% G! k3 i' m6 B7 B% {. Y</LI></UL></B>< align=justify>在介绍这几个工具之前,首先介绍一下</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>中单元与窗体的概念以及它们之间的关系。</P>< align=justify>在</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>中,</FONT><FONT face="宋体, MS Song" size=3>C++</FONT><FONT face=宋体 size=3>(或其它语言)的源代码文件被称为单元文件(</FONT><FONT face="宋体, MS Song" size=3>Unit</FONT><FONT face=宋体 size=3>)。窗体是</FONT><FONT face="宋体, MS Song" size=3>Windows</FONT><FONT face=宋体 size=3>应用程序中的基本界面,在</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>中,窗体的设计是完全可视化和所见即所得的,一个窗体总是和三个文件相关联:一个窗体文件(扩展名为</FONT><FONT face="宋体, MS Song" size=3>.dfm</FONT><FONT face=宋体 size=3>)、一个头文件(扩展名为</FONT><FONT face="宋体, MS Song" size=3>.h</FONT><FONT face=宋体 size=3>)和一个单元文件(扩展名为</FONT><FONT face="宋体, MS Song" size=3>.cpp</FONT><FONT face=宋体 size=3>),这三个文件的名字相同,但扩展名不同。</P>< align=justify>窗体文件定义了窗体的大小、形状以及其它各种属性,</FONT><FONT face="宋体, MS Song" size=3>CBuilder 5</FONT><FONT face=宋体 size=3>的窗体文件比老版本做了较大的改进,由以前的二进制格式改成了文本格式,大大增强了其可读性。为了在代码中对窗体进行操作,每个窗体又用一个</FONT><FONT face="宋体, MS Song" size=3>C++</FONT><FONT face=宋体 size=3>类来封装,窗体类的声明位于头文件中,而类的实现位于相应的单元文件中。</P>< align=justify>由此可见,</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>的每个窗体都包含了一个单元文件,但单元文件的应用范围并不仅仅局限于窗体。</P><UL><B>< align=justify><LI>代码编辑器 <p></LI></UL></B>< align=justify>代码编辑器是编写源代码的地方,除了</FONT><FONT face="宋体, MS Song" size=3>C/C++</FONT><FONT face=宋体 size=3>源文件之外,</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>代码编辑器还可以编辑</FONT><FONT face="宋体, MS Song" size=3>Delphi</FONT><FONT face=宋体 size=3>单元文件(</FONT><FONT face="宋体, MS Song" size=3>.pas</FONT><FONT face=宋体 size=3>文件)以及其它以文本格式来保存的文件。代码编辑器除了具有很强的文本编辑功能之外,还具有语法检查、查找定位、智能化代码生成等功能,它同时也是程序调试的主要场所。</P></FONT><FONT size=3>< align=justify>CBuilder</FONT><FONT face=宋体 size=3>代码编辑器(图</FONT><FONT size=3>3-1</FONT><FONT face=宋体 size=3>)由标题条、标签区、标志区、文本编辑区和状态条组成。其中标题条显示了当前正在编辑的文件名。</P>< align=justify>代码编辑器采用分页式窗口,每一个打开的源文件即为一页,每页都有一个标签,标签上显示了相应的文件名,用户可以单击标签以便在不同的文件之间切换。如果代码编辑器中打开的页过多,标签区显示不下所有的标签时,用户可以通过点击标签区右侧的一对箭头来滚动标签。</P></FONT><FONT size=3>< align=justify>CBuilder</FONT><FONT face=宋体 size=3>代码编辑器不支持分割窗口、多窗口重排等功能,但它支持通过</FONT><FONT size=3>View-&gt;New Edit Window</FONT><FONT face=宋体 size=3>菜单命令打开一个新的代码编辑器窗口,并且在任何一个代码编辑器窗口中所做的修改会立即反映到其它所有代码编辑器窗口之中。</P>< align=justify>代码编辑器的文本编辑区使用不同的颜色和字体来显示程序中的不同内容,例如,蓝色文字表示注释,</FONT><FONT face="宋体, MS Song" size=3>C/C++</FONT><FONT face=宋体 size=3>定义的关键字则采用黑色粗体字符来显示,断点用红底白字来显示,这种显示方法比较醒目,增强了程序的易读性,也有助于减少输入错误,例如我们本想输入一个关键字“</FONT><FONT face="宋体, MS Song" size=3>int</FONT><FONT face=宋体 size=3>”,却不小心敲成了“</FONT><FONT face="宋体, MS Song" size=3>itn</FONT><FONT face=宋体 size=3>”,此时文本编辑器不会将它显示成粗体,由此我们就能及时发现输入错误。</P>< align=justify>代码编辑器的配色方案还可以根据个人的喜好在</FONT><FONT face="宋体, MS Song" size=3>Editor Properties</FONT><FONT face=宋体 size=3>对话框中的</FONT><FONT face="宋体, MS Song" size=3>Colors</FONT><FONT face=宋体 size=3>属性页中进行修改,该对话框可以通过</FONT><FONT face="宋体, MS Song" size=3>Tools-&gt;Editor Option</FONT><FONT face=宋体 size=3>菜单命令或关联菜单中的</FONT><FONT face="宋体, MS Song" size=3>roperties</FONT><FONT face=宋体 size=3>命令调出来。</P>< align=justify>文本编辑区的左侧是标志区,其用途是显示各种标志,如书签、断点,以及调试过程中的下一条要执行的语句等。代码编辑器下端的状态条主要用来显示当前行号、列号等信息。</P>< align=justify>在代码编辑器中打开文件有几种方式,标准的方法是通过</FONT><FONT face="宋体, MS Song" size=3>File-&gt;Open</FONT><FONT face=宋体 size=3>菜单命令选择一个源代码文件,如果该文件是和窗体相关联的单元文件,那么</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>会首先在窗体编辑器中打开该窗体,这时可以通过</FONT><FONT face="宋体, MS Song" size=3>View-&gt;Toggle Form/Unit</FONT><FONT face=宋体 size=3>命令切换到代码编辑器中,从而打开该源文件。另一种方法是在</FONT><FONT face="宋体, MS Song" size=3>roject Manager</FONT><FONT face=宋体 size=3>或</FONT><FONT face="宋体, MS Song" size=3>View Units</FONT><FONT face=宋体 size=3>窗口中双击某个单元文件,就可以在代码编辑器中将其打开。</FONT><FONT face="宋体, MS Song" size=3>roject Manager</FONT><FONT face=宋体 size=3>或</FONT><FONT face="宋体, MS Song" size=3>View Units</FONT><FONT face=宋体 size=3>窗口中不会显示头文件,如果需要打开头文件,可以在代码编辑器中按鼠标右键弹出关联菜单,选择其中的</FONT><FONT face="宋体, MS Song" size=3>Open Source/Header Files</FONT><FONT face=宋体 size=3>命令来打开相应的头文件。除此之外,关联菜单里还有一个“</FONT><FONT face="宋体, MS Song" size=3>Open File at Cursor</FONT><FONT face=宋体 size=3>”命令,可以快速打开代码中包含的文件名对应的文件,例如,正在编辑的源代码中有一行语句如下:</P></FONT><FONT size=3>< align=justify>#include &lt;vcl.h&gt;</P></FONT><FONT face=宋体 size=3>< align=justify>那么将光标移到“</FONT><FONT face="宋体, MS Song" size=3>vcl.h</FONT><FONT face=宋体 size=3>”处并按鼠标右键,选择“</FONT><FONT face="宋体, MS Song" size=3>Open File at Cursor</FONT><FONT face=宋体 size=3>”命令,便会在代码编辑器中打开</FONT><FONT face="宋体, MS Song" size=3>vcl.h</FONT><FONT face=宋体 size=3>文件。</P>< align=justify>在代码编辑器中关闭某个文件,可以选择</FONT><FONT face="宋体, MS Song" size=3>File-&gt;Close</FONT><FONT face=宋体 size=3>命令或关联菜单中的</FONT><FONT face="宋体, MS Song" size=3>Close Page</FONT><FONT face=宋体 size=3>命令,代码编辑器标题条上的关闭按钮是用来关闭整个代码编辑器的,不能用来关闭某个编辑页,另外,当代码编辑器中的所有页被关闭后,编辑器窗口也会自动关闭。</P></FONT><FONT size=3>< align=justify>CBuilder</FONT><FONT face=宋体 size=3>代码编辑器集成了一个非常有用的功能——</FONT><FONT size=3>Code Insight</FONT><FONT face=宋体 size=3>,它相当于</FONT><FONT size=3>VC</FONT><FONT face=宋体 size=3>的</FONT><FONT size=3>IntelliSense</FONT><FONT face=宋体 size=3>功能,是一个智能化的辅助编程工具,能够根据当前编辑状态进行类成员提示、函数参数提示、自动代码补全、查看变量取值以及标识声明信息提示。</FONT><FONT size=3>Code Insight</FONT><FONT face=宋体 size=3>可以大大减轻编写源代码的工作量,并降低输入出错的概率。</P>< align=justify>图</FONT><FONT face="宋体, MS Song" size=3>3-2</FONT><FONT face=宋体 size=3>显示了</FONT><FONT face="宋体, MS Song" size=3>Code Insight</FONT><FONT face=宋体 size=3>的类成员提示功能,当正在编辑的代码需要引用一个对象的属性或成员函数时,</FONT><FONT face="宋体, MS Song" size=3>Code Insight</FONT><FONT face=宋体 size=3>会自动将对象所属类的成员信息显示在一个列表框中,且自动匹配与用户输入最接近的条目,用户只要选择列表框中的某个条目,并按下回车键后,</FONT><FONT face="宋体, MS Song" size=3>Code Insight</FONT><FONT face=宋体 size=3>就会自动用该条目来补全代码。</P>< align=justify>图</FONT><FONT face="宋体, MS Song" size=3>3-3</FONT><FONT face=宋体 size=3>显示了</FONT><FONT face="宋体, MS Song" size=3>Code Insight</FONT><FONT face=宋体 size=3>的函数参数提示功能,用户输入了函数名称之后,</FONT><FONT face="宋体, MS Song" size=3>Code Insight</FONT><FONT face=宋体 size=3>自动弹出一个提示条,显示函数各参数的类型信息,并且在输入过程中会自动检测用户输入的参数类型是否正确,不正确时该提示条将自动消失。函数参数提示功能可以减少一些常见的输入错误和编程错误,例如函数名拼写错误、变量未定义等等。</P>< align=justify>查看变量取值功能是指在调试状态下,把鼠标移动到某个变量处并停留片刻,</FONT><FONT face="宋体, MS Song" size=3>Code Insight</FONT><FONT face=宋体 size=3>就会自动弹出一个提示条,里面显示了变量的当前值,如图</FONT><FONT face="宋体, MS Song" size=3>3-4</FONT><FONT face=宋体 size=3>所示。</P>< align=justify>标识声明信息提示功能是指在编辑状态下,把鼠标移到某个标识上,</FONT><FONT face="宋体, MS Song" size=3>Code Insight</FONT><FONT face=宋体 size=3>就会自动弹出一个提示条来显示该标识声明所在的文件及位置,例如图</FONT><FONT face="宋体, MS Song" size=3>3-1</FONT><FONT face=宋体 size=3>中的提示条显示了</FONT><FONT face="宋体, MS Song" size=3>TForm</FONT><FONT face=宋体 size=3>类的声明位于</FONT><FONT face="宋体, MS Song" size=3>Unit1.cpp</FONT><FONT face=宋体 size=3>的第</FONT><FONT face="宋体, MS Song" size=3>11</FONT><FONT face=宋体 size=3>行。</P><UL><B>< align=justify><LI>窗体编辑器和对象浏览器 <p></LI></UL></B>< align=justify>窗体编辑器是</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>集成开发环境的另一个重要组成部分。传统意义上的编程的绝大部分工作都是编写源代码,但对于</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>来说,很大一部分“编程”工作都是在窗体编辑器中通过可视化的操作来设计和实现的,另外,窗体编辑器还必须与它的搭档——对象浏览器一起,才能在设计阶段发挥其强大的功能。</P>< align=justify>窗体编辑器和代码编辑器不同,它没有统一的窗口,每一个设计中的窗体就是一个窗体编辑器窗口。窗体在设计状态下可以任意改变大小和位置,可以通过窗体标题上的按钮进行最大化、最小化以及关闭操作。窗体又是元件的载体,从元件面板上选取一个元件,再用鼠标在窗体适当位置上画一个区域,就可以向窗体添加一个元件,并且元件的大小和位置也与指定的区域一致(当然,对某些运行时不可见的控件来说,其大小和位置并不重要的)。窗体上一般都有等间隔的网格点,用来对齐元件,使窗体界面显得整齐美观,网格的大小可以在</FONT><FONT face="宋体, MS Song" size=3>Enviroment Options</FONT><FONT face=宋体 size=3>对话框中调节。用户在窗体编辑器中进行的主要操作包括添加、删除元件、以及改变元件的布局等。</P><P align=justify>窗体编辑器的另一个作用是选取对象,用鼠标左键单击窗体上的某个元件或窗体本身,就可以选中单个元件或窗体对象,被选中对象的属性就显示在对象浏览器中。按住鼠标左键并拖动出一个矩形框,可以同时选中矩形框内的多个对象,此时对象浏览器将显示出这些对象相同的属性。</P><P align=justify>对象浏览器如图</FONT><FONT face="宋体, MS Song" size=3>3-5</FONT><FONT face=宋体 size=3>所示,它包括有一个对象选择列表(</FONT><FONT face="宋体, MS Song" size=3>Object Selector</FONT><FONT face=宋体 size=3>)、一个属性页(</FONT><FONT face="宋体, MS Song" size=3>Properties</FONT><FONT face=宋体 size=3>)和一个事件页(</FONT><FONT face="宋体, MS Song" size=3>Events</FONT><FONT face=宋体 size=3>)。对象浏览器在程序设计中,特别是窗体编辑阶段,是常用并且十分重要的一个工具,如果不希望它被其它窗口遮盖住,可以通过它的关联菜单中的</FONT><FONT face="宋体, MS Song" size=3>Stay on Top</FONT><FONT face=宋体 size=3>命令使其总是浮在最上层。由于</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>提供的元件数量众多,每种元件又有多种属性,即使一个熟练的程序员也很难记住所有元件的所有属性的意义和用法,而通过对象浏览器,当我们想了解某一属性(或事件)的意义和用法时,可以选中该属性(或事件),按</FONT><FONT face="宋体, MS Song" size=3>F1</FONT><FONT face=宋体 size=3>键就能够迅速获得相关的帮助信息。</P><P align=justify>对象浏览器中的内容是随着所选对象的不同而自动变化的。选择对象可以在窗体编辑器中选取,也可以在对象选择列表中选取。对象选择列表中列出了当前窗体中的所有可视化对象(包括窗体本身)。</P><P align=justify>属性页用于浏览和设置对象的属性。在</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>中,每一个对象都有自己的属性,属性页列出的部分属性是大多数可视化对象都有的,如长、宽等等,而有些属性是某一类对象特有的,如</FONT><FONT face="宋体, MS Song" size=3>TForm::BorderIcons</FONT><FONT face=宋体 size=3>属性等等。属性页中的属性通常是按属性名称的字母顺序来排列的,如果需要的话,可以切换成按类别排列,还可以将某些类别的属性隐藏起来,方法是选择属性页关联菜单中的</FONT><FONT face="宋体, MS Song" size=3>Arrange</FONT><FONT face=宋体 size=3>和</FONT><FONT face="宋体, MS Song" size=3>View</FONT><FONT face=宋体 size=3>命令。</P><P align=justify>用鼠标选中某一项属性后,它的属性值单元格会变成可修改的输入框,我们可以在其中修改属性的值。修改属性值有三种方式:第一种是直接输入,例如修改</FONT><FONT face="宋体, MS Song" size=3>TForm::Height</FONT><FONT face=宋体 size=3>属性时,属性值单元格是一个编辑框,我们可以在此直接输入高度的数值;第二种方法从下拉式列表框中选取,例如修改</FONT><FONT face="宋体, MS Song" size=3>TForm::BorderStyle</FONT><FONT face=宋体 size=3>属性时,属性值单元格是一个下拉式列表框,我们可以从中选择一个值;第三种方法是通过相应的对话框来设置属性,例如修改</FONT><FONT face="宋体, MS Song" size=3>TForm::Icon</FONT><FONT face=宋体 size=3>属性时,输入框的右侧有一个“…”号按钮,单击该按钮就能调出相应的对话框,我们可以从中选择图标文件。</P><P align=justify>有些属性的左侧有个加号,如</FONT><FONT face="宋体, MS Song" size=3>TForm::BorderIcon</FONT><FONT face=宋体 size=3>,表示该属性由多个子属性复合而成,我们可以对每个子属性进行分别设置。当对象的某个属性被修改之后,窗体编辑器会立即反映出该对象在修改之后的效果。</P><P align=justify>事件页用于创建或定位对象的事件处理函数。在</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>的编程模型中,应用程序是基于事件驱动的,事件处理函数决定了应用程序想做什么以及怎么实现。事件页中的左栏是所选对象可响应的事件,右栏是实际的事件处理函数。并不是所有的事件都有事件处理函数,空白右栏表示该事件目前还没有处理函数。利用对象浏览器,我们可以很容易地为某个事件添加处理函数,方法是双击空白的事件处理函数栏。对已有的处理函数的事件来说,双击操作可以快速定位到该函数的实现代码。在后面的讲座中心铃还要详细介绍如何创建事件处理函数,以及如何利用事件处理函数实现所需要的功能。</P><UL><B><P align=justify><LI>类浏览器 <p></LI></UL></B><P align=justify>图</FONT><FONT face="宋体, MS Song" size=3>3-6</FONT><FONT face=宋体 size=3>是类浏览器(</FONT><FONT face="宋体, MS Song" size=3>Class Explorer</FONT><FONT face=宋体 size=3>),其中显示了工程中的所有自定义类及其类成员。类是</FONT><FONT face="宋体, MS Song" size=3>C++</FONT><FONT face=宋体 size=3>中封装对象的基本数据结构,一个较大的开发项目可能会包含几百个甚至上千个类,类浏览器能够帮助开发者快速查阅这些类,通过查看类的方法和属性来了解各个类的功能,定位类的声明以及实现代码,此外,通过类浏览器还能方便地添加新的类成员函数及变量。类浏览器中的信息是实时更新的,当程序员编辑和修改程序时,类浏览器将自动检测出类的变化并刷新窗口。</P><P align=justify>除了</FONT><FONT face="宋体, MS Song" size=3>C++</FONT><FONT face=宋体 size=3>类之外,类浏览器还列出了工程中的结构、接口等数据类型和全局函数,这些数据类型、函数,以及类或结构中不同类型的属性和方法都由不同的图标来表示。</P><P align=justify>在类浏览器中双击类的名称,可以快速定位到类的声明,双击类的成员函数,可以快速定位到该成员函数的实现代码处。通过类浏览器中的关联菜单可以添加三种类型的类成员:域(</FONT><FONT face="宋体, MS Song" size=3>Field</FONT><FONT face=宋体 size=3>)、属性(</FONT><FONT face="宋体, MS Song" size=3>Property</FONT><FONT face=宋体 size=3>)和方法(</FONT><FONT face="宋体, MS Song" size=3>Method</FONT><FONT face=宋体 size=3>)。</P></FONT><FONT size=3><P align=justify>CBuilder</FONT><FONT face=宋体 size=3>集成开发环境还提供了一个功能与类浏览器相似的工具——类层次窗口(</FONT><FONT size=3>Class Hierarchy</FONT><FONT face=宋体 size=3>),它们的不同之处在于显示类成员的方式,类浏览器以树和节点的方式来显示类成员,而类层次窗口将类成员显示在一个列表中。类层次窗口可以通过选择类浏览器的关联菜单中的</FONT><FONT size=3>Class Hierarchy</FONT><FONT face=宋体 size=3>命令来激活。</P><UL><B><P align=justify><LI>消息窗口 <p></LI></UL></B><P align=justify>消息窗口(</FONT><FONT face="宋体, MS Song" size=3>Messages</FONT><FONT face=宋体 size=3>)用于显示编译时的警告或错误消息。消息窗口平时不可见,只有在编译、连接、生成可执行文件时,如果出现了警告或错误才会显示出来。在消息窗口中双击一条警告或错误消息,就可以快速定位到产生警告或错误的代码处。</P><UL><B><P align=justify><LI>图象编辑器 <p></LI></UL></B><P align=justify>图象编辑器(</FONT><FONT face="宋体, MS Song" size=3>Image Editor</FONT><FONT face=宋体 size=3>)用来创建和编辑位图(</FONT><FONT face="宋体, MS Song" size=3>.BMP</FONT><FONT face=宋体 size=3>)、图标(</FONT><FONT face="宋体, MS Song" size=3>.ICO</FONT><FONT face=宋体 size=3>)、光标(</FONT><FONT face="宋体, MS Song" size=3>.CUR</FONT><FONT face=宋体 size=3>)等一些图象资源文件,它可以脱离集成开发环境单独启动,也可以通过集成开发环境的</FONT><FONT face="宋体, MS Song" size=3>Tools-&gt;Image Editor</FONT><FONT face=宋体 size=3>命令来调用。图像编辑器的使用方法并不复杂,读者朋友不妨自已试着编辑几幅图像。</P><P align=justify> </P><P align=justify>在上一讲和本讲中,心铃为大家介绍了</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>集成开发环境的组成及其使用方法,相信大家对</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>集成开发环境已经比较熟悉了,下一讲心铃要为大家介绍</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>的编程模型。</P></FONT>
作者: 韩冰    时间: 2005-1-26 01:05
<b><FONT size=6> </FONT></b>< align=center>C++ Builder<FONT face=宋体 size=6>的编程模式</P></FONT><FONT face=宋体 size=3>< align=justify>我们知道,</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>是一个可视化的</FONT><FONT face="宋体, MS Song" size=3>Windows</FONT><FONT face=宋体 size=3>应用程序开发工具,并且它以</FONT><FONT face="宋体, MS Song" size=3>C/C++</FONT><FONT face=宋体 size=3>语言作为基础,对初学编程的朋友来说,这意味着在学习使用</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>的同时也要学习</FONT><FONT face="宋体, MS Song" size=3>Windows</FONT><FONT face=宋体 size=3>编程、</FONT><FONT face="宋体, MS Song" size=3>C/C++</FONT><FONT face=宋体 size=3>编程和面向对象程序设计方面的知识,除此之外,要成为一位真正的软件开发高手,还需要了解一些软件工程方面的知识。因此,心铃准备结合有关</FONT><FONT face="宋体, MS Song" size=3>Windows</FONT><FONT face=宋体 size=3>应用程序运行的特点、面向对象编程、</FONT><FONT face="宋体, MS Song" size=3>C++</FONT><FONT face=宋体 size=3>类和软件工程等方面的一些简单的理论知识来介绍</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>编程特点,这些内容虽然显得很枯燥,但相信今后大家会发现它们相当有用,因为它们可以帮助大家建立起良好的程序设计指导思想,当然,讲座中介绍的只是少量的基本概念,有志于搞软件开发的朋友可以自己通过不断的学习和实践来深入地掌握相关的知识。</P><UL></FONT><B><FONT size=3>< align=justify><LI>Windows</FONT><FONT face=宋体 size=3>系统及其应用程序的特点 6 y* X% T! i2 @( g- ?$ {
</LI></UL></B>< align=justify>使用</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>来编写</FONT><FONT face="宋体, MS Song" size=3>Windows</FONT><FONT face=宋体 size=3>应用程序时,</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>已经为我们隐藏了许多与</FONT><FONT face="宋体, MS Song" size=3>Windows</FONT><FONT face=宋体 size=3>操作系统内部有关的细节,使得我们无需深入了解操作系统的运行机制就可以进行编程工作,不过,多数程序员都不会只满足于这种“知其然,不知其所以然”的程序开发模式,对编程的热爱将促使他们学习更多更深入的知识。就</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>而言,如果能够了解</FONT><FONT face="宋体, MS Song" size=3>Windows</FONT><FONT face=宋体 size=3>系统及其应用程序的运行机制,将有助于我们更好地理解</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>程序的结构,也更有助于我们在已有工具的基础上开发出具有更强大功能的应用程序。</P>< align=justify>在介绍</FONT><FONT face="宋体, MS Song" size=3>Windows</FONT><FONT face=宋体 size=3>应用程序的运行机制之前,首先让我们来看看</FONT><FONT face="宋体, MS Song" size=3>MS-DOS</FONT><FONT face=宋体 size=3>应用程序的特点。</P></FONT><FONT size=3>< align=justify>MS-DOS</FONT><FONT face=宋体 size=3>与</FONT><FONT size=3>Windows</FONT><FONT face=宋体 size=3>最大的不同点在于,</FONT><FONT size=3>MS-DOS</FONT><FONT face=宋体 size=3>是一个单任务的操作系统,同一时刻只有一个应用程序在运行,该应用程序可以独占整个计算机系统的硬件和软件资源,如</FONT><FONT size=3>CPU</FONT><FONT face=宋体 size=3>、内存、屏幕、鼠标和键盘等。因此,稍微复杂一点的</FONT><FONT size=3>MS-DOS</FONT><FONT face=宋体 size=3>应用程序中,大都包括设置屏幕模式、分配内存、接管鼠标、扫描键盘等操作,并负责对系统中所发生的多数事件进行响应和处理。除此之外,</FONT><FONT size=3>MS-DOS</FONT><FONT face=宋体 size=3>应用程序的另一个特点是,从程序的启动入口点到程序运行结束退出的过程中,几乎每一步都有明确的调用关系(中断服务例程除外,这类代码的执行可以在任意时刻由中断触发),这正是单任务操作系统下应用程序的典型运行模式。</P></FONT><FONT size=3>< align=justify>Windows</FONT><FONT face=宋体 size=3>是目前</FONT><FONT size=3>C</FONT><FONT face=宋体 size=3>机上最流行的操作系统,它是一个多任务的操作系统,同一时刻允许多个应用程序并行运行,计算机的资源被</FONT><FONT size=3>Windows</FONT><FONT face=宋体 size=3>中的所有应用程序所共享,其中包括鼠标、键盘等输入设备。为了顺利实现共享,</FONT><FONT size=3>Windows</FONT><FONT face=宋体 size=3>负责接收所有的输入事件,并将这些事件转换成一条条消息后送入到相应的应用程序的消息队列中,而应用程序将从自己的消息队列中获得消息,并作出响应或进行处理,这种消息处理过程被称为“消息驱动机制”,它与</FONT><FONT size=3>MS-DOS</FONT><FONT face=宋体 size=3>程序截然不同。</P>< align=justify>“消息驱动”是理解</FONT><FONT face="宋体, MS Song" size=3>Windows</FONT><FONT face=宋体 size=3>应用程序运行机制的最重要的概念。在消息驱动下的</FONT><FONT face="宋体, MS Song" size=3>Windows</FONT><FONT face=宋体 size=3>应用程序有一类称为回调函数的执行代码,它们不是由应用程序本身调用的,而是由</FONT><FONT face="宋体, MS Song" size=3>Windows</FONT><FONT face=宋体 size=3>操作系统调用的,例如窗口的消息处理函数</FONT><FONT face="宋体, MS Song" size=3>WndProc</FONT><FONT face=宋体 size=3>,就是由操作系统在接收到属于该窗口的消息时调用的。</P></FONT><FONT size=3>< align=justify>CBuilder</FONT><FONT face=宋体 size=3>采用了在消息驱动的基础上发展出来的事件驱动编程模式,事件可以理解成消息的延伸,通常一条消息可以看作一个事件的发生,但有的消息有可能会引发几个相关的事件。在事件驱动编程模式下,事件处理函数代替了原来的消息处理函数,从而改变了传统</FONT><FONT size=3>Windows</FONT><FONT face=宋体 size=3>编程中窗口的消息处理代码都在</FONT><FONT size=3>WndProc</FONT><FONT face=宋体 size=3>中实现的模式,使得不同事件的处理函数可以相互独立开来。总的来说,事件驱动编程模式是面向对象的编程思想成功运用到</FONT><FONT size=3>Windows</FONT><FONT face=宋体 size=3>应用程序开发中的结果。</P><UL><B>< align=justify><LI>面向对象编程 <p></LI></UL></B></FONT><FONT size=3>< align=justify>CBuilder</FONT><FONT face=宋体 size=3>是面向对象的开发工具,那什么是对象(</FONT><FONT size=3>Object</FONT><FONT face=宋体 size=3>)呢?广义地说,客观世界的一切事物都是对象,在计算机软件领域中,对象是客观实体在计算机中的抽象,它是由代表客观实体的属性和行为的一个封装。具体到</FONT><FONT size=3>CBuilder</FONT><FONT face=宋体 size=3>的窗体编辑器中,对象是一个个可视化的或非可视化的元件,而在</FONT><FONT size=3>C++</FONT><FONT face=宋体 size=3>程序代码中,对象是类的一个实例(有时指向对象的指针也称为对象)。</P>< align=justify>到目前为止,人们主要使用两种方式对客观世界进行描述,一种是过程式描述,另一种是对象式描述,因此产生了过程式程序设计和面向对象程序设计两种主要的程序设计方法。过程式描述将问题分解为一系列顺序执行的过程,这种描述方式特别符合计算机本身的构造和运算模式,因此在处理计算性的操作时特别有效,根据操作系统的特点,过程式描述的应用程序比较适合单任务的</FONT><FONT face="宋体, MS Song" size=3>MS-DOS</FONT><FONT face=宋体 size=3>操作系统。</P>< align=justify>但是,客观世界的事物往往是复杂的、并发的,很难用一串连续的过程加以描述,因此产生了对象式描述。面向对象设计方法最基本的思想就是把客观世界看成一个个相对独立而又相互联系的实体,即对象。每个对象都有自己的状态和行为,能够完成一定的功能。</P>< align=justify>在面向对象的程序设计中,状态称为属性,对应</FONT><FONT face="宋体, MS Song" size=3>C++</FONT><FONT face=宋体 size=3>类的数据成员;行为称为方法,对应</FONT><FONT face="宋体, MS Song" size=3>C++</FONT><FONT face=宋体 size=3>类的成员函数。面向对象的思想就是把方法和属性结合起来,把它们看成一个有机整体,这个结合的过程被称为封装。封装把发生关联的所有属性和方法捆绑在一起,从而使对象内部有了明确的范围和清楚的外部边界。封装是面向对象理论中十分重要的概念,因为封装实现了数据隐藏,保护了对象的数据不被外界随意改变,并且封装使对象成了相对独立的功能模块,提高了软件设计的结构化和模块化程序,如果需要改变某个对象时,只要它对外的接口保持不变,系统的其它部分就可以不受影响。</P>< align=justify>面向对象的描述方式符合客观事物的本来面貌,也符合人的思维习惯,因此非常适合于开发大型应用程序和解决复杂问题,当然,这并不是说大型应用程序中不需要过程式程序设计方法,过程式程序设计方法有其特有的优点,在解决局部问题,特别是偏重计算的问题时,采用过程式程序设计方法还是特别有效的。</P>< align=justify>另外,根据单任务操作系统与多任务操作系统的不同,对象式程序设计方法特别适合于多任务操作系统,以</FONT><FONT face="宋体, MS Song" size=3>Windows</FONT><FONT face=宋体 size=3>为例,</FONT><FONT face="宋体, MS Song" size=3>Windows</FONT><FONT face=宋体 size=3>的消息驱动机制就比较适合于面向对象编程,应用程序的各对象之间可以通过消息相互作用,例如触发对象的方法。</P><UL></FONT><B><FONT size=3>< align=justify><LI>C++</FONT><FONT face=宋体 size=3>语言中的类 <p></LI></UL></B>< align=justify>前面介绍了面向对象程序设计的少量理论知识,在程序开发过程中,我们还需要使用支持面向对象的编程语言来将理论运用到实际的工作中。</FONT><FONT face="宋体, MS Song" size=3>C++</FONT><FONT face=宋体 size=3>是目前较流行的面向对象编程语言,学习使用</FONT><FONT face="宋体, MS Song" size=3>C++</FONT><FONT face=宋体 size=3>进行面向对象编程时,应该首先了解</FONT><FONT face="宋体, MS Song" size=3>C++</FONT><FONT face=宋体 size=3>中类的概念。</P>< align=justify>类是对象的一个抽象,是同类对象的总称。在</FONT><FONT face="宋体, MS Song" size=3>C++</FONT><FONT face=宋体 size=3>语言中,类又是一种特殊的数据类型,类的定义包括三个方面的内容:类标识符、类体和类成员函数的实现。</P>< align=justify>下面给出</FONT><FONT face="宋体, MS Song" size=3>C++</FONT><FONT face=宋体 size=3>中类声明的一般形式:</P></FONT><FONT size=3>< align=justify>class </FONT><FONT face=宋体 size=3>类名</FONT><FONT size=3> </FONT><FONT face=宋体 size=3>{</P><DIR></FONT><FONT size=3>< align=justify>private:</P></FONT><FONT face=宋体 size=3>< align=justify>私有的数据成员</FONT><FONT size=3><FONT face="宋体, MS Song">;</FONT></P></FONT><FONT face=宋体 size=3>< align=justify>私有的成员函数</FONT><FONT size=3><FONT face="宋体, MS Song">;</FONT></P></DIR>< align=justify>protected:</P><DIR></FONT><FONT face=宋体 size=3>< align=justify>被保护的数据成员</FONT><FONT size=3><FONT face="宋体, MS Song">;</FONT></P></FONT><FONT face=宋体 size=3>< align=justify>被保护的成员函数</FONT><FONT size=3><FONT face="宋体, MS Song">;</FONT></P></DIR>< align=justify>public:</P><DIR></FONT><FONT face=宋体 size=3>< align=justify>公共的数据成员</FONT><FONT size=3><FONT face="宋体, MS Song">;</FONT></P></FONT><FONT face=宋体 size=3><P align=justify>公共的成员函数</FONT><FONT size=3><FONT face="宋体, MS Song">;</FONT></P></DIR></FONT><FONT face=宋体 size=3><P align=justify>}</FONT><FONT size=3><FONT face="宋体, MS Song">;</FONT></P><P align=justify>class</FONT><FONT face=宋体 size=3>是</FONT><FONT size=3>C++</FONT><FONT face=宋体 size=3>的关键字,它引入了类的声明。类名称的命名应遵循方便好记的原则,匈牙利命名原则是一种目前</FONT><FONT size=3>Windows</FONT><FONT face=宋体 size=3>编程中使用得最广泛的一种命名原则,心铃建议大家尽量按照该原则来命名类标识符,以增加代码的可读性。</P><P align=justify>类声明体包含在一对大括号中,其中定义了类的数据成员和成员函数。根据外界对成员的存取权限,类的成员分为</FONT><FONT face="宋体, MS Song" size=3>3</FONT><FONT face=宋体 size=3>种类型:私有的、保护的和公共的,分别用关键字</FONT><FONT face="宋体, MS Song" size=3>private</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>protected</FONT><FONT face=宋体 size=3>和</FONT><FONT face="宋体, MS Song" size=3>public</FONT><FONT face=宋体 size=3>来表示。</P><P align=justify>除了类的声明以外,完整的类定义还需要类成员函数的实现。类成员函数实现代码的一般形式如下所示:</P><P align=justify>数据类型</FONT><FONT face="宋体, MS Song" size=3> </FONT><FONT face=宋体 size=3>类名</FONT><FONT face="宋体, MS Song" size=3>::</FONT><FONT face=宋体 size=3>成员函数名</FONT><FONT face="宋体, MS Song" size=3>(</FONT><FONT face=宋体 size=3>参数说明</FONT><FONT size=3><FONT face="宋体, MS Song">) {</FONT></P><DIR></FONT><FONT face=宋体 size=3><P align=justify>函数体</P></DIR><P align=justify>}</P><P align=justify>其中双冒号“</FONT><FONT face="宋体, MS Song" size=3>::</FONT><FONT face=宋体 size=3>”是作用域运算符,它标明类名称后面的函数是该类的成员函数,并且成员函数的作用域只在该类中才有效。</P></FONT><FONT size=3><P align=justify>C++</FONT><FONT face=宋体 size=3>类支持继承性和多态性,继承性是指通过已有的类派生出新的类,新的类(称为子类或派生类)将继承和使用原有类(称为父类或基类)的代码,并有自己新的数据成员或成员函数。多态性描述了</FONT><FONT size=3>C++</FONT><FONT face=宋体 size=3>依据程序的运行情况而产生不同动作的能力,例如,基类定义了一种成员函数,其派生出的新类也定义了名字相同的成员函数,它们的实现互不相同,应用程序在运行时能够确定什么时候调用哪个成员函数,这种现象称作多态性。</P><P align=justify>许多朋友在初学阶段都会对类和对象的联系与区别感到困惑,其实,类和对象的关系就象普通数据类型与变量的关系一样,我们定义了一个类后,在使用它之前还必须生成一个对象实例。类只是对象的抽象,程序在运行过程中操作的必须是对象的实例,而不是类,对象实例是根据类的定义来分配的一块实实在在的内存区域。程序访问对象成员的方法是在对象名后加上引用符“</FONT><FONT face="宋体, MS Song" size=3>.</FONT><FONT face=宋体 size=3>”,再引用其数据成员或成员函数,另外也可以通过指向对象的指针来访问对象,只是引用符要改用“</FONT><FONT face="宋体, MS Song" size=3>-&gt;</FONT><FONT face=宋体 size=3>”。</P><P align=justify>在</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>中,应用程序的窗体及窗体上的元件都是可视化的对象,这些对象的生成和释放通常由</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>自动生成的代码来完成,而我们在程序代码中通常使用指向这些对象的指针,即用对象指针来访问对象的方法和属性。</P><UL><B><P align=justify><LI>软件开发的要求 <p></LI></UL></B><P align=justify>无论使用何种编程工具,正规的软件开发工作总要以软件工程的有关理论作为指导。软件工程理论指出在软件开发过程中,系统分析和系统设计是关键的两个环节。</P><P align=justify>结合到面向对象程序设计中,系统分析可以分为下面五个关键步骤:需求分析、识别类和对象、定义属性和方法、识别结构、识别主题。</P><P align=justify>需求分析是要确定系统要完成什么样的功能以及确定系统的边界,明确系统边界上的接口,这时是将系统整体作为一个对象来看待。识别类和对象是指将系统的功能进一步细分,确定系统可能需要的全部对象。定义属性和方法是根据识别出来的对象,定义其属性和方法。识别结构是确定各个对象之间的关系,如继承关系、包容关系、关联关系等。识别主题是指确定能完成独立功能的子系统,描述其中各对象之间的关系。</P><P align=justify>面向对象的系统分析着重于弄清系统是什么样,有什么功能,而面向对象的系统设计着重于类的实现,解决系统如何工作的问题。一个好的系统设计应遵循以下几个基本原则:</P><OL><P align=justify><LI>高度的凝聚性 <p><P align=justify>即类和类的的继承必须具有高度的凝聚性。所谓凝聚性是指类应具有单一的用途,如果某个类具有多个用途,应将其分解为多个专用的类。</P><P align=justify></P><LI>松散的耦合 <p><P align=justify>即类与类之间的耦合应很松散。所谓耦合,是指系统的各组成部分之间的相互依赖性。象方法和类这样的要素,设计时应尽可能互相独立。如果某个类过于依赖其他类来完成其工作,那么就必然要牺牲可重用性与可移植性。</P><P align=justify></P><LI>数据隐藏 <p><P align=justify>类的数据实现细节对于别的类来说应该是不可见的。因此在设计</FONT><FONT face="宋体, MS Song" size=3>C++</FONT><FONT face=宋体 size=3>类时,应尽量避免下列情况:在一个类中有大量公用数据元素;类的实现依赖于全局变量;类中含有大量友元(其它特定类能够直接访问的成员变量)。</P><P align=justify></P><LI>尽可能重复使用现有代码 <p><P align=justify>设计类时,首先应尽可能从所用的开发环境提供的类库中选择最合适的类作为基类,可以从要设计的多个类中抽象出新基类,同样,设计函数时,应尽可能使用函数库中的函数。</P><P align=justify></P><LI>设计类时保持类接口的稳定性 <p></LI></OL><P align=justify>类接口也就是类的</FONT><FONT face="宋体, MS Song" size=3>public</FONT><FONT face=宋体 size=3>部分,对派生类来说,还包括其基类的</FONT><FONT face="宋体, MS Song" size=3>protect</FONT><FONT face=宋体 size=3>部分。类接口定义了该类怎样同外部世界交流,保持其稳定性是实现兼容性的必需要求。</P><P align=justify>以上是</FONT><FONT face="宋体, MS Song" size=3>C++</FONT><FONT face=宋体 size=3>开发面向对象系统的一般原则,在编程实践中,需要根据具体情况加以运用,对有些不太复杂的应用程序可以省去其中某些步骤。</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>作为快速应用程序开发工具,具有高度模块化和可视化的特点,即符合软件工程化的要求,又可大大简化系统分析与系统设计的工作。</P><UL></FONT><B><FONT size=3><P align=justify><LI>CBuilder</FONT><FONT face=宋体 size=3>编程的特点 <p></LI></UL></B><P align=justify>开发</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>应用程序一般需要完成两个阶段的工作。第一阶段,根据应用程序的要求,以可视化的方式设计应用程序窗口界面,此阶段不需要编写任何编程代码,只需要创建应用程序窗体,设置窗体的属性参数,在应用程序窗体中放置可视化或非可视化的元件并设置元件的属性参数。第二阶段,根据应用程序功能的要求,使窗体及其包含的元件对某些特定事件进行响应,事件响应处理函数可通过对象监视器的事件页进行添加,函数体的代码则需要手工编写。</P></FONT><FONT size=3><P align=justify>CBuilder</FONT><FONT face=宋体 size=3>用来设计和实现应用程序的基本单元是元件,元件是一个具有特定功能的软件模块,每个元件都对应一个</FONT><FONT size=3>C++</FONT><FONT face=宋体 size=3>封装类,最常用的元件有</FONT><FONT size=3>Application</FONT><FONT face=宋体 size=3>元件、窗体和放置在窗体中的各种元件,如按钮、编辑控件、列表控件、对话框和菜单等。</P><P align=justify>在运行时,</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>应用程序首先会创建一个</FONT><FONT face="宋体, MS Song" size=3>Application</FONT><FONT face=宋体 size=3>对象,</FONT><FONT face="宋体, MS Song" size=3>Application</FONT><FONT face=宋体 size=3>对象负责创建窗体和从操作系统消息队列中接收消息,并将其发送到相应的窗体中。窗体对象一般包含了多个可视化或不可视化的元件,它从</FONT><FONT face="宋体, MS Song" size=3>Application</FONT><FONT face=宋体 size=3>对象接收到消息后,由窗体根据消息类型确定由哪一个元件对象或是由窗体本身对其进行处理,并将此消息发送到相应的对象,后者负责完成具体的功能。</P><P align=justify> </P><P align=justify>本讲心铃简要地介绍了一些关于</FONT><FONT face="宋体, MS Song" size=3>Windows</FONT><FONT face=宋体 size=3>应用程序的特点、面向对象的编程原理、</FONT><FONT face="宋体, MS Song" size=3>C++</FONT><FONT face=宋体 size=3>语言的特点和软件工程等方面的基础知识,它们构成了</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>编程的理论基础,估计不少朋友可能会感到很不好理解,这没有关系,因为这些知识不是短短的讲座所能涵盖,也不是一朝一夕就能学会的,需要朋友们下一番苦工作才能真正理解和掌握。从下一讲开始,我们就要实际动手编写一个应用程序了,下星期再见吧。</P></FONT>
作者: 韩冰    时间: 2005-1-26 01:09
<b><FONT face=宋体 size=6> </FONT></b>< align=center>设计一个<FONT face="宋体, MS Song" size=6>MP3</FONT><FONT face=宋体 size=6>收藏程序</P></FONT><FONT face=宋体 size=3>< align=justify>从这一讲开始,我们要进入真正的程序设计阶段了。今天为大家介绍的是如何创建一个工程,以及工程设置的有关问题。</P><B>< align=justify>·确定应用程序的功能</P></B>< align=justify>在动手编程之前,首先应该弄清楚程序所需要完成的功能。在这里,心铃要和大家一起编制一个</FONT><FONT face="宋体, MS Song" size=3>MP3</FONT><FONT face=宋体 size=3>收藏程序,它可以用来搜集整理我们喜爱的</FONT><FONT face="宋体, MS Song" size=3>MP3</FONT><FONT face=宋体 size=3>音乐。读者朋友们中一定有不少是</FONT><FONT face="宋体, MS Song" size=3>MP3</FONT><FONT face=宋体 size=3>发烧友吧,心铃也不例外,平时工作的时候,心铃最喜欢一边放着</FONT><FONT face="宋体, MS Song" size=3>MP3</FONT><FONT face=宋体 size=3>,一边随着音乐的旋律敲击着键盘,灵感来时,还要哼上两句(经常跑调,遭遇不少抗议),真是其乐无穷。除了喜欢听,心铃还经常从网上搜集各种好听的</FONT><FONT face="宋体, MS Song" size=3>MP3</FONT><FONT face=宋体 size=3>,可是数量多了,有时想找一首歌却很麻烦,就产生了编写一个程序来分门别类地管理这些</FONT><FONT face="宋体, MS Song" size=3>MP3</FONT><FONT face=宋体 size=3>音乐的念头。这个程序应该能够记录</FONT><FONT face="宋体, MS Song" size=3>MP3</FONT><FONT face=宋体 size=3>音乐的文件路径、歌曲名称和歌手名称,能够按照这几种条件查找所需要的文件,能够方便地增加、删除和修改</FONT><FONT face="宋体, MS Song" size=3>MP3</FONT><FONT face=宋体 size=3>记录,并且具有</FONT><FONT face="宋体, MS Song" size=3>MP3</FONT><FONT face=宋体 size=3>播放功能。</P><B>< align=justify>·确定核心数据结构</P></B>< align=justify>程序功能清楚了,接下来要考虑具体的实现细节。首先确定程序中记录的数据结构。根据前面分析的程序功能,我们认为,对收藏的</FONT><FONT face="宋体, MS Song" size=3>MP3</FONT><FONT face=宋体 size=3>文件,我们主要关心的是它的文件路径、歌曲名称和歌手名称这三类信息,因此,我们用一个类</FONT><FONT face="宋体, MS Song" size=3>TMP3</FONT><FONT face=宋体 size=3>(根据</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>中的惯例,类名称的第一个字母用</FONT><FONT face="宋体, MS Song" size=3>T</FONT><FONT face=宋体 size=3>来表示这是一个类)来封装该记录:</P></FONT><FONT size=3>< align=justify>class TMP3 {</P>< align=justify>public:</P><DIR>< align=justify>AnsiString PathName;</P>< align=justify>AnsiString SongName;</P>< align=justify>AnsiString SingerName;</P></DIR></FONT><FONT face=宋体 size=3>< align=justify>}</FONT><FONT size=3><FONT face="宋体, MS Song">;</FONT></P>< align=justify>TMP3</FONT><FONT face=宋体 size=3>类中定义了</FONT><FONT size=3>3</FONT><FONT face=宋体 size=3>个</FONT><FONT size=3>AnsiString</FONT><FONT face=宋体 size=3>类型的数据成员变量,且</FONT><FONT size=3>3</FONT><FONT face=宋体 size=3>个数据成员都为公共型的成员,这虽然不太符合数据隐藏的设计原则,但方便了外界的访问,对于目前这个功能本来就不是特别复杂的程序来说是比较适用的。</FONT><FONT size=3>AnsiString</FONT><FONT face=宋体 size=3>是</FONT><FONT size=3>CBuilder</FONT><FONT face=宋体 size=3>中的字符串类,该类提供了字符串赋值、字符串相加、字符串截断、字符串比较、格式化字符串等功能,是</FONT><FONT size=3>VCL</FONT><FONT face=宋体 size=3>库函数中常用的数据类型。</FONT><FONT size=3>AnsiString</FONT><FONT face=宋体 size=3>类对字符串操作非常方便,在后面的程序代码部分会通过实际的例子介绍它的使用。</P><B>< align=justify>·创建工程</P></B>< align=justify>接下来,我们要通过一个具体的工程将上述的程序设计思想付诸实现。工程(</FONT><FONT face="宋体, MS Song" size=3>roject</FONT><FONT face=宋体 size=3>)是与一个应用程序有关的所有文件的有机组合。</FONT><FONT face="宋体, MS Song" size=3>CBuilder IDE</FONT><FONT face=宋体 size=3>中可以同时打开多个工程(即工程项目组</FONT><FONT face="宋体, MS Song" size=3>roject Group</FONT><FONT face=宋体 size=3>),但其中只有一个是活动工程,即同一时刻只有一个工程可以编译连接和调试运行。</P>< align=justify>创建工程的方法有很多种,最简单的方法是通过</FONT><FONT face="宋体, MS Song" size=3>File|New Application</FONT><FONT face=宋体 size=3>菜单命令,创建包含一个空白窗体的工程,这也是本例子程序中所采用的工程类型。除此之外,</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>还提供了其他一些工程模板和向导,可以用于定制某些特殊功能的工程。启动这些工程模板或向导的方法是通过</FONT><FONT face="宋体, MS Song" size=3>File|New</FONT><FONT face=宋体 size=3>命令,调出“</FONT><FONT face="宋体, MS Song" size=3>New Items</FONT><FONT face=宋体 size=3>”对话框,该对话框中有专门的工程模板向导(</FONT><FONT face="宋体, MS Song" size=3>rojects</FONT><FONT face=宋体 size=3>)页,其中包括单文档应用程序、多文档应用程序、应用程序向导等,除此之外,新对象(</FONT><FONT face="宋体, MS Song" size=3>New</FONT><FONT face=宋体 size=3>)页中还有控制台程序向导、</FONT><FONT face="宋体, MS Song" size=3>DLL</FONT><FONT face=宋体 size=3>向导等工程向导。用户可以根据需要选择其中合适的工程模板或向导。</P>< align=justify>通过</FONT><FONT face="宋体, MS Song" size=3>File|New Application</FONT><FONT face=宋体 size=3>菜单命令创建的新工程名称缺省为</FONT><FONT face="宋体, MS Song" size=3>roject1</FONT><FONT face=宋体 size=3>,生成文件的缺省路径为“</FONT><FONT face="宋体, MS Song" size=3>CBuilder5\Projects\</FONT><FONT face=宋体 size=3>”目录,为了便于管理,我们要将其保存到指定的目录下,并为新工程起一个好记的名称。保存工程的方法是通过</FONT><FONT face="宋体, MS Song" size=3>File|Save Project As</FONT><FONT face=宋体 size=3>命令或工具栏上的“</FONT><FONT face="宋体, MS Song" size=3>Save All</FONT><FONT face=宋体 size=3>”工具按钮,这时会首先弹出“</FONT><FONT face="宋体, MS Song" size=3>Save Unit1 As</FONT><FONT face=宋体 size=3>”对话框,</FONT><FONT face="宋体, MS Song" size=3>Unit1</FONT><FONT face=宋体 size=3>是新工程中主窗体对应的源代码文件(有关单元与窗体的关系,可以参考第三讲中的相关论述),在这个对话框中我们指定该单元的保存路径和文件名为</FONT><FONT face="宋体, MS Song" size=3>C:\MP3Collect\MainForm.cpp</FONT><FONT face=宋体 size=3>。这时我们可以看到,</FONT><FONT face="宋体, MS Song" size=3>C:\MP3Collect\</FONT><FONT face=宋体 size=3>目录下除了</FONT><FONT face="宋体, MS Song" size=3>MainForm.cpp</FONT><FONT face=宋体 size=3>之外,同时也保存了该窗体的窗体文件</FONT><FONT face="宋体, MS Song" size=3>MainForm.dfm</FONT><FONT face=宋体 size=3>和头文件</FONT><FONT face="宋体, MS Song" size=3>MainForm.h</FONT><FONT face=宋体 size=3>。保存了窗体后,接着会弹出“</FONT><FONT face="宋体, MS Song" size=3>Save Project1 As</FONT><FONT face=宋体 size=3>”对话框,在这里我们指定工程的保存路径和文件名为</FONT><FONT face="宋体, MS Song" size=3>C:\MP3Collect\MP3Collect.bpr</FONT><FONT face=宋体 size=3>。保存了工程文件后,我们可以看到</FONT><FONT face="宋体, MS Song" size=3>C:\MP3Collect\</FONT><FONT face=宋体 size=3>目录下又新增加了</FONT><FONT face="宋体, MS Song" size=3>MP3Collect.bpr</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>MP3Collect.cpp</FONT><FONT face=宋体 size=3>和</FONT><FONT face="宋体, MS Song" size=3>MP3Collect.res</FONT><FONT face=宋体 size=3>三个文件,</FONT><FONT face="宋体, MS Song" size=3>CBuilder IDE</FONT><FONT face=宋体 size=3>中显示的工程名称也从</FONT><FONT face="宋体, MS Song" size=3>roject1</FONT><FONT face=宋体 size=3>变为</FONT><FONT face="宋体, MS Song" size=3>MP3Collect</FONT><FONT face=宋体 size=3>。</P><B>< align=justify>·工程编译连接与运行</P></B>< align=justify>到现在为此,一个空白的工程框架就已经搭好了,我们可以试运行一下,看看效果。</P>< align=justify>运行程序之前,还需要对工程进行编译连接,生成可执行文件。选择</FONT><FONT face="宋体, MS Song" size=3>roject|Make MP3Collect</FONT><FONT face=宋体 size=3>菜单命令,启动</FONT><FONT face="宋体, MS Song" size=3>IDE</FONT><FONT face=宋体 size=3>中的编译连接工具,这时会弹出“</FONT><FONT face="宋体, MS Song" size=3>Background Compiling</FONT><FONT face=宋体 size=3>”对话框显示编译连接的进度,连接完成后对话框自动消失。由于我们还未对</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>自动生成的程序框架作任何修改,应该不会有任何错误或警告,在</FONT><FONT face="宋体, MS Song" size=3>C:\MP3Collect\</FONT><FONT face=宋体 size=3>目录下成功生成</FONT><FONT face="宋体, MS Song" size=3>MP3Collect.exe</FONT><FONT face=宋体 size=3>。即使是第一次编译连接,我们还是可以感受到,</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>的编译连接速度还是相当快的,以后的</FONT><FONT face="宋体, MS Song" size=3>Make</FONT><FONT face=宋体 size=3>操作还会更快,因为以后的编译连接会自动检查工程中哪些部分进行了修改,从而只对改变了的部分进行处理。除了</FONT><FONT face="宋体, MS Song" size=3>Make</FONT><FONT face=宋体 size=3>命令以外,</FONT><FONT face="宋体, MS Song" size=3>roject|Build MP3Collect</FONT><FONT face=宋体 size=3>命令同样可以编译连接工程,只不过该命令总是处理所有的文件,所以比较慢。</P>< align=justify>生成了可执行文件,便可以运行该程序。在</FONT><FONT face="宋体, MS Song" size=3>IDE</FONT><FONT face=宋体 size=3>中按下</FONT><FONT face="宋体, MS Song" size=3>F9</FONT><FONT face=宋体 size=3>热键(对应</FONT><FONT face="宋体, MS Song" size=3>Run|Run</FONT><FONT face=宋体 size=3>菜单命令或工具栏中的“</FONT><FONT face="Courier New" size=3>►</FONT><FONT face=宋体 size=3>”按钮),便可在调试状态下开始运行该程序了(如果运行工程之前,程序没有编译连接好,“</FONT><FONT face="宋体, MS Song" size=3>Run</FONT><FONT face=宋体 size=3>”命令会自动启动“</FONT><FONT face="宋体, MS Song" size=3>Make</FONT><FONT face=宋体 size=3>”操作)。运行中的程序和我们在窗体编辑状态下看到的一样,是一个空白的窗体,今后我们就要在这个空白的窗体上添加需要的功能。根据心铃的经验,每添加一项功能,最好马上试运行一下看看效果如何,因为尽管</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>是所见即所得的编程工具,可是程序的许多功能还是只有在运行时的动态行为中体现,这样做的另一个好处是可以早点发现和排除错误。因此,修改程序、保存工程、编译运行,是我们在编程中需要不断重复的三部曲。</P><B>< align=justify>·工程设置</P></B>< align=justify>工程设置可以修改工程的属性和编译选项。通过</FONT><FONT face="宋体, MS Song" size=3>Project|Options</FONT><FONT face=宋体 size=3>菜单,或</FONT><FONT face="宋体, MS Song" size=3>Ctrl+Shift+F11</FONT><FONT face=宋体 size=3>快捷键,便可启动工程设置对话框,如图</FONT><FONT face="宋体, MS Song" size=3>5-1</FONT><FONT face=宋体 size=3>所示。工程设置对话框由多个选项页组成,每个选项页代表工程某一方面的设置选项。选项页的下方有三个按钮,“</FONT><FONT face="宋体, MS Song" size=3>OK</FONT><FONT face=宋体 size=3>”表示确定,“</FONT><FONT face="宋体, MS Song" size=3>Cancel</FONT><FONT face=宋体 size=3>”表示取消,“</FONT><FONT face="宋体, MS Song" size=3>Help</FONT><FONT face=宋体 size=3>”可以获取当前选项页中选项的说明。选项页的下方还有一个</FONT><FONT face="宋体, MS Song" size=3>Default</FONT><FONT face=宋体 size=3>复选框,选中该复选框,表示改变今后新工程的缺省设置,取消该复选框,则所作的改变只对当前活动工程有效。不同类型的工程,其选项页的数量的内容会有所不同,下面我们以</FONT><FONT face="宋体, MS Song" size=3>MP3Collect</FONT><FONT face=宋体 size=3>应用程序工程为例,分别介绍一下各个工程设置选项页的功能和含义。</P></FONT><B><FONT size=3><P align=justify>Forms</B></FONT><FONT face=宋体 size=3>选项页决定工程中的哪些窗体对象是自动创建的,以及哪一个窗体是程序的主窗体。第四讲中讲过,</FONT><FONT size=3>CBuilder</FONT><FONT face=宋体 size=3>应用程序中的窗体的生成和释放由</FONT><FONT size=3>CBuilder</FONT><FONT face=宋体 size=3>生成的代码自动完成的,其实这只是缺省情况下如此。在</FONT><FONT size=3>Forms</FONT><FONT face=宋体 size=3>选项页中列出了自动创建的窗体和非自动创建的窗体,缺省情况下,工程中所有窗体都是自动创建的,有时为了节约内存,我们可以指定某些窗体为非自动创建(反之亦然),使用非自动创建的窗体之前,需要通过代码创建其对象实例。本选项页中还可以指定哪一个窗体为应用程序的主窗体,主窗体总是自动创建的。</P></FONT><B><FONT size=3><P align=justify>Application</B></FONT><FONT face=宋体 size=3>选项页可以设置应用程序的标题、帮助文件的路径和文件名、应用程序的图标文件名,以及编译连接输出的文件后缀。标题和图标是指程序最小化后显示在系统工具栏中文字和图标。对于应用程序来说,输出的文件后缀通常为</FONT><FONT size=3>exe</FONT><FONT face=宋体 size=3>。</P></FONT><B><FONT size=3><P align=justify>Compiler</B></FONT><FONT face=宋体 size=3>选项页用于设置编译器的一般选项。如编译器优化选项、警告消息选项、调试信息选项、预编译选项等。编译选项内容比较多,好在</FONT><FONT size=3>CBuilder 5</FONT><FONT face=宋体 size=3>根据调试程序和发布程序的不同要求,预定义了两种编译设置:</FONT><FONT size=3>Full Debug</FONT><FONT face=宋体 size=3>和</FONT><FONT size=3>Release</FONT><FONT face=宋体 size=3>,我们一般只需要用到这两种设置就可以了。</P></FONT><B><FONT size=3><P align=justify>Advanced Compiler</B></FONT><FONT face=宋体 size=3>设置编译器的高级选项。其中,指令集(</FONT><FONT size=3>Instruction set</FONT><FONT face=宋体 size=3>)选项组可以选择执行代码的指令集,一般用缺省值</FONT><FONT size=3>80386</FONT><FONT face=宋体 size=3>即可。数据对齐(</FONT><FONT size=3>Data alignment</FONT><FONT face=宋体 size=3>)选项组可以设置数据在内存中的对齐方式,缺省值为</FONT><FONT size=3>4</FONT><FONT face=宋体 size=3>字节。函数调用规则(</FONT><FONT size=3>Calling convention</FONT><FONT face=宋体 size=3>)可以设置函数调用时参数的传递方式,缺省方式是</FONT><FONT size=3>C</FONT><FONT face=宋体 size=3>方式(有兴趣的朋友可以了解一下所列的几种调用规则的不同之处)。寄存器变量(</FONT><FONT size=3>Register variables</FONT><FONT face=宋体 size=3>)设置程序中是否使用寄存器变量。输出(</FONT><FONT size=3>Output</FONT><FONT face=宋体 size=3>)选项组设置</FONT><FONT size=3>.Obj</FONT><FONT face=宋体 size=3>文件中是否包含头文件的路径信息,以及函数名是否添加下划线作为前缀。浮点(</FONT><FONT size=3>Floating point</FONT><FONT face=宋体 size=3>)选项设置对浮点运算的优化开关,例如,其中的“</FONT><FONT size=3>Correct Pentium FDIV flaw</FONT><FONT face=宋体 size=3>”开关可以改正早期奔腾芯片中的</FONT><FONT size=3>FDIV</FONT><FONT face=宋体 size=3>浮点错误。语言兼容性(</FONT><FONT size=3>Language compliance</FONT><FONT face=宋体 size=3>)用来设置程序代码中与那种</FONT><FONT size=3>C++</FONT><FONT face=宋体 size=3>语言版本兼容,缺省值为</FONT><FONT size=3>Borland</FONT><FONT face=宋体 size=3>。代码(</FONT><FONT size=3>Source</FONT><FONT face=宋体 size=3>)选项可以设置代码中是否支持注释嵌套,是否支持</FONT><FONT size=3>MFC</FONT><FONT face=宋体 size=3>代码风格,还可以设置代码中标识符(变量名称或宏名称等都属于标识符)的最大有效长度,</FONT><FONT size=3>CBuilder</FONT><FONT face=宋体 size=3>支持的最大标识符长度为</FONT><FONT size=3>250</FONT><FONT face=宋体 size=3>。</P></FONT><B><FONT size=3><P align=justify>C++</B></FONT><FONT face=宋体 size=3>选项页是与</FONT><FONT size=3>C++</FONT><FONT face=宋体 size=3>语言有关的编译选项。其中成员指针(</FONT><FONT size=3>Member pointers</FONT><FONT face=宋体 size=3>)选项组可以设置指针引用类成员及其基类成员时的限制,缺省设置为无限制(</FONT><FONT size=3>All Cases</FONT><FONT face=宋体 size=3>)。兼容(</FONT><FONT size=3>Compatibility</FONT><FONT face=宋体 size=3>)选项用于与老版本的</FONT><FONT size=3>ANSI C++</FONT><FONT face=宋体 size=3>语言保持兼容。通用(</FONT><FONT size=3>General</FONT><FONT face=宋体 size=3>)选项用于与</FONT><FONT size=3>MFC</FONT><FONT face=宋体 size=3>类库中长度为</FONT><FONT size=3>0</FONT><FONT face=宋体 size=3>的基类兼容。</FONT><FONT size=3>Templates</FONT><FONT face=宋体 size=3>选项决定如何实例化</FONT><FONT size=3>Templates</FONT><FONT face=宋体 size=3>。异常处理(</FONT><FONT size=3>Exception handling</FONT><FONT face=宋体 size=3>)是有关运行时异常的处理方式。虚拟表(</FONT><FONT size=3>Virtula table</FONT><FONT face=宋体 size=3>)可用于优化虚拟函数表的大小。本选项页中的选项涉及到一些</FONT><FONT size=3>C++</FONT><FONT face=宋体 size=3>术语,可能令大家感到比较陌生,不过不要紧,因为我们目前还很难得用到它,以后需要的时候只要知道在这里进行设置就可以了。</P></FONT><B><FONT size=3><P align=justify>Linker</B></FONT><FONT face=宋体 size=3>选项页设置连接选项。连接和编译一样,是生成程序的必须步骤,其选项的内容也很丰富。心铃在这里只介绍其中几个选项的意义,想了解更多的内容可以参考联机帮助。生成调试信息(</FONT><FONT size=3>Create debug information</FONT><FONT face=宋体 size=3>)是指在可执行文件中加入调试信息。使用动态</FONT><FONT size=3>RTL</FONT><FONT face=宋体 size=3>(</FONT><FONT size=3>Use dynamic RTL</FONT><FONT face=宋体 size=3>)是指以动态连接的方式使用</FONT><FONT size=3>RTL.DLL</FONT><FONT face=宋体 size=3>,这种方式可以使执行文件较小,但在发布程序时必须同时发布该</FONT><FONT size=3>DLL</FONT><FONT face=宋体 size=3>。使用调试版本的</FONT><FONT size=3>VCL</FONT><FONT face=宋体 size=3>库文件(</FONT><FONT size=3>Use debug libraries</FONT><FONT face=宋体 size=3>)会使生成的文件较大,但允许调试时跟踪到</FONT><FONT size=3>VCL</FONT><FONT face=宋体 size=3>库的源程序中,心铃建议有对编程较有兴趣的朋友可以打开该选项,深入了解</FONT><FONT size=3>VCL</FONT><FONT face=宋体 size=3>库的实现。不生成连接状态文件(</FONT><FONT size=3>Don't generate state files</FONT><FONT face=宋体 size=3>)令每次连接时间同样长,一般不打开该选项。最大连接错误(</FONT><FONT size=3>Max errors</FONT><FONT face=宋体 size=3>)允许的最大错误数从</FONT><FONT size=3>0</FONT><FONT face=宋体 size=3>到</FONT><FONT size=3>255</FONT><FONT face=宋体 size=3>,超过最大错误时连接操作会自动停止。连接警告可以打开所有警告,也可以屏蔽部分警告。</P></FONT><B><FONT size=3><P align=justify>Advanced Linker</B></FONT><FONT face=宋体 size=3>设置高级连接选项。其中大小写敏感(</FONT><FONT size=3>Case-insensitive link</FONT><FONT face=宋体 size=3>)是指连接时对全局或外部的符号(变量、函数名等)大小写敏感,因为</FONT><FONT size=3>C/C++</FONT><FONT face=宋体 size=3>是大小写敏感的语言,所以一般应打开该选项。其它几个选项编程中较少涉及,就不细述了。</P></FONT><B><FONT size=3><P align=justify>Version Info</B></FONT><FONT face=宋体 size=3>选项页可以让生成的执行文件中包含版本信息,并设置版本信息的内容。查看</FONT><FONT size=3>EXE</FONT><FONT face=宋体 size=3>文件的版本信息,可以在资源管理器中用右键单击该文件,并在关联菜单中选择“属性”,如果该</FONT><FONT size=3>EXE</FONT><FONT face=宋体 size=3>文件包含版本信息,则属性对话框中会出现“版本”属性页。</P></FONT><B><FONT size=3><P align=justify>Package</B></FONT><FONT face=宋体 size=3>选项页如图</FONT><FONT size=3>5-2</FONT><FONT face=宋体 size=3>所示,它可以设置工程的设计时有效的包以及运行时所需要的包。第二讲中介绍过,包是</FONT><FONT size=3>CBuilder</FONT><FONT face=宋体 size=3>特有的动态连接库,后缀是</FONT><FONT size=3>.bpl</FONT><FONT face=宋体 size=3>。</FONT><FONT size=3>CBuilder</FONT><FONT face=宋体 size=3>的元件大部分都位于包文件中,所以选择设计时包文件,可以决定设计时能够使用的元件种类。如图</FONT><FONT size=3>2</FONT><FONT face=宋体 size=3>所示,选项页的上部用于选择设计时有效的包。其中列表框列出了所有</FONT><FONT size=3>CBuilder</FONT><FONT face=宋体 size=3>中已安装的包,每个包的右侧都有一个复选框,显示该包是否为设计时有效。列表框的下方显示当前选中包的路径名。“</FONT><FONT size=3>Add</FONT><FONT face=宋体 size=3>”、“</FONT><FONT size=3>Remove</FONT><FONT face=宋体 size=3>”按钮可以安装和卸载</FONT><FONT size=3>CBuilder</FONT><FONT face=宋体 size=3>中的包,“</FONT><FONT size=3>Edit</FONT><FONT face=宋体 size=3>”按钮可以编辑包的源文件,“</FONT><FONT size=3>Components</FONT><FONT face=宋体 size=3>”按钮可显示当前选中包中的元件。选项页的下半部分设置运行时包,运行时包是指运行时以动态连接方式调用的包文件,这种方式生成的应用程序较小,但程序发布时必须同运行时包文件一起发布。我们可以通过“</FONT><FONT size=3>Build with runtime packages</FONT><FONT face=宋体 size=3>”复选框来确定是否使用运行时包文件,如果使用,则所需的包文件显示在一个编辑框中,文件之间用分号隔开。</P></FONT><B><FONT size=3><P align=justify>Directories/Conditionals</B></FONT><FONT face=宋体 size=3>选项页设置路径和条件参数。路径包括搜索路径和输出路径,搜索路径是指</FONT><FONT size=3>CBuilder IDE</FONT><FONT face=宋体 size=3>需要某一类文件时,除了当前目录之外的搜索目录,多个目录之间可用分号隔开。以头文件路径为例,缺省设置为“</FONT><FONT size=3>$(BCB)</FONT><FONT face=宋体 size=3>\</FONT><FONT size=3>Projects\;$(BCB)\include;$(BCB)\include\vcl</FONT><FONT face=宋体 size=3>”,其中</FONT><FONT size=3>$(BCB)</FONT><FONT face=宋体 size=3>表示</FONT><FONT size=3>CBuilder</FONT><FONT face=宋体 size=3>的安装目录,它表示除了当前工作目录之外,</FONT><FONT size=3>IDE</FONT><FONT face=宋体 size=3>可以到上述三个目录下搜索相关头文件。可设置的路径有头文件、库文件、调试库的源文件、</FONT><FONT size=3>OBJ</FONT><FONT face=宋体 size=3>输出路径、最终输出文件(指最终生成的</FONT><FONT size=3>EXE</FONT><FONT face=宋体 size=3>、</FONT><FONT size=3>DLL</FONT><FONT face=宋体 size=3>等)路径、</FONT><FONT size=3>BPI/LIB</FONT><FONT face=宋体 size=3>库输出路径,后三个输出路径的缺省值都为空,表示输出到当前工作目录。条件(</FONT><FONT size=3>Conditionals</FONT><FONT face=宋体 size=3>)参数设置编译符号,如“</FONT><FONT size=3>_Debug</FONT><FONT face=宋体 size=3>”等。多个条件参数之间可以用分号分隔。别名(</FONT><FONT size=3>Alias</FONT><FONT face=宋体 size=3>)可以设置单元文件别名。</P></FONT><B><FONT size=3><P align=justify>CodeGuard</B></FONT><FONT face=宋体 size=3>选项页可以启用</FONT><FONT size=3>CodeGuard</FONT><FONT face=宋体 size=3>功能,</FONT><FONT size=3>CodeGuard</FONT><FONT face=宋体 size=3>是</FONT><FONT size=3>CBuilder</FONT><FONT face=宋体 size=3>内集成的运行时态排错工具,它可以在运行时检查全局变量、堆栈、指针和对象等操作的合法性。</P><P align=justify>除了上述几个较为常用的选项页以外,应用程序工程设置对话框还有</FONT><FONT face="宋体, MS Song" size=3>Pascal</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>Tasm</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>CORBA</FONT><FONT face=宋体 size=3>几个选项页,分别是与</FONT><FONT face="宋体, MS Song" size=3>Pascal</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>Tasm</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>CORBA</FONT><FONT face=宋体 size=3>语言有关的编译选项,由于本讲座以</FONT><FONT face="宋体, MS Song" size=3>C++</FONT><FONT face=宋体 size=3>语言为主,这些选项就不详细介绍了。</P><P align=justify> </P><P align=justify>本讲中心铃为大家介绍了如何根据需求分析,创建一个</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>工程,以及如何设置工程的各种参数,下一讲心铃还要继续围绕该工程来介绍它的文件组成。</P></FONT>
作者: 韩冰    时间: 2005-1-26 01:11
<b><FONT face=宋体 size=6> </FONT></b>< align=center>工程框架分析</P><FONT face=宋体 size=3>< align=justify>在上一讲中,我们创建了一个</FONT><FONT face="宋体, MS Song" size=3>MP3Collect</FONT><FONT face=宋体 size=3>工程,并学习了怎样用工程设置对话框来设置工程的各种属性。本讲我们将要进一步深入到工程的内部去了解其结构。</P><UL><B>< align=justify><LI>工程的文件组成
1 i* W( M: a- @/ v' _</LI></UL></B>< align=justify>第五讲曾经提到,新创建的工程</FONT><FONT face="宋体, MS Song" size=3>MP3Collect</FONT><FONT face=宋体 size=3>在工作目录下有一系列文件,它们分别是:</P>< align=justify>工程文件:</FONT><FONT size=3><FONT face="宋体, MS Song">MP3Collect.bpr</FONT></P></FONT><FONT face=宋体 size=3>< align=justify>单元文件:</FONT><FONT face="宋体, MS Song" size=3>MP3Collect.cpp</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>MainForm.cpp</FONT><FONT face=宋体 size=3>及其头文件</FONT><FONT size=3><FONT face="宋体, MS Song">MainForm.h</FONT></P></FONT><FONT face=宋体 size=3>< align=justify>窗体文件:</FONT><FONT face="宋体, MS Song" size=3>MainForm.dfm</FONT><FONT face=宋体 size=3>。</P>< align=justify>资源文件:</FONT><FONT size=3><FONT face="宋体, MS Song">MP3Collect.res</FONT></P></FONT><FONT face=宋体 size=3>< align=justify>这些文件的有机组合构成了工程。下面心铃将逐一介绍各个文件的格式和内容。</P><UL><B>< align=justify><LI>工程文件——</FONT><FONT size=3><FONT face="宋体, MS Song">MP3Collect.bpr </FONT><p></LI></UL></B>< align=justify>MP3Collect.bpr</FONT><FONT face=宋体 size=3>是工程的</FONT><FONT size=3>Makefile</FONT><FONT face=宋体 size=3>文件,是一个文本文件,它以</FONT><FONT size=3>XML</FONT><FONT face=宋体 size=3>标记语言的格式描述了工程的编译连接选项等各项设置。通常情况都不要手工修改此文件,而是通过工程设置对话框来修改。</P><UL><B>< align=justify><LI>应用程序入口单元——</FONT><FONT size=3><FONT face="宋体, MS Song">MP3Collect.cpp </FONT><p></LI></UL></B>< align=justify>MP3Collect.cpp</FONT><FONT face=宋体 size=3>文件中包含了</FONT><FONT size=3>Windows</FONT><FONT face=宋体 size=3>应用程序的入口</FONT><FONT size=3>WinMain()</FONT><FONT face=宋体 size=3>函数,同时指明了应用程序包含的其它源程序文件。下面我们来逐行分析</FONT><FONT size=3>MP3Collect.cpp</FONT><FONT face=宋体 size=3>的源代码(为了方便说明,心铃在每一行代码前都添加了行号,实际的代码中并没有这些行号):</P></FONT><FONT face="Courier New" size=3>< align=justify>1</FONT><FONT face=宋体 size=3>.</FONT><FONT face="Courier New" size=3>#include &lt;vcl.h&gt;</P>< align=justify>2</FONT><FONT face=宋体 size=3>.</FONT><FONT face="Courier New" size=3>#pragma hdrstop</P>< align=justify>3</FONT><FONT face=宋体 size=3>.</FONT><FONT face="Courier New" size=3>USERES("MP3Collect.res");</P>< align=justify>4</FONT><FONT face=宋体 size=3>.</FONT><FONT face="Courier New" size=3>USEFORM("MainFrom.cpp", MainForm);</P>< align=justify>5</FONT><FONT face=宋体 size=3>.</FONT><FONT face="Courier New" size=3>WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)</P>< align=justify>6</FONT><FONT face=宋体 size=3>.{</P></FONT><FONT face="Courier New" size=3>< align=justify>7</FONT><FONT face=宋体 size=3>. </FONT><FONT face="Courier New" size=3>try</P>< align=justify>8</FONT><FONT face=宋体 size=3>. {</P></FONT><FONT face="Courier New" size=3>< align=justify>9</FONT><FONT face=宋体 size=3>. </FONT><FONT face="Courier New" size=3>Application-&gt;Initialize();</P>< align=justify>10</FONT><FONT face=宋体 size=3>. </FONT><FONT face="Courier New" size=3>Application-&gt;CreateForm(__classid(TMainForm),&amp;MainForm);</P>< align=justify>11</FONT><FONT face=宋体 size=3>. </FONT><FONT face="Courier New" size=3>Application-&gt;Run();</P>< align=justify>12</FONT><FONT face=宋体 size=3>. }</P></FONT><FONT face="Courier New" size=3>< align=justify>13</FONT><FONT face=宋体 size=3>. </FONT><FONT face="Courier New" size=3>catch (Exception &amp;exception) </P>< align=justify>14</FONT><FONT face=宋体 size=3>. { </P></FONT><FONT face="Courier New" size=3>< align=justify>15</FONT><FONT face=宋体 size=3>. </FONT><FONT face="Courier New" size=3>Application-&gt;ShowException(&amp;exception);</P>< align=justify>16</FONT><FONT face=宋体 size=3>. }</P></FONT><FONT face="Courier New" size=3>< align=justify>17</FONT><FONT face=宋体 size=3>. </FONT><FONT face="Courier New" size=3>return 0;</P><P align=justify>18</FONT><FONT face=宋体 size=3>.}</P><P align=justify>第</FONT><FONT face="宋体, MS Song" size=3>1</FONT><FONT face=宋体 size=3>行是一条预处理指令。</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>编译器在正式编译一段代码之前,会预先扫描一遍代码,并根据预处理指令进行一些预先的处理,</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>编译器一共支持十几个预处理指令,每条预处理指令前都有一个“</FONT><FONT face="宋体, MS Song" size=3>#</FONT><FONT face=宋体 size=3>”符号。“</FONT><FONT face="宋体, MS Song" size=3>#include </FONT><FONT face=宋体 size=3>……”指令的意义是包含一个头文件,这在里就是告诉预处理器将</FONT><FONT face="宋体, MS Song" size=3>vcl.h</FONT><FONT face=宋体 size=3>包含进来。</FONT><FONT face="宋体, MS Song" size=3>vcl.h</FONT><FONT face=宋体 size=3>是使用</FONT><FONT face="宋体, MS Song" size=3>VCL</FONT><FONT face=宋体 size=3>库时必需的头文件,其中包括了使用</FONT><FONT face="宋体, MS Song" size=3>VCL</FONT><FONT face=宋体 size=3>库所需的各种声明和定义。</FONT><FONT face="宋体, MS Song" size=3>vcl.h</FONT><FONT face=宋体 size=3>内部又包含了多个其它的头文件,因此编译这个头文件需要花费较长的时间,为了缩短编译时间,</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>对这种些固定的头文件采取了预编译处理,第一次编译时进行完全编译,在以后的编译过程中,只要这些头文件没有变化,就不再处理它们,</FONT><FONT face="宋体, MS Song" size=3>MP3Collect.cpp</FONT><FONT face=宋体 size=3>中的第二条语句就是</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>的预编译开关指令,它表示预编译头文件部分到此结束。</P><P align=justify>第</FONT><FONT face="宋体, MS Song" size=3>3</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>4</FONT><FONT face=宋体 size=3>行的</FONT><FONT face="宋体, MS Song" size=3>USERES</FONT><FONT face=宋体 size=3>和</FONT><FONT face="宋体, MS Song" size=3>USEFORMS</FONT><FONT face=宋体 size=3>均为</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>定义的宏,前者用来定义工程的资源文件,后者用来指明工程中包含的窗体。</FONT><FONT face="宋体, MS Song" size=3>USEFORMS</FONT><FONT face=宋体 size=3>的第一个参数为窗体的单元文件名,第二个参数为窗体对象的名称。如果工程中有多个窗体,会在这里逐一用</FONT><FONT face="宋体, MS Song" size=3>USEFORMS</FONT><FONT face=宋体 size=3>宏指明。</P><P align=justify>从第</FONT><FONT face="宋体, MS Song" size=3>5</FONT><FONT face=宋体 size=3>行到第</FONT><FONT face="宋体, MS Song" size=3>18</FONT><FONT face=宋体 size=3>行定义了函数</FONT><FONT face="宋体, MS Song" size=3>WinMain</FONT><FONT face=宋体 size=3>,这是</FONT><FONT face="宋体, MS Song" size=3>Windows</FONT><FONT face=宋体 size=3>应用程序的标准入口函数,其参数的含义如下:</FONT><FONT face="宋体, MS Song" size=3>HINSTANCE hInstance</FONT><FONT face=宋体 size=3>(程序的当前实例句柄),</FONT><FONT face="宋体, MS Song" size=3>HINSTANCE hPrevInstance</FONT><FONT face=宋体 size=3>(程序的前一个实例句柄),</FONT><FONT face="宋体, MS Song" size=3>LPSTR lpCmdLine</FONT><FONT face=宋体 size=3>,(命令行字符串指针),</FONT><FONT face="宋体, MS Song" size=3>int nCmdShow</FONT><FONT face=宋体 size=3>(主窗口的显示方式)。</P></FONT><FONT size=3><P align=justify>WinMain</FONT><FONT face=宋体 size=3>函数的主体是</FONT><FONT size=3>try</FONT><FONT face=宋体 size=3>语句引出的一段代码和</FONT><FONT size=3>catch</FONT><FONT face=宋体 size=3>语句引出的异常处理代码。</FONT><FONT size=3>try</FONT><FONT face=宋体 size=3>和</FONT><FONT size=3>catch</FONT><FONT face=宋体 size=3>是</FONT><FONT size=3>C++</FONT><FONT face=宋体 size=3>中的关键字,用来处理程序运行时产生的异常,关于</FONT><FONT size=3>CBuilder</FONT><FONT face=宋体 size=3>的异常处理机制,讲座后期还要详细介绍,这里大家需要了解的只是:</FONT><FONT size=3>try</FONT><FONT face=宋体 size=3>语句引出一段可能产生异常的代码,如果运行时该段代码产生了异常,则中断该代码的执行,自动转入到由</FONT><FONT size=3>catch</FONT><FONT face=宋体 size=3>引出的异常处理代码中运行,一条</FONT><FONT size=3>try</FONT><FONT face=宋体 size=3>语句至少要有一条</FONT><FONT size=3>catch</FONT><FONT face=宋体 size=3>语句与之相对应,如果不产生异常,</FONT><FONT size=3>catch</FONT><FONT face=宋体 size=3>中的异常处理代码不会被执行。</P><P align=justify>下面我们来分析</FONT><FONT face="宋体, MS Song" size=3>try</FONT><FONT face=宋体 size=3>语句所包括的第</FONT><FONT face="宋体, MS Song" size=3>9</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>10</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>11</FONT><FONT face=宋体 size=3>行代码,它们都引用了</FONT><FONT face="宋体, MS Song" size=3>Application</FONT><FONT face=宋体 size=3>对象。</FONT><FONT face="宋体, MS Song" size=3>Application</FONT><FONT face=宋体 size=3>对象代表</FONT><FONT face="宋体, MS Song" size=3>Windows</FONT><FONT face=宋体 size=3>应用程序自身(在这里就是</FONT><FONT face="宋体, MS Song" size=3>MP3Collect</FONT><FONT face=宋体 size=3>),它对应的</FONT><FONT face="宋体, MS Song" size=3>VCL</FONT><FONT face=宋体 size=3>类是</FONT><FONT face="宋体, MS Song" size=3>TApplication</FONT><FONT face=宋体 size=3>,该类实现了应用程序初始化、创建窗体、运行、消息循环、异常处理、退出等基本功能。</FONT><FONT face="宋体, MS Song" size=3>Application</FONT><FONT face=宋体 size=3>对象的定义和创建是在</FONT><FONT face="宋体, MS Song" size=3>VCL</FONT><FONT face=宋体 size=3>库中完成的,它的声明</FONT><FONT face="宋体, MS Song" size=3>extern TApplication * Application</FONT><FONT face=宋体 size=3>位于头文件</FONT><FONT face="宋体, MS Song" size=3>Forms.hpp</FONT><FONT face=宋体 size=3>中(</FONT><FONT face="宋体, MS Song" size=3>vcl.h</FONT><FONT face=宋体 size=3>包含了</FONT><FONT face="宋体, MS Song" size=3>Forms.hpp</FONT><FONT face=宋体 size=3>)。第</FONT><FONT face="宋体, MS Song" size=3>9</FONT><FONT face=宋体 size=3>行语句调用</FONT><FONT face="宋体, MS Song" size=3>Application</FONT><FONT face=宋体 size=3>对象的</FONT><FONT face="宋体, MS Song" size=3>Initialize</FONT><FONT face=宋体 size=3>方法来初始化应用程序。第</FONT><FONT face="宋体, MS Song" size=3>10</FONT><FONT face=宋体 size=3>行语句创建主窗体,</FONT><FONT face="宋体, MS Song" size=3>CreateForm</FONT><FONT face=宋体 size=3>函数的第一个参数为主窗体类,第二个参数为主窗体对象,</FONT><FONT face="宋体, MS Song" size=3>__classid</FONT><FONT face=宋体 size=3>是获取</FONT><FONT face="宋体, MS Song" size=3>VCL</FONT><FONT face=宋体 size=3>类的操作符。如果应用程序中有多个自动创建的窗体,都会在这里以同样的方式创建,其中第一个创建的窗体为主窗体。第</FONT><FONT face="宋体, MS Song" size=3>11</FONT><FONT face=宋体 size=3>行语句调用</FONT><FONT face="宋体, MS Song" size=3>Application</FONT><FONT face=宋体 size=3>对象的</FONT><FONT face="宋体, MS Song" size=3>Run</FONT><FONT face=宋体 size=3>方法开始程序的运行,</FONT><FONT face="宋体, MS Song" size=3>Run</FONT><FONT face=宋体 size=3>函数中包含了应用程序的主消息循环,只有消息循环结束后,该函数才会返回。</P><P align=justify>第</FONT><FONT face="宋体, MS Song" size=3>15</FONT><FONT face=宋体 size=3>行语句是异常处理代码,利用</FONT><FONT face="宋体, MS Song" size=3>Application</FONT><FONT face=宋体 size=3>对象的</FONT><FONT face="宋体, MS Song" size=3>ShowException</FONT><FONT face=宋体 size=3>方法显示异常事件的相关信息。第</FONT><FONT face="宋体, MS Song" size=3>18</FONT><FONT face=宋体 size=3>行语句表示应用程序结束后,返回结束代码</FONT><FONT face="宋体, MS Song" size=3>0</FONT><FONT face=宋体 size=3>。</P><UL><B><P align=justify><LI>单元文件</FONT><FONT face="宋体, MS Song" size=3>MainForm.cpp</FONT><FONT face=宋体 size=3>及其头文件</FONT><FONT size=3><FONT face="宋体, MS Song">MainForm.h </FONT><p></LI></UL></B><P align=justify>MainForm.cpp</FONT><FONT face=宋体 size=3>和</FONT><FONT size=3>MainForm.h</FONT><FONT face=宋体 size=3>一起给出了主窗体的定义,其中</FONT><FONT size=3>MainForm.h</FONT><FONT face=宋体 size=3>中定义了主窗体类</FONT><FONT size=3>TMainFrom</FONT><FONT face=宋体 size=3>。</P></FONT><FONT face="Courier New" size=3><P align=justify>1</FONT><FONT face=宋体 size=3>. </FONT><FONT face="Courier New" size=3>#ifndef MainFromH</P><P align=justify>2</FONT><FONT face=宋体 size=3>. </FONT><FONT face="Courier New" size=3>#define MainFromH</P><P align=justify>3</FONT><FONT face=宋体 size=3>. </FONT><FONT face="Courier New" size=3>#include &lt;Classes.hpp&gt;</P><P align=justify>4</FONT><FONT face=宋体 size=3>. </FONT><FONT face="Courier New" size=3>#include &lt;Controls.hpp&gt;</P><P align=justify>5</FONT><FONT face=宋体 size=3>. </FONT><FONT face="Courier New" size=3>#include &lt;StdCtrls.hpp&gt;</P><P align=justify>6</FONT><FONT face=宋体 size=3>. </FONT><FONT face="Courier New" size=3>#include &lt;Forms.hpp&gt;</P><P align=justify>7</FONT><FONT face=宋体 size=3>. </FONT><FONT face="Courier New" size=3>class TMainForm: public TForm</P><P align=justify>8</FONT><FONT face=宋体 size=3>. {</P></FONT><FONT face="Courier New" size=3><P align=justify>9</FONT><FONT face=宋体 size=3>. </FONT><FONT face="Courier New" size=3>__published: // IDE-managed Components</P><P align=justify>10</FONT><FONT face=宋体 size=3>. </FONT><FONT face="Courier New" size=3>private: // User declarations</P><P align=justify>11</FONT><FONT face=宋体 size=3>. </FONT><FONT face="Courier New" size=3>public: // User declarations</P><P align=justify>12</FONT><FONT face=宋体 size=3>. </FONT><FONT face="Courier New" size=3>__fastcall TMainForm(TComponent* Owner);</P><P align=justify>13</FONT><FONT face=宋体 size=3>.}</FONT><FONT face="Courier New" size=3>;</P><P align=justify>14</FONT><FONT face=宋体 size=3>.</FONT><FONT face="Courier New" size=3>extern PACKAGE TMainForm *MainForm;</P><P align=justify>15</FONT><FONT face=宋体 size=3>.</FONT><FONT face="Courier New" size=3>#endif</P></FONT><FONT face=宋体 size=3><P align=justify>其中第</FONT><FONT face="宋体, MS Song" size=3>1</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>15</FONT><FONT face=宋体 size=3>行是条件编译指令。编译器根据这两条指令,首先检测</FONT><FONT face="宋体, MS Song" size=3>MainFormH</FONT><FONT face=宋体 size=3>是否已定义,如果未定义,才会继续编译第</FONT><FONT face="宋体, MS Song" size=3>2~14</FONT><FONT face=宋体 size=3>行的语句。第</FONT><FONT face="宋体, MS Song" size=3>2</FONT><FONT face=宋体 size=3>行定义</FONT><FONT face="宋体, MS Song" size=3>MainFormH</FONT><FONT face=宋体 size=3>,目的是避免重复编译</FONT><FONT face="宋体, MS Song" size=3>MainForm.h</FONT><FONT face=宋体 size=3>。第</FONT><FONT face="宋体, MS Song" size=3>3</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>4</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>5</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>6</FONT><FONT face=宋体 size=3>行包含了使用窗体和控件的头文件,</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>会根据窗体上的控件自动添加所需要的头文件。</P><P align=justify>第</FONT><FONT face="宋体, MS Song" size=3>7</FONT><FONT face=宋体 size=3>行是类定义的开始,其中</FONT><FONT face="宋体, MS Song" size=3>class</FONT><FONT face=宋体 size=3>是定义类的</FONT><FONT face="宋体, MS Song" size=3>C++</FONT><FONT face=宋体 size=3>关键字,</FONT><FONT face="宋体, MS Song" size=3>TMainFrom</FONT><FONT face=宋体 size=3>是类的名称,“:”符号指示类的父类,即</FONT><FONT face="宋体, MS Song" size=3>TMainFrom</FONT><FONT face=宋体 size=3>类的父类为</FONT><FONT face="宋体, MS Song" size=3>TForm</FONT><FONT face=宋体 size=3>,且继承方式为</FONT><FONT face="宋体, MS Song" size=3>public</FONT><FONT face=宋体 size=3>方式。</P><P align=justify>第</FONT><FONT face="宋体, MS Song" size=3>10</FONT><FONT face=宋体 size=3>到</FONT><FONT face="宋体, MS Song" size=3>13</FONT><FONT face=宋体 size=3>行语句为类的定义体,其中定义了类的各种属性和方法。第三讲中我们介绍过,根据外界对成员的存取限制,</FONT><FONT face="宋体, MS Song" size=3>C++</FONT><FONT face=宋体 size=3>类的成员分为</FONT><FONT face="宋体, MS Song" size=3>3</FONT><FONT face=宋体 size=3>种类型:</FONT><FONT face="宋体, MS Song" size=3>private</FONT><FONT face=宋体 size=3>私有的、</FONT><FONT face="宋体, MS Song" size=3>protect</FONT><FONT face=宋体 size=3>保护的和</FONT><FONT face="宋体, MS Song" size=3>public</FONT><FONT face=宋体 size=3>公共的,这里我们会遇到</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>引入的一种新成员类型:</FONT><FONT face="宋体, MS Song" size=3>__published</FONT><FONT face=宋体 size=3>,该类型成员与</FONT><FONT face="宋体, MS Song" size=3>public</FONT><FONT face=宋体 size=3>类型成员一样可以被外界的函数访问,而不同的地方在于:</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>编译连接器会为</FONT><FONT face="宋体, MS Song" size=3>__published</FONT><FONT face=宋体 size=3>类的成员生成运行时类型信息(</FONT><FONT face="宋体, MS Song" size=3>RTTI</FONT><FONT face=宋体 size=3>),使这种类型的成员能够显示在对象监视器中。对于新建的</FONT><FONT face="宋体, MS Song" size=3>TMainForm</FONT><FONT face=宋体 size=3>来说,因为还未添加任何控件和事件处理函数,所以</FONT><FONT face="宋体, MS Song" size=3>__published</FONT><FONT face=宋体 size=3>下的成员为空。如果我们在窗体上添加一个按钮,再双击该按钮添加其缺省事件处理函数:</FONT><FONT face="宋体, MS Song" size=3>Button1Click</FONT><FONT face=宋体 size=3>(),这时就会发现</FONT><FONT face="宋体, MS Song" size=3>__published</FONT><FONT face=宋体 size=3>下面多了两个成员:</P></FONT><FONT size=3><P align=justify>__published: // IDE-managed Components</P><P align=justify>TButton *Button1;</P><P align=justify>void __fastcall Button1Click(TObject *Sender);</P></FONT><FONT face=宋体 size=3><P align=justify>同样,新建的</FONT><FONT face="宋体, MS Song" size=3>TMainForm</FONT><FONT face=宋体 size=3>类中,</FONT><FONT face="宋体, MS Song" size=3>private</FONT><FONT face=宋体 size=3>类型的成员也为空。只有一个</FONT><FONT face="宋体, MS Song" size=3>public</FONT><FONT face=宋体 size=3>类型的构造函数(见第</FONT><FONT face="宋体, MS Song" size=3>12</FONT><FONT face=宋体 size=3>行)。构造函数前面的关键字“</FONT><FONT face="宋体, MS Song" size=3>__fastcall</FONT><FONT face=宋体 size=3>”是一种函数调用类型修饰符,表明该函数通过寄存器传递参数(普通的</FONT><FONT face="宋体, MS Song" size=3>C/C++</FONT><FONT face=宋体 size=3>函数是通过堆栈来传递参数),</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>中窗体的成员函数都是采用</FONT><FONT face="宋体, MS Song" size=3>__fastcal</FONT><FONT face=宋体 size=3>调用类型,这样可以加快程序的运行速度。</P><P align=justify>第</FONT><FONT face="宋体, MS Song" size=3>14</FONT><FONT face=宋体 size=3>行声明了一个指向</FONT><FONT face="宋体, MS Song" size=3>TMainForm</FONT><FONT face=宋体 size=3>类对象的指针</FONT><FONT face="宋体, MS Song" size=3>MainFrom</FONT><FONT face=宋体 size=3>,根据</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>编程的习惯,我们也称</FONT><FONT face="宋体, MS Song" size=3>MainFrom</FONT><FONT face=宋体 size=3>为对象。</P><P align=justify>下面我们再来看看主窗体类的实现代码,即单元文件</FONT><FONT face="宋体, MS Song" size=3>MainForm.cpp</FONT><FONT face=宋体 size=3>。</P></FONT><FONT face="Courier New" size=3><P align=justify>1</FONT><FONT face=宋体 size=3>. </FONT><FONT face="Courier New" size=3>#include &lt;vcl.h&gt;</P><P align=justify>2</FONT><FONT face=宋体 size=3>. </FONT><FONT face="Courier New" size=3>#pragma hdrstop</P><P align=justify>3</FONT><FONT face=宋体 size=3>. </FONT><FONT face="Courier New" size=3>#include "MainForm.h"</P><P align=justify>4</FONT><FONT face=宋体 size=3>. </FONT><FONT face="Courier New" size=3>#pragma package(smart_init)</P><P align=justify>5</FONT><FONT face=宋体 size=3>. </FONT><FONT face="Courier New" size=3>#pragma resource "*.dfm"</P><P align=justify>6</FONT><FONT face=宋体 size=3>. </FONT><FONT face="Courier New" size=3>TMainForm *MainForm;</P><P align=justify>7</FONT><FONT face=宋体 size=3>. </FONT><FONT face="Courier New" size=3>__fastcall TMainForm::TMainForm(TComponent* Owner)</P><P align=justify>8</FONT><FONT face=宋体 size=3>. </FONT><FONT face="Courier New" size=3>: TForm(Owner)</P><P align=justify>9</FONT><FONT face=宋体 size=3>. {</P></FONT><FONT face="Courier New" size=3><P align=justify>10</FONT><FONT face=宋体 size=3>.}</P><P align=justify>其中第</FONT><FONT face="宋体, MS Song" size=3>1</FONT><FONT face=宋体 size=3>行与应用程序入口单元</FONT><FONT face="宋体, MS Song" size=3>MP3Collect.cpp</FONT><FONT face=宋体 size=3>一样,指示包含头文件</FONT><FONT face="宋体, MS Song" size=3>vcl.h</FONT><FONT face=宋体 size=3>。第</FONT><FONT face="宋体, MS Song" size=3>2</FONT><FONT face=宋体 size=3>行表示预编译头文件结束。第</FONT><FONT face="宋体, MS Song" size=3>3</FONT><FONT face=宋体 size=3>行包含头文件</FONT><FONT face="宋体, MS Song" size=3>MainForm.h</FONT><FONT face=宋体 size=3>。有的朋友可能已经注意到,同样是包含头文件,第</FONT><FONT face="宋体, MS Song" size=3>1</FONT><FONT face=宋体 size=3>行中用尖括号</FONT><FONT face="宋体, MS Song" size=3>&lt;&gt;</FONT><FONT face=宋体 size=3>来包括文件名,第</FONT><FONT face="宋体, MS Song" size=3>3</FONT><FONT face=宋体 size=3>行中则用引号</FONT><FONT face="宋体, MS Song" size=3>""</FONT><FONT face=宋体 size=3>来包括文件名,两者的差别是编译器在搜索头文件时查找的缺省路径有所不同,一般来说,</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>的标准头文件用</FONT><FONT face="宋体, MS Song" size=3>&lt;&gt;</FONT><FONT face=宋体 size=3>来包含,而工程中的头文件则用</FONT><FONT face="宋体, MS Song" size=3>""</FONT><FONT face=宋体 size=3>来包含。</P><P align=justify>第</FONT><FONT face="宋体, MS Song" size=3>4</FONT><FONT face=宋体 size=3>行是一行预处理指令,其作用是保证单元的初始化按照单元之间的依赖过程进行。例如,“</FONT><FONT face="宋体, MS Song" size=3>UnitA</FONT><FONT face=宋体 size=3>”中使用到了“</FONT><FONT face="宋体, MS Song" size=3>UnitB</FONT><FONT face=宋体 size=3>”,则编译器应保证</FONT><FONT face="宋体, MS Song" size=3>UnitB</FONT><FONT face=宋体 size=3>应在</FONT><FONT face="宋体, MS Song" size=3>UnitA</FONT><FONT face=宋体 size=3>之前初始化。</P><P align=justify>第</FONT><FONT face="宋体, MS Song" size=3>5</FONT><FONT face=宋体 size=3>行预处理指令指明了当前的单元文件是窗体单元文件,</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>集成开发环境在处理此单元文件时会自动查找同名的窗体文件(</FONT><FONT face="Courier New" size=3>*.dfm</FONT><FONT face=宋体 size=3>文件)和头文件(</FONT><FONT face="Courier New" size=3>*.h</FONT><FONT face=宋体 size=3>文件)。</P><P align=justify>第</FONT><FONT face="宋体, MS Song" size=3>6</FONT><FONT face=宋体 size=3>行定义了</FONT><FONT face="宋体, MS Song" size=3>TMainForm</FONT><FONT face=宋体 size=3>类对象</FONT><FONT face="宋体, MS Song" size=3>MainFrom</FONT><FONT face=宋体 size=3>。</FONT><FONT face="宋体, MS Song" size=3>MainForm.h</FONT><FONT face=宋体 size=3>文件中的第</FONT><FONT face="宋体, MS Song" size=3>14</FONT><FONT face=宋体 size=3>行语句与此很相似,只是多了关键词“</FONT><FONT face="宋体, MS Song" size=3>extern</FONT><FONT face=宋体 size=3>”,因为有了该关键词,使得这两句的意义完全不相同。这里的第</FONT><FONT face="宋体, MS Song" size=3>6</FONT><FONT face=宋体 size=3>行语句是定义一个变量,程序会为这个变量分配一块实实在在的内存,而</FONT><FONT face="宋体, MS Song" size=3>MainForm.h</FONT><FONT face=宋体 size=3>中的第</FONT><FONT face="宋体, MS Song" size=3>14</FONT><FONT face=宋体 size=3>行则只是声明了一个变量,声明变量的意义是告诉编译器,应用程序的某一处已经定义了这样一个变量,使得后续的代码中可以使用该变量,变量声明并不会真正分配内存,这就是声明与定义的基本区别(在有些资料中的称法可能不太相同,把变量定义称为“定义性声明”,把变量声明称为“非定义性声明”。在本讲座中,如不特殊说明,仍然使用“变量定义”和“变量声明”的称法)。</P><P align=justify>第</FONT><FONT face="宋体, MS Song" size=3>7</FONT><FONT face=宋体 size=3>到</FONT><FONT face="宋体, MS Song" size=3>10</FONT><FONT face=宋体 size=3>行语句给出了</FONT><FONT face="宋体, MS Song" size=3>TMainForm</FONT><FONT face=宋体 size=3>类的构造函数的实现。函数名前的“</FONT><FONT face="宋体, MS Song" size=3>TMainForm::</FONT><FONT face=宋体 size=3>”为作用域限制符,表示函数的作用域为</FONT><FONT face="宋体, MS Song" size=3>TMainForm</FONT><FONT face=宋体 size=3>类,即该函数为</FONT><FONT face="宋体, MS Song" size=3>TMainForm</FONT><FONT face=宋体 size=3>类的成员函数。函数的参数为</FONT><FONT face="宋体, MS Song" size=3>TComponent* Owner</FONT><FONT face=宋体 size=3>,</FONT><FONT face="宋体, MS Song" size=3>Owner</FONT><FONT face=宋体 size=3>为本窗体的父元件对象。第</FONT><FONT face="宋体, MS Song" size=3>8</FONT><FONT face=宋体 size=3>行语句表示该构造函数会首先调用其基类的构造函数,并将</FONT><FONT face="宋体, MS Song" size=3>Owner</FONT><FONT face=宋体 size=3>参数传递到基类的构造函数中。构造函数中一般进行类初始化所需要的一些操作,相应的代码可以加在第</FONT><FONT face="宋体, MS Song" size=3>9</FONT><FONT face=宋体 size=3>行和第</FONT><FONT face="宋体, MS Song" size=3>10</FONT><FONT face=宋体 size=3>行中间。</P><UL><B><P align=justify><LI>窗体文件</FONT><FONT size=3><FONT face="宋体, MS Song">MainForm.dfm </FONT><p></LI></UL></B></FONT><FONT face=宋体 size=3><P align=justify>窗体文件</FONT><FONT face="宋体, MS Song" size=3>MainForm.dfm</FONT><FONT face=宋体 size=3>为文本格式的文件,描述了窗体的各种属性及其上的元件以及元件属性,如下所示:</P><DIR></FONT><FONT size=3><P align=justify>object MainForm: TMainForm</P><P align=justify>Left = 321</P><P align=justify>Top = 107</P><P align=justify>Width = 544</P><P align=justify>Height = 375</P><P align=justify>Caption = 'Form1'</P><P align=justify>Color = clBtnFace</P><P align=justify>Font.Charset = DEFAULT_CHARSET</P><P align=justify>Font.Color = clWindowText</P><P align=justify>Font.Height = -11</P><P align=justify>Font.Name = 'MS Sans Serif'</P><P align=justify>Font.Style = []</P><P align=justify>OldCreateOrder = False</P><P align=justify>PixelsPerInch = 96</P><P align=justify>TextHeight = 13</P><P align=justify>end</P></DIR></FONT><FONT face=宋体 size=3><P align=justify>通常我们都是通过</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>的窗体编辑器来设计和修改窗体,因此不建议大家手工修改</FONT><FONT face="宋体, MS Song" size=3>.dfm</FONT><FONT face=宋体 size=3>文件,这里也不再详述其格式了</P><UL><B><P align=justify><LI>资源文件</FONT><FONT size=3><FONT face="宋体, MS Song">MP3Collect.res </FONT><p></LI></UL></B><P align=justify>CBuilder</FONT><FONT face=宋体 size=3>使用标准格式的</FONT><FONT size=3>Windows</FONT><FONT face=宋体 size=3>资源文件,工程项目中所使用的资源,如位图、光标、图标等均在此文件中定义。</P><P align=justify> </P><P align=justify>本讲我们深入到了一个</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>工程的内部,了解了各个文件的组成、结构和作用,特别是对于其中的</FONT><FONT face="宋体, MS Song" size=3>C++</FONT><FONT face=宋体 size=3>源文件,几乎是逐行进行了讲解。由于代码中涉及到了一些</FONT><FONT face="宋体, MS Song" size=3>C++</FONT><FONT face=宋体 size=3>术语和</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>的关键词,初学编程的朋友可能会感到有些不好懂,这些朋友不妨多结合实践和其他参考资料,尽量在接触程序代码的开始就把概念搞清楚。</P></FONT>
作者: 韩冰    时间: 2005-1-26 01:13
<b><FONT face=宋体 size=6> </FONT></b>< align=center>调试应用程序</P><FONT face=宋体 size=3>< align=justify>上一讲详细介绍了工程的文件组成,相信朋友们已经做了不少练习,对</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>工程有了较深入的了解。本讲中,心铃要为大家介绍在调试应用程序的方法。在应用程序的开发过程中,程序调试的重要性并不亚于编写代码,因为一个设计得再好的程序,也难免会出现错误,这些错误需要通过调试来排除,通常程序的功能越是复杂,调试过程的工作量也就越大,而且显得越为重要。</P><UL><B>< align=justify><LI>程序的错误类型 $ k7 D9 ^% e6 r  I$ f! x, Q
</LI></UL></B>< align=justify>编写应用程序时可能产生的错误通常可以分为三大类:语法错误、运行时错误和逻辑错误。语法错误是程序代码违反了</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>的语法规则而产生的错误,典型的语法错误有书写代码时缺少标点符号、函数调用的参数类型不匹配、使用未声明的变量等,语法错误在编译阶段就会被编译器检查出来。</P>< align=justify>运行时错误只有在运行时才会体现出来,例如,在应用程序过程中打开了并不存在的文件,或者使用越界的指针等等。运行时错误可以在集成调试环境下通过设置断点、单步跟踪、添加监视等方法来查找和排除。</P>< align=justify>逻辑错误是由于程序算法不完善而产生的,运行结果不符合程序设计功能的问题,这一类错误比较难以检查,一般需要通过监视和检查程序中数据的变化情况,来检查错误发生的位置。还有些错误在“正常”的使用中不会出现,但在某些输入条件下才会产生(软件中的</FONT><FONT face="宋体, MS Song" size=3>Bugs</FONT><FONT face=宋体 size=3>有很大一部分属于这种类型),避免这一类错误的出现在很大程度上是属于软件工程的问题,需要设计完善的测试条件,提早发现和避免这类错误。</P><UL></FONT><B><FONT size=3>< align=justify><LI>CBuilder</FONT><FONT face=宋体 size=3>的集成调试环境 <p></LI></UL></B>< align=justify>为了能使用</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>的调试工具来进行调试,我们需要在工程设置中打开一些与调试有关的开关,使得</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>在编译、连接和生成可执行程序的过程中产生必需的调试信息,这些开关请大家参考第五讲的内容。</P>< align=justify>按照第五讲介绍的方法生成了包含有调试信息的可执行程序后,就可以在</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>集成调试环境下运行该程序了。应用程序在调试状态下运行时,与非调试状态下运行所执行的功能一样,可以进行响应用户输入、显示窗口等操作,但通过</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>调试工具,我们可以控制程序的执行,使程序在某些特定时刻暂停执行,当程序暂停执行时,我们可以使用调试工具来分析程序当前的工作状态,如变量、函数、调用关系、</FONT><FONT face="宋体, MS Song" size=3>CPU</FONT><FONT face=宋体 size=3>、寄存器等。通过分析程序的运行情况并和预先设计的状态进行对比,就可以检查出可能存在的错误。</P></FONT><FONT size=3>< align=justify>CBuilder</FONT><FONT face=宋体 size=3>的集成调试环境主要由代码编辑窗口、</FONT><FONT size=3>CPU</FONT><FONT face=宋体 size=3>状态窗口、调用堆栈窗口、监视窗口、局部变量窗口和</FONT><FONT size=3>CodeGuard</FONT><FONT face=宋体 size=3>记录窗口组成。除了代码编辑窗口之外,其余的调试窗口均可以通过菜单</FONT><FONT size=3>View-&gt;Debug Windows</FONT><FONT face=宋体 size=3>下面的命令来激活。</P>< align=justify>代码编辑窗口用于显示程序执行的状态、当前执行点的位置等。在调试状态下,代码编辑窗口左侧的标志条会显示出一排蓝色小圆点,每个蓝色小圆点代表一条可执行的语句,当程序暂停执行时,下一条将要执行的语句被高亮度显示出来,并在左侧的标志条中显示一个绿色的箭头。在调试状态下,代码编辑窗口的</FONT><FONT face="宋体, MS Song" size=3>CodeInsight</FONT><FONT face=宋体 size=3>功能还增加了一项显示变量取值的功能,即把鼠标放在某个变量上方停留片刻,便会出现一个提示条,其中显示了该变量当前的取值。</P>< align=justify>代码编辑窗口是程序调试时使用的主要窗口,但有时调试人员可能希望了解更多的低层信息,就会使用</FONT><FONT face="宋体, MS Song" size=3>CPU</FONT><FONT face=宋体 size=3>状态窗口。</FONT><FONT face="宋体, MS Song" size=3>CPU</FONT><FONT face=宋体 size=3>状态窗口如图</FONT><FONT face="宋体, MS Song" size=3>7-1</FONT><FONT face=宋体 size=3>所示,其中显示了当程序运行时的一系列低层状态信息,如内存、堆栈、寄存器、</FONT><FONT face="宋体, MS Song" size=3>CPU</FONT><FONT face=宋体 size=3>标志位等。</FONT><FONT face="宋体, MS Song" size=3>CPU</FONT><FONT face=宋体 size=3>状态窗口由五个子窗口区域组成,分别是汇编指令窗口、内存窗口、程序堆栈窗口、寄存器窗口和</FONT><FONT face="宋体, MS Song" size=3>CPU</FONT><FONT face=宋体 size=3>标志窗口。其中汇编指令窗口可以让调试人员在汇编指令级跟踪和调试程序,该子窗口片还会标出与一段汇编指令相对应的</FONT><FONT face="宋体, MS Song" size=3>C/C++</FONT><FONT face=宋体 size=3>语句,更便于程序的调试。</P>< align=justify>调用堆栈窗口(</FONT><FONT face="宋体, MS Song" size=3>Call Stack</FONT><FONT face=宋体 size=3>)显示了函数的调用关系,从调用堆栈窗口中可以看出当前执行的语句经过了哪几层函数调用。心铃在程序调试时经常要使用它,因为从错误的产生到错误显现出来,可能已经经过了好几层函数调用,有了调用堆栈窗口就可以很容易追本溯源了。</P>< align=justify>监视窗口(</FONT><FONT face="宋体, MS Song" size=3>Watches</FONT><FONT face=宋体 size=3>)可以监视变量以及变量表达式的取值和取值的变化,调试人员可以向其中添加或删除监视点。</P>< align=justify>局部变量窗口(</FONT><FONT face="宋体, MS Song" size=3>Local Variables</FONT><FONT face=宋体 size=3>)显示当前执行语句所属函数的所有局部变量的值。</P></FONT><FONT size=3>< align=justify>CodeGuard</FONT><FONT face=宋体 size=3>记录窗口(</FONT><FONT size=3>CodeGuard Log</FONT><FONT face=宋体 size=3>)只有在工程中打开了</FONT><FONT size=3>CodeGuard</FONT><FONT face=宋体 size=3>功能才有效,它会自动检测一些运行时错误,遇到错误时自动暂停程序的运行,并将错误的原因、错误发生的语句等记录下来。</P>< align=justify>另外,在第六讲介绍应用程序的入口函数</FONT><FONT face="宋体, MS Song" size=3>WinMain</FONT><FONT face=宋体 size=3>时,介绍过它的一个参数是命令行参数。命令行参数是</FONT><FONT face="宋体, MS Song" size=3>DOS</FONT><FONT face=宋体 size=3>时代十分常用的一种程序启动参数,在</FONT><FONT face="宋体, MS Song" size=3>Windows</FONT><FONT face=宋体 size=3>环境下,应用程序的启动不再通过命令行方式,但命令行参数仍然十分有用,例如,我们双击一个文件,系统会启动与之相关联的应用程序打开和处理该文件,就是通过命令行参数的方式将文件名传递给应用程序的。在</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>中调试应用程序时,也可以设置应用程序的命行参数,方法是通过</FONT><FONT face="宋体, MS Song" size=3>Run-&gtarameters</FONT><FONT face=宋体 size=3>菜单,打开运行参数对话框,在</FONT><FONT face="宋体, MS Song" size=3>arameters</FONT><FONT face=宋体 size=3>编辑框中输入命令行参数。</P><UL><B>< align=justify><LI>控制程序运行 <p></LI></UL></B></FONT><FONT size=3>< align=justify>CBuilder</FONT><FONT face=宋体 size=3>集成调试器提供了多个控制程序运行的命令:直接运行、单步运行、单步跟踪、跟踪到下一行源代码语句、运行到光标所在语句、运行直到函数返回、暂停运行、终止运行。下面介绍一下几个常用控制命令意义和用法。</P>< align=justify>直接运行命令(</FONT><FONT face="宋体, MS Song" size=3>Run-&gt;Run</FONT><FONT face=宋体 size=3>)与启动程序调试过程的命令相同,当程序暂停后,用直接运行命令可以让程序恢复正常运行状态,除非遇到断点才会再次暂停。直接运行方式可以加快调试的速度,对</FONT><FONT face="宋体, MS Song" size=3>Windows</FONT><FONT face=宋体 size=3>应用程序来说,大部分时间都在消息循环中等待消息,只有在处理某些消息时才会执行程序员编制的代码,因此可以让程序以直接运行方式处理消息循环,并配合断点的使用,让其在需要的地方暂停,可以提高调试的效率。</P>< align=justify>采用单步运行(</FONT><FONT face="宋体, MS Song" size=3>Run-&gt;Step</FONT><FONT face=宋体 size=3>)或单步跟踪(</FONT><FONT face="宋体, MS Song" size=3>Run-&gt;Trace</FONT><FONT face=宋体 size=3>)调试时,集成调试器每次只执行完一条语句就暂停,等待后续的执行命令。这里的一条语句既可以是一条</FONT><FONT face="宋体, MS Song" size=3>C++</FONT><FONT face=宋体 size=3>源代码语句,也可以是一条可执行的汇编指令,要根据当前调试窗口是代码编辑器还是</FONT><FONT face="宋体, MS Song" size=3>CPU</FONT><FONT face=宋体 size=3>状态窗口而定,当然,通常我们都是在</FONT><FONT face="宋体, MS Song" size=3>C/C++</FONT><FONT face=宋体 size=3>源代码上进行调试的。在遇到函数时,单步运行命令会将函数调用当作一条语句,一次执行完成整个函数。而单步跟踪命令则会跟踪到函数内部。单步运行或单步跟踪方式适合于细致的调试工作,当产生错误的大致范围已经清楚,利用这两种运行方式可以逐行地检查每一条语句的运行,直到查出产生错误的语句为止。</P>< align=justify>运行到光标处(</FONT><FONT face="宋体, MS Song" size=3>Run-&gt;Run To Cursor</FONT><FONT face=宋体 size=3>)是将程序执行到当前光标所在行,相当于在该行处设置了一个临时的断点,由于不需要设置和清除断点,因此使用很方便,是常用的调试命令之一。</P>< align=justify>前面的几条命令都是在程序暂停时才有效的命令,而暂停命令则只有在程序运行过程中才有效。暂停命令(</FONT><FONT face="宋体, MS Song" size=3>rogram Pause</FONT><FONT face=宋体 size=3>)可以随时暂停应用程序的运行,并且暂停的位置是随机的,而不是预先指定的。对于</FONT><FONT face="宋体, MS Song" size=3>Windows</FONT><FONT face=宋体 size=3>应用程序来说,大部分时候都在处理消息循环,所以暂停后应用程序常常停在查找消息的循环中,对程序调试而言意义不大。只有在处理一个时间较长的操作时,可以用暂停命令,以查看操作的进度。</P>< align=justify>正常情况下,程序的终止是由于用户选择了关闭或退出该应用程序的操作,程序终止后,调试也随之终止,</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>又恢复到设计状态。有时,我们也需要提前或强制终止程序的运行,此时可以使用</FONT><FONT face="宋体, MS Song" size=3>Run-&gtrogram Reset</FONT><FONT face=宋体 size=3>命令,该命令在整个调试期间都有效,无论是程序运行状态还是暂停状态下都可以使用该命令。通常当程序出现了明显的错误,或者希望修改程序重新调试时,我们可以使用该命令。</P><UL><B>< align=justify><LI>使用断点 <p></LI></UL></B>< align=justify>断点是程序调试过程中最常用的调试手段之一。所谓断点是在程序的某一处设置一个标志,告诉调试器,当程序执行到这个位置时暂停程序的执行。我们可以在代码编辑器中设置断点,并且无论是在设计状态下还是在调试状态下均可设置和清除断点,设置了断点的语句会用红色的背景突出显示,并在左侧标志条中打上一个红色的圆点标志。断点只在调试器中才有效,当应用程序脱离调试器单独运行时,断点不会影响它的运行。</P><P align=justify>设置断点的方法很简单,将光标移到需要添加断点的位置处,使用快捷键</FONT><FONT face="宋体, MS Song" size=3>F5</FONT><FONT face=宋体 size=3>即可添加断点,如果该位置本来就有断点,该操作则可以清除该断点。另外,也可用鼠标单击该语句左侧的标志条来添加和清除断点。需要注意的是,断点只能设在有效的代码行,如果设置在空白行、注释行或变量声明行等非执行语句上时,程序执行时将自动将其忽略,并在左侧的红色圆点上加了“</FONT><FONT face="宋体, MS Song" size=3>×</FONT><FONT face=宋体 size=3>”号。</P><P align=justify>断点又可分为无条件断点和有条件断点。缺省的断点都为无条件的,程序执行时,只要遇到这种断点,就会暂停执行。对于有条件断点,只有断点要求的条件得到满足时程序才会暂停执行。</P></FONT><FONT size=3><P align=justify>CBuilder</FONT><FONT face=宋体 size=3>允许创建和使用两种类型的断点条件:布尔类型的断点条件和通过断点次数。布尔类型的断点中可以设置条件表达式,当程序运行通过该断点时,调试器会自动计算条件表达式的值,如果结果为真,则暂停程序,否则程序继续运行。通过断点次数则可以为断点设置一个通过次数值,当程序每通过一次该断点,调试器都会自动计数一次,当计数值达到或超过设置值时才会暂停程序。条件断点的使用大大增强了调试器的功能,使得调试手段更加灵活。但是,由于调试器在每次通过条件断点时,都要作一些检查和判断,因此过多的条件断点可能会使调试运行的速度下降。</P><P align=justify>设置条件断点的方法是,先将光标移到需要添加断点的位置处,选择</FONT><FONT face="宋体, MS Song" size=3>Run-&gt;Add Breakpoint-&gt;Source Breadpoint</FONT><FONT face=宋体 size=3>命令,弹出如图</FONT><FONT face="宋体, MS Song" size=3>7-2</FONT><FONT face=宋体 size=3>所示的添加断点对话框,该对话框中标出了断点所在的源文件名和语句位置,另外还有布尔条件输入框(</FONT><FONT face="宋体, MS Song" size=3>Condition</FONT><FONT face=宋体 size=3>)和通过次数设置框(</FONT><FONT face="宋体, MS Song" size=3>Pass count</FONT><FONT face=宋体 size=3>),如果要创建的是无条件断点,则</FONT><FONT face="宋体, MS Song" size=3>Condition</FONT><FONT face=宋体 size=3>应为空,</FONT><FONT face="宋体, MS Song" size=3>Pass count</FONT><FONT face=宋体 size=3>为</FONT><FONT face="宋体, MS Song" size=3>0</FONT><FONT face=宋体 size=3>;如果创建布尔型的条件断点,则在</FONT><FONT face="宋体, MS Song" size=3>Condition</FONT><FONT face=宋体 size=3>中输入一个条件判断表达式;如果要创建通过次数类型的断点,则在</FONT><FONT face="宋体, MS Song" size=3>Pass count</FONT><FONT face=宋体 size=3>中设置通过次数值。如果断点同时设置了布尔条件和通过次数,则必需同时满足条件时程序才会暂停,而且只有在布尔条件为真时,计数值才会增加,直到计数值达到通过次数时才算满足条件。</P><P align=justify>如果工程中添加了多个断点,可以选择菜单命令</FONT><FONT face="宋体, MS Song" size=3>View-&gt;Debug Windows-&gt;Breakpoints</FONT><FONT face=宋体 size=3>,调出如图</FONT><FONT face="宋体, MS Song" size=3>7-3</FONT><FONT face=宋体 size=3>所示的断点列表窗口,断点列表窗口不仅可以查看所有的断点,还可以通过窗口内的关联菜单进行添加、删除断点、设置断点的有效性、或者修改断点的属性。修改断点的属性与添加断点所进行的设置内容差不多,包括其所在的文件、语句行号、布尔条件、通过次数、断点操作和是否有效等。当应用程序暂时不需要某些断点时,还可以设置这些断点处于无效状态,无效的断点对应用程序的调试不产生影响。如果以后需要重新使用这些断点,可以使之恢复为有效状态。</P><UL><B><P align=justify><LI>使用监视器 <p></LI></UL></B><P align=justify>监视器是程序调试过程中另一个最常用的工具。监视器可以监视一个变量,也可以监视包含变量的表达式,表达式中可以有数学运算和逻辑运算,但是不能包含函数调用。添加监视的方法有多种,最简单的方法是在将光标移到要监视的变量上(或者将要监视的表达式选中),按鼠标右键调出关联菜单,选择其中的</FONT><FONT face="宋体, MS Song" size=3>Debug-&gt;Add Watch at Cursor</FONT><FONT face=宋体 size=3>菜单命令,就能将其添加到工程的监视列表(</FONT><FONT face="宋体, MS Song" size=3>Watch List</FONT><FONT face=宋体 size=3>)中。另外一种方法是选择菜单命令</FONT><FONT face="宋体, MS Song" size=3>Run-&gt;Add Watch</FONT><FONT face=宋体 size=3>,调出如图</FONT><FONT face="宋体, MS Song" size=3>7-4</FONT><FONT face=宋体 size=3>所示的监视属性对话框,对话框中除了可以设置要监视的表达式,还可以设置监视的重复次数(</FONT><FONT face="宋体, MS Song" size=3>Repeat Count</FONT><FONT face=宋体 size=3>),以及监视值显示的格式。工程中所有的监视都会显示在监视窗口中,当工程在调试环境下运行时,监视窗口会自动显示被监视的变量或表达式的取值。监视窗口如图</FONT><FONT face="宋体, MS Song" size=3>7-5</FONT><FONT face=宋体 size=3>所示,除了显示监视点之外,我们还可以在该窗口中添加、编辑、删除监视点。</P><P align=justify>在</FONT><FONT face="宋体, MS Song" size=3>Cbuilder</FONT><FONT face=宋体 size=3>集成调试环境中,不仅可以监视应用程序在运行过程中变量值的变化情况,同时也可以计算和更改变量的值。计算和更改变量值的方法如下,在代码编辑器中合适的代码行上设置断点,运行应用程序到断点所在的代码行,选择</FONT><FONT face="宋体, MS Song" size=3>Run-&gt;Evaluate/Modify</FONT><FONT face=宋体 size=3>菜单项,打开如图</FONT><FONT face="宋体, MS Song" size=3>7-6</FONT><FONT face=宋体 size=3>所示的计算修改对话框。在表达式编辑框中输入需要监视的变量或表达式,在对话框工具栏上按下</FONT><FONT face="宋体, MS Song" size=3>Evaluate</FONT><FONT face=宋体 size=3>按钮,就可以计算出所设定变量或表达式的值。如果想修改变量值,可以在对话框的</FONT><FONT face="宋体, MS Song" size=3>New value</FONT><FONT face=宋体 size=3>编辑框中输入新的变量值,然后按下工具栏上的</FONT><FONT face="宋体, MS Song" size=3>Modify</FONT><FONT face=宋体 size=3>按钮。通过更改运行时变量的取值,可以人为地改变应用程序的运行状态,更好地检查应用程序中是否包含错误。</P><P align=justify> </P><P align=justify>本讲介绍了</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>的基本调试工具及其使用方法,由于调试程序是一项经验性非常强的工作,朋友们还需要在实践中多摸索,才能更好地掌握调试技巧,提高程序开发的总体效率。</P></FONT>
作者: 韩冰    时间: 2005-1-26 01:15
<b><FONT face=宋体 size=6> </FONT></b>< align=center>设计用户界面</P><FONT face=宋体 size=3>< align=justify>经过前面几讲的学习后,我们已经了解了</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>各个部件的基本使用方法,并且学习了如何用</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>来生成、编译、连接和运行一个工程,这些都是今后我们使用</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>进行编程的基础。</P></FONT><FONT size=3>< align=justify>CBuilder</FONT><FONT face=宋体 size=3>缺省生成的工程只是一个框架,并没有完成任何实际的功能,因此从本讲起,心铃将带领大家为这个缺省工程添砖加瓦,让它成为一个真正的</FONT><FONT size=3>MP3</FONT><FONT face=宋体 size=3>收藏和播放程序。本讲中我们首先要利用窗体编辑器和对象浏览器来为</FONT><FONT size=3>Mp3Collect</FONT><FONT face=宋体 size=3>工程设计用户界面,图</FONT><FONT size=3>8-1</FONT><FONT face=宋体 size=3>是程序最终完成并运行后的用户界面,这也就是我们的设计目标。</P><UL><B>< align=justify><LI>添加列表框控件
! {& c" Q' m" I% o</LI></UL></B>< align=justify>第二讲曾经介绍过,</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>提供有大量功能强大的元件,我们在开发应用程序过程中,通常会根据程序的功能和要求,首先考虑尽量使用现成的元件,以便减轻编程的工作量,只有当现成元件无法满足要求时才自己创建新的元件。</P></FONT><FONT size=3>< align=justify>Mp3Collect</FONT><FONT face=宋体 size=3>的核心功能是管理</FONT><FONT size=3>MP3</FONT><FONT face=宋体 size=3>音乐,因此需要一个控件用于记录显示,这里我们选择具有分列显示功能的列表框,即位于</FONT><FONT size=3>Win32</FONT><FONT face=宋体 size=3>元件栏中的</FONT><FONT size=3>ListView</FONT><FONT face=宋体 size=3>控件。</FONT><FONT size=3>ListView</FONT><FONT face=宋体 size=3>控件是一个可以用多种形式来显示用户信息的窗体控件,</FONT><FONT size=3>Windows</FONT><FONT face=宋体 size=3>资源管理器中的文件信息就是用</FONT><FONT size=3>ListView</FONT><FONT face=宋体 size=3>控件来显示的,还有我们熟悉的</FONT><FONT size=3>NetAnts</FONT><FONT face=宋体 size=3>也使用了</FONT><FONT size=3>ListView</FONT><FONT face=宋体 size=3>控件来显示需要下载的任务,可见它的用途相当广泛。</FONT><FONT size=3>CBuilder</FONT><FONT face=宋体 size=3>的</FONT><FONT size=3>VCL</FONT><FONT face=宋体 size=3>库中提供了</FONT><FONT size=3>TListView</FONT><FONT face=宋体 size=3>类来封装</FONT><FONT size=3>ListView</FONT><FONT face=宋体 size=3>控件,同时还提供了</FONT><FONT size=3>TListItem</FONT><FONT face=宋体 size=3>类和</FONT><FONT size=3>TListColumn</FONT><FONT face=宋体 size=3>类,分别用于封装</FONT><FONT size=3>ListView</FONT><FONT face=宋体 size=3>控件中的列表项和列表头,在后面编写具体代码时,我们就要与这三个类打交道。</P>< align=justify>第三讲曾经介绍过向窗体中添加元件的两种方法,一种方法是双击元件板中需要添加的元件,例如这里的</FONT><FONT face="宋体, MS Song" size=3>ListView</FONT><FONT face=宋体 size=3>控件,它就会自动出现在窗体中央,另一种方法是单击元件板中的元件,然后在窗体的某个位置上单击一次,选定的元件就会出现在指定位置处。</P>< align=justify>我们首先选中</FONT><FONT face="宋体, MS Song" size=3>Mp3Collect</FONT><FONT face=宋体 size=3>的主窗体,拖动其边框将窗体扩大到合适的大小,然后按照上述方法为窗体中添加一个列表框控件。刚放入的列表框控件的大小和位置可能还需要调整,此时可以拖动控件来移动位置,或者先选中它,然后拖动它周围出现的小黑框来改变其大小,如此重复操作,直到你对控件的大小和位置都满意为止。</P>< align=justify>新加入的控件都有缺省的名字,例如列表框控件为</FONT><FONT face="宋体, MS Song" size=3>ListView1</FONT><FONT face=宋体 size=3>,按钮为。。。,再次添加同一类控件时,新控件的名字将为</FONT><FONT face="宋体, MS Song" size=3>ListView2</FONT><FONT face=宋体 size=3>或。。。,依此类推。如果你想为控件更改一个名字,可以先选中它,然后在对象浏览器中修改。。。属性。</P></FONT><FONT size=3>< align=justify>ListView</FONT><FONT face=宋体 size=3>控件有四种显示方式:大图标、小图标、列表和报表(想想资源管理器文件窗口的四种显示方式),在</FONT><FONT size=3>Mp3Collect</FONT><FONT face=宋体 size=3>中,我们要使用具有分列显示功能的报表方式来显示歌曲记录。由于新添加的</FONT><FONT size=3>ListView</FONT><FONT face=宋体 size=3>控件缺省为。。。方式,我们需要修改决定</FONT><FONT size=3>ListView</FONT><FONT face=宋体 size=3>控件显示方式的</FONT><FONT size=3>ViewStyle</FONT><FONT face=宋体 size=3>属性,该属性是可读可写的,而且在设计时和运行时都可以更改,它有四种取值:</FONT><FONT size=3>vsIcon</FONT><FONT face=宋体 size=3>、</FONT><FONT size=3>vsSmallIcon</FONT><FONT face=宋体 size=3>、</FONT><FONT size=3>vsList</FONT><FONT face=宋体 size=3>和</FONT><FONT size=3>vsReport</FONT><FONT face=宋体 size=3>,分别代表四种显示方式。选中</FONT><FONT size=3>ListView</FONT><FONT face=宋体 size=3>控件后,在对象浏览器中选中</FONT><FONT size=3>ViewStyle</FONT><FONT face=宋体 size=3>属性,其属性值输入框自动变成下拉式列表框,选择</FONT><FONT size=3>vsReport</FONT><FONT face=宋体 size=3>,就可以把</FONT><FONT size=3>ListView</FONT><FONT face=宋体 size=3>控件的显示方式设置为报表方式。</P>< align=justify> </P>< align=justify>接下来我们要设置列表中的表头,即</FONT><FONT face="宋体, MS Song" size=3>ListView</FONT><FONT face=宋体 size=3>控件中的列标题。在对象浏览器中选择</FONT><FONT face="宋体, MS Song" size=3>ListView</FONT><FONT face=宋体 size=3>控件</FONT><FONT face="宋体, MS Song" size=3>Columns</FONT><FONT face=宋体 size=3>属性,单击属性值输入框右侧的“…”按钮,调出列表控件表头编辑框,如图</FONT><FONT face="宋体, MS Song" size=3>8-2</FONT><FONT face=宋体 size=3>所示。对话框的工具栏上有四个按钮,分别用于添加表头项、删除表头项以及调整表头项显示的顺序。每添加一个表头项,对象浏览器都会显示出新添表头项的属性,我们可以在其中输入表头的标题及列的宽度,按照这样的方法为</FONT><FONT face="宋体, MS Song" size=3>ListView</FONT><FONT face=宋体 size=3>控件添加三个列标题:文件名称、歌曲名称和歌手。</P>< align=justify>设计阶段所需要设置的</FONT><FONT face="宋体, MS Song" size=3>ListView</FONT><FONT face=宋体 size=3>属性就只有这么多,其他属性值直接采用缺省值,包括其缺省的对象名称</FONT><FONT face="宋体, MS Song" size=3>ListView1</FONT><FONT face=宋体 size=3>。由于</FONT><FONT face="宋体, MS Song" size=3>ListView</FONT><FONT face=宋体 size=3>控件的属性较多,这里不可能一一介绍,不过在后续的讲座中还会多次通过实际代码,具体介绍该控件的使用方法的。</P>< align=justify> </P>< align=justify> </P>< align=justify>如图</FONT><FONT face="宋体, MS Song" size=3>1</FONT><FONT face=宋体 size=3>所示,列表框控件分为</FONT><FONT face="宋体, MS Song" size=3>3</FONT><FONT face=宋体 size=3>列,分别显示文件路径、歌曲名称和歌手姓名。</P>< align=justify>为了便于添加和修改记录,窗体中使用三个编辑框(</FONT><FONT face="宋体, MS Song" size=3>Standard</FONT><FONT face=宋体 size=3>元件栏中的</FONT><FONT face="宋体, MS Song" size=3>Edit</FONT><FONT face=宋体 size=3>控件)用于获取用户输入,以及三个标签控件(</FONT><FONT face="宋体, MS Song" size=3>Standard</FONT><FONT face=宋体 size=3>元件栏中的</FONT><FONT face="宋体, MS Song" size=3>Label</FONT><FONT face=宋体 size=3>控件)用于提示编辑框的用途。由于手工输入文件名的方式比较麻烦,所以在程序中设计了文件浏览、获取文件名的功能,当用户点击文件名输入框右侧的“…”按钮时,可以调出标准的</FONT><FONT face="宋体, MS Song" size=3>Windows</FONT><FONT face=宋体 size=3>文件浏览对话框来获取</FONT><FONT face="宋体, MS Song" size=3>MP3</FONT><FONT face=宋体 size=3>歌曲的路径和文件名。其中“…”按钮是由命令按钮(</FONT><FONT face="宋体, MS Song" size=3>Standard</FONT><FONT face=宋体 size=3>元件栏中的</FONT><FONT face="宋体, MS Song" size=3>Button</FONT><FONT face=宋体 size=3>控件)实现,而标准文件浏览对话框则使用了</FONT><FONT face="宋体, MS Song" size=3>Dialogs</FONT><FONT face=宋体 size=3>元件栏中的</FONT><FONT face="宋体, MS Song" size=3>OpenDialog</FONT><FONT face=宋体 size=3>控件。</P>< align=justify>用户对记录的操作共有五种,分别是添加、修改、删除、查找和显示所有歌曲,分别用五个命令按钮控件实现,另外还在窗体中设计了“退出”按钮用于退出程序运行。</P>< align=justify>除了对</FONT><FONT face="宋体, MS Song" size=3>MP3</FONT><FONT face=宋体 size=3>文件记录进行操作之外,程序的另外一个重要功能是播放</FONT><FONT face="宋体, MS Song" size=3>MP3</FONT><FONT face=宋体 size=3>歌曲。有的朋友也许会问,播放</FONT><FONT face="宋体, MS Song" size=3>MP3</FONT><FONT face=宋体 size=3>音乐是不是很难?当然,如果需要自己来做</FONT><FONT face="宋体, MS Song" size=3>MP3</FONT><FONT face=宋体 size=3>的解码和音频数据的播放肯定是很难的,好在我们可以利用现成的控件——媒体播放控件(</FONT><FONT face="宋体, MS Song" size=3>System</FONT><FONT face=宋体 size=3>元件栏中的</FONT><FONT face="宋体, MS Song" size=3>MediaPlayer</FONT><FONT face=宋体 size=3>控件),这个控件支持多种媒体文件格式,包括</FONT><FONT face="宋体, MS Song" size=3>CD</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>MIDI</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>WAV</FONT><FONT face=宋体 size=3>以及现在最流行的</FONT><FONT face="宋体, MS Song" size=3>MP3</FONT><FONT face=宋体 size=3>音乐,功能很全面,而且使用起来也非常方便,后面还会详细介绍其使用方法。</P>< align=justify>为了使播放时具有循环播放的功能,窗体上设计了一个选项按钮(</FONT><FONT face="宋体, MS Song" size=3>Standard</FONT><FONT face=宋体 size=3>元件栏中的</FONT><FONT face="宋体, MS Song" size=3>CheckBox</FONT><FONT face=宋体 size=3>控件)。除了以上的主要功能控件以外,为了美观起见,我们还用了一个组合框将位于窗体上半部分的控件包括在一起。</P><B>< align=justify>元件的布局设计</P></B>< align=justify>第三讲中介绍过,向窗体添加元件的方法很简单,可以双击元件板中的所需要元件,它会自动出现在窗体的中央,也可以单击元件板中的所需元件,然后在窗体的指定位置上单击一次,所选定的元件便会出现在指定位置上。直接放置在窗体中的元件的大小和位置,往往不能完全符合应用程序的界面设计要求,特别是当窗体中的元件比较多时,更需要借助</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>的窗体元件布局工具来调整元件的大小和位置,使其更加整齐、美观。</P>< align=justify>在对任何一个元件做进一步的操作之前,首先需要将其选中,方法是用鼠标单击该元件,此时元件的四周将出现一个虚拟的边框,边框由上、下、左、右、左上、左下、右上、右下位置上的八个黑色控制点组成,如图</FONT><FONT face="宋体, MS Song" size=3>2</FONT><FONT face=宋体 size=3>所示。将鼠标按住边框内的一点并拖动,即可在保持元件大小情况下改变元件的位置。而当鼠标按住边框上的控制点并拖动时,可以使得元件的大小发生相应的变化。</P>< align=justify>除了选中单个元件,</FONT><FONT face="宋体, MS Song" size=3>CBuilder IDE</FONT><FONT face=宋体 size=3>还允许我们同时选中多个元件。选取多个元件的方法是用鼠标在窗体上划出一个虚框,虚框内的元件会被同时选中。另外还可以在按下</FONT><FONT face="宋体, MS Song" size=3>Shift</FONT><FONT face=宋体 size=3>键的同时用鼠标单击来选取多个元件,被选中的多个元件如图</FONT><FONT face="宋体, MS Song" size=3>3</FONT><FONT face=宋体 size=3>所示,选中元件的四周会出现灰色的控制点,这时不能够再通过鼠标拖动的方式来改变元件的大小,但是还可以利用其它更有效的方法同时改变多个元件的大小和位置。下面介绍的方法如不特别说明,对单个对象和多个对象都是有效的。</P>< align=justify>首先可以利用的工具是对象浏览器,随着所选元件对象的改变,对象浏览器会自动显示当前选中元件的属性(如果是多个元件对象被同时选中,对象浏览器中显示的是它们的共有的属性),利用对象浏览器可以改变元件的布局属性,如</FONT><FONT face="宋体, MS Song" size=3>Top</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>Left</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>Height</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>Width</FONT><FONT face=宋体 size=3>等布局属性,优点是非常精确,可以不受网格对齐的约束,能够精确到</FONT><FONT face="宋体, MS Song" size=3>1</FONT><FONT face=宋体 size=3>个象素,而缺点则是不如鼠标拖动的方式来得直观。</P>< align=justify>除了对象浏览器,菜单命令也是设计中常用的工具。</FONT><FONT face="宋体, MS Song" size=3>Edit</FONT><FONT face=宋体 size=3>菜单为元件布局操作提供了一组命令,分别是</FONT><FONT face="宋体, MS Song" size=3>Size</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>Scale</FONT><FONT face=宋体 size=3>和</FONT><FONT face="宋体, MS Song" size=3>Align</FONT><FONT face=宋体 size=3>,每个命令对应一个设置对话框。在对话框中选择合适的选项,然后单击</FONT><FONT face="宋体, MS Song" size=3>OK</FONT><FONT face=宋体 size=3>按钮,就可以一次性改变所有选中对象的大小及位置属性,例如,</FONT><FONT face="宋体, MS Song" size=3>MP3Collect</FONT><FONT face=宋体 size=3>主窗体中的六个命令按钮控件,可以通过使用</FONT><FONT face="宋体, MS Song" size=3>Size</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>Align</FONT><FONT face=宋体 size=3>命令使它们大小相等,并按两行三列排列整齐。需要注意的是</FONT><FONT face="宋体, MS Song" size=3>Scale</FONT><FONT face=宋体 size=3>命令的作用对象不仅是选中的元件,窗体上所有元件(除了窗体本身),包括元件表面的字体,都会按照一定的比例放大或缩小。</P>< align=justify>除了</FONT><FONT face="宋体, MS Song" size=3>Align</FONT><FONT face=宋体 size=3>对话框之外,还可以使用</FONT><FONT face="宋体, MS Song" size=3>Align</FONT><FONT face=宋体 size=3>工具栏进行元件的对齐操作。</FONT><FONT face="宋体, MS Song" size=3>Align</FONT><FONT face=宋体 size=3>工具栏如图</FONT><FONT face="宋体, MS Song" size=3>4</FONT><FONT face=宋体 size=3>所示,工具栏中包含</FONT><FONT face="宋体, MS Song" size=3>10</FONT><FONT face=宋体 size=3>个快捷按钮,可以方便地进行左右对齐、上下对齐、居中对齐等操作。缺省状态下,</FONT><FONT face="宋体, MS Song" size=3>Align</FONT><FONT face=宋体 size=3>工具栏是隐藏起来的,可以通过</FONT><FONT face="宋体, MS Song" size=3>View|Alignment Palette</FONT><FONT face=宋体 size=3>菜单将其显示在窗口的最前端。</P>< align=justify>当窗体上的元件数量比较多时,有的元件可能会位于其它元件的上面,这时我们可能需要调整某些元件的叠放层次,方法是在所选元件上调出关联菜单,选择其中的</FONT><FONT face="宋体, MS Song" size=3>Bring to Front</FONT><FONT face=宋体 size=3>和</FONT><FONT face="宋体, MS Song" size=3>Send to Back</FONT><FONT face=宋体 size=3>菜单命令改变元件的叠放层次。</P>< align=justify>在设计窗体时,还需要考虑元件的</FONT><FONT face="宋体, MS Song" size=3>Tab</FONT><FONT face=宋体 size=3>次序,即用户按下</FONT><FONT face="宋体, MS Song" size=3>Tab</FONT><FONT face=宋体 size=3>键时,各个元件获得键盘输入焦点的次序。不过,具有</FONT><FONT face="宋体, MS Song" size=3>Tab</FONT><FONT face=宋体 size=3>次序的元件都是能够获得键盘输入的元件,对于标签控件和快捷按钮控件来说,由于不会获得键盘输入,因此这一类的元件也就没有</FONT><FONT face="宋体, MS Song" size=3>Tab</FONT><FONT face=宋体 size=3>次序。控件缺省的</FONT><FONT face="宋体, MS Song" size=3>Tab</FONT><FONT face=宋体 size=3>次序是按照设计时元件的添加顺序,也可以在对象浏览器中修改元件的</FONT><FONT face="宋体, MS Song" size=3>TabStop</FONT><FONT face=宋体 size=3>和</FONT><FONT face="宋体, MS Song" size=3>TabOrder</FONT><FONT face=宋体 size=3>属性来调整元件的</FONT><FONT face="宋体, MS Song" size=3>Tab</FONT><FONT face=宋体 size=3>次序,或者选择</FONT><FONT face="宋体, MS Song" size=3>Edit|Tab Order</FONT><FONT face=宋体 size=3>菜单,调出</FONT><FONT face="宋体, MS Song" size=3>Tab</FONT><FONT face=宋体 size=3>次序编辑对话框,来调整元件元件的</FONT><FONT face="宋体, MS Song" size=3>Tab</FONT><FONT face=宋体 size=3>次序。</P>< align=justify>在设计窗体时,我们还可以利用拷贝和粘贴命令来拷贝和粘贴元件,新粘贴的元件和原来的元件除了名称不同之外,具有完全相同的属性。因此设计好一个元件的属性,再通过拷贝和粘贴的方法添加其它类似的元件,也是提高设计效率的常用方法。</P><P align=justify>在调整好窗体中各个元件的位置之后,可以选择</FONT><FONT face="宋体, MS Song" size=3>Edit|Lock Controls</FONT><FONT face=宋体 size=3>菜单命令,来锁定窗体中的各个元件。锁定后的各个元件的位置和大小不能再改变了。如果希望重新修改时,需要再次选择</FONT><FONT face="宋体, MS Song" size=3>Edit|Lock Controls</FONT><FONT face=宋体 size=3>菜单解除锁定。</P><B><P align=justify>元件的属性</P></B><P align=justify>接下来,我们要为窗体上的每个元件设置合适的属性,同时也要学习这些常用元件的使用方法。</P><P align=justify>首先设置</FONT><FONT face="宋体, MS Song" size=3>ListView</FONT><FONT face=宋体 size=3>控件的属性。</FONT><FONT face="宋体, MS Song" size=3>ListView</FONT><FONT face=宋体 size=3>控件是一个可以用多种形式来显示用户信息的窗体控件,</FONT><FONT face="宋体, MS Song" size=3>Windows</FONT><FONT face=宋体 size=3>资源管理器中的文件信息就是用</FONT><FONT face="宋体, MS Song" size=3>ListView</FONT><FONT face=宋体 size=3>控件来显示的,另外,还有我们大家所熟悉的</FONT><FONT face="宋体, MS Song" size=3>NetAnts</FONT><FONT face=宋体 size=3>中也使用了</FONT><FONT face="宋体, MS Song" size=3>ListView</FONT><FONT face=宋体 size=3>控件来显示需要下载的任务,因此它是一个用途很广泛的控件。</FONT><FONT face="宋体, MS Song" size=3>CBuilder VCL</FONT><FONT face=宋体 size=3>库中提供了</FONT><FONT face="宋体, MS Song" size=3>TListView</FONT><FONT face=宋体 size=3>类封装</FONT><FONT face="宋体, MS Song" size=3>ListView</FONT><FONT face=宋体 size=3>控件,同时还提供了</FONT><FONT face="宋体, MS Song" size=3>TListItem</FONT><FONT face=宋体 size=3>类和</FONT><FONT face="宋体, MS Song" size=3>TListColumn</FONT><FONT face=宋体 size=3>类,分别用于封装</FONT><FONT face="宋体, MS Song" size=3>ListView</FONT><FONT face=宋体 size=3>控件中的列表项和列表头。</P></FONT><FONT size=3><P align=justify>ListView</FONT><FONT face=宋体 size=3>控件有四种显示形式:大图标、小图标、列表和报表,这里我们选用具有分列显示功能的报表形式来显示歌曲记录。显示方式由其属性</FONT><FONT size=3>ViewStyle</FONT><FONT face=宋体 size=3>决定。该属性是可读可写的,而且在设计时和运行时都可以更改。该属性的可能取值有四种:</FONT><FONT size=3>vsIcon</FONT><FONT face=宋体 size=3>、</FONT><FONT size=3>vsSmallIcon</FONT><FONT face=宋体 size=3>、</FONT><FONT size=3>vsList</FONT><FONT face=宋体 size=3>和</FONT><FONT size=3>vsReport</FONT><FONT face=宋体 size=3>,分别代表它的四种显示方式,选中该控件后,在对象浏览器中选中</FONT><FONT size=3>ViewStyle</FONT><FONT face=宋体 size=3>属性,其属性值输入框自动变成下拉式列表框,从其中选出</FONT><FONT size=3>vsReport</FONT><FONT face=宋体 size=3>,就可以将</FONT><FONT size=3>ListView</FONT><FONT face=宋体 size=3>控件的显示方式设置为报表形式。</P><P align=justify>接下来我们要设置列表中的表头,即</FONT><FONT face="宋体, MS Song" size=3>ListView</FONT><FONT face=宋体 size=3>控件中的列标题。在对象浏览器中选择</FONT><FONT face="宋体, MS Song" size=3>ListView</FONT><FONT face=宋体 size=3>控件</FONT><FONT face="宋体, MS Song" size=3>Columns</FONT><FONT face=宋体 size=3>属性,单击属性值输入框右侧的“…”按钮,调出列表控件表头编辑框,如图</FONT><FONT face="宋体, MS Song" size=3>5</FONT><FONT face=宋体 size=3>所示。对话框的工具栏上有四个按钮,分别用于添加表头项、删除表头项以及调整表头项显示的顺序。每添加一个表头项,对象浏览器都会显示出新添表头项的属性,我们可以在其中输入表头的标题及列的宽度,按照这样的方法为</FONT><FONT face="宋体, MS Song" size=3>ListView</FONT><FONT face=宋体 size=3>控件添加三个列标题:文件名称、歌曲名称和歌手。</P><P align=justify>设计阶段所需要设置的</FONT><FONT face="宋体, MS Song" size=3>ListView</FONT><FONT face=宋体 size=3>属性就只有这么多,其他属性值直接采用缺省值,包括其缺省的对象名称</FONT><FONT face="宋体, MS Song" size=3>ListView1</FONT><FONT face=宋体 size=3>。由于</FONT><FONT face="宋体, MS Song" size=3>ListView</FONT><FONT face=宋体 size=3>控件的属性较多,这里不可能一一介绍,不过在后续的讲座中还会多次通过实际代码,具体介绍该控件的使用方法的。</P><P align=justify>接下来设置用于将小元件组合在一起的组合框控件的属性。当窗体上的元件较多时,常常需要把逻辑上相关联的元件组合在一起,使用户界面显得整齐、有条理,也便于同时控制多个元件。</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>中有多个元件可以用来把元件分组,它们分别是</FONT><FONT face="宋体, MS Song" size=3>Standard</FONT><FONT face=宋体 size=3>元件栏中的</FONT><FONT face="宋体, MS Song" size=3>GroupBox</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>RadioGroup</FONT><FONT face=宋体 size=3>和</FONT><FONT face="宋体, MS Song" size=3>Panel</FONT><FONT face=宋体 size=3>,</FONT><FONT face="宋体, MS Song" size=3>Win32</FONT><FONT face=宋体 size=3>元件栏上的</FONT><FONT face="宋体, MS Song" size=3>ToolBar</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>PageControl</FONT><FONT face=宋体 size=3>等,这些元件又叫做包容器元件(</FONT><FONT face="宋体, MS Song" size=3>Container Components</FONT><FONT face=宋体 size=3>)。使用包容器元件的原则是先在窗体上添加包容器元件,在选中该包容器元件的情况下添加其它元件。例如,在本程序中应先添加组合框控件</FONT><FONT face="宋体, MS Song" size=3>GroupBox1</FONT><FONT face=宋体 size=3>,再依次添加标签、编辑框、按钮、媒体播放控件等,每添加一个元件之前,都应先选中</FONT><FONT face="宋体, MS Song" size=3>GroupBox1</FONT><FONT face=宋体 size=3>对象。这时我们可以看到,添加到组内的元件已经不能再把它们移动到</FONT><FONT face="宋体, MS Song" size=3>GroupBox1</FONT><FONT face=宋体 size=3>之外去了,而且当我们拖动</FONT><FONT face="宋体, MS Song" size=3>GroupBox1</FONT><FONT face=宋体 size=3>时,其中的所有元件都会跟着一起移动,不用担心相对位置会被弄乱。在本程序中,</FONT><FONT face="宋体, MS Song" size=3>GroupBox1</FONT><FONT face=宋体 size=3>的作用主要是将小的、零碎的元件组合在一起,使它们看起来比较美观,所以并没有太多属性需要设置,只需要将其标题(</FONT><FONT face="宋体, MS Song" size=3>Caption</FONT><FONT face=宋体 size=3>)属性设为空字符串</FONT><FONT face="宋体, MS Song" size=3>""</FONT><FONT face=宋体 size=3>就可以了。</P><P align=justify>窗体中的“文件名”、“歌曲名称”和“歌手”为标签控件(</FONT><FONT face="宋体, MS Song" size=3>Standard</FONT><FONT face=宋体 size=3>元件栏的</FONT><FONT face="宋体, MS Song" size=3>Label</FONT><FONT face=宋体 size=3>控件),该控件主要用于标识和提示用户注意,它最重要的属性为</FONT><FONT face="宋体, MS Song" size=3>Caption</FONT><FONT face=宋体 size=3>属性,即其显示的内容,另外该控件还有一个</FONT><FONT face="宋体, MS Song" size=3>AutoSize</FONT><FONT face=宋体 size=3>属性,表示控件的大小是否根据</FONT><FONT face="宋体, MS Song" size=3>Caption</FONT><FONT face=宋体 size=3>的内容自动调节,本程序中将三个标签的</FONT><FONT face="宋体, MS Song" size=3>AutoSize</FONT><FONT face=宋体 size=3>属性都设为真(</FONT><FONT face="宋体, MS Song" size=3>true</FONT><FONT face=宋体 size=3>),并将其字体颜色(</FONT><FONT face="宋体, MS Song" size=3>Font-&gt;Color</FONT><FONT face=宋体 size=3>)属性设为蓝色。</P><P align=justify>三个编辑框分别用于显示当前选中记录的各项内容,也可以让用户输入新的记录和修改已有的记录,还可以用于输入记录查询条件。编辑框控件可以让用户在其中输入和编辑文本,其最重要的属性是</FONT><FONT face="宋体, MS Song" size=3>Text</FONT><FONT face=宋体 size=3>属性,程序可以读写此属性来获取用户的输入和设置编辑框中显示的内容。在设计时,通过对象编辑器我们将三个编辑框的对象名称分别设置为</FONT><FONT face="宋体, MS Song" size=3>EdtFileName</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>EdtSongName</FONT><FONT face=宋体 size=3>和</FONT><FONT face="宋体, MS Song" size=3>EdtSingerName</FONT><FONT face=宋体 size=3>。并把三个编辑框的</FONT><FONT face="宋体, MS Song" size=3>Text</FONT><FONT face=宋体 size=3>属性置为空字符串</FONT><FONT face="宋体, MS Song" size=3>""</FONT><FONT face=宋体 size=3>。</P><P align=justify>窗体中的六个命令按钮和“…”按钮使用命令按钮按钮来实现。它们的的属性设置比较简单,只是将其</FONT><FONT face="宋体, MS Song" size=3>Name</FONT><FONT face=宋体 size=3>依次设置为:</FONT><FONT face="宋体, MS Song" size=3>btnAdd</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>btnModify</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>btnDelete</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>btnFind</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>btnShowAll</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>btnExit</FONT><FONT face=宋体 size=3>和</FONT><FONT face="宋体, MS Song" size=3>btnFileName</FONT><FONT face=宋体 size=3>,相应的</FONT><FONT face="宋体, MS Song" size=3>Caption</FONT><FONT face=宋体 size=3>属性如图</FONT><FONT face="宋体, MS Song" size=3>1</FONT><FONT face=宋体 size=3>中所示。除了这种普通的命令按钮,</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>还提供了图形按钮(</FONT><FONT face="宋体, MS Song" size=3>Additional</FONT><FONT face=宋体 size=3>元件栏中的</FONT><FONT face="宋体, MS Song" size=3>BitBtn</FONT><FONT face=宋体 size=3>控件)和快捷按钮(</FONT><FONT face="宋体, MS Song" size=3>Additional</FONT><FONT face=宋体 size=3>元件栏中的</FONT><FONT face="宋体, MS Song" size=3>SpeedButton</FONT><FONT face=宋体 size=3>)两种按钮,这几种按钮的功能基本一样,用于发送某个操作命令,但比普通按钮增加了一些功能,例如图形支持和平坦表面的效果。以</FONT><FONT face="宋体, MS Song" size=3>SpeedButton</FONT><FONT face=宋体 size=3>为例,不仅可以单独使用,也可以用于工具栏中的快捷按钮。</FONT><FONT face="宋体, MS Song" size=3>SpeedButton</FONT><FONT face=宋体 size=3>控件具有</FONT><FONT face="宋体, MS Song" size=3>Flat</FONT><FONT face=宋体 size=3>属性,当其为真时,平时是平坦的,只有当用户将鼠标移动到该控件的上方时,它的边缘才会凸起。</FONT><FONT face="宋体, MS Song" size=3>SpeedButton</FONT><FONT face=宋体 size=3>控件和</FONT><FONT face="宋体, MS Song" size=3>BitBtn</FONT><FONT face=宋体 size=3>控件都支持图形化的按钮表面,它们都具有</FONT><FONT face="宋体, MS Song" size=3>Glyph</FONT><FONT face=宋体 size=3>属性,</FONT><FONT face="宋体, MS Song" size=3>Glyph</FONT><FONT face=宋体 size=3>属性可以指定四幅大小一样的位图或图标,分别代表其四种状态:抬起、压下、失效、始终保持压下。设置</FONT><FONT face="宋体, MS Song" size=3>Glyph</FONT><FONT face=宋体 size=3>属性的方法是在对象浏览器中选中该属性,单击输入框右侧的“</FONT><FONT face="宋体, MS Song" size=3>…</FONT><FONT face=宋体 size=3>”按钮,调出如图</FONT><FONT face="宋体, MS Song" size=3>6</FONT><FONT face=宋体 size=3>所示的图片编辑器,如果该图片属性本身为空,可以使用</FONT><FONT face="宋体, MS Song" size=3>Load</FONT><FONT face=宋体 size=3>按钮装入一幅位图或图标文件。图片编辑器一次只能调入一个图片文件,而</FONT><FONT face="宋体, MS Song" size=3>SpeedButton</FONT><FONT face=宋体 size=3>控件或</FONT><FONT face="宋体, MS Song" size=3>BitBtn</FONT><FONT face=宋体 size=3>控件的</FONT><FONT face="宋体, MS Song" size=3>Glyph</FONT><FONT face=宋体 size=3>属性最多可以设置四幅图片,这又是怎么实现的呢?首先,需要在控件的</FONT><FONT face="宋体, MS Song" size=3>NumGlyphs</FONT><FONT face=宋体 size=3>属性中设置实际的图片数(最多为</FONT><FONT face="宋体, MS Song" size=3>4</FONT><FONT face=宋体 size=3>),</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>会根据</FONT><FONT face="宋体, MS Song" size=3>NumGlyphs</FONT><FONT face=宋体 size=3>的数值自动将</FONT><FONT face="宋体, MS Song" size=3>Glyph</FONT><FONT face=宋体 size=3>中装载的图片横向等分为几份。并按顺序赋给控件的不同状态。图形化的按钮是非常流行的界面元素,在</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>中实现起来也非常简单,尽管本程序中并没有为按钮添加图形表面,不过有心的读者可以自己试着找几幅漂亮的图片,把几个命令按钮都改成图形按钮,一定会让程序增色不少。</P><P align=justify>“循环播放”选项按钮的属性中,我们只设置其名称为</FONT><FONT face="宋体, MS Song" size=3>chkLoop</FONT><FONT face=宋体 size=3>。以上介绍了窗体中</FONT><FONT face="宋体, MS Song" size=3>Windows</FONT><FONT face=宋体 size=3>常用控件的使用方法,余下的媒体播放控件和“</FONT><FONT face="宋体, MS Song" size=3>OpenDialog</FONT><FONT face=宋体 size=3>”控件会在后面的讲座中结合实际代码再详细介绍。</P><P align=justify> </P><P align=justify>本讲以</FONT><FONT face="宋体, MS Song" size=3>MP3Collect</FONT><FONT face=宋体 size=3>工程为例,介绍了设计用户界面的基本方法以及一些常用元件的属性设置。下一讲要为这些元件添加事件处理代码,使程序的功能完整起来。</P><P align=justify> </P><P align=justify> </P></FONT>
作者: 韩冰    时间: 2005-1-26 01:18
<b><FONT face=宋体 size=6> </FONT></b>< align=center>事件和事件处理函数</P><FONT face=宋体 size=3>< align=justify>在上一讲中我们主要学习了如何设计用户界面,了解了向窗体中添加元件、设置元件属性和调整元件的布局的方法,到目前为止,音乐收藏小程序</FONT><FONT face="宋体, MS Song" size=3>MP3Collect</FONT><FONT face=宋体 size=3>的用户界面已经初具雏形了,但是界面上的元件还不能响应用户的输入,因此在本讲中,我们就来为元件添加事件响应函数,让程序真正活起来。</P><UL><B>< align=justify><LI>添加记录
) _; W' n  |9 v</LI></UL></B></FONT><FONT size=3>< align=justify>MP3Collect</FONT><FONT face=宋体 size=3>主要的用途是管理音乐文件,我们首先就来实现添加记录的功能。按照我们的设想,添加记录的功能是由用户按下“添加”按钮时启动的,那么怎样才知道用户按下了这个按钮呢?这就引出了今天要介绍的元件事件及其事件处理函数的问题。</P>< align=justify>讲座前面曾经强调过,</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>开发的应用程序是事件驱动的,用户的操作、系统环境变化以及应用程序之间的相互作用都会触发一些事件,</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>提供的元件可以对这些事件进行响应,每一种元件都有特定的事件集合,该集合与它所实现的功能有关。</P>< align=justify>选中“添加”命令按钮后,调出它在对象浏览器中的事件页(图</FONT><FONT face="宋体, MS Song" size=3>9-1</FONT><FONT face=宋体 size=3>),查看它的事件集合,我们可以发现一个简单的命令按钮能够响应十多个事件,每种事件的名称都具有“</FONT><FONT face="宋体, MS Song" size=3>OnXXXX</FONT><FONT face=宋体 size=3>”的格式,其中前缀“</FONT><FONT face="宋体, MS Song" size=3>On</FONT><FONT face=宋体 size=3>”表示这是事件的名称,而“</FONT><FONT face="宋体, MS Song" size=3>XXXX</FONT><FONT face=宋体 size=3>”则代表了事件的性质。多数事件的名称都很好理解,如果想进一步了解各个事件的详细含义,可以按</FONT><FONT face="宋体, MS Song" size=3>F1</FONT><FONT face=宋体 size=3>键查看联机帮助,例如通过联机帮助我们可以了解到:当用户按下命令按钮时,就会触发</FONT><FONT face="宋体, MS Song" size=3>OnClick</FONT><FONT face=宋体 size=3>事件,因此我们需要响应</FONT><FONT face="宋体, MS Song" size=3>OnClick</FONT><FONT face=宋体 size=3>事件,从而实现添加记录的功能。</P>< align=justify>所谓响应事件,是指为元件的某个事件指定一个且只能指定一个处理函数,当该事件发生时,程序会自动执行该函数。</P>< align=justify>我们在对象浏览器中选中“添加”按钮对象的</FONT><FONT face="宋体, MS Song" size=3>OnClick</FONT><FONT face=宋体 size=3>事件,并在事件名称右侧的编辑框中输入事件处理函数的名称“</FONT><FONT face="宋体, MS Song" size=3>BtnAddSongClick</FONT><FONT face=宋体 size=3>”(可根据需要自行修改),然后按回车键,</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>集成开发环境就会在</FONT><FONT face="宋体, MS Song" size=3>TMainForm</FONT><FONT face=宋体 size=3>文件中自动添加一个空的事件处理函数:</P></FONT><FONT size=3>< align=justify>void __fastcall TMainForm::BtnAddSongClick(TObject *Sender)</P></FONT><FONT face=宋体 size=3>< align=justify>除了上述方法之外,还有好几种可以更方便地添加事件处理函数的方法。一种方法是双击事件名称右侧的空白输入框,便能自动添加一个事件处理函数,自动添加的函数的名称是由元件名称和事件名称组合而来的。另一种方法是直接双击放在窗体上的元件对象本身,</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>就会自动为该元件添加缺省事件的处理函数,</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>的每一种元件都有其缺省的事件。</P>< align=justify>下面我们来给</FONT><FONT face="宋体, MS Song" size=3>TMainForm::BtnAddSongClick</FONT><FONT face=宋体 size=3>添加程序代码,完成添加记录的功能。</P>< align=justify>每条</FONT><FONT face="宋体, MS Song" size=3>MP3</FONT><FONT face=宋体 size=3>音乐记录由三个部分组成:“文件名称”、“歌曲名称”和“歌手名称”,其中“文件名称”是</FONT><FONT face="宋体, MS Song" size=3>MP3</FONT><FONT face=宋体 size=3>歌曲文件所在的路径全名,它是每条记录必须有的内容,而“歌曲名称”和“歌手名称”允许为空字符串,即没有内容。上述三部分信息需要用户在三个编辑框中输入,因此在进行添加记录操作时,程序需要首先读取三个编辑框的内容,并检查其中的“文件名称”是否为空,如果为空,则提醒用户该项目不能为空,并中断添加记录的操作,如果不为空,则可以添加该记录。下面就是这部分代码的内容:</P></FONT><FONT size=3>< align=justify>void __fastcall TMainForm::BtnAddSongClick(TObject *Sender) </P>< align=justify>{</P>< align=justify>if(edtFileName-&gt;Text.IsEmpty())//</FONT><FONT face=宋体 size=3>判断文件名编辑框中是否为空</P>< align=justify>{</P><DIR></FONT><FONT size=3>< align=justify>Application-&gt;MessageBox("</FONT><FONT face=宋体 size=3>文件名称不能为空,请重新输入文件名称</FONT><FONT size=3>","MP3Collect",MB_OK);</P>< align=justify>edtFileName-&gt;SetFocus();//</FONT><FONT face=宋体 size=3>让文件名编辑框获得键盘输入焦点</P><DIR></FONT><FONT size=3>< align=justify>return;</P></DIR></DIR></FONT><FONT face=宋体 size=3>< align=justify>}</P></FONT><FONT size=3>< align=justify>TListItem *newItem=ListView1-&gt;Items-&gt;Add();//</FONT><FONT face=宋体 size=3>列表项集合中添加一个列表项</P></FONT><FONT size=3>< align=justify>newItem-&gt;Caption = edtFileName-&gt;Text;//</FONT><FONT face=宋体 size=3>列表项的标题属性为文件名称</P></FONT><FONT size=3>< align=justify>newItem-&gt;SubItems-&gt;Add(edtSongName-&gt;Text);//</FONT><FONT face=宋体 size=3>添加列表项的第一个子项:歌曲名称</P></FONT><FONT size=3>< align=justify>newItem-&gt;SubItems-&gt;Add(edtSingerName-&gt;Text);// </FONT><FONT face=宋体 size=3>添加列表项的第二个子项:歌手名称</P>< align=justify>}</P>< align=justify>其中,编辑框的内容可以通过读取其</FONT><FONT face="宋体, MS Song" size=3>Text</FONT><FONT face=宋体 size=3>属性来获得,该属性的类型为</FONT><FONT face="宋体, MS Song" size=3>AnsiString</FONT><FONT face=宋体 size=3>类,我们可以直接利用</FONT><FONT face="宋体, MS Song" size=3>AnsiString</FONT><FONT face=宋体 size=3>类的</FONT><FONT face="宋体, MS Song" size=3>IsEmpty</FONT><FONT face=宋体 size=3>方法来判断该字符串是否为空,如果为空则需要显示错误提示信息,为此我们利用应用程序对象</FONT><FONT face="宋体, MS Song" size=3>Application</FONT><FONT face=宋体 size=3>的</FONT><FONT face="宋体, MS Song" size=3>MessageBox</FONT><FONT face=宋体 size=3>方法来显示如图</FONT><FONT face="宋体, MS Song" size=3>9-2</FONT><FONT face=宋体 size=3>所示的消息框,从消息框返回后,我们利用编辑框的</FONT><FONT face="宋体, MS Song" size=3>SetFocus</FONT><FONT face=宋体 size=3>方法把键盘输入焦点直接移到</FONT><FONT face="宋体, MS Song" size=3>edtFileName</FONT><FONT face=宋体 size=3>编辑框处,以便让用户重新输入文件名。</P>< align=justify>如果文件名不为空,就把三个编辑框中的内容添加到</FONT><FONT face="宋体, MS Song" size=3>MP3</FONT><FONT face=宋体 size=3>音乐记录集合中去。我们应该用什么方法来管理和操作记录集合呢?学过数据结构的朋友知道该集合应该为一种双向链表,便于进行定位、添加、删除等操作,但是对于不熟悉数据结构的朋友来说,这种方法实现起来有一定的困难。好在我们使用的是</FONT><FONT face="宋体, MS Song" size=3>ListView</FONT><FONT face=宋体 size=3>控件,它有一个属性为</FONT><FONT face="宋体, MS Song" size=3>Items</FONT><FONT face=宋体 size=3>,即列表项的集合,也就是说,</FONT><FONT face="宋体, MS Song" size=3>ListView</FONT><FONT face=宋体 size=3>本身就具有较强的操作和管理列表项的功能,这正好符合我们对操作和管理记录集合的要求。因此,我们可以简单地将新记录添加到</FONT><FONT face="宋体, MS Song" size=3>ListView</FONT><FONT face=宋体 size=3>控件中,直接利用该控件的</FONT><FONT face="宋体, MS Song" size=3>Items</FONT><FONT face=宋体 size=3>属性来代替记录集合。</P></FONT><FONT size=3>< align=justify>Items</FONT><FONT face=宋体 size=3>属性的类型为</FONT><FONT size=3>TListItems *</FONT><FONT face=宋体 size=3>,我们利用它的</FONT><FONT size=3>Add</FONT><FONT face=宋体 size=3>方法可以添加一个列表项。</FONT><FONT size=3>Add</FONT><FONT face=宋体 size=3>方法返回新添加的列表项对象</FONT><FONT size=3>newItem</FONT><FONT face=宋体 size=3>,这是一个</FONT><FONT size=3>TListItem</FONT><FONT face=宋体 size=3>类型的指针。每一个列表项要显示三个字符串,其中第一个字符串为</FONT><FONT size=3>newItem</FONT><FONT face=宋体 size=3>的</FONT><FONT size=3>Caption</FONT><FONT face=宋体 size=3>属性,其它两个字符串为</FONT><FONT size=3>newItem</FONT><FONT face=宋体 size=3>的</FONT><FONT size=3>SubItems</FONT><FONT face=宋体 size=3>属性。</FONT><FONT size=3>Caption</FONT><FONT face=宋体 size=3>属性为</FONT><FONT size=3>AnsiString</FONT><FONT face=宋体 size=3>类型,可以直接通过赋值操作符“</FONT><FONT size=3>=</FONT><FONT face=宋体 size=3>”把另外一个</FONT><FONT size=3>AnsiString</FONT><FONT face=宋体 size=3>变量赋给该属性。</FONT><FONT size=3>SubItems</FONT><FONT face=宋体 size=3>属性为</FONT><FONT size=3>TStrings</FONT><FONT face=宋体 size=3>类型,</FONT><FONT size=3>TStrings</FONT><FONT face=宋体 size=3>是字符串集合类,它的基本方法有添加</FONT><FONT size=3>Add</FONT><FONT face=宋体 size=3>、删除</FONT><FONT size=3>Delete</FONT><FONT face=宋体 size=3>等,代码中就是利用</FONT><FONT size=3>Add</FONT><FONT face=宋体 size=3>方法来实现添加字符串的功能。</P><UL><B>< align=justify><LI>显示当前选中的记录 <p></LI></UL></B>< align=justify>当用户在</FONT><FONT face="宋体, MS Song" size=3>ListView1</FONT><FONT face=宋体 size=3>中选中某条记录时,三个编辑框应该能够显示选中记录的内容,用户便可以在此基础上进行修改,下面我们就来实现这一功能。</P><P align=justify>通过查阅联机帮助,我们得知,当用户在列表框中选择某条记录时,会触发</FONT><FONT face="宋体, MS Song" size=3>ListView</FONT><FONT face=宋体 size=3>控件的</FONT><FONT face="宋体, MS Song" size=3>OnSelectItem</FONT><FONT face=宋体 size=3>事件,于是我们就在对象浏览器中选中</FONT><FONT face="宋体, MS Song" size=3>ListView</FONT><FONT face=宋体 size=3>控件的</FONT><FONT face="宋体, MS Song" size=3>OnSelectItem</FONT><FONT face=宋体 size=3>事件,并双击该事件右侧的空白输入栏,添加该事件的处理函数,并编写如下代码。</P></FONT><FONT size=3><P align=justify>void __fastcall TMainForm:istView1SelectItem(TObject *Sender, TListItem *Item, bool Selected)</P><P align=justify>{</P><P align=justify>//</FONT><FONT face=宋体 size=3>参数</FONT><FONT size=3>Item</FONT><FONT face=宋体 size=3>为新选中的列表项,判断它是否为有效的列表项对象</P></FONT><FONT size=3><P align=justify>if(Item)</P></FONT><FONT face=宋体 size=3><P align=justify>{</P></FONT><FONT size=3><P align=justify>//</FONT><FONT face=宋体 size=3>将列表项第一列的内容,即其</FONT><FONT size=3>Caption</FONT><FONT face=宋体 size=3>属性的内容写入“文件名称”编辑框中</P></FONT><FONT size=3><P align=justify>edtFileName-&gt;Text=Item-&gt;Caption;</P><P align=justify>//</FONT><FONT face=宋体 size=3>将第二列的内容,即</FONT><FONT size=3>SubItems</FONT><FONT face=宋体 size=3>属性中的第一个字符串,写入“歌曲名称”编辑框</P><DIR></FONT><FONT size=3><P align=justify>edtSongName-&gt;Text=Item-&gt;SubItems-&gt;Strings[0]; </P><P align=justify>//</FONT><FONT face=宋体 size=3>将第三列的内容,即</FONT><FONT size=3>SubItems</FONT><FONT face=宋体 size=3>属性中的第二个字符串,写入“歌手名称”编辑框</P></FONT><FONT size=3><P align=justify>edtSingerName-&gt;Text=Item-&gt;SubItems-&gt;Strings[1]; </P></DIR></FONT><FONT face=宋体 size=3><P align=justify>}</P><P align=justify>}</P><P align=justify>为了确保列表框中一次只能选中一条记录,我们将</FONT><FONT face="宋体, MS Song" size=3>ListView1</FONT><FONT face=宋体 size=3>的</FONT><FONT face="宋体, MS Song" size=3>MultiSelect</FONT><FONT face=宋体 size=3>属性设为</FONT><FONT face="宋体, MS Song" size=3>false</FONT><FONT face=宋体 size=3>。另外,当</FONT><FONT face="宋体, MS Song" size=3>ListView</FONT><FONT face=宋体 size=3>拥有键盘输入焦点时,当前选中的某个列表项会以高亮度显示出来,如果用户把键盘输入焦点移出</FONT><FONT face="宋体, MS Song" size=3>ListView</FONT><FONT face=宋体 size=3>控件,它会根据</FONT><FONT face="宋体, MS Song" size=3>HideSelection</FONT><FONT face=宋体 size=3>属性来决定是否把选中的列表项用灰色显示出示,以示与其它列表项的区别,我们最好将该属性设为“</FONT><FONT face="宋体, MS Song" size=3>false</FONT><FONT face=宋体 size=3>”,以便让用户始终能够辨认出哪个是选中的列表项,如图</FONT><FONT face="宋体, MS Song" size=3>9-3</FONT><FONT face=宋体 size=3>所示。</P><UL><B><P align=justify><LI>删除记录 <p></LI></UL></B><P align=justify>当用户按下“删除”按钮后,程序应当把当前选中的记录删除。</P><P align=justify>我们首先在窗体上双击“删除”命令按钮,让</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>自动添加缺省的事件处理函数</FONT><FONT face="宋体, MS Song" size=3>BtnDeleteSongClick</FONT><FONT face=宋体 size=3>,然后编写如下代码:</P></FONT><FONT size=3><P align=justify>void __fastcall TMainForm::BtnDeleteSongClick(TObject *Sender)</P><P align=justify>{</P><P align=justify>// Selected</FONT><FONT face=宋体 size=3>属性为列表框中当前选中列表项,首先判断该列表项是否为有效列表项。</P></FONT><FONT size=3><P align=justify>if(ListView1-&gt;Selected)</P></FONT><FONT face=宋体 size=3><P align=justify>{</P><DIR></FONT><FONT size=3><P align=justify>//TListItems</FONT><FONT face=宋体 size=3>的</FONT><FONT size=3>Delete</FONT><FONT face=宋体 size=3>方法需要列表项的序号做为参数</P></FONT><FONT size=3><P align=justify>//</FONT><FONT face=宋体 size=3>即</FONT><FONT size=3>TListItem</FONT><FONT face=宋体 size=3>对象的</FONT><FONT size=3>Index</FONT><FONT face=宋体 size=3>属性。</P></FONT><FONT size=3><P align=justify>ListView1-&gt;Items-&gt;Delete(ListView1-&gt;Selected-&gt;Index);</P></DIR></FONT><FONT face=宋体 size=3><P align=justify>}</P><P align=justify>}</P><P align=justify>从代码可见,为了删除记录,首先要判断用户是否选择了</FONT><FONT face="宋体, MS Song" size=3>ListView1</FONT><FONT face=宋体 size=3>中的某个记录,如果有,就获得当前选中的列表项的序号,即</FONT><FONT face="宋体, MS Song" size=3>ListView1-&gt;Selected-&gt;Index</FONT><FONT face=宋体 size=3>,然后利用</FONT><FONT face="宋体, MS Song" size=3>ListView</FONT><FONT face=宋体 size=3>控件的</FONT><FONT face="宋体, MS Song" size=3>Items</FONT><FONT face=宋体 size=3>属性的</FONT><FONT face="宋体, MS Song" size=3>Delete</FONT><FONT face=宋体 size=3>方法将其删除。</P><UL><B><P align=justify><LI>修改记录 <p></LI></UL></B><P align=justify>修改记录的操作步骤如下:当用户选中某个列表项时,程序自动将该列表项的内容显示在编辑框中,然后用户便可以在编辑框中修改记录的三部分内容,修改完毕后,用户按下“修改”按钮,表示确认此次修改。</P><P align=justify>为了实现上述功能,我们在窗体上双击“修改”按钮,添加其缺省的事件处理函数</FONT><FONT face="宋体, MS Song" size=3>BtnModifySongClick</FONT><FONT face=宋体 size=3>,并编写如下代码。</P></FONT><FONT size=3><P align=justify>void __fastcall TMainForm::BtnModifySongClick(TObject *Sender)</P><P align=justify>{</P><P align=justify>// Selected</FONT><FONT face=宋体 size=3>属性为列表框中当前选中列表项,首先判断该列表项是否为有效列表项。</P></FONT><FONT size=3><P align=justify>TListItem *theItem=ListView1-&gt;Selected;</P><P align=justify>if(theItem)</P></FONT><FONT face=宋体 size=3><P align=justify>{</P></FONT><FONT size=3><P align=justify>//</FONT><FONT face=宋体 size=3>将“文件名称”编辑框的内容写入</FONT><FONT size=3>Caption</FONT><FONT face=宋体 size=3>属性</FONT><FONT size=3> </P><DIR><P align=justify>theItem-&gt;Caption = edtFileName-&gt;Text;</P></DIR><P align=justify>//</FONT><FONT face=宋体 size=3>将“歌曲名称”编辑框的内容写入</FONT><FONT size=3>SubItems</FONT><FONT face=宋体 size=3>属性中的第一个字符串,</FONT><FONT size=3> </P><DIR><P align=justify>theItem-&gt;SubItems-&gt;Strings[0]=edtSongName-&gt;Text;</P><P align=justify>//</FONT><FONT face=宋体 size=3>将“歌手名称”编辑框的内容写入</FONT><FONT size=3>SubItems</FONT><FONT face=宋体 size=3>属性中的第二个字符串,</FONT><FONT size=3> </P><P align=justify>theItem-&gt;SubItems-&gt;Strings[1]=edtSingerName-&gt;Text;</P></DIR></FONT><FONT face=宋体 size=3><P align=justify>}</P><P align=justify>}</P><P align=justify>其实</FONT><FONT face="宋体, MS Song" size=3>ListView</FONT><FONT face=宋体 size=3>控件本身就支持直接修改列表项的标题部分,当用户选中某个列表项,再单击该列表项的标题部分,就会出现一个输入框,如图</FONT><FONT face="宋体, MS Song" size=3>9-4</FONT><FONT face=宋体 size=3>所示,用户可在其中进行修改,编辑结束后,回车加以确认即可。这项功能是由</FONT><FONT face="宋体, MS Song" size=3>ReadOnly</FONT><FONT face=宋体 size=3>属性决定的,</FONT><FONT face="宋体, MS Song" size=3>ReadOnly</FONT><FONT face=宋体 size=3>为</FONT><FONT face="宋体, MS Song" size=3>false</FONT><FONT face=宋体 size=3>表示可以编辑,否则不行。为了简便起见,我们在</FONT><FONT face="宋体, MS Song" size=3>Mp3Collect</FONT><FONT face=宋体 size=3>中将</FONT><FONT face="宋体, MS Song" size=3>ListView1</FONT><FONT face=宋体 size=3>的</FONT><FONT face="宋体, MS Song" size=3>ReadOnly</FONT><FONT face=宋体 size=3>属性设为</FONT><FONT face="宋体, MS Song" size=3>true</FONT><FONT face=宋体 size=3>,即不允许修改。</P><UL><B><P align=justify><LI>对事件处理函数的进一步讨论 <p></LI></UL></B><P align=justify>在添加事件处理函数过程中,我们会发现,每种事件都有其特定的函数原型(即特定的返回类型及参数类型),窗体类中所有符合原型要求的成员函数都可以作为该事件的处理函数。因此,在对象浏览器中选中某个事件后,打开响应函数输入框旁边的下拉框(参考图</FONT><FONT face="宋体, MS Song" size=3>9-1</FONT><FONT face=宋体 size=3>),其中列出了窗体类所有符合该事件响应函数原型的成员函数,我们可以在其中选取一个作为事件处理函数。利用这个方法,我们可以给一组相同元件的相同事件指定同一个事件处理函数。例如,我们可以为“添加”、“修改”、“删除”三个按钮指定同一个</FONT><FONT face="宋体, MS Song" size=3>Click</FONT><FONT face=宋体 size=3>事件处理函数</FONT><FONT face="宋体, MS Song" size=3>ButtonClick</FONT><FONT face=宋体 size=3>,为了区分到底是哪一个按钮产生的事件,可以检查事件处理函数的输入参数</FONT><FONT face="宋体, MS Song" size=3>TObject *Sender</FONT><FONT face=宋体 size=3>,该参数代表了产生</FONT><FONT face="宋体, MS Song" size=3>Click</FONT><FONT face=宋体 size=3>事件的按钮对象。</FONT><FONT face="宋体, MS Song" size=3>ButtonClick</FONT><FONT face=宋体 size=3>函数举例如下:</P></FONT><FONT size=3><P align=justify>void __fastcall TMainForm::ButtonClick(TObject *Sender)</P><P align=justify>{</P><P align=justify>if(Sender==btnAddSong)</P><P align=justify>AddSongClick(Sender);</P><P align=justify>if(Sender==btnModifySong)</P><P align=justify>BtnModifySongClick(Sender);</P><P align=justify>if(Sender==btnDeleteSong)</P><P align=justify>BtnDeleteSongClick(Sender);</P></FONT><FONT face=宋体 size=3><P align=justify>}</P><P align=justify>有时候我们需要取消某个事件的响应函数,取消的方法是在对象浏览器中相应事件处删除掉函数名称,</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>就会取消事件与函数之间的关联,这种方法并不会真正删除处理函数本身,如果想彻底删除函数本身,可以将函数体中的代码删除,只保留空白的函数框架,然后再保存该工程,这样就会从</FONT><FONT face="宋体, MS Song" size=3>.CPP</FONT><FONT face=宋体 size=3>文件和</FONT><FONT face="宋体, MS Song" size=3>.H</FONT><FONT face=宋体 size=3>文件中彻底删除该事件处理函数。</P><P align=justify> </P><P align=justify>现在运行</FONT><FONT face="宋体, MS Song" size=3>Mp3Collect</FONT><FONT face=宋体 size=3>,我们会发现它已经能够响应用户的多种输入了,但还有很多功能不完整,例如退出程序之后,输入的记录就丢失掉了,因此在后面的讲座里,我们还将进一步完善</FONT><FONT face="宋体, MS Song" size=3>Mp3Collect</FONT><FONT face=宋体 size=3>的功能。</P></FONT>
作者: 韩冰    时间: 2005-1-26 01:20
<b><FONT face=宋体 size=6> </FONT></b>< align=center>文件读写操作</P><FONT face=宋体 size=3>< align=justify>上一讲我们学习了事件和事件处理函数的有关知识,并为</FONT><FONT face="宋体, MS Song" size=3>Mp3Collect</FONT><FONT face=宋体 size=3>程序添加的进行记录操作的代码,但是程序还缺少保存记录的功能,以至于当程序退出之后,我们辛苦输入的记录就丢失了,因此在本讲中,我们就首先来学习有关文件读写操作的知识,然后继续添加事件处理函数,实现查询记录的功能。</P>< align=justify>在应用程序中保存信息和数据的常用方法有三种:第一种是保存在</FONT><FONT face="宋体, MS Song" size=3>Windows</FONT><FONT face=宋体 size=3>的注册表中,第二种是保存在程序专用的文件中,第三种则是保存在数据库中。第一种方法只适合于保存少量关键的信息,例如程序的参数和选项,对于我们的例子程序来说,歌曲记录的数量可以是非常多的,因此不适合保存在注册表中。第二种方法是最常用的,也比较容易实现,因此现在我们先采用第二种方法来保存记录。第三种方法对于保存大量结构化的数据是最有效的,例如</FONT><FONT face="宋体, MS Song" size=3>Mp3Collect</FONT><FONT face=宋体 size=3>的歌曲记录,但实现起来相对要复杂得多,在讲座的后面我们再来学习数据库操作方法。</P>< align=justify>用于文件操作的函数也有很多种,我们选择使用</FONT><FONT face="宋体, MS Song" size=3>I/O</FONT><FONT face=宋体 size=3>流函数和</FONT><FONT face="宋体, MS Song" size=3>FILE *</FONT><FONT face=宋体 size=3>指针来进行对文件的操作,因为这些函数符合</FONT><FONT face="宋体, MS Song" size=3>ANSI C/C++</FONT><FONT face=宋体 size=3>规范,可移植性较好,能够用于</FONT><FONT face="宋体, MS Song" size=3>Win32</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>Unix</FONT><FONT face=宋体 size=3>平台,是比较常用的文件操作方式。</FONT><FONT face="宋体, MS Song" size=3>I/O</FONT><FONT face=宋体 size=3>流函数和</FONT><FONT face="宋体, MS Song" size=3>FILE</FONT><FONT face=宋体 size=3>结构的声明和定义位于头文件</FONT><FONT face="宋体, MS Song" size=3>stdio.h</FONT><FONT face=宋体 size=3>中。</P><UL><B>< align=justify><LI>保存记录文件
9 r$ A6 G/ _0 s% X5 p</LI></UL></B>< align=justify>下面介绍如何保存文件记录。</P>< align=justify>首先,为主窗体类添加一个</FONT><FONT face="宋体, MS Song" size=3>SaveFile()</FONT><FONT face=宋体 size=3>成员函数。在类浏览器中找到</FONT><FONT face="宋体, MS Song" size=3>TMainForm</FONT><FONT face=宋体 size=3>类,用右键单击该类,在关联菜单中选择</FONT><FONT face="宋体, MS Song" size=3>New Method</FONT><FONT face=宋体 size=3>命令,就会弹出如图</FONT><FONT face="宋体, MS Song" size=3>10-1</FONT><FONT face=宋体 size=3>所示的</FONT><FONT face="宋体, MS Song" size=3>Add Method</FONT><FONT face=宋体 size=3>对话框。在其中的</FONT><FONT face="宋体, MS Song" size=3>Method Name</FONT><FONT face=宋体 size=3>中输入新的成员函数名</FONT><FONT face="宋体, MS Song" size=3>SaveFile</FONT><FONT face=宋体 size=3>,函数的参数(</FONT><FONT face="宋体, MS Song" size=3>Arguments</FONT><FONT face=宋体 size=3>)为空,返回类型为</FONT><FONT face="宋体, MS Song" size=3>void</FONT><FONT face=宋体 size=3>,即没有返回值。函数的访问权限为私有的(</FONT><FONT face="宋体, MS Song" size=3>rivate</FONT><FONT face=宋体 size=3>),函数的调用方式为</FONT><FONT face="宋体, MS Song" size=3>__fastcall</FONT><FONT face=宋体 size=3>,这是因为按照</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>的规定,所有窗体类的成员函数的调用方式都必须为</FONT><FONT face="宋体, MS Song" size=3>__fastcall</FONT><FONT face=宋体 size=3>方式。设置好这些函数属性后,按下“</FONT><FONT face="宋体, MS Song" size=3>OK</FONT><FONT face=宋体 size=3>”按钮,</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>就会自动添加好</FONT><FONT face="宋体, MS Song" size=3>SaveFile()</FONT><FONT face=宋体 size=3>函数的框架。</P>< align=justify>接下来在</FONT><FONT face="宋体, MS Song" size=3>SaveFile()</FONT><FONT face=宋体 size=3>函数中添加代码,实现保存文件的功能。我们约定保存记录的文件名为</FONT><FONT face="宋体, MS Song" size=3>Mp3Collect.sav</FONT><FONT face=宋体 size=3>,文件目录为当前工作目录,当前工作目录是通过调用</FONT><FONT face="宋体, MS Song" size=3>GetCurrentDir()</FONT><FONT face=宋体 size=3>函数获得的。文件的格式为普通的文本文件,每个列表项的内容以字符串的方式写入文件中,其中每个字符串为单独的一行,因此每个列表项在文件中占三行。在对文件进行</FONT><FONT face="宋体, MS Song" size=3>I/O</FONT><FONT face=宋体 size=3>流操作之前,首先需要打开文件,并获取文件的</FONT><FONT face="宋体, MS Song" size=3>FILE*</FONT><FONT face=宋体 size=3>指针。</P>< align=justify>我们通过</FONT><FONT face="宋体, MS Song" size=3>fopen()</FONT><FONT face=宋体 size=3>函数以文本以及创建新文件的方式打开</FONT><FONT face="宋体, MS Song" size=3>Mp3Collect.sav</FONT><FONT face=宋体 size=3>文件,然后读取</FONT><FONT face="宋体, MS Song" size=3>ListView1</FONT><FONT face=宋体 size=3>中的列表项,利用函数</FONT><FONT face="宋体, MS Song" size=3>fprintf()</FONT><FONT face=宋体 size=3>将每个列表项的内容写入文件中。下面</FONT><FONT face="宋体, MS Song" size=3>SaveFile()</FONT><FONT face=宋体 size=3>函数的实现代码:</P></FONT><FONT size=3>< align=justify>void __fastcall TMainForm::SaveButtonClick(TObject *Sender)</P>< align=justify>{</P>< align=justify>FILE * fp;</P>< align=justify>//</FONT><FONT face=宋体 size=3>获取当前工作目录,并构造含路径的文件全名。其中,文件名与路径用斜线</FONT><FONT size=3>'\'</FONT><FONT face=宋体 size=3>分开,</P></FONT><FONT size=3>< align=justify>//</FONT><FONT face=宋体 size=3>在</FONT><FONT size=3>CBuilder</FONT><FONT face=宋体 size=3>中用双引号构造字符串时,连续两个斜线表示实际字符串中的一个斜线。</P></FONT><FONT size=3>< align=justify>AnsiString sFilePath =GetCurrentDir()+AnsiString("\\Mp3Collect.sav");</P>< align=justify>//fopen</FONT><FONT face=宋体 size=3>函数的第一个参数表示文件名。第二个参数为打开文件的方式,其中</FONT><FONT size=3>w</FONT><FONT face=宋体 size=3>表示以创建</P></FONT><FONT size=3>< align=justify>//</FONT><FONT face=宋体 size=3>文件打开,</FONT><FONT size=3>t</FONT><FONT face=宋体 size=3>表示以文本方式打开。</P></FONT><FONT size=3>< align=justify>fp=fopen(sFilePath.c_str(),"wt");</P>< align=justify>//fopen</FONT><FONT face=宋体 size=3>返回文件指针,如果为无效的指针,则显示出错信息并返回</P></FONT><FONT size=3>< align=justify>if(fp==NULL)</FONT><FONT face=宋体 size=3>{</P><DIR></FONT><FONT size=3>< align=justify>ShowMessage("</FONT><FONT face=宋体 size=3>不能打开文件</FONT><FONT size=3>Mp3Collect.sav</FONT><FONT face=宋体 size=3>,请检查是否为共享冲突</FONT><FONT size=3>");</P>< align=justify>return;</P></DIR></FONT><FONT face=宋体 size=3>< align=justify>}</P></FONT><FONT size=3>< align=justify>int i;</P>< align=justify>TListItem * theItem;</P>< align=justify>//</FONT><FONT face=宋体 size=3>循环遍历列表框</FONT><FONT size=3>ListView1</FONT><FONT face=宋体 size=3>的所有列表项</P></FONT><FONT size=3>< align=justify>for(i=0;i&lt;ListView1-&gt;Items-&gt;Count;i++){</P><DIR>< align=justify>//</FONT><FONT face=宋体 size=3>通过</FONT><FONT size=3>ListView1</FONT><FONT face=宋体 size=3>的</FONT><FONT size=3>Items</FONT><FONT face=宋体 size=3>属性获得它的第</FONT><FONT size=3>i</FONT><FONT face=宋体 size=3>个列表项</P></FONT><FONT size=3>< align=justify>theItem=ListView1-&gt;Items-&gt;Item; </P><P align=justify>//</FONT><FONT face=宋体 size=3>将列表项中的记录信息分别写入文件中,每个字符串后插入回车换行字符。</P></FONT><FONT size=3><P align=justify>fprintf(fp,"%s\n\r%s\n\r%s\n\r",theItem-&gt;Caption,</P><P align=justify>theItem-&gt;SubItems-&gt;Strings[0],theItem-&gt;SubItems-&gt;Strings[1]);</P></DIR></FONT><FONT face=宋体 size=3><P align=justify>}</P></FONT><FONT size=3><P align=justify>//</FONT><FONT face=宋体 size=3>关闭文件</P></FONT><FONT size=3><P align=justify>fclose(fp);</P></FONT><FONT face=宋体 size=3><P align=justify>}</P><P align=justify></FONT><FONT face="宋体, MS Song" size=3>SaveFile()</FONT><FONT face=宋体 size=3>功能实现后,还要在合适的地方调用该函数,以真正实现保存记录的功能了。由于每次添加、删除、修改记录项都使记录集的内容发生了变化,我们可以在</FONT><FONT face="宋体, MS Song" size=3>AddSongClick()</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>BtnModifySongClick()</FONT><FONT face=宋体 size=3>和</FONT><FONT face="宋体, MS Song" size=3>BtnDeleteSongClick()</FONT><FONT face=宋体 size=3>函数返回前调用</FONT><FONT face="宋体, MS Song" size=3>SaveFile()</FONT><FONT face=宋体 size=3>,及时保存记录集的最新信息。</P><UL><B><P align=justify><LI>读取文件中的记录 <p></LI></UL></B><P align=justify>接下来我们继续实现从文件中读取记录,并将其显示在列表框</FONT><FONT face="宋体, MS Song" size=3>ListView1</FONT><FONT face=宋体 size=3>中的功能。</P><P align=justify>在编辑状态下,双击主窗体上的“所有</FONT><FONT face="宋体, MS Song" size=3>MP3</FONT><FONT face=宋体 size=3>”按钮,添加事件处理函数</FONT><FONT face="宋体, MS Song" size=3>BtnShowAllClick()</FONT><FONT face=宋体 size=3>,在该函数中以文本和只读方式打开文件</FONT><FONT face="宋体, MS Song" size=3>Mp3Collect.sav</FONT><FONT face=宋体 size=3>,利用</FONT><FONT face="宋体, MS Song" size=3>fgets()</FONT><FONT face=宋体 size=3>函数从文件中一次读入一个字符串,每三个字符串构成一个列表项,并将列表项添加到列表框</FONT><FONT face="宋体, MS Song" size=3>ListView1</FONT><FONT face=宋体 size=3>中,具体的实现代码如下所 示:</P></FONT><FONT size=3><P align=justify>void __fastcall TMainForm::BtnShowAllClick()</P><P align=justify>{</P><P align=justify>FILE * fp;</P><P align=justify>//</FONT><FONT face=宋体 size=3>获取当前工作目录,并构造含路径的文件全名。</P></FONT><FONT size=3><P align=justify>AnsiString sFilePath =GetCurrentDir()+AnsiString("\\MP3Collect.sav");</P><P align=justify>//fopen</FONT><FONT face=宋体 size=3>函数的打开文件方式参数中,其中</FONT><FONT size=3>r</FONT><FONT face=宋体 size=3>表示以只读方式,</FONT><FONT size=3>t</FONT><FONT face=宋体 size=3>表示以文本方式打开。</P></FONT><FONT size=3><P align=justify>fp=fopen(sFilePath.c_str(),"rt");</P><P align=justify>int i,j;</P><P align=justify>char strbuf[255];</P><P align=justify>TListItem * theItem;</P><P align=justify>ListView1-&gt;Items-&gt;Clear();//</FONT><FONT face=宋体 size=3>清除列表框</FONT><FONT size=3>ListView1</FONT><FONT face=宋体 size=3>中的内容</P></FONT><FONT size=3><P align=justify>if(fp!=NULL) //</FONT><FONT face=宋体 size=3>如果文件存在,则返回的文件指针不为空,才能继续下面的操作</P><P align=justify>{</P><DIR></FONT><FONT size=3><P align=justify>i=0;//i</FONT><FONT face=宋体 size=3>指示添加到第几个列表项</P></FONT><FONT size=3><P align=justify>while(!feof(fp)) //</FONT><FONT face=宋体 size=3>判断是否读到了文件尾</P><P align=justify>{</P><DIR></FONT><FONT size=3><P align=justify>theItem=ListView1-&gt;Items-&gt;Add();//</FONT><FONT face=宋体 size=3>添加一项新的列表项</P></FONT><FONT size=3><P align=justify>for(j=0;j&lt;3;j++) //</FONT><FONT face=宋体 size=3>连续读三个字符串</P><P align=justify>{</P><DIR><DIR></FONT><FONT size=3><P align=justify>if(fgets(strbuf,255,fp)==NULL) //</FONT><FONT face=宋体 size=3>如果字符串为空,表示文件已结束</P><P align=justify>{</P><DIR></FONT><FONT size=3><P align=justify>ListView1-&gt;Items-&gt;Delete(i);</P><P align=justify>break;</P></DIR></FONT><FONT face=宋体 size=3><P align=justify>}</P></FONT><FONT size=3><P align=justify>//</FONT><FONT face=宋体 size=3>将字符串值赋给列表项,因为读出的字符串中可能包括回车换行等不能</P></FONT><FONT size=3><P align=justify>//</FONT><FONT face=宋体 size=3>显示的字符,因此用</FONT><FONT size=3>AnsiString</FONT><FONT face=宋体 size=3>的</FONT><FONT size=3>Trim</FONT><FONT face=宋体 size=3>函数去除这些字符</P></FONT><FONT size=3><P align=justify>if(j==0) theItem-&gt;Caption=AnsiString(strbuf).Trim();</P><P align=justify>else theItem-&gt;SubItems-&gt;Add(AnsiString(strbuf).Trim());</P></DIR></DIR></FONT><FONT face=宋体 size=3><P align=justify>}</P></FONT><FONT size=3><P align=justify>i++;</P></DIR></FONT><FONT face=宋体 size=3><P align=justify>}</P></DIR><P align=justify>}</P></FONT><FONT size=3><P align=justify>fclose(fp);//</FONT><FONT face=宋体 size=3>每次对文件操作完毕后,都要关闭文件</P><P align=justify>}</P><UL><B><P align=justify><LI>查询显示 <p></LI></UL></B><P align=justify>除了显示所有</FONT><FONT face="宋体, MS Song" size=3>MP3</FONT><FONT face=宋体 size=3>记录之外,我们还要为程序添加按条件查询并显示特定记录的功能。为了简单起见,我们约定查询条件也在记录输入框中输入。例如,在文件名中输入“</FONT><FONT face="宋体, MS Song" size=3>A</FONT><FONT face=宋体 size=3>”,表示记录的文件名部分必须包括</FONT><FONT face="宋体, MS Song" size=3>A</FONT><FONT face=宋体 size=3>,在歌曲名称中输入“月亮”则表示记录的歌曲名称中必须包括“月亮”,如果某个输入框为空白,则表示不检查该部分内容。三个查询条件之间是与的关系,即,输入的条件越多,查询标准越严格。</P><P align=justify>查询操作的原理和显示所有记录的原理基本一致,也需要打开</FONT><FONT face="宋体, MS Song" size=3>Mp3Collect.sav</FONT><FONT face=宋体 size=3>文件,读取其中所有记录信息,不同的是,查询操作需要将记录的各部分内容与条件输入框中的内容相比较,只有符合要求的记录项才会显示在列表框中。查询操作中进行条件比较的方法是利用</FONT><FONT face="宋体, MS Song" size=3>AnsiString</FONT><FONT face=宋体 size=3>类的</FONT><FONT face="宋体, MS Song" size=3>Pos()</FONT><FONT face=宋体 size=3>函数,检测字符串中是否包括查询条件中指定的子字符串。</P><P align=justify>为了添加查询显示功能,首先在窗体上双击“查找”按钮,添加事件响应函数</FONT><FONT face="宋体, MS Song" size=3>BtnFindClick()</FONT><FONT face=宋体 size=3>,并为该函数添加如下代码:</P></FONT><FONT size=3><P align=justify>void __fastcall TMainForm:: BtnFindClick (TObject *Sender)</P><P align=justify>{</P><P align=justify>FILE * fp;</P><P align=justify>//</FONT><FONT face=宋体 size=3>获取当前工作目录,并构造含路径的文件全名。</P><P align=justify></FONT><FONT size=3><FONT face="宋体, MS Song">AnsiString sFilePath =GetCurrentDir()+AnsiString("\\MP3Collect.sav");</FONT></P><P align=justify>fp=fopen(sFilePath.c_str(),"rt");//</FONT><FONT face=宋体 size=3>以只读、文本方式打开文件。</P></FONT><FONT size=3><P align=justify>int i,j ,bFound;</P><P align=justify>char strbufFileName[100],strbufSongName[100],strbufSingerName[100];</P><P align=justify>TListItem * theItem;</P><P align=justify>ListView1-&gt;Items-&gt;Clear();//</FONT><FONT face=宋体 size=3>清除列表框内原有的内容</P></FONT><FONT size=3><P align=justify>if(fp!=NULL) //</FONT><FONT face=宋体 size=3>如果文件存在,则返回的文件指针不为空,才能继续下面的操作</P><P align=justify>{</P><DIR></FONT><FONT size=3><P align=justify>i=0; //i</FONT><FONT face=宋体 size=3>指示添加到第几个列表项</P></FONT><FONT size=3><P align=justify>while(!feof(fp)) //</FONT><FONT face=宋体 size=3>判断是否读到了文件尾</P><P align=justify>{</P><DIR></FONT><FONT size=3><P align=justify>if(fgets(strbufFileName,100,fp)==NULL) break;</P><P align=justify>if(fgets(strbufSongName,100,fp)==NULL) break;</P><P align=justify>if(fgets(strbufSingerName,100,fp)==NULL) break;</P><P align=justify>bFound=TRUE;//bFound</FONT><FONT face=宋体 size=3>为是否符合查询条件标志,预先设定为</FONT><FONT size=3>TRUE</P><P align=justify>//</FONT><FONT face=宋体 size=3>如果“文件名称”输入框不为空,则判断</FONT><FONT size=3>strbufFileName</FONT><FONT face=宋体 size=3>中是否包括</P></FONT><FONT size=3><P align=justify>//</FONT><FONT face=宋体 size=3>“文件名称”输入条件</P></FONT><FONT size=3><P align=justify>if(!edtFileName-&gt;Text.IsEmpty())</P><DIR><DIR><P align=justify>if(!(AnsiString(strbufFileName).Pos(edtFileName-&gt;Text))) bFound=FALSE;</P></DIR></DIR><P align=justify>//</FONT><FONT face=宋体 size=3>检查“歌曲名称”查询条件</P></FONT><FONT size=3><P align=justify>if(!edtSongName-&gt;Text.IsEmpty())</P><DIR><DIR><P align=justify>if(!(AnsiString(strbufSongName).Pos(edtSongName-&gt;Text))) bFound=FALSE;</P></DIR></DIR><P align=justify>//</FONT><FONT face=宋体 size=3>检查“歌手名称”查询条件</P></FONT><FONT size=3><P align=justify>if(!edtSingerName-&gt;Text.IsEmpty())</P><DIR><DIR><P align=justify>if(!(AnsiString(strbufSingerName).Pos(edtSingerName-&gt;Text))) bFound=FALSE;</P></DIR></DIR><P align=justify>if(bFound) //</FONT><FONT face=宋体 size=3>如果符合查询条件,则添加到列表框控件中。</P><P align=justify>{</P><DIR><DIR></FONT><FONT size=3><P align=justify>theItem=ListView1-&gt;Items-&gt;Add();</P><P align=justify>theItem-&gt;Caption=AnsiString(strbufFileName).Trim();</P><P align=justify>theItem-&gt;SubItems-&gt;Add(AnsiString(strbufSongName).Trim());</P><P align=justify>theItem-&gt;SubItems-&gt;Add(AnsiString(strbufSingerName).Trim());</P><P align=justify>i++;</P></DIR></DIR></FONT><FONT face=宋体 size=3><P align=justify>}</P></DIR><P align=justify>}</P></DIR><P align=justify>}</P></FONT><FONT size=3><P align=justify>fclose(fp);</P></FONT><FONT face=宋体 size=3><P align=justify>}</P><P align=justify> </P><P align=justify>在本讲中我们学习了如何利用文件来保存记录集,以及如何从文件中读取记录信息,接着又为</FONT><FONT face="宋体, MS Song" size=3>Mp3Collect</FONT><FONT face=宋体 size=3>增加了查询显示的功能。到目前为此,围绕记录的操作已经介绍得差不多了,下一讲我们就来学习使用媒体操作器控件播放</FONT><FONT face="宋体, MS Song" size=3>MP3</FONT><FONT face=宋体 size=3>歌曲的方法,让</FONT><FONT face="宋体, MS Song" size=3>Mp3Collect</FONT><FONT face=宋体 size=3>变得“有声有色”。</P></FONT>
作者: 韩冰    时间: 2005-1-26 01:22
<b><FONT face=宋体 size=6> </FONT></b>< align=center>使用媒体播放器控件</P><FONT face=宋体 size=3>< align=justify>上一讲中我们学习了利用文件来保存记录以及从文件中读取记录的方法,想必读者朋友们已经动手实践过了。其实,心铃在上一讲中给出的源代码中留下了一个隐藏的问题,不知道是否有朋友发现了?这个问题是:按照目前的代码,当我们利用查询功能查询出部分记录后,再添加一个新的记录,就会发现文件中原有的部分记录(当前未显示的记录)丢失了。第七讲曾经介绍过,编程错误通常可分为语法错误、运行时错误和逻辑错误三种类型,逻辑错误往往会引起程序功能上的问题,同时也不容易发现,上一讲留下的问题就属于一种逻辑错误,究其原因,是因为我们暂时用</FONT><FONT face="宋体, MS Song" size=3>ListView</FONT><FONT face=宋体 size=3>控件来管理记录集,当查询功能执行后,</FONT><FONT face="宋体, MS Song" size=3>ListView</FONT><FONT face=宋体 size=3>控件中的记录数量就减少了,此后再执行添加功能时,</FONT><FONT face="宋体, MS Song" size=3>BtnAddSongClick</FONT><FONT face=宋体 size=3>调用</FONT><FONT face="宋体, MS Song" size=3>SaveFile</FONT><FONT face=宋体 size=3>只会把</FONT><FONT face="宋体, MS Song" size=3>ListView</FONT><FONT face=宋体 size=3>控件中的记录保存在文件中,从而造成记录丢失。</P>< align=justify>为了解决这一问题,可以在执行添加操作时先从文件中读取所有记录,然后再写回去,或者用一个专门的数据链表来管理记录集,这两种方法的具体实现就作为练习留给读者朋友自己来完成,在后面的讲座中,我们将改用数据库来管理记录集,从而解决上述问题。在本讲中,我们将要学习使用媒体播放器控件来播放</FONT><FONT face="宋体, MS Song" size=3>MP3</FONT><FONT face=宋体 size=3>歌曲的方法。</P><UL><B>< align=justify><LI>媒体播放器控件简介
0 C) h: G+ T3 A$ D, h& N& j</LI></UL></B></FONT><FONT size=3>< align=justify>CBuilder</FONT><FONT face=宋体 size=3>的媒体播放器控件是能够播放音频、视频等多种多媒体文件的控件,它的</FONT><FONT size=3>VCL</FONT><FONT face=宋体 size=3>封装类为</FONT><FONT size=3>TMediaPlayer</FONT><FONT face=宋体 size=3>。媒体播放器控件的工作原理是通过</FONT><FONT size=3>Windows</FONT><FONT face=宋体 size=3>的</FONT><FONT size=3>MCI</FONT><FONT face=宋体 size=3>接口来控制多媒体播放设备,它支持的媒体数据种类很多,如</FONT><FONT size=3>WAV</FONT><FONT face=宋体 size=3>文件、</FONT><FONT size=3>AVI</FONT><FONT face=宋体 size=3>文件、</FONT><FONT size=3>CD-ROM</FONT><FONT face=宋体 size=3>音乐、</FONT><FONT size=3>MIDI</FONT><FONT face=宋体 size=3>音乐,以及</FONT><FONT size=3>MP3</FONT><FONT face=宋体 size=3>音乐等等。</P>< align=justify>媒体播放器控件(图</FONT><FONT face="宋体, MS Song" size=3>11-1</FONT><FONT face=宋体 size=3>)由一系列按钮组成,其中包括:播放(</FONT><FONT face="宋体, MS Song" size=3>lay</FONT><FONT face=宋体 size=3>)、暂停(</FONT><FONT face="宋体, MS Song" size=3>ause</FONT><FONT face=宋体 size=3>)、停止(</FONT><FONT face="宋体, MS Song" size=3>Stop</FONT><FONT face=宋体 size=3>)、下一首(</FONT><FONT face="宋体, MS Song" size=3>Next</FONT><FONT face=宋体 size=3>)、前一首(</FONT><FONT face="宋体, MS Song" size=3>rev</FONT><FONT face=宋体 size=3>)、前进(</FONT><FONT face="宋体, MS Song" size=3>Step</FONT><FONT face=宋体 size=3>)、后退(</FONT><FONT face="宋体, MS Song" size=3>Back</FONT><FONT face=宋体 size=3>)、录制(</FONT><FONT face="宋体, MS Song" size=3>Record</FONT><FONT face=宋体 size=3>)、弹出(</FONT><FONT face="宋体, MS Song" size=3>Eject</FONT><FONT face=宋体 size=3>)等,用户可以通过这些按钮来控制媒体播放器的播放操作。</P>< align=justify>媒体播放器控件最主要的属性是</FONT><FONT face="宋体, MS Song" size=3>DeviceType</FONT><FONT face=宋体 size=3>和</FONT><FONT face="宋体, MS Song" size=3>FileName</FONT><FONT face=宋体 size=3>,其中</FONT><FONT face="宋体, MS Song" size=3>DeviceType</FONT><FONT face=宋体 size=3>指定要操作的媒体设备类型,这里的媒体设备可以是硬件设备也可以是软件驱动设备,例如</FONT><FONT face="宋体, MS Song" size=3>dtCDAudio</FONT><FONT face=宋体 size=3>表示</FONT><FONT face="宋体, MS Song" size=3>CD-ROM</FONT><FONT face=宋体 size=3>音乐播放设备,</FONT><FONT face="宋体, MS Song" size=3>dtVCR</FONT><FONT face=宋体 size=3>表示</FONT><FONT face="宋体, MS Song" size=3>WAV</FONT><FONT face=宋体 size=3>播放设备,如果不能确定媒体设备的类型,则可以设置此属性为</FONT><FONT face="宋体, MS Song" size=3>dtAutoSelect</FONT><FONT face=宋体 size=3>,媒体播放控件就会根据</FONT><FONT face="宋体, MS Song" size=3>FileName</FONT><FONT face=宋体 size=3>属性的文件类型来自动选择合适的播放设备。</FONT><FONT face="宋体, MS Song" size=3>FileName</FONT><FONT face=宋体 size=3>属性为</FONT><FONT face="宋体, MS Song" size=3>AnsiString</FONT><FONT face=宋体 size=3>类型的字符串,用来指定播放或录制的媒体文件名称。</P>< align=justify>设置了媒体播放器控件的</FONT><FONT face="宋体, MS Song" size=3>DeviceType</FONT><FONT face=宋体 size=3>和</FONT><FONT face="宋体, MS Song" size=3>FileName</FONT><FONT face=宋体 size=3>属性后,还需要打开该媒体设备,才能进行播放等操作。当媒体播放器控件的</FONT><FONT face="宋体, MS Song" size=3>AutoOpen</FONT><FONT face=宋体 size=3>属性为</FONT><FONT face="宋体, MS Song" size=3>true</FONT><FONT face=宋体 size=3>时,媒体设备会自动打开,该属性为</FONT><FONT face="宋体, MS Song" size=3>false</FONT><FONT face=宋体 size=3>时,程序中必须通过控件的</FONT><FONT face="宋体, MS Song" size=3>Open()</FONT><FONT face=宋体 size=3>方法来打开媒体播放设备。</P>< align=justify>如果打开媒体设备正确,用户就可以通过控件上的按钮进行播放、停止、前进、后退等操作,程序中也可以通过调用控件的方法,例如</FONT><FONT face="宋体, MS Song" size=3>lay()</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>Stop()</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>Step()</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>Back()</FONT><FONT face=宋体 size=3>等进行相同的操作。对于不同的媒体类型,用户可以进行的操作是不同的,例如,对</FONT><FONT face="宋体, MS Song" size=3>MP3</FONT><FONT face=宋体 size=3>音乐文件来说,录音、弹出等操作是无效的;即使对同一个媒体文件,在不同的状态下可进行的操作也不相同。如果设置媒体播放器控件的</FONT><FONT face="宋体, MS Song" size=3>AutoEnable</FONT><FONT face=宋体 size=3>属性为</FONT><FONT face="宋体, MS Song" size=3>true</FONT><FONT face=宋体 size=3>,则控件可以自己管理其上的</FONT><FONT face="宋体, MS Song" size=3>9</FONT><FONT face=宋体 size=3>个按钮是有效还是失效状态,如果该属性为</FONT><FONT face="宋体, MS Song" size=3>false</FONT><FONT face=宋体 size=3>,则程序中可以通过设置控件的</FONT><FONT face="宋体, MS Song" size=3>EnableButtons</FONT><FONT face=宋体 size=3>属性来决定哪些按钮有效。</P>< align=justify>媒体播放器控件既可以播放音频数据,也可以播放视频数据。如果播放的媒体文件中包含视频信息,则可以设置控件的</FONT><FONT face="宋体, MS Song" size=3>Display</FONT><FONT face=宋体 size=3>属性,作为视频信息的输出窗口。如果将</FONT><FONT face="宋体, MS Song" size=3>Display</FONT><FONT face=宋体 size=3>属性设为</FONT><FONT face="宋体, MS Song" size=3>NULL</FONT><FONT face=宋体 size=3>,则控件在播放视频文件时,会自动创建一个窗口用于视频输出。</P>< align=justify>上面简要介绍了媒体播放器控件的主要功能及其基本使用方法,下面我们就来学习如何在</FONT><FONT face="宋体, MS Song" size=3>Mp3Collect</FONT><FONT face=宋体 size=3>中使用媒体播放器控件。</P><UL><B>< align=justify><LI>设置属性 <p></LI></UL></B>< align=justify>使用媒体播放器控件之前,应该在编辑状态下设置好它的各项属性。首先设置控件的媒体类型属性</FONT><FONT face="宋体, MS Song" size=3>DeviceType</FONT><FONT face=宋体 size=3>为</FONT><FONT face="宋体, MS Song" size=3>dtAutoSelect</FONT><FONT face=宋体 size=3>,媒体播放器控件在</FONT><FONT face="宋体, MS Song" size=3>Mp3Collect</FONT><FONT face=宋体 size=3>中主要用于播放</FONT><FONT face="宋体, MS Song" size=3>MP3</FONT><FONT face=宋体 size=3>文件,由于</FONT><FONT face="宋体, MS Song" size=3>MP3</FONT><FONT face=宋体 size=3>文件格式较新,帮助文档中没有给出</FONT><FONT face="宋体, MS Song" size=3>MP3</FONT><FONT face=宋体 size=3>专用的媒体属性值,因此将</FONT><FONT face="宋体, MS Song" size=3>DeviceType</FONT><FONT face=宋体 size=3>设为</FONT><FONT face="宋体, MS Song" size=3>dtAutoSelect</FONT><FONT face=宋体 size=3>,只要是媒体播放器控件支持的,并且系统中又安装了相应驱动程序的媒体类型都可以适用。</P>< align=justify>由于</FONT><FONT face="宋体, MS Song" size=3>MP3</FONT><FONT face=宋体 size=3>文件名称需要在运行时根据用户的选择进行设定,因此我们在编辑时把媒体播放器控件的另一个重要属性</FONT><FONT face="宋体, MS Song" size=3>FileName</FONT><FONT face=宋体 size=3>设为空。媒体播放器控件是一个自动化程度较高的控件,可以设置其</FONT><FONT face="宋体, MS Song" size=3>AutoEnable</FONT><FONT face=宋体 size=3>属性为</FONT><FONT face="宋体, MS Song" size=3>true</FONT><FONT face=宋体 size=3>,让它在运行时自动响应用户的操作,自动管理各个按钮是否为有效状态。另外,设置控件的</FONT><FONT face="宋体, MS Song" size=3>AutoOpen</FONT><FONT face=宋体 size=3>属性为</FONT><FONT face="宋体, MS Song" size=3>false</FONT><FONT face=宋体 size=3>,取消其自动打开媒体设备的功能,由程序控制媒体设备的打开操作;并设置控件的</FONT><FONT face="宋体, MS Song" size=3>AutoRewind</FONT><FONT face=宋体 size=3>属性为</FONT><FONT face="宋体, MS Song" size=3>true</FONT><FONT face=宋体 size=3>,使一个</FONT><FONT face="宋体, MS Song" size=3>MP3</FONT><FONT face=宋体 size=3>文件播放完毕后可以自动回到文件头的位置。除此之外,其余的属性接受缺省值即可。</P><UL><B>< align=justify><LI>实现简单播放功能 <p></LI></UL></B>< align=justify>当用户在列表框中选中某一首</FONT><FONT face="宋体, MS Song" size=3>MP3</FONT><FONT face=宋体 size=3>音乐时,让媒体播放器控件打开该文件,如果打开成功,则控件上的相应按钮自动变为有效的状态,用户可以通过操作控件上的按钮,播放该</FONT><FONT face="宋体, MS Song" size=3>MP3</FONT><FONT face=宋体 size=3>音乐。这是最简单的播放功能的实现方法。在第九讲中曾介绍过显示当前选中记录的实现方法,我们就在此基础上,将当前选中记录的</FONT><FONT face="宋体, MS Song" size=3>MP3</FONT><FONT face=宋体 size=3>文件名赋给媒体播放器控件的</FONT><FONT face="宋体, MS Song" size=3>FileName</FONT><FONT face=宋体 size=3>属性,并调用其</FONT><FONT face="宋体, MS Song" size=3>Open()</FONT><FONT face=宋体 size=3>方法打开该文件,实现简单播放功能。另外,为了便于后面实现向前向后浏览和循环播放等功能,我们在</FONT><FONT face="宋体, MS Song" size=3>TMainForm</FONT><FONT face=宋体 size=3>类中添加成员变量</FONT><FONT face="宋体, MS Song" size=3>int m_CurPlayIndex</FONT><FONT face=宋体 size=3>,用于记录当前播放的文件序号,即当前播放的</FONT><FONT face="宋体, MS Song" size=3>MP3</FONT><FONT face=宋体 size=3>记录在</FONT><FONT face="宋体, MS Song" size=3>ListView1</FONT><FONT face=宋体 size=3>控件列表中的序号。打开当前选中的</FONT><FONT face="宋体, MS Song" size=3>MP3</FONT><FONT face=宋体 size=3>文件的代码如下所示:</P></FONT><FONT size=3>< align=justify>void __fastcall TMainForm:istView1SelectItem(TObject *Sender, TListItem *Item, bool Selected)</P>< align=justify>{</P>< align=justify>if(Item)</P>< align=justify>{</P><DIR>< align=justify>//</FONT><FONT face=宋体 size=3>将当前选中列表项的内容写入编辑框中</P><DIR>< align=justify>……(略)</P></DIR></FONT><FONT size=3>< align=justify>m_CurPlayIndex=Item-&gt;Index; //</FONT><FONT face=宋体 size=3>当前播放的文件序号为</FONT><FONT size=3>ListView1</FONT><FONT face=宋体 size=3>控件中的列表序号</P></FONT><FONT size=3>< align=justify>//</FONT><FONT face=宋体 size=3>把记录的文件名赋给媒体播放控件的</FONT><FONT size=3>FileName</FONT><FONT face=宋体 size=3>属性</P></FONT><FONT size=3>< align=justify>MediaPlayer1-&gt;FileName=edtFileName-&gt;Text;</P>< align=justify>MediaPlayer1-&gt;Open();//</FONT><FONT face=宋体 size=3>打开该</FONT><FONT size=3>MP3</FONT><FONT face=宋体 size=3>文件</P></DIR><P align=justify>}</P><P align=justify>}</P><UL><B><P align=justify><LI>实现向前、向后浏览功能 <p></LI></UL></B><P align=justify>接下来我们要实现向前向后浏览功能,即当用户点击媒体播放器控件的</FONT><FONT face="宋体, MS Song" size=3>Prev</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>Next</FONT><FONT face=宋体 size=3>按钮时,程序可以在</FONT><FONT face="宋体, MS Song" size=3>ListView1</FONT><FONT face=宋体 size=3>中向前或向后浏览并播放相应的</FONT><FONT face="宋体, MS Song" size=3>MP3</FONT><FONT face=宋体 size=3>文件。为了实现这一功能,我们需要处理用户点击媒体播放器按钮时所产生的</FONT><FONT face="宋体, MS Song" size=3>OnClick</FONT><FONT face=宋体 size=3>事件。通过对象浏览器添加该事件的处理函数</FONT><FONT face="宋体, MS Song" size=3>MediaPlayer1Click()</FONT><FONT face=宋体 size=3>,该函数的实现代码在下一小节中给出,这里先介绍一下它的编程思路。</P><P align=justify>事件处理函数</FONT><FONT face="宋体, MS Song" size=3>MediaPlayer1Click()</FONT><FONT face=宋体 size=3>有一个</FONT><FONT face="宋体, MS Song" size=3>TMPBtnType Button</FONT><FONT face=宋体 size=3>参数,它指出了用户点击的是哪一个按钮。当我们判断出用户点击了</FONT><FONT face="宋体, MS Song" size=3>Next</FONT><FONT face=宋体 size=3>按钮时,就让</FONT><FONT face="宋体, MS Song" size=3>m_CurPlayIndex</FONT><FONT face=宋体 size=3>加一,如果</FONT><FONT face="宋体, MS Song" size=3>m_CurPlayIndex</FONT><FONT face=宋体 size=3>的值超过了列表框控件中的记录总数,则让</FONT><FONT face="宋体, MS Song" size=3>m_CurPlayIndex</FONT><FONT face=宋体 size=3>等于</FONT><FONT face="宋体, MS Song" size=3>0</FONT><FONT face=宋体 size=3>。同样,当用户点击</FONT><FONT face="宋体, MS Song" size=3>Prev</FONT><FONT face=宋体 size=3>按钮时,就让</FONT><FONT face="宋体, MS Song" size=3>m_CurPlayIndex</FONT><FONT face=宋体 size=3>减一,如果</FONT><FONT face="宋体, MS Song" size=3>m_CurPlayIndex</FONT><FONT face=宋体 size=3>小于</FONT><FONT face="宋体, MS Song" size=3>0</FONT><FONT face=宋体 size=3>,则让</FONT><FONT face="宋体, MS Song" size=3>m_CurPlayIndex</FONT><FONT face=宋体 size=3>回到记录的尾部。</P><P align=justify>调整好</FONT><FONT face="宋体, MS Song" size=3>m_CurPlayIndex</FONT><FONT face=宋体 size=3>的值以后,我们再将其对应的</FONT><FONT face="宋体, MS Song" size=3>MP3</FONT><FONT face=宋体 size=3>文件名赋给媒体播放器控件的</FONT><FONT face="宋体, MS Song" size=3>FileName</FONT><FONT face=宋体 size=3>属性,并调用控件的</FONT><FONT face="宋体, MS Song" size=3>Open()</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>Play()</FONT><FONT face=宋体 size=3>方法来打开并播放该文件,这些播放操作统一在成员函数</FONT><FONT face="宋体, MS Song" size=3>PlayTheSong()</FONT><FONT face=宋体 size=3>中完成,其实现如下:</P></FONT><FONT size=3><P align=justify>void __fastcall TMainForm:layTheSong()</P></FONT><FONT face=宋体 size=3><P align=justify>{</P></FONT><FONT size=3><P align=justify>TListItem *theItem;</P><P align=justify>theItem=ListView1-&gt;Items-&gt;Item[m_CurPlayIndex];//</FONT><FONT face=宋体 size=3>获取</FONT><FONT size=3>m_CurPlayIndex</FONT><FONT face=宋体 size=3>对应的列表项</P></FONT><FONT size=3><P align=justify>edtFileName-&gt;Text=theItem-&gt;Caption;</P><P align=justify>edtSongName-&gt;Text=theItem-&gt;SubItems-&gt;Strings[0];</P><P align=justify>edtSingerName-&gt;Text=theItem-&gt;SubItems-&gt;Strings[1];</P><P align=justify>ListView1-&gt;Selected =theItem;//</FONT><FONT face=宋体 size=3>将</FONT><FONT size=3>m_CurPlayIndex</FONT><FONT face=宋体 size=3>对应的列表项设为当前选中项</P></FONT><FONT size=3><P align=justify>MediaPlayer1-&gt;FileName=theItem-&gt;Caption;</P><P align=justify>MediaPlayer1-&gt;Open();</P><P align=justify>MediaPlayer1-&gt;Play();</P></FONT><FONT face=宋体 size=3><P align=justify>}</P><UL><B><P align=justify><LI>实现循环播放功能 <p></LI></UL></B><P align=justify>循环播放是指当一个</FONT><FONT face="宋体, MS Song" size=3>MP3</FONT><FONT face=宋体 size=3>文件播放完毕后,媒体播放器控件自动跳到下一个</FONT><FONT face="宋体, MS Song" size=3>MP3</FONT><FONT face=宋体 size=3>文件,如此循环,直到用户按下</FONT><FONT face="宋体, MS Song" size=3>Stop</FONT><FONT face=宋体 size=3>按钮停止播放为止。</P><P align=justify>实现该功能的关键是怎样判断什么时候一个</FONT><FONT face="宋体, MS Song" size=3>MP3</FONT><FONT face=宋体 size=3>文件已播放完毕,心铃准备使用定时查询的方法来检测是否播放到了</FONT><FONT face="宋体, MS Song" size=3>MP3</FONT><FONT face=宋体 size=3>文件的尾部。定时查询的方法需要添加一个时钟控件</FONT><FONT face="宋体, MS Song" size=3>Timer1</FONT><FONT face=宋体 size=3>,该控件位于</FONT><FONT face="宋体, MS Song" size=3>System</FONT><FONT face=宋体 size=3>元件栏中,</FONT><FONT face="宋体, MS Song" size=3>VCL</FONT><FONT face=宋体 size=3>类为</FONT><FONT face="宋体, MS Song" size=3>TTimer</FONT><FONT face=宋体 size=3>。</FONT><FONT face="宋体, MS Song" size=3>Timer1</FONT><FONT face=宋体 size=3>控件在运行时是不可见的,但每隔一定的时间间隔便会产生定时事件</FONT><FONT face="宋体, MS Song" size=3>OnTimer</FONT><FONT face=宋体 size=3>。我们把</FONT><FONT face="宋体, MS Song" size=3>Timer1</FONT><FONT face=宋体 size=3>控件的时间间隔属性</FONT><FONT face="宋体, MS Song" size=3>Interval</FONT><FONT face=宋体 size=3>设为</FONT><FONT face="宋体, MS Song" size=3>200</FONT><FONT face=宋体 size=3>毫秒,</FONT><FONT face="宋体, MS Song" size=3>Enabled</FONT><FONT face=宋体 size=3>属性为</FONT><FONT face="宋体, MS Song" size=3>false</FONT><FONT face=宋体 size=3>,并添加定时事件处理函数</FONT><FONT face="宋体, MS Song" size=3>Timer1Timer()</FONT><FONT face=宋体 size=3>。</P><P align=justify>在</FONT><FONT face="宋体, MS Song" size=3>Timer1Timer()</FONT><FONT face=宋体 size=3>中,程序首先检查媒体播放器控件当前播放的位置</FONT><FONT face="宋体, MS Song" size=3>Position</FONT><FONT face=宋体 size=3>,将其与</FONT><FONT face="宋体, MS Song" size=3>MP3</FONT><FONT face=宋体 size=3>音乐的长度相比较,如果二者相等,则表示已经播放到了文件尾。再检测循环选项按钮</FONT><FONT face="宋体, MS Song" size=3>chkLoop</FONT><FONT face=宋体 size=3>是否处于选中状态,以及媒体播放器是否处于播放状态,如果这两个条件均符合,就打开并播放列表框中的下一个</FONT><FONT face="宋体, MS Song" size=3>MP3</FONT><FONT face=宋体 size=3>文件;否则表示播放结束,关闭时钟。事件处理函数</FONT><FONT face="宋体, MS Song" size=3>Timer1Timer()</FONT><FONT face=宋体 size=3>如下所示。</P></FONT><FONT size=3><P align=justify>void __fastcall TMainForm::Timer1Timer(TObject *Sender)</P><P align=justify>{</P><P align=justify>if(MediaPlayer1-&gt;Position == MediaPlayer1-&gt;Length)</P></FONT><FONT face=宋体 size=3><P align=justify>{</P><DIR></FONT><FONT size=3><P align=justify>//</FONT><FONT face=宋体 size=3>检测</FONT><FONT size=3>chkLoop</FONT><FONT face=宋体 size=3>是否处于选中状态,以及媒体播放器是否处于播放状态</P></FONT><FONT size=3><P align=justify>if(chkLoop-&gt;Checked &amp;&amp; m_bIsPlaying) //</FONT><FONT face=宋体 size=3>如果条件符合,则计算下一个</FONT><FONT size=3>MP3</FONT><FONT face=宋体 size=3>记录序号</P><P align=justify>{</P><DIR></FONT><FONT size=3><P align=justify>if(m_CurPlayIndex&lt;ListView1-&gt;Items-&gt;Count-1) m_CurPlayIndex++;</P><P align=justify>else m_CurPlayIndex=0;</P><P align=justify>PlayTheSong();//</FONT><FONT face=宋体 size=3>打开并播放该</FONT><FONT size=3>MP3</FONT><FONT face=宋体 size=3>文件</P></DIR><P align=justify>}</P></FONT><FONT size=3><P align=justify>else</P></FONT><FONT face=宋体 size=3><P align=justify>{</P><DIR></FONT><FONT size=3><P align=justify>EnableButtons(true);//</FONT><FONT face=宋体 size=3>使记录操作按钮有效</P></FONT><FONT size=3><P align=justify>Timer1-&gt;Enabled =false;//</FONT><FONT face=宋体 size=3>关闭时钟</P></DIR><P align=justify>}</P></DIR><P align=justify>}</P><P align=justify>}</P><P align=justify>其中,</FONT><FONT face="宋体, MS Song" size=3>EnableButtons()</FONT><FONT face=宋体 size=3>用来设置“添加”、“删除”、“修改”等记录操作按钮的状态。当媒体播放器控件正在播放时,为了避免因用户操作引起冲突,最好让这些记录操作按钮为无效状态,播放完毕后,再让它们有效。</FONT><FONT face="宋体, MS Song" size=3>EnableButtons()</FONT><FONT face=宋体 size=3>函数如下所示:</P></FONT><FONT size=3><P align=justify>void __fastcall TMainForm::EnableButtons(bool bEnable)</P><P align=justify>{</P><P align=justify>btnAdd-&gt;Enabled=bEnable;</P><P align=justify>btnDelete-&gt;Enabled=bEnable;</P><P align=justify>btnModify-&gt;Enabled=bEnable;</P><P align=justify>btnFind-&gt;Enabled =bEnable;</P><P align=justify>btnShowAll-&gt;Enabled=bEnable;</P></FONT><FONT face=宋体 size=3><P align=justify>}</P></FONT><FONT size=3><P align=justify>Timer1</FONT><FONT face=宋体 size=3>控件的初始状态是无效的,只有在播放期间是有效的。播放期间起始于用户按下</FONT><FONT size=3>Play</FONT><FONT face=宋体 size=3>按钮时,终止于用户按下</FONT><FONT size=3>Stop</FONT><FONT face=宋体 size=3>按钮,因此我们要在事件处理函数</FONT><FONT size=3>MediaPlayer1Click()</FONT><FONT face=宋体 size=3>中处理</FONT><FONT size=3>Play</FONT><FONT face=宋体 size=3>和</FONT><FONT size=3>Stop</FONT><FONT face=宋体 size=3>按钮的点击事件,分别打开和关闭</FONT><FONT size=3>Timer1</FONT><FONT face=宋体 size=3>。另外,我们还要在</FONT><FONT size=3>TMainForm</FONT><FONT face=宋体 size=3>类中添加了一个成员变量</FONT><FONT size=3>bool m_bIsPlaying</FONT><FONT face=宋体 size=3>,用来表示当前媒体播放器是否处于播放状态,设置和清除</FONT><FONT size=3>m_bIsPlaying</FONT><FONT face=宋体 size=3>的操作也都在</FONT><FONT size=3>MediaPlayer1Click()</FONT><FONT face=宋体 size=3>中完成。下面就是</FONT><FONT size=3>MediaPlayer1Click()</FONT><FONT face=宋体 size=3>的实现代码:</P></FONT><FONT size=3><P align=justify>void __fastcall TMainForm::MediaPlayer1Click(TObject *Sender,TMPBtnType Button,bool &amp;DoDefault)</P><P align=justify>{</P><P align=justify>switch(Button) //</FONT><FONT face=宋体 size=3>根据</FONT><FONT size=3>Button</FONT><FONT face=宋体 size=3>参数判断用户点击了什么按钮</P><P align=justify>{</P></FONT><FONT size=3><P align=justify>case btPlay: //</FONT><FONT face=宋体 size=3>如果为</FONT><FONT size=3>Play</FONT><FONT face=宋体 size=3>按钮,设置</FONT><FONT size=3>m_bIsPlaying</FONT><FONT face=宋体 size=3>标志、打开时钟、使记录操作按钮失效</P><DIR></FONT><FONT size=3><P align=justify>EnableButtons(false); //</FONT><FONT face=宋体 size=3>使记录操作按钮失效</P></FONT><FONT size=3><P align=justify>m_bIsPlaying=true; //</FONT><FONT face=宋体 size=3>设置</FONT><FONT size=3>m_bIsPlaying</FONT><FONT face=宋体 size=3>标志</P></FONT><FONT size=3><P align=justify>Timer1-&gt;Enabled=true;//</FONT><FONT face=宋体 size=3>打开时钟</P></FONT><FONT size=3><P align=justify>break;</P></DIR><P align=justify>case btStop: //</FONT><FONT face=宋体 size=3>如果为</FONT><FONT size=3>Stop</FONT><FONT face=宋体 size=3>按钮,清除</FONT><FONT size=3>m_bIsPlaying</FONT><FONT face=宋体 size=3>标志、关闭时钟、使记录操作按钮有效</P><DIR></FONT><FONT size=3><P align=justify>EnableButtons(true); //</FONT><FONT face=宋体 size=3>使记录操作按钮有效</P></FONT><FONT size=3><P align=justify>m_bIsPlaying=false; //</FONT><FONT face=宋体 size=3>清除</FONT><FONT size=3>m_bIsPlaying</FONT><FONT face=宋体 size=3>标志</P></FONT><FONT size=3><P align=justify>Timer1-&gt;Enabled=false; //</FONT><FONT face=宋体 size=3>关闭时钟</P></FONT><FONT size=3><P align=justify>break;</P></DIR><P align=justify>case Mplayer::btNext: //</FONT><FONT face=宋体 size=3>如果为</FONT><FONT size=3>Next</FONT><FONT face=宋体 size=3>按钮,播放下一个</FONT><FONT size=3>MP3</FONT><FONT face=宋体 size=3>文件</P><DIR></FONT><FONT size=3><P align=justify>EnableButtons(false);</P><P align=justify>//</FONT><FONT face=宋体 size=3>计算下一个</FONT><FONT size=3>MP3</FONT><FONT face=宋体 size=3>文件的记录序号</P></FONT><FONT size=3><P align=justify>if(m_CurPlayIndex&lt;ListView1-&gt;Items-&gt;Count-1) m_CurPlayIndex++;</P><P align=justify>else m_CurPlayIndex=0;</P><P align=justify>m_bIsPlaying=true;</P><P align=justify>DoDefault=false; //</FONT><FONT face=宋体 size=3>不执行缺省的按钮事件</P></FONT><FONT size=3><P align=justify>PlayTheSong();//</FONT><FONT face=宋体 size=3>执行打开和播放</FONT><FONT size=3>MP3</FONT><FONT face=宋体 size=3>文件等操作</P></FONT><FONT size=3><P align=justify>Timer1-&gt;Enabled=true; </P><P align=justify>break;</P></DIR><P align=justify>case Mplayer::btPrev: //</FONT><FONT face=宋体 size=3>如果为</FONT><FONT size=3>Next</FONT><FONT face=宋体 size=3>按钮,播放前一个</FONT><FONT size=3>MP3</FONT><FONT face=宋体 size=3>文件</P><DIR></FONT><FONT size=3><P align=justify>EnableButtons(false);</P><P align=justify>//</FONT><FONT face=宋体 size=3>计算前一个</FONT><FONT size=3>MP3</FONT><FONT face=宋体 size=3>文件的记录序号</P></FONT><FONT size=3><P align=justify>if(m_CurPlayIndex&gt;0) m_CurPlayIndex--;</P><P align=justify>else m_CurPlayIndex=ListView1-&gt;Items-&gt;Count-1;</P><P align=justify>m_bIsPlaying=true;</P><DIR><P align=justify>DoDefault=false;</P></DIR><P align=justify>PlayTheSong();</P><P align=justify>Timer1-&gt;Enabled=true;</P><P align=justify>break;</P></DIR></FONT><FONT face=宋体 size=3><P align=justify>}</P><P align=justify>}</P><B><P align=justify> </P></B><P align=justify>本讲中我们学习了如何使用媒体播放器控件来播放</FONT><FONT face="宋体, MS Song" size=3>MP3</FONT><FONT face=宋体 size=3>音乐,到目前为至,</FONT><FONT face="宋体, MS Song" size=3>Mp3Collect</FONT><FONT face=宋体 size=3>程序的大部分功能都已经实现了,下一讲中我们要为</FONT><FONT face="宋体, MS Song" size=3>Mp3Collect</FONT><FONT face=宋体 size=3>添加一些辅助功能,并学习有关界面设计更多的知识。另外,下一讲结束之后,心铃会把</FONT><FONT face="宋体, MS Song" size=3>Mp3Collect</FONT><FONT face=宋体 size=3>第一阶段的源程序以及讲座的部分电子文档放在主页上供朋友们下载,至于网址嘛,请看下回分解。</P></FONT>
作者: 韩冰    时间: 2005-1-26 01:24
<b><FONT face=宋体 size=6> </FONT></b>< align=center>进一步完善应用程序</P><FONT face=宋体 size=3>< align=justify>到上一讲为至,</FONT><FONT face="宋体, MS Song" size=3>Mp3Collect</FONT><FONT face=宋体 size=3>程序已经具有了记录、编辑、存取文件、查找记录、播放</FONT><FONT face="宋体, MS Song" size=3>MP3</FONT><FONT face=宋体 size=3>音乐等功能,基本上达到了我们的设计目标,但就操作方便程度而言,</FONT><FONT face="宋体, MS Song" size=3>Mp3Collect</FONT><FONT face=宋体 size=3>还有所欠缺,因此在本讲中,我们就来为</FONT><FONT face="宋体, MS Song" size=3>Mp3Collect</FONT><FONT face=宋体 size=3>添加一些辅助功能,使之更加完善。</P><UL><B>< align=justify><LI>实现排序功能 7 P: c5 S8 p5 h3 i8 p9 y- e3 t
</LI></UL></B>< align=justify>为</FONT><FONT face="宋体, MS Song" size=3>Mp3Collect</FONT><FONT face=宋体 size=3>添加排序功能之后,用户只要用鼠标点击记录列表框的某一列标题头,就可以以该项内容为基础按照字母排列顺序对记录进行排序,如果用户连续两次点击同一列,则可以在升序排列和降序排列之间切换。要实现这个功能,首先需要响应列表框的标题点击事件</FONT><FONT face="宋体, MS Song" size=3>OnColumnClick</FONT><FONT face=宋体 size=3>,在该事件处理函数中判断是哪一列的标题头被点击,并利用列表框控件的</FONT><FONT face="宋体, MS Song" size=3>AlphaSort()</FONT><FONT face=宋体 size=3>方法对列表框中的记录进行排序。</P></FONT><FONT size=3>< align=justify>AlphaSort()</FONT><FONT face=宋体 size=3>方法可以依据两种标准来进行排序,一是根据列表框控件的</FONT><FONT size=3>SortType</FONT><FONT face=宋体 size=3>属性,该属性支持按照列表项的</FONT><FONT size=3>Caption</FONT><FONT face=宋体 size=3>属性以及</FONT><FONT size=3>Data</FONT><FONT face=宋体 size=3>属性进行排序,而本程序中需要实现对任意一个子列进行排序,不能通过简单地设置</FONT><FONT size=3>SortType</FONT><FONT face=宋体 size=3>属性来实现,因此我们采用第二种方法,即为列表框控件添加</FONT><FONT size=3>OnCompare</FONT><FONT face=宋体 size=3>事件处理函数。添加了</FONT><FONT size=3>OnCompare</FONT><FONT face=宋体 size=3>事件处理函数之后,列表框控件在排序时会自动调用该函数来比较两个列表项的次序,并根据</FONT><FONT size=3>OnCompare</FONT><FONT face=宋体 size=3>返回的结果进行排序。</P>< align=justify>下面就是</FONT><FONT face="宋体, MS Song" size=3>ListView1</FONT><FONT face=宋体 size=3>控件的</FONT><FONT face="宋体, MS Song" size=3>OnColumnClick</FONT><FONT face=宋体 size=3>和</FONT><FONT face="宋体, MS Song" size=3>OnCompare</FONT><FONT face=宋体 size=3>两个事件的处理函数:</P></FONT><FONT size=3>< align=justify>//ListView1</FONT><FONT face=宋体 size=3>控件的</FONT><FONT size=3>OnCompare</FONT><FONT face=宋体 size=3>事件处理函数,其中参数</FONT><FONT size=3>Item1</FONT><FONT face=宋体 size=3>和</FONT><FONT size=3>Item2</FONT><FONT face=宋体 size=3>是进行比较的列表项,</P></FONT><FONT size=3>< align=justify>//</FONT><FONT face=宋体 size=3>通过参数</FONT><FONT size=3>Compare</FONT><FONT face=宋体 size=3>返回比较的结果。</P></FONT><FONT size=3>< align=justify>void __fastcall TMainForm:istView1Compare(TObject *Sender, TListItem *Item1, TListItem *Item2, int Data, int &amp;Compare)</P>< align=justify>{</P>< align=justify>if (ColumnToSort == 0)//</FONT><FONT face=宋体 size=3>如果</FONT><FONT size=3>ColumnToSort</FONT><FONT face=宋体 size=3>为</FONT><FONT size=3>0</FONT><FONT face=宋体 size=3>,则按列表项</FONT><FONT size=3>Caption</FONT><FONT face=宋体 size=3>属性进行比较</P><DIR></FONT><FONT size=3>< align=justify>Compare = CompareText(Item1-&gt;Caption,Item2-&gt;Caption);</P></DIR>< align=justify>else //</FONT><FONT face=宋体 size=3>如果</FONT><FONT size=3>ColumnToSort</FONT><FONT face=宋体 size=3>不为</FONT><FONT size=3>0</FONT><FONT face=宋体 size=3>,计算子列的序号,并按子列项进行比较</P>< align=justify>{</P><DIR></FONT><FONT size=3>< align=justify>int ix = ColumnToSort-1;</P>< align=justify>Compare = CompareText(Item1-&gt;SubItems-&gt;Strings[ix], Item2-&gt;SubItems-&gt;Strings[ix]);</P></DIR></FONT><FONT face=宋体 size=3>< align=justify>}</P></FONT><FONT size=3>< align=justify>//Tag</FONT><FONT face=宋体 size=3>属性为</FONT><FONT size=3>1</FONT><FONT face=宋体 size=3>时升序排列,为</FONT><FONT size=3>0</FONT><FONT face=宋体 size=3>时降序排列</P></FONT><FONT size=3>< align=justify>if(ListView1-&gt;Columns-&gt;Items[ColumnToSort]-&gt;Tag) Compare = -Compare;</P></FONT><FONT face=宋体 size=3>< align=justify>}</P></FONT><FONT size=3>< align=justify>//ListView1</FONT><FONT face=宋体 size=3>控件的</FONT><FONT size=3>OnColumnClick</FONT><FONT face=宋体 size=3>事件处理函数</P></FONT><FONT size=3>< align=justify>void __fastcall TMainForm:istView1ColumnClick(TObject *Sender, TListColumn *Column)</P>< align=justify>{</P>< align=justify>//</FONT><FONT face=宋体 size=3>如果是连接点击同一列,则切换该列的升、降序标志,否则记录新的排序列号</P></FONT><FONT size=3>< align=justify>if(ColumnToSort==Column-&gt;Index) Column-&gt;Tag = 1-Column-&gt;Tag; </P>< align=justify>else ColumnToSort = Column-&gt;Index;</P>< align=justify>//</FONT><FONT face=宋体 size=3>调用列表框控件的排序方法</P></FONT><FONT size=3>< align=justify>((TCustomListView *)Sender)-&gt;AlphaSort();</P></FONT><FONT face=宋体 size=3>< align=justify>}</P>< align=justify>我们在上述代码中使用了</FONT><FONT face="宋体, MS Song" size=3>TMainForm</FONT><FONT face=宋体 size=3>类的一个新成员变量</FONT><FONT face="宋体, MS Song" size=3>ColumnToSort</FONT><FONT face=宋体 size=3>,其类型为</FONT><FONT face="宋体, MS Song" size=3>int</FONT><FONT face=宋体 size=3>,用来存放当前准备排序的列号。另外,为了标志当前应该做升序排列还是降序排列,我们还用到了</FONT><FONT face="宋体, MS Song" size=3>VCL</FONT><FONT face=宋体 size=3>元件的一个常用属性:</FONT><FONT face="宋体, MS Song" size=3>Tag</FONT><FONT face=宋体 size=3>,该属性可以在元件对象中保存一个整数值,该属性的意义可以由程序自行进行解释,例如,窗体上有一组相同元件的多个对象时,就可以为各个对象赋予不同的</FONT><FONT face="宋体, MS Song" size=3>Tag</FONT><FONT face=宋体 size=3>属性值,以此来区分不同的对象。在本程序中,我们就是利用</FONT><FONT face="宋体, MS Song" size=3>TColumnItem</FONT><FONT face=宋体 size=3>对象(即列标框控件的子列标题)的</FONT><FONT face="宋体, MS Song" size=3>Tag</FONT><FONT face=宋体 size=3>属性来标志当前应该做升序排列还是降序排列,其初值为</FONT><FONT face="宋体, MS Song" size=3>0</FONT><FONT face=宋体 size=3>,即缺省操作为降序排列。</P><UL><B><P align=justify><LI>获取文件名对话框 <p></LI></UL></B><P align=justify>大家肯定注意到了,到目前为止,</FONT><FONT face="宋体, MS Song" size=3>Mp3Collect</FONT><FONT face=宋体 size=3>主界面上还有两个按钮的功能未实现,它们分别是“…”和“退出”按钮。其中“…”按钮是为了方便用户查找和获得文件名称而设计的,当用户点击该按钮(</FONT><FONT face="宋体, MS Song" size=3>btnFileName</FONT><FONT face=宋体 size=3>)时,</FONT><FONT face="宋体, MS Song" size=3>Mp3Collect</FONT><FONT face=宋体 size=3>就会弹出如图</FONT><FONT face="宋体, MS Song" size=3>12-1</FONT><FONT face=宋体 size=3>所示的获取文件名对话框,用户可以在其中浏览和查找所需要的文件。</P><P align=justify>图</FONT><FONT face="宋体, MS Song" size=3>12-1</FONT><FONT face=宋体 size=3>是一个典型的</FONT><FONT face="宋体, MS Song" size=3>Windows</FONT><FONT face=宋体 size=3>打开文件对话框,</FONT><FONT face="宋体, MS Song" size=3>Windows 95</FONT><FONT face=宋体 size=3>以上的操作系统为此功能提供了标准的对话框,</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>的</FONT><FONT face="宋体, MS Song" size=3>VCL</FONT><FONT face=宋体 size=3>库把该对话框封装成为了</FONT><FONT face="宋体, MS Song" size=3>OpenDialog</FONT><FONT face=宋体 size=3>控件,在程序中使用起来更为方便。</P><P align=justify>在第八讲中,我们已经在</FONT><FONT face="宋体, MS Song" size=3>Mp3Collect</FONT><FONT face=宋体 size=3>的窗体上添加了一个</FONT><FONT face="宋体, MS Song" size=3>OpenDialog</FONT><FONT face=宋体 size=3>控件,其对象名称为缺省值</FONT><FONT face="宋体, MS Song" size=3>OpenDialog1</FONT><FONT face=宋体 size=3>,现在我们来设置它的属性。</P><P align=justify>首先设置其</FONT><FONT face="宋体, MS Song" size=3>Title</FONT><FONT face=宋体 size=3>属性为“打开一个</FONT><FONT face="宋体, MS Song" size=3>MP3</FONT><FONT face=宋体 size=3>音乐”,接下来双击</FONT><FONT face="宋体, MS Song" size=3>Filter</FONT><FONT face=宋体 size=3>属性,设置文件类型过滤器。文件类型过滤器是指让对话框在浏览目录时只显示特定的文件类型,例如,如果我们希望对话框中只显示</FONT><FONT face="宋体, MS Song" size=3>MP3</FONT><FONT face=宋体 size=3>音乐文件,就可以设置其过滤器为“</FONT><FONT face="宋体, MS Song" size=3>*.MP3</FONT><FONT face=宋体 size=3>”,过滤器标题为“</FONT><FONT face="宋体, MS Song" size=3>MP3</FONT><FONT face=宋体 size=3>音乐”。设置过滤器的对话框如图</FONT><FONT face="宋体, MS Song" size=3>12-2</FONT><FONT face=宋体 size=3>所示,该对话框允许添加多个过滤器,我们在其中输入想要浏览的文件类型及相应的扩展名后,按下“</FONT><FONT face="宋体, MS Song" size=3>OK</FONT><FONT face=宋体 size=3>”按钮确定所作的设置。除了上述属性之外,</FONT><FONT face="宋体, MS Song" size=3>OpenDialog1</FONT><FONT face=宋体 size=3>控件的其它属性均采用缺省值。</P></FONT><FONT size=3><P align=justify>OpenDialog1</FONT><FONT face=宋体 size=3>控件在运行时一般是不可见的,只有程序调用它的</FONT><FONT size=3>Excute()</FONT><FONT face=宋体 size=3>方法时才会弹出图</FONT><FONT size=3>12-1</FONT><FONT face=宋体 size=3>的对话框,该对话框是模态对话框,即只有关闭对话框后,输入焦点才会回到父窗体中。如果用户选择一个文件并按下“打开”按钮,</FONT><FONT size=3>Excute()</FONT><FONT face=宋体 size=3>方法返回真,如果按“取消”按钮或直接关闭窗口,则</FONT><FONT size=3>Excute()</FONT><FONT face=宋体 size=3>返回假。当</FONT><FONT size=3>Excute()</FONT><FONT face=宋体 size=3>返回真时,通过</FONT><FONT size=3>OpenDialog1</FONT><FONT face=宋体 size=3>控件的</FONT><FONT size=3>FileName</FONT><FONT face=宋体 size=3>属性便可以获得用户选择的文件名。</P><P align=justify>需要进一步说明的是,</FONT><FONT face="宋体, MS Song" size=3>OpenDialog</FONT><FONT face=宋体 size=3>控件不仅支持选择单个文件也支持同时选中多个文件,其</FONT><FONT face="宋体, MS Song" size=3>Options</FONT><FONT face=宋体 size=3>属性中的标志</FONT><FONT face="宋体, MS Song" size=3>ofAllowMultiSelect</FONT><FONT face=宋体 size=3>可以决定允许单选还是多选。在“…”按钮启动的浏览功能中,我们采用缺省的单选方式,在本讲的后面,心铃还会介绍</FONT><FONT face="宋体, MS Song" size=3>OpenDialog</FONT><FONT face=宋体 size=3>控件多选方式的使用方法。</P><P align=justify>下面是</FONT><FONT face="宋体, MS Song" size=3>btnFileName</FONT><FONT face=宋体 size=3>按钮的事件处理函数</FONT><FONT face="宋体, MS Song" size=3>btnFileNameClick</FONT><FONT face=宋体 size=3>:</P></FONT><FONT size=3><P align=justify>void __fastcall TMainForm::btnFileNameClick(TObject *Sender)</P><P align=justify>{</P><P align=justify>if(OpenDialog1-&gt;Execute()) //</FONT><FONT face=宋体 size=3>调出打开文件对话框</P><P align=justify>{</P><DIR></FONT><FONT size=3><P align=justify>//</FONT><FONT face=宋体 size=3>从</FONT><FONT size=3>OpenDialog1</FONT><FONT face=宋体 size=3>控件的</FONT><FONT size=3>FileName</FONT><FONT face=宋体 size=3>属性中获取用户选择的文件名</P></FONT><FONT size=3><P align=justify>//</FONT><FONT face=宋体 size=3>并将获取的文件名赋给</FONT><FONT size=3>edtFileName</FONT><FONT face=宋体 size=3>编辑框</P></FONT><FONT size=3><P align=justify>edtFileName-&gt;Text=OpenDialog1-&gt;FileName;</P><P align=justify>//</FONT><FONT face=宋体 size=3>把文件名的路径部分和扩展名部分去除,生成缺省的歌曲名称,</P></FONT><FONT size=3><P align=justify>edtSongName-&gt;Text=ChangeFileExt(ExtractFileName(OpenDialog1-&gt;FileName),"");</P><P align=justify>edtSingerName-&gt;Text="";</P><P align=justify>//</FONT><FONT face=宋体 size=3>在</FONT><FONT size=3>MediaPlayer1</FONT><FONT face=宋体 size=3>控件中打开该文件,可以让用户试听音乐的效果</P></FONT><FONT size=3><P align=justify>MediaPlayer1-&gt;FileName=OpenDialog1-&gt;FileName;</P><P align=justify>MediaPlayer1-&gt;Open();</P></DIR></FONT><FONT face=宋体 size=3><P align=justify>}</P><P align=justify>}</P><P align=justify>实现了文件浏览功能后,程序会出现一个新的问题,就是</FONT><FONT face="宋体, MS Song" size=3>OpenDialog1</FONT><FONT face=宋体 size=3>对话框在浏览文件时会改变程序的工作目录,随后保存记录文件及读取记录文件时就会到错误的目录下打开文件。</P><P align=justify>解决这个问题的方法很简单:只要在</FONT><FONT face="宋体, MS Song" size=3>TMainForm</FONT><FONT face=宋体 size=3>类中添加一个新的成员变量</FONT><FONT face="宋体, MS Song" size=3>AnsiString m_PathName</FONT><FONT face=宋体 size=3>,并为</FONT><FONT face="宋体, MS Song" size=3>MainForm</FONT><FONT face=宋体 size=3>窗体添加</FONT><FONT face="宋体, MS Song" size=3>OnCreate</FONT><FONT face=宋体 size=3>事件处理函数,在其中添加初始化代码</FONT><FONT face="宋体, MS Song" size=3>m_PathName=GetCurrentDir()</FONT><FONT face=宋体 size=3>;然后用成员变量</FONT><FONT face="宋体, MS Song" size=3>m_PathName</FONT><FONT face=宋体 size=3>代替保存记录文件以及读取记录文件代码中对</FONT><FONT face="宋体, MS Song" size=3>GetCurrentDir()</FONT><FONT face=宋体 size=3>的调用。</P><P align=justify>这个问题告诉我们,在程序开发过程中,有时添加一个新功能可能会与已经实现的功能产生冲突,这一方面要求我们认真规划好程序开发的每一步,在程序设计时尽量考虑周到,避免前后矛盾的地方,另一方面说明了测试工作相当重要,只要可能,应在完成一项功能后就测试一项,尽可能早地发现错误并进行改正。</P><UL><B><P align=justify><LI>添加右键关联菜单 <p></LI></UL></B><P align=justify>在使用</FONT><FONT face="宋体, MS Song" size=3>Windows</FONT><FONT face=宋体 size=3>以及</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>集成开发环境的过程中,我们已经深刻感受到了关联菜单的重要性和灵活性,下面心铃就来介绍一下如何为</FONT><FONT face="宋体, MS Song" size=3>Mp3Collect</FONT><FONT face=宋体 size=3>程序添加关联菜单。</P><P align=justify>首先在</FONT><FONT face="宋体, MS Song" size=3>Standard</FONT><FONT face=宋体 size=3>元件栏中找到弹出式菜单控件(</FONT><FONT face="宋体, MS Song" size=3>PopupMenu</FONT><FONT face=宋体 size=3>),为窗体添加一个</FONT><FONT face="宋体, MS Song" size=3>PopupMenu</FONT><FONT face=宋体 size=3>控件,其名称为</FONT><FONT face="宋体, MS Song" size=3>PopupMenu1</FONT><FONT face=宋体 size=3>,然后双击</FONT><FONT face="宋体, MS Song" size=3>PopupMenu1</FONT><FONT face=宋体 size=3>,调出如图</FONT><FONT face="宋体, MS Song" size=3>12-3</FONT><FONT face=宋体 size=3>所示的菜单编辑器。</P><P align=justify>初次打开菜单编辑器时,它会在编辑对象(即</FONT><FONT face="宋体, MS Song" size=3>PopupMenu1</FONT><FONT face=宋体 size=3>菜单)中自动生成一个新的菜单项,对象浏览器也会自动显示出该菜单项的属性。我们在对象浏览器中设置新菜单项的</FONT><FONT face="宋体, MS Song" size=3>Name</FONT><FONT face=宋体 size=3>属性为</FONT><FONT face="宋体, MS Song" size=3>mnuAdd</FONT><FONT face=宋体 size=3>,</FONT><FONT face="宋体, MS Song" size=3>Caption</FONT><FONT face=宋体 size=3>属性为“添加多个记录”,表示用户选择该菜单命令时,可以调用前面讲过的</FONT><FONT face="宋体, MS Song" size=3>OpenDialog</FONT><FONT face=宋体 size=3>对话框,一次性获取并添加多条</FONT><FONT face="宋体, MS Song" size=3>MP3</FONT><FONT face=宋体 size=3>文件记录。</P><P align=justify>设置好一个菜单项并确定后,菜单编辑器会自动生成一个新的菜单项。我们按照同样的方法生成三个新的菜单项,其属性分别为:第二菜单项的</FONT><FONT face="宋体, MS Song" size=3>Name</FONT><FONT face=宋体 size=3>属性为</FONT><FONT face="宋体, MS Song" size=3>mnuDelete</FONT><FONT face=宋体 size=3>,</FONT><FONT face="宋体, MS Song" size=3>Caption</FONT><FONT face=宋体 size=3>属性为“删除”(即删除一条记录);第三菜单项为一个分隔条,设置分隔条的方法很简单,只要将其“</FONT><FONT face="宋体, MS Song" size=3>Caption</FONT><FONT face=宋体 size=3>”属性设为“-”即可;第四菜单项的</FONT><FONT face="宋体, MS Song" size=3>Name</FONT><FONT face=宋体 size=3>属性为</FONT><FONT face="宋体, MS Song" size=3>mnuSort</FONT><FONT face=宋体 size=3>,</FONT><FONT face="宋体, MS Song" size=3>Caption</FONT><FONT face=宋体 size=3>属性为“排列”。</P><P align=justify>第四菜单为级联式菜单,即它的下一层还有子菜单。创建子菜单的方法是在菜单编辑器中选中该菜单项,弹出右键关联菜单,并选择其中的“</FONT><FONT face="宋体, MS Song" size=3>Create SubMenu</FONT><FONT face=宋体 size=3>”命令即可。我们在“排列”的下一层子菜单要添加三个菜单项,它们的</FONT><FONT face="宋体, MS Song" size=3>Name</FONT><FONT face=宋体 size=3>和</FONT><FONT face="宋体, MS Song" size=3>Caption</FONT><FONT face=宋体 size=3>属性分别为:</FONT><FONT face="宋体, MS Song" size=3>mnuSortByFileName</FONT><FONT face=宋体 size=3>(“按文件名”)、</FONT><FONT face="宋体, MS Song" size=3>mnuSortBySongName</FONT><FONT face=宋体 size=3>(“按歌曲名称”)、</FONT><FONT face="宋体, MS Song" size=3>mnuSortBySingerName</FONT><FONT face=宋体 size=3>(“按歌手名称”)。</P><P align=justify>设计好关联菜单控件</FONT><FONT face="宋体, MS Song" size=3>PopupMenu1</FONT><FONT face=宋体 size=3>,接下来我们要把它与某个控件关联起来。大部分可视的</FONT><FONT face="宋体, MS Song" size=3>VCL</FONT><FONT face=宋体 size=3>元件都具有</FONT><FONT face="宋体, MS Song" size=3>PopupMenu</FONT><FONT face=宋体 size=3>属性,利用该属性可以为元件指定一个关联菜单对象,运行时,用户在该元件区域内点击右键,就会弹出相应的关联菜单。按照这一方法,我们将</FONT><FONT face="宋体, MS Song" size=3>ListView1</FONT><FONT face=宋体 size=3>的</FONT><FONT face="宋体, MS Song" size=3>PopupMenu</FONT><FONT face=宋体 size=3>属性设为</FONT><FONT face="宋体, MS Song" size=3>PopupMenu1</FONT><FONT face=宋体 size=3>,即让设计好的弹出式菜单与列表框控件</FONT><FONT face="宋体, MS Song" size=3>ListView1</FONT><FONT face=宋体 size=3>相关联。</P><P align=justify>最后要完成菜单命令的事件处理函数,大家应该已经注意到了,</FONT><FONT face="宋体, MS Song" size=3>PopupMenu1</FONT><FONT face=宋体 size=3>中的菜单命令所完成的大部分功能都已经在前面介绍过了,因此心铃在这里只介绍其中“添加多条记录”菜单命令的实现方法,其余的几个命令处理函数就作为练习由读者朋友自己来完成吧。</P><P align=justify>我们在菜单编辑器中双击</FONT><FONT face="宋体, MS Song" size=3>mnuAdd</FONT><FONT face=宋体 size=3>菜单项,由</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>自动生成该菜单的命令处理函数</FONT><FONT face="宋体, MS Song" size=3>mnuAddClick()</FONT><FONT face=宋体 size=3>的框架。该处理函数完成的功能是这样的,首先调出文件浏览对话框,允许用户一次选择多个文件,然后再将这些文件逐条添加到</FONT><FONT face="宋体, MS Song" size=3>MP3</FONT><FONT face=宋体 size=3>记录集中。下面是</FONT><FONT face="宋体, MS Song" size=3>mnuAddClick</FONT><FONT face=宋体 size=3>函数的代码。</P></FONT><FONT size=3><P align=justify>void __fastcall TMainForm::mnuAddClick(TObject *Sender)</P><P align=justify>{</P><P align=justify>int i;</P><P align=justify>TListItem * newItem;</P><P align=justify>//</FONT><FONT face=宋体 size=3>设置打开文件对话框的属性,使其能够一次选中多个文件</P></FONT><FONT size=3><P align=justify>OpenDialog1-&gt;Options.Clear();</P><P align=justify>OpenDialog1-&gt;Options&lt;&lt;ofAllowMultiSelect&lt;&lt; ofFileMustExist&lt;&lt; ofHideReadOnly;</P><P align=justify>OpenDialog1-&gt;Title="</FONT><FONT face=宋体 size=3>选择多个</FONT><FONT size=3>MP3</FONT><FONT face=宋体 size=3>音乐</FONT><FONT size=3>";</P><P align=justify>if(OpenDialog1-&gt;Execute())//</FONT><FONT face=宋体 size=3>运行打开文件对话框,获取多个</FONT><FONT size=3>MP3</FONT><FONT face=宋体 size=3>文件名</P><P align=justify>{</P><DIR></FONT><FONT size=3><P align=justify>AnsiString InputString = InputBox("</FONT><FONT face=宋体 size=3>歌手名称</FONT><FONT size=3>", "</FONT><FONT face=宋体 size=3>请输入歌手名称</FONT><FONT size=3>", "");</P><P align=justify>for(i=0;i&lt;OpenDialog1-&gt;Files-&gt;Count ;i++)</P><P align=justify>{</P><DIR><P align=justify>newItem=ListView1-&gt;Items-&gt;Add();</P><P align=justify>newItem-&gt;Caption = OpenDialog1-&gt;Files-&gt;Strings;</P><P align=justify>newItem-&gt;SubItems-&gt;Add(ChangeFileExt(ExtractFileName(</P><DIR><DIR><DIR><P align=justify>OpenDialog1-&gt;Files-&gt;Strings.c_str()),""));</P></DIR></DIR></DIR><P align=justify>newItem-&gt;SubItems-&gt;Add(InputString);</P></DIR></FONT><FONT face=宋体 size=3><P align=justify>}</P></FONT><FONT size=3><P align=justify>SaveFile();</P></DIR></FONT><FONT face=宋体 size=3><P align=justify>}</P></FONT><FONT size=3><P align=justify>//</FONT><FONT face=宋体 size=3>恢复</FONT><FONT size=3>OpenDialog1</FONT><FONT face=宋体 size=3>原来的属性设置</P></FONT><FONT size=3><P align=justify>OpenDialog1-&gt;Title="</FONT><FONT face=宋体 size=3>打开一个</FONT><FONT size=3>MP3</FONT><FONT face=宋体 size=3>音乐</FONT><FONT size=3>";</P><P align=justify>OpenDialog1-&gt;Options.Clear();</P><P align=justify>OpenDialog1-&gt;Options&lt;&lt; ofFileMustExist&lt;&lt; ofHideReadOnly; //</FONT><FONT face=宋体 size=3>此处“</FONT><FONT size=3>&lt;&lt;</FONT><FONT face=宋体 size=3>”不是移位操作符</P><P align=justify>}</P><UL><B><P align=justify><LI>退出功能 <p></LI></UL></B><P align=justify>退出功能实现起来非常简单。关闭一个应用程序有很多种方法,它们的原理主要是关闭主窗口或结束消息循环。对</FONT><FONT face="宋体, MS Song" size=3>Mp3Collect</FONT><FONT face=宋体 size=3>来说,只要关闭主窗体</FONT><FONT face="宋体, MS Song" size=3>MainForm</FONT><FONT face=宋体 size=3>,就可以退出整个程序的运行。因此在“退出”按钮的事件处理函数中我们只要简单地调用</FONT><FONT face="宋体, MS Song" size=3>Close()</FONT><FONT face=宋体 size=3>方法就可以了。</P><P align=justify> </P><P align=justify>本讲中我们又为</FONT><FONT face="宋体, MS Song" size=3>Mp3Collect</FONT><FONT face=宋体 size=3>添加了一些功能,让它使用起来更加方便,同时我们还学习了</FONT><FONT face="宋体, MS Song" size=3>PopupMenu</FONT><FONT face=宋体 size=3>和</FONT><FONT face="宋体, MS Song" size=3>OpenDialog</FONT><FONT face=宋体 size=3>两种新控件的使用方法,其实,熟练掌握各种元件的使用方法是学习</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>编程的关键点之一,朋友们要想提高</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>编程的水平,除了学习讲座中讲解的内容以外,还要自己多做练习,努力用好</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>的各种元件。</P></FONT><FONT size=3><P align=justify>CBuilder</FONT><FONT face=宋体 size=3>讲座已经过半了,心铃把讲座的电子文档以及第一阶段的源代码上传到了一位朋友的主页上,地址是:</FONT><a href="http://windwind.home.china.com/" target="_blank" ><FONT size=3>http://windwind.home.china.com</FONT></A><FONT face=宋体 size=3>,需要的朋友可以去下载,如果有什么问题,欢迎朋友们来信指教。</P></FONT>
作者: 韩冰    时间: 2005-1-26 01:28
<b><FONT face=宋体 size=6> </FONT></b>< align=center>异常处理</P><FONT face=宋体 size=3>< align=justify>在程序设计过程中,我们不仅仅要考虑如何实现程序的功能,还要防止可能出现的异常情况,所谓异常情况就是指在程序运行过程中出现的不正常或不可预料的情况,例如打开的文件不存在、不能分配所需的内存等等。特别是当一个软件要面向大量用户时,它所遇到的运行情况可能千差万别,如果不能够应付各种异常情况,其功能再好再强大也难以弥被这样的缺陷。本讲要介绍的就是如何在</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>中实现异常处理,并为</FONT><FONT face="宋体, MS Song" size=3>Mp3Collect</FONT><FONT face=宋体 size=3>添加异常处理代码。</P><UL><B>< align=justify><LI>传统的异常处理方法 3 {' T" g2 [7 N) p' t
</LI></UL></B>< align=justify>为了应付可能出现的不正常情况,传统的方法主要是通过条件判断语句来检查是否产生异常的事件。例如,在</FONT><FONT face="宋体, MS Song" size=3>MP3Collect</FONT><FONT face=宋体 size=3>程序的</FONT><FONT face="宋体, MS Song" size=3>SaveFile</FONT><FONT face=宋体 size=3>函数中,我们添加了如下的条件语句,以处理可能产生的打开文件错误:</P></FONT><FONT size=3>< align=justify>if(fp==NULL)</P></FONT><FONT face=宋体 size=3>< align=justify>{</P><DIR></FONT><FONT size=3>< align=justify>ShowMessage("</FONT><FONT face=宋体 size=3>不能打开文件</FONT><FONT size=3>Mp3Collect.sav</FONT><FONT face=宋体 size=3>,请检查是否为共享冲突</FONT><FONT size=3>");</P>< align=justify>return;</P></FONT><FONT face=宋体 size=3>< align=justify>}</P></DIR>< align=justify>在检测到了异常事件后,一般需要做两件事,一是显示错误的信息,例如以上代码中对</FONT><FONT face="宋体, MS Song" size=3>ShowMessage()</FONT><FONT face=宋体 size=3>函数的调用,再一个就是中断程序原有的执行流程,因为异常的发生已经使得程序无法满足继续执行原有流程的条件,在</FONT><FONT face="宋体, MS Song" size=3>SaveFile()</FONT><FONT face=宋体 size=3>函数中,如果文件打开失败,就不能继续后面的写文件操作,因此在异常处理中用</FONT><FONT face="宋体, MS Song" size=3>return</FONT><FONT face=宋体 size=3>语句直接返回,中断了保存文件的操作。</P>< align=justify>这种异常处理的方法当然最容易理解,但在大型的软件开发项目中,需要考虑的异常情况非常多,如果每个地方都使用</FONT><FONT face="宋体, MS Song" size=3>if</FONT><FONT face=宋体 size=3>语句来检查错误并处理异常,就会使编程工作变得非常繁杂,源代码的可读性也会大大降低。为了解决这一问题,人们在面向对象编程中找到了更加结构化和更简便的方法来实现异常处理。</P><UL></FONT><B><FONT size=3>< align=justify><LI>CBuilder</FONT><FONT face=宋体 size=3>中的异常处理机制 <p></LI></UL></B></FONT><FONT size=3>< align=justify>CBuilder</FONT><FONT face=宋体 size=3>支持多种异常处理机制,其中包括符合</FONT><FONT size=3>ANSI</FONT><FONT face=宋体 size=3>标准的</FONT><FONT size=3>C++</FONT><FONT face=宋体 size=3>异常处理机制,微软公司提供的</FONT><FONT size=3>Win32</FONT><FONT face=宋体 size=3>结构化异常处理机制,以及基于</FONT><FONT size=3>VCL</FONT><FONT face=宋体 size=3>的异常处理机制,后者是</FONT><FONT size=3>Borland</FONT><FONT face=宋体 size=3>公司建议在</FONT><FONT size=3>CBuilder</FONT><FONT face=宋体 size=3>编程中采用的异常处理方式。</P>< align=justify>基于</FONT><FONT face="宋体, MS Song" size=3>VCL</FONT><FONT face=宋体 size=3>的典型异常处理结构的形式如下所示</FONT><FONT size=3><FONT face="宋体, MS Song">:</FONT></P><DIR>< align=justify>try{</P>< align=justify>//</FONT><FONT face=宋体 size=3>可能引起异常的代码段</P>< align=justify>}</P></FONT><FONT size=3>< align=justify>catch</FONT><FONT face=宋体 size=3>(</FONT><FONT size=3>Exception &amp;e</FONT><FONT face=宋体 size=3>){</P></FONT><FONT size=3>< align=justify>//</FONT><FONT face=宋体 size=3>对异常进行处理的代码</P>< align=justify>}</P></DIR>< align=justify>其中</FONT><FONT face="宋体, MS Song" size=3>try</FONT><FONT face=宋体 size=3>和</FONT><FONT face="宋体, MS Song" size=3>catch</FONT><FONT face=宋体 size=3>为</FONT><FONT face="宋体, MS Song" size=3>C++</FONT><FONT face=宋体 size=3>关键字。</FONT><FONT face="宋体, MS Song" size=3>try</FONT><FONT face=宋体 size=3>用于标志可能产生异常的代码段(</FONT><FONT face="宋体, MS Song" size=3>Block</FONT><FONT face=宋体 size=3>),该代码段用</FONT><FONT face="宋体, MS Song" size=3>try</FONT><FONT face=宋体 size=3>后紧跟的一对大括号{}包括在内。如果这段程序在运行时产生了异常,系统会中止</FONT><FONT face="宋体, MS Song" size=3>try</FONT><FONT face=宋体 size=3>代码段中的代码执行,并查找相应的</FONT><FONT face="宋体, MS Song" size=3>catch</FONT><FONT face=宋体 size=3>代码段,如果找到了合适的</FONT><FONT face="宋体, MS Song" size=3>catch</FONT><FONT face=宋体 size=3>代码段,即表示错误被捕捉到,这时相应的</FONT><FONT face="宋体, MS Song" size=3>catch</FONT><FONT face=宋体 size=3>代码段被执行,如果没有找到合适的</FONT><FONT face="宋体, MS Song" size=3>catch</FONT><FONT face=宋体 size=3>代码段,即错误始终没有被捕捉到,则系统会调用</FONT><FONT face="宋体, MS Song" size=3>VCL</FONT><FONT face=宋体 size=3>库按照缺省的方法来处理异常。当然,如果</FONT><FONT face="宋体, MS Song" size=3>try</FONT><FONT face=宋体 size=3>代码段在运行时一切正常,则</FONT><FONT face="宋体, MS Song" size=3>catch</FONT><FONT face=宋体 size=3>代码段是不会被调用的。</P>< align=justify>在上面的异常处理结构中,我们看到,</FONT><FONT face="宋体, MS Song" size=3>catch</FONT><FONT face=宋体 size=3>语句带有一个参数</FONT><FONT face="宋体, MS Song" size=3>Exception &amp;e</FONT><FONT face=宋体 size=3>,该参数是一个异常对象的引用。其中</FONT><FONT face="宋体, MS Song" size=3>Exception</FONT><FONT face=宋体 size=3>是</FONT><FONT face="宋体, MS Song" size=3>VCL</FONT><FONT face=宋体 size=3>库提供的异常处理类,该类代表了</FONT><FONT face="宋体, MS Song" size=3>VCL</FONT><FONT face=宋体 size=3>库对异常事件的一个封装。也许有的朋友要问,</FONT><FONT face="宋体, MS Song" size=3>catch</FONT><FONT face=宋体 size=3>语句中的</FONT><FONT face="宋体, MS Song" size=3>Exception &amp;e</FONT><FONT face=宋体 size=3>对象是哪里来的呢?整个程序代码中没有该对象的声明或定义呀?这正是</FONT><FONT face="宋体, MS Song" size=3>VCL</FONT><FONT face=宋体 size=3>异常处理机制的特点,当异常产生时,</FONT><FONT face="宋体, MS Song" size=3>VCL</FONT><FONT face=宋体 size=3>库会自动生成该异常对象,并将其作为参数调用合适的</FONT><FONT face="宋体, MS Song" size=3>catch</FONT><FONT face=宋体 size=3>代码段。</P></FONT><FONT size=3>< align=justify>Exception</FONT><FONT face=宋体 size=3>类也是其它</FONT><FONT size=3>VCL</FONT><FONT face=宋体 size=3>异常处理类的基类。为了处理不同的异常原因,</FONT><FONT size=3>CBuilder</FONT><FONT face=宋体 size=3>提供了多种异常处理类,例如,代表申请内存失败的</FONT><FONT size=3>EOutOfMemory</FONT><FONT face=宋体 size=3>异常,代表除数为</FONT><FONT size=3>0</FONT><FONT face=宋体 size=3>的</FONT><FONT size=3>EDivByZero</FONT><FONT face=宋体 size=3>异常,代表文件打开错误的</FONT><FONT size=3>EFOpenError</FONT><FONT face=宋体 size=3>,代表数据库操作错误的</FONT><FONT size=3>EDatabaseError</FONT><FONT face=宋体 size=3>,以及代表多媒体操作错误的</FONT><FONT size=3>EMCIDeviceError</FONT><FONT face=宋体 size=3>等。</P>< align=justify>事实上,一个代码块可能产生不止一种类型的错误,这样,对一个</FONT><FONT face="宋体, MS Song" size=3>try</FONT><FONT face=宋体 size=3>代码段可以采用多个</FONT><FONT face="宋体, MS Song" size=3>catch</FONT><FONT face=宋体 size=3>代码段。例如,一个</FONT><FONT face="宋体, MS Song" size=3>try</FONT><FONT face=宋体 size=3>代码段内部可能产生申请内存失败异常</FONT><FONT face="宋体, MS Song" size=3>EOutOfMemory</FONT><FONT face=宋体 size=3>和打开文件错误</FONT><FONT face="宋体, MS Song" size=3>EFOpenError</FONT><FONT face=宋体 size=3>,那么我们可以使用两个</FONT><FONT face="宋体, MS Song" size=3>catch</FONT><FONT face=宋体 size=3>语句来分别监视两种异常情况。采用多个</FONT><FONT face="宋体, MS Song" size=3>catch</FONT><FONT face=宋体 size=3>语句的优点在于,可以对不同类型的异常分别进行捕捉和处理,但有时即使使用了多个</FONT><FONT face="宋体, MS Song" size=3>catch</FONT><FONT face=宋体 size=3>语句后仍无法保证能够捕捉到所有的异常,这时可以使用参数为省略号</FONT><FONT face="宋体, MS Song" size=3>(...)</FONT><FONT face=宋体 size=3>的通用</FONT><FONT face="宋体, MS Song" size=3>catch</FONT><FONT face=宋体 size=3>语句,它可以捕捉尚未捕捉的所有任意类型的异常。</P>< align=justify>下面是使用多个</FONT><FONT face="宋体, MS Song" size=3>catch</FONT><FONT face=宋体 size=3>及通用</FONT><FONT face="宋体, MS Song" size=3>catch</FONT><FONT face=宋体 size=3>语句的典型例子,</FONT><FONT face="宋体, MS Song" size=3>try</FONT><FONT face=宋体 size=3>代码段中进行了打开文件操作、分配内存操作、文件读操作和整数除法操作,这些操作都有可能引起异常,程序中对打开文件异常和分配内存异常分别进行了处理,对剩下的异常则统一由</FONT><FONT face="宋体, MS Song" size=3>catch(...)</FONT><FONT face=宋体 size=3>语句进行处理。</P></FONT><FONT size=3>< align=justify>try{</P><DIR>< align=justify>FILE * fp=fopen("test.dat","rb");//</FONT><FONT face=宋体 size=3>可能出现</FONT><FONT size=3>EFOpenError</FONT><FONT face=宋体 size=3>类异常</P></FONT><FONT size=3>< align=justify>BYTE * buf=new BYTE[1024];//</FONT><FONT face=宋体 size=3>可能出现</FONT><FONT size=3>EOutOfMemory</FONT><FONT face=宋体 size=3>类异常</P></FONT><FONT size=3>< align=justify>int k,i=100,j=fread(buf,1024,1,fp);// </FONT><FONT face=宋体 size=3>可能出现</FONT><FONT size=3>EReadError</FONT><FONT face=宋体 size=3>类异常</P></FONT><FONT size=3>< align=justify>k=i/j; //</FONT><FONT face=宋体 size=3>可能出现</FONT><FONT size=3>EDivByZero</FONT><FONT face=宋体 size=3>类异常</P></FONT><FONT size=3><P align=justify>fclose(fp);</P><P align=justify>delete buf;</P></DIR></FONT><FONT face=宋体 size=3><P align=justify>}</P></FONT><FONT size=3><P align=justify>catch(EFOpenError &amp;e){</P><DIR><P align=justify>ShowMessage("test.dat</FONT><FONT face=宋体 size=3>:打开文件错误</FONT><FONT size=3>");</P></DIR></FONT><FONT face=宋体 size=3><P align=justify>}</P></FONT><FONT size=3><P align=justify>catch(EOutOfMemory &amp;e){</P><DIR><P align=justify>ShowMessage("</FONT><FONT face=宋体 size=3>内存不足错误</FONT><FONT size=3>");</P></DIR></FONT><FONT face=宋体 size=3><P align=justify>}</P></FONT><FONT size=3><P align=justify>catch(...){</P><DIR><P align=justify>ShowMessage("</FONT><FONT face=宋体 size=3>应用程序出现异常错误</FONT><FONT size=3>");</P></DIR></FONT><FONT face=宋体 size=3><P align=justify>}</P></FONT><FONT size=3><P align=justify>CBuilder</FONT><FONT face=宋体 size=3>为</FONT><FONT size=3>VCL</FONT><FONT face=宋体 size=3>库提供了非常灵活的异常唤醒和异常处理机制,除了由</FONT><FONT size=3>VCL</FONT><FONT face=宋体 size=3>库检测和产生异常之外,还可以由程序通过</FONT><FONT size=3>throw</FONT><FONT face=宋体 size=3>语句来强制产生一个异常,例如下面的代码在检测到异常情况后,强制产生一个异常,并初始化异常消息,交由</FONT><FONT size=3>catch</FONT><FONT face=宋体 size=3>代码段进行处理,后者将显示出现异常的信息。在这段代码中,异常检测仍然采用的是传统的条件语句检测方法,但异常处理则采用的是面向对象的异常处理方式。</P></FONT><FONT size=3><P align=justify>try{</P><DIR><P align=justify>FILE * fp=fopen("test.dat","rb");</P><P align=justify>if(fp==NULL) //</FONT><FONT face=宋体 size=3>检测异常条件</P><DIR></FONT><FONT size=3><P align=justify>throw Exception("test.dat</FONT><FONT face=宋体 size=3>:打开文件错误</FONT><FONT size=3>"); //</FONT><FONT face=宋体 size=3>创建异常对象,并抛出异常对象</P></DIR></FONT><FONT size=3><P align=justify>...//</FONT><FONT face=宋体 size=3>正常的执行代码</P></DIR><P align=justify>}</P></FONT><FONT size=3><P align=justify>catch(Exception &amp;e){</P><DIR><P align=justify>ShowMessage(e.Message);//</FONT><FONT face=宋体 size=3>显示异常信息</P></DIR><P align=justify>}</P><UL><B><P align=justify><LI>为</FONT><FONT face="宋体, MS Song" size=3>MP3Collect</FONT><FONT face=宋体 size=3>程序添加异常处理功能 <p></LI></UL></B><P align=justify>了解了有关</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>中异常处理的基础知识后,下面我们就来为</FONT><FONT face="宋体, MS Song" size=3>Mp3Collect</FONT><FONT face=宋体 size=3>添加异常处理代码,以提高程序的容错性和强壮性。</P><P align=justify>实际上,由</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>自动生成的程序框架中已经包含了异常处理代码,在应用程序入口单元文件</FONT><FONT face="宋体, MS Song" size=3>MP3Collect.cpp</FONT><FONT face=宋体 size=3>中,入口函数</FONT><FONT face="宋体, MS Song" size=3>WinMain()</FONT><FONT face=宋体 size=3>便包含有</FONT><FONT face="宋体, MS Song" size=3>try</FONT><FONT face=宋体 size=3>和</FONT><FONT face="宋体, MS Song" size=3>catch</FONT><FONT face=宋体 size=3>代码段。不过,仅仅依靠这些缺省的异常处理还不够,我们还需要针对不同的错误情况分别进行处理,才能保证程序运行的可靠性。</P><P align=justify>在</FONT><FONT face="宋体, MS Song" size=3>Mp3Collect</FONT><FONT face=宋体 size=3>中,可能出现的异常情况主要是由媒体播放器控件产生的</FONT><FONT face="宋体, MS Song" size=3>EMCIDeviceError</FONT><FONT face=宋体 size=3>和进行文件操作时产生的各种文件操作异常,具体地说,可能产生异常的函数主要有</FONT><FONT face="宋体, MS Song" size=3>btnShowAllClick()</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>btnFindClick()</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>SaveFile()</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>btnFileNameClick()</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>mnuAddClick()</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>ListView1SelectItem()</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>MediaPlayer1Click()</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>Timer1Timer()</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>PlayTheSong()</FONT><FONT face=宋体 size=3>等。不过,为了简化程序代码,心铃准备统一采用了</FONT><FONT face="宋体, MS Song" size=3>Exception</FONT><FONT face=宋体 size=3>类来捕捉所有的</FONT><FONT face="宋体, MS Song" size=3>VCL</FONT><FONT face=宋体 size=3>异常对象,并利用对象的类名称属性</FONT><FONT face="宋体, MS Song" size=3>ClassName</FONT><FONT face=宋体 size=3>来显示该异常的类别。</P></FONT><FONT size=3><P align=justify>BtnFileNameClick()</FONT><FONT face=宋体 size=3>的主要功能是运行打开文件对话框</FONT><FONT size=3>OpenDialog1</FONT><FONT face=宋体 size=3>,并将获取的文件名赋给文件名称编辑框和媒体播放器,其中,从</FONT><FONT size=3>OpenDialog1-&gt;Execute()</FONT><FONT face=宋体 size=3>开始就可能产生异常,下面是添加了异常处理后的</FONT><FONT size=3>btnFileNameClick()</FONT><FONT face=宋体 size=3>:</P></FONT><FONT size=3><P align=justify>void __fastcall TMainForm::btnFileNameClick(TObject *Sender)</P><P align=justify>{</P><P align=justify>try{//</FONT><FONT face=宋体 size=3>标志可能产生异常的代码段</P><DIR></FONT><FONT size=3><P align=justify>if(OpenDialog1-&gt;Execute()) </FONT><FONT face=宋体 size=3>{</P><DIR></FONT><FONT size=3><P align=justify>MediaPlayer1-&gt;FileName=OpenDialog1-&gt;FileName;</P><P align=justify>edtFileName-&gt;Text=OpenDialog1-&gt;FileName;</P><P align=justify>edtSongName-&gt;Text=ChangeFileExt(ExtractFileName(OpenDialog1-&gt;FileName),"");</P><P align=justify>edtSingerName-&gt;Text="";</P><P align=justify>MediaPlayer1-&gt;Open();</P></DIR></FONT><FONT face=宋体 size=3><P align=justify>}</P></DIR><P align=justify>}</P></FONT><FONT size=3><P align=justify>catch(Exception &amp;e){//</FONT><FONT face=宋体 size=3>异常信息由两部分组成:异常对象的类名称、异常对象的错误消息</P><DIR></FONT><FONT size=3><P align=justify>ShowMessage(AnsiString(e.ClassName())+ ": " + e.Message);</P></DIR></FONT><FONT face=宋体 size=3><P align=justify>}</P><P align=justify>}</P></FONT><FONT size=3><P align=justify>mnuAddClick()</FONT><FONT face=宋体 size=3>与</FONT><FONT size=3>btnFileNameClick()</FONT><FONT face=宋体 size=3>相似,此处不再重复。</P></FONT><FONT size=3><P align=justify>ListView1SelectItem()</FONT><FONT face=宋体 size=3>在操作</FONT><FONT size=3>MediaPlayer1</FONT><FONT face=宋体 size=3>控件时容易产生异常,因此</FONT><FONT size=3>try</FONT><FONT face=宋体 size=3>代码段中应包括对</FONT><FONT size=3>MediaPlayer1</FONT><FONT face=宋体 size=3>的操作,添加异常处理后的该函数如下:</P></FONT><FONT size=3><P align=justify>void __fastcall TMainForm:istView1SelectItem(TObject *Sender, TListItem *Item, bool Selected)</P><P align=justify>{</P><P align=justify>if(Item &amp;&amp; Selected) </FONT><FONT face=宋体 size=3>{</P><DIR><P align=justify>……</FONT><FONT face="宋体, MS Song" size=3>//</FONT><FONT face=宋体 size=3>其它操作</P></FONT><FONT size=3><P align=justify>try{//try</FONT><FONT face=宋体 size=3>代码段包括对</FONT><FONT size=3>MediaPlayer1</FONT><FONT face=宋体 size=3>的操作</P><DIR></FONT><FONT size=3><P align=justify>MediaPlayer1-&gt;FileName=edtFileName-&gt;Text;</P><P align=justify>MediaPlayer1-&gt;Open();</P></DIR></FONT><FONT face=宋体 size=3><P align=justify>}</P></FONT><FONT size=3><P align=justify>catch(Exception &amp;e){</P><P align=justify>//</FONT><FONT face=宋体 size=3>异常消息由三部分组成:异常的类名称、</FONT><FONT size=3>MediaPlayer1</FONT><FONT face=宋体 size=3>的错误代码及其错误信息</P><DIR><DIR><DIR></FONT><FONT size=3><P align=justify>ShowMessage(AnsiString(e.ClassName())+" Error " + IntToStr(MediaPlayer1-&gt;Error) + ": " + MediaPlayer1-&gt;ErrorMessage);</P></DIR></DIR></DIR></FONT><FONT face=宋体 size=3><P align=justify>}</P></DIR><P align=justify>}</P><P align=justify>}</P></FONT><FONT size=3><P align=justify>MediaPlayer1Click()</FONT><FONT face=宋体 size=3>函数体内原有的全部代码都应该被包括在</FONT><FONT size=3>try</FONT><FONT face=宋体 size=3>之内,并且在</FONT><FONT size=3>catch</FONT><FONT face=宋体 size=3>代码中,除了显示异常信息外,还需要清除播放标志,并关闭</FONT><FONT size=3>Timer1</FONT><FONT face=宋体 size=3>。添加了异常处理代码的该函数如下:</P></FONT><FONT size=3><P align=justify>void __fastcall TMainForm::MediaPlayer1Click(TObject *Sender,TMPBtnType Button,bool &amp;DoDefault)</P><P align=justify>{</P><P align=justify>try{</P><DIR><P align=justify>switch(Button){</P><DIR></FONT><FONT face=宋体 size=3><P align=justify>……</FONT><FONT face="宋体, MS Song" size=3>//</FONT><FONT face=宋体 size=3>根据</FONT><FONT face="宋体, MS Song" size=3>Button</FONT><FONT face=宋体 size=3>参数判断用户点击了什么按钮,进行相应的处理</P></DIR><P align=justify>}</P></DIR><P align=justify>}</P></FONT><FONT size=3><P align=justify>catch(Exception &amp;e)//</FONT><FONT face=宋体 size=3>捷捉可能产生的异常</P><P align=justify>{</P><DIR></FONT><FONT size=3><P align=justify>DoDefault=false;//</FONT><FONT face=宋体 size=3>取消缺省操作</P></FONT><FONT size=3><P align=justify>m_bIsPlaying=false;//</FONT><FONT face=宋体 size=3>清除播放标志</P></FONT><FONT size=3><P align=justify>Timer1-&gt;Enabled=false;//</FONT><FONT face=宋体 size=3>关闭时钟</P></FONT><FONT size=3><P align=justify>EnableButtons(true);//</FONT><FONT face=宋体 size=3>使能命令按钮</P><DIR><DIR><DIR></FONT><FONT size=3><P align=justify>ShowMessage(AnsiString(e.ClassName())+" Error " + IntToStr(MediaPlayer1-&gt;Error) + ": " + e.Message);</P></DIR></DIR></DIR></DIR></FONT><FONT face=宋体 size=3><P align=justify>}</P><P align=justify>}</P></FONT><FONT size=3><P align=justify>Timer1Timer()</FONT><FONT face=宋体 size=3>与</FONT><FONT size=3>MediaPlayer1Click()</FONT><FONT face=宋体 size=3>的异常处理方式基本一致,也是将函数体内原有的全部代码标志为</FONT><FONT size=3>try</FONT><FONT face=宋体 size=3>代码段,并在</FONT><FONT size=3>catch</FONT><FONT face=宋体 size=3>代码段中进行清除播放标志、关闭</FONT><FONT size=3>Timer1</FONT><FONT face=宋体 size=3>等操作。另外,在时钟处理函数中应该尽量缩短函数的执行时间,避免函数重入引起的问题,因此</FONT><FONT size=3>Timer1Timer()</FONT><FONT face=宋体 size=3>函数的</FONT><FONT size=3>catch</FONT><FONT face=宋体 size=3>代码段最好不要显示异常信息,如果确实需要显示,必须在关闭</FONT><FONT size=3>Timer1</FONT><FONT face=宋体 size=3>之后再显示。</P><P align=justify>由于</FONT><FONT face="宋体, MS Song" size=3>PlayTheSong()</FONT><FONT face=宋体 size=3>被</FONT><FONT face="宋体, MS Song" size=3>MediaPlayer1Click()</FONT><FONT face=宋体 size=3>和</FONT><FONT face="宋体, MS Song" size=3>Timer1Timer()</FONT><FONT face=宋体 size=3>调用,而后两个函数中的异常处理代码完全可以处理</FONT><FONT face="宋体, MS Song" size=3>PlayTheSong()</FONT><FONT face=宋体 size=3>可能产生的异常,因此就不需要再单独添加异常处理代码了。</P><P align=justify>最后,</FONT><FONT face="宋体, MS Song" size=3>btnShowAllClick()</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>btnFindClick()</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>SaveFile()</FONT><FONT face=宋体 size=3>三个函数已经有了基于传统的条件判断式的异常检测和异常处理代码,能够处理打开文件不正常的情况,读者朋友可以自行练习一下,把这一部分的异常处理改用</FONT><FONT face="宋体, MS Song" size=3>try</FONT><FONT face=宋体 size=3>和</FONT><FONT face="宋体, MS Song" size=3>catch</FONT><FONT face=宋体 size=3>代码段来实现。</P><P align=justify> </P><P align=justify>本讲介绍了在</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>中进行异常处理的内容,不少初学</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>(或其它编程语言)的朋友因为觉得异常处理很复杂或是用处不大,就忽略了这部分内容,其实,异常处理的原理并不复杂,无非是中断产生异常的程序代码,捕捉可能产生的异常并进行相应处理,掌握了这一基本原理之后,就容易理解为什么要引入异常处理机制,以及如何使用异常处理机制了。</P></FONT>
作者: 韩冰    时间: 2005-1-26 01:30
<b><FONT face=宋体 size=6> </FONT></b>< align=center>数据库编程基础</P><FONT face=宋体 size=3>< align=justify>到上一讲为止,我们的音乐收藏小程序</FONT><FONT face="宋体, MS Song" size=3>Mp3Collect</FONT><FONT face=宋体 size=3>的第一个版本已经完成了,这个版本的实现是基于文件的,具有简单的记录编辑和管理能力,但它也存在一些缺陷,因此在接下来的几讲中,我们就来编写</FONT><FONT face="宋体, MS Song" size=3>Mp3Collect</FONT><FONT face=宋体 size=3>的第二个版本,第二版将利用数据库来保存记录,并具备访问查询数据库的能力。由于数据库在讲座中是全新的内容,所以在动手编程之前,心铃首先介绍一下在</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>中进行数据库编程的一些基础知识。</P><UL><B>< align=justify><LI>什么是数据库
; l, O3 Z  {; D" J</LI></UL></B>< align=justify>通常我们在谈论数据库的时候,很容易把数据库(</FONT><FONT face="宋体, MS Song" size=3>Database</FONT><FONT face=宋体 size=3>)、数据库管理系统(</FONT><FONT face="宋体, MS Song" size=3>Database Management System</FONT><FONT face=宋体 size=3>)、和数据库应用程序(</FONT><FONT face="宋体, MS Song" size=3>Database Application</FONT><FONT face=宋体 size=3>)混在一起,实际上,它们是构成数据库应用系统的三个组成部分,其中数据库是按照一定的结构组织在一起的相关数据的集合;数据库管理系统是建立、使用和管理数据库的软件系统,简称为</FONT><FONT face="宋体, MS Song" size=3>DBMS</FONT><FONT face=宋体 size=3>;而数据库应用程序则是具有数据库访问能力的应用程序,它提供用户一个访问和操作特定数据库的用户界面。</P>< align=justify>举例来说,我们常用的</FONT><FONT face="宋体, MS Song" size=3>Office</FONT><FONT face=宋体 size=3>办公套件中有一个</FONT><FONT face="宋体, MS Song" size=3>Access</FONT><FONT face=宋体 size=3>软件,它就是一种数据库管理系统,如果利用</FONT><FONT face="宋体, MS Song" size=3>Access</FONT><FONT face=宋体 size=3>创建一个</FONT><FONT face="宋体, MS Song" size=3>MP3Collect.mdb</FONT><FONT face=宋体 size=3>文件用于保存</FONT><FONT face="宋体, MS Song" size=3>MP3</FONT><FONT face=宋体 size=3>音乐信息,那么这个</FONT><FONT face="宋体, MS Song" size=3>MP3Collect.mdb</FONT><FONT face=宋体 size=3>文件就是一个数据库,而将要编写的第二版</FONT><FONT face="宋体, MS Song" size=3>MP3Collect.exe</FONT><FONT face=宋体 size=3>能够访问</FONT><FONT face="宋体, MS Song" size=3>MP3Collect.mdb</FONT><FONT face=宋体 size=3>中保存的记录信息,因此它是一个数据库应用程序。</P>< align=justify>数据库和数据库管理系统是密切相关的,通常我们称某某数据库是某一类型的数据库,就是按照该数据库管理系统的名称来命名的。例如,</FONT><FONT face="宋体, MS Song" size=3>MP3Collect.mdb</FONT><FONT face=宋体 size=3>可以称为一个</FONT><FONT face="宋体, MS Song" size=3>Access</FONT><FONT face=宋体 size=3>数据库。数据库管理系统不仅可以直接访问某一类型的数据库,还可以提供给其它应用程序一个访问该类型数据库的引擎(即驱动程序),这样,应用程序在访问数据库时就不用考虑数据库的物理存储方式、检索算法的实现等具体问题,而只要把命令传给数据库引擎,然后从数据库引擎处获取结果数据就可以了。</P>< align=justify>根据数据库对数据组织方式的不同,数据库管理系统又分为几种类型,如关系数据库、对象数据库等。其中关系数据库以表格的形式存储数据,是目前应用最广泛的数据库管理系统。我们讲座中要用到的</FONT><FONT face="宋体, MS Song" size=3>Access</FONT><FONT face=宋体 size=3>就是一种关系数据库管理系统。一个关系数据库是由一个或多个数据表(</FONT><FONT face="宋体, MS Song" size=3>Table</FONT><FONT face=宋体 size=3>)组成,而一个数据表又是由许多结构相同的记录(</FONT><FONT face="宋体, MS Song" size=3>Record</FONT><FONT face=宋体 size=3>)组成,每条记录相当于数据表的一行,数据表的列又称为字段(</FONT><FONT face="宋体, MS Song" size=3>Field</FONT><FONT face=宋体 size=3>),字段定义了该项数据内容的数据类型、数据宽度等。有些数据库是以文件形式存在的,例如</FONT><FONT face="宋体, MS Song" size=3>Access</FONT><FONT face=宋体 size=3>的一个</FONT><FONT face="宋体, MS Song" size=3>MDB</FONT><FONT face=宋体 size=3>文件就是一个数据库,其所有的数据表都包含在文件的内部,而有些数据库则是指一个目录,例如</FONT><FONT face="宋体, MS Song" size=3>aradox</FONT><FONT face=宋体 size=3>和</FONT><FONT face="宋体, MS Song" size=3>dBase</FONT><FONT face=宋体 size=3>就是使用目录的数据库,每个数据表在该目录下以独立的文件形式存在。</P><UL></FONT><B><FONT size=3>< align=justify><LI>CBuilder</FONT><FONT face=宋体 size=3>数据库开发环境 <p></LI></UL></B></FONT><FONT size=3>< align=justify>CBuilder</FONT><FONT face=宋体 size=3>在其开发环境中提供了强大的数据库支持,使</FONT><FONT size=3>CBuilder</FONT><FONT face=宋体 size=3>开发的应用程序能够很方便地具有数据库访问能力。</P>< align=justify>首先,</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>提供了</FONT><FONT face="宋体, MS Song" size=3>Borland</FONT><FONT face=宋体 size=3>公司的数据库引擎(</FONT><FONT face="宋体, MS Song" size=3>Borland Database Engine</FONT><FONT face=宋体 size=3>,简称</FONT><FONT face="宋体, MS Song" size=3>BDE</FONT><FONT face=宋体 size=3>),它是</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>数据库应用程序开发环境的核心。</FONT><FONT face="宋体, MS Song" size=3>BDE</FONT><FONT face=宋体 size=3>位于应用程序和</FONT><FONT face="宋体, MS Song" size=3>DBMS</FONT><FONT face=宋体 size=3>的数据库引擎之间,使得应用程序可以更加方便地访问不同类型的数据库。</FONT><FONT face="宋体, MS Song" size=3>BDE</FONT><FONT face=宋体 size=3>支持直接访问</FONT><FONT face="宋体, MS Song" size=3>aradox</FONT><FONT face=宋体 size=3>和</FONT><FONT face="宋体, MS Song" size=3>dBase</FONT><FONT face=宋体 size=3>数据库,通过合适的驱动程序和数据库引擎,</FONT><FONT face="宋体, MS Song" size=3>BDE</FONT><FONT face=宋体 size=3>还可以访问</FONT><FONT face="宋体, MS Song" size=3>FoxPro</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>Access</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>Infomix</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>DB2</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>Oracle</FONT><FONT face=宋体 size=3>等多种流行的桌面数据库和远程数据库,同时</FONT><FONT face="宋体, MS Song" size=3>BDE</FONT><FONT face=宋体 size=3>也是</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>提供的众多数据库元件的功能基础。</P></FONT><FONT size=3>< align=justify>CBuilder</FONT><FONT face=宋体 size=3>中包含了大量和数据库应用程序相关的元件,它们可分为数据库访问元件和数据控制元件。数据访问元件位于</FONT><FONT size=3>Data Access</FONT><FONT face=宋体 size=3>元件栏中,主要包括</FONT><FONT size=3>DataSource</FONT><FONT face=宋体 size=3>控件、</FONT><FONT size=3>Table</FONT><FONT face=宋体 size=3>控件、</FONT><FONT size=3>Query</FONT><FONT face=宋体 size=3>控件等。数据访问元件在运行过程中是不可见的,它主要是为应用程序提供一条访问数据库的通道。数据控制元件位于</FONT><FONT size=3>Data Controls</FONT><FONT face=宋体 size=3>元件栏中,它们为应用程序提供可视化的用户界面,常用的数据控制元件包括</FONT><FONT size=3>DBNavigator</FONT><FONT face=宋体 size=3>、</FONT><FONT size=3>DBGrid</FONT><FONT face=宋体 size=3>、</FONT><FONT size=3>DBEdit</FONT><FONT face=宋体 size=3>、</FONT><FONT size=3>DBText</FONT><FONT face=宋体 size=3>等。很多数据控制元件都是在普通的用户界面元件的基础上增加了数据感知能力,如</FONT><FONT size=3>DBEdit</FONT><FONT face=宋体 size=3>控件(数据库编辑控件),它不仅具有普通</FONT><FONT size=3>Edit</FONT><FONT face=宋体 size=3>控件的用户输入、编辑、浏览文本的能力,还可以和数据库访问元件关联在一起,从而具有浏览、编辑数据库记录的能力。</P>< align=justify>在</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>中开发数据库应用程序的基本思路是:<B>使用数据访问元件与数据库建立联接,获取所需的数据集(</FONT><FONT face="宋体, MS Song" size=3>Dataset</FONT><FONT face=宋体 size=3>),并将数据控制元件与数据访问元件相关联,实现用户浏览、操作数据的界面。</P></B></FONT><FONT size=3>< align=justify>CBuilder</FONT><FONT face=宋体 size=3>的数据库开发环境中还包括几个工具软件,它们是</FONT><FONT size=3>BDE</FONT><FONT face=宋体 size=3>管理器(</FONT><FONT size=3>BDE Administrator</FONT><FONT face=宋体 size=3>)、</FONT><FONT size=3>SQL</FONT><FONT face=宋体 size=3>浏览器(</FONT><FONT size=3>SQL Explorer</FONT><FONT face=宋体 size=3>)、数据库桌面(</FONT><FONT size=3>Database Desktop</FONT><FONT face=宋体 size=3>)等。</P></FONT><FONT size=3>< align=justify>BDE</FONT><FONT face=宋体 size=3>管理器是</FONT><FONT size=3>BDE</FONT><FONT face=宋体 size=3>管理和配置的工具软件,它可以创建和维护</FONT><FONT size=3>BDE</FONT><FONT face=宋体 size=3>数据库别名(</FONT><FONT size=3>Alias</FONT><FONT face=宋体 size=3>),安装和删除数据库驱动程序。其中数据库别名是</FONT><FONT size=3>BDE</FONT><FONT face=宋体 size=3>引入的一个重要概念,它的意义和创建方法将在后面进行介绍。</P>< align=justify>数据库桌面是一个简单的数据库管理工具,可以进行许多基于数据表的操作,如创建数据表、修改数据表的结构以及查看和编辑数据表的内容等等。</P></FONT><FONT size=3>< align=justify>SQL</FONT><FONT face=宋体 size=3>浏览器是一个数据库浏览工具,可以浏览数据库中的各种对象,如数据表、字段、索引等,还可以创建和维护数据库别名,编辑和显示数据表中的记录,以及对数据表执行</FONT><FONT size=3>SQL</FONT><FONT face=宋体 size=3>查询等。其中,</FONT><FONT size=3>SQL</FONT><FONT face=宋体 size=3>的全称是结构化查询语言(</FONT><FONT size=3>Structured Query Language</FONT><FONT face=宋体 size=3>),它是目前使用得最广泛的一种标准的数据库查询语言,几乎所有的数据库都支持</FONT><FONT size=3>SQL</FONT><FONT face=宋体 size=3>语言。</P><UL><B>< align=justify><LI>建立一个</FONT><FONT face="宋体, MS Song" size=3>ACCESS</FONT><FONT face=宋体 size=3>数据库 <p></LI></UL></B>< align=justify>下面,我们以</FONT><FONT face="宋体, MS Song" size=3>Mp3Collect</FONT><FONT face=宋体 size=3>程序为例,一步一步地学习如何在</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>中开发数据库应用程序。第一步需要建立一个数据库。我们以</FONT><FONT face="宋体, MS Song" size=3>Microsoft</FONT><FONT face=宋体 size=3>的</FONT><FONT face="宋体, MS Song" size=3>Access 2000</FONT><FONT face=宋体 size=3>为例来说明创建数据库的方法。选用</FONT><FONT face="宋体, MS Song" size=3>Access 2000</FONT><FONT face=宋体 size=3>是因为它是目前比较流行的桌面数据库,使用和管理起来都很方便。</P>< align=justify>首先启动</FONT><FONT face="宋体, MS Song" size=3>Access 2000</FONT><FONT face=宋体 size=3>,选择新建空的数据库,在要求输入数据库名称和路径时输入“</FONT><FONT face="宋体, MS Song" size=3>MP3Collect\MP3Collect.mdb</FONT><FONT face=宋体 size=3>”(即</FONT><FONT face="宋体, MS Song" size=3>Mp3Collect</FONT><FONT face=宋体 size=3>所在目录)。接下来在新建的空白数据库中选择表对象,并双击其中的“使用表设计器创建表”命令,创建一个数据表。</P>< align=justify>在表设计器中,依次定义四个字段:</FONT><FONT face="宋体, MS Song" size=3>ID</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>FileName</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>SongName</FONT><FONT face=宋体 size=3>和</FONT><FONT face="宋体, MS Song" size=3>SingerName</FONT><FONT face=宋体 size=3>。后面三个字段的意义我们已经非常熟悉了,它们的数据类型定义为文本,</FONT><FONT face="宋体, MS Song" size=3>FileName</FONT><FONT face=宋体 size=3>的字段大小为</FONT><FONT face="宋体, MS Song" size=3>255</FONT><FONT face=宋体 size=3>,其它两个字段的大小为</FONT><FONT face="宋体, MS Song" size=3>50</FONT><FONT face=宋体 size=3>,并且</FONT><FONT face="宋体, MS Song" size=3>FileName</FONT><FONT face=宋体 size=3>字段中不允许空字符串,而</FONT><FONT face="宋体, MS Song" size=3>SongName</FONT><FONT face=宋体 size=3>和</FONT><FONT face="宋体, MS Song" size=3>SingerName</FONT><FONT face=宋体 size=3>允许空字符串。另外,我们还要为这三个字段添加允许重复的索引,因为在程序中需要按照这三个字段对数据库进行查询,添加了索引的字段,可以加快查询的速度。</FONT><FONT face="宋体, MS Song" size=3>ID</FONT><FONT face=宋体 size=3>是自动编号类型的字段,这个字段的引入是为了给每个记录一个唯一的数字标识,在关系数据库中,这样的数字标识对提高访问效率和系统性能很有用。另外,由于每条记录的</FONT><FONT face="宋体, MS Song" size=3>ID</FONT><FONT face=宋体 size=3>是唯一的,我们可以为</FONT><FONT face="宋体, MS Song" size=3>ID</FONT><FONT face=宋体 size=3>添加无重复的索引,并且指定其新值的产生方式为递增。设置好这四个字段以后,关闭表设计器,这时</FONT><FONT face="宋体, MS Song" size=3>Access</FONT><FONT face=宋体 size=3>会提示输入新表的名称,这里我们将其命名为</FONT><FONT face="宋体, MS Song" size=3>MP3Info</FONT><FONT face=宋体 size=3>。</P>< align=justify>这样,数据库</FONT><FONT face="宋体, MS Song" size=3>MP3Collect.mdb</FONT><FONT face=宋体 size=3>就创建好了,虽然这只是一个简单的单数据表的数据库,但是通过创建这个数据库,我们可以更直观地了解数据库、表、记录、字段、索引的概念,以及它们相互间的关系。有兴趣的朋友不妨再在库中添加一个歌手档案数据库,学习关系数据库中多数据表之间是怎样关联起来的。</P><UL><B>< align=justify><LI>创建</FONT><FONT face="宋体, MS Song" size=3>ODBC</FONT><FONT face=宋体 size=3>数据源和使用数据库别名 <p></LI></UL></B>< align=justify>接下来我们要为</FONT><FONT face="宋体, MS Song" size=3>MP3Collect.mdb</FONT><FONT face=宋体 size=3>数据库创建一个</FONT><FONT face="宋体, MS Song" size=3>ODBC</FONT><FONT face=宋体 size=3>数据源。什么是</FONT><FONT face="宋体, MS Song" size=3>ODBC</FONT><FONT face=宋体 size=3>?它的全称是开放式数据库互联(</FONT><FONT face="宋体, MS Song" size=3>Open Database Connectivity</FONT><FONT face=宋体 size=3>),这是一个数据库的访问标准。由于不同的数据库在存储结构、检索算法上存在着很大的差异,为了使应用程序能够通过统一、通用的方法访问不同的数据库,微软提出了</FONT><FONT face="宋体, MS Song" size=3>ODBC</FONT><FONT face=宋体 size=3>数据库访问标准。目前几乎所有的数据库管理系统都支持</FONT><FONT face="宋体, MS Song" size=3>ODBC</FONT><FONT face=宋体 size=3>标准。</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>的</FONT><FONT face="宋体, MS Song" size=3>BDE</FONT><FONT face=宋体 size=3>也具有</FONT><FONT face="宋体, MS Song" size=3>ODBC</FONT><FONT face=宋体 size=3>接口,可以在</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>下访问支持</FONT><FONT face="宋体, MS Song" size=3>ODBC</FONT><FONT face=宋体 size=3>的数据库。</P>< align=justify>数据源是</FONT><FONT face="宋体, MS Song" size=3>ODBC</FONT><FONT face=宋体 size=3>标准中的一个概念,它把一个具体的数据库定义成为一个数据源,数据源中指定了数据库的类型、所使用的驱动程序、所处的路径等信息。应用程序在访问数据库时,只需要和数据源建立联接,而不用考虑数据库所处的具体位置。这样,即使数据库所在的位置(如移到另一个目录中)发生了变化,我们只需要重新设置数据源,而不需要改变应用程序中的代码。</P></FONT><FONT size=3>< align=justify>ODBC</FONT><FONT face=宋体 size=3>数据源由操作系统进行创建和管理。我们打开</FONT><FONT size=3>Windows</FONT><FONT face=宋体 size=3>的控制面板中,找到并运行其中的</FONT><FONT size=3>ODBC</FONT><FONT face=宋体 size=3>数据源工具,就会出现如图</FONT><FONT size=3>14-1</FONT><FONT face=宋体 size=3>所示的</FONT><FONT size=3>ODBC</FONT><FONT face=宋体 size=3>数据源管理器,其中有用户数据源、文件数据源、系统数据源等多个选项。我们在用户数据源选项页中单击“添加”按钮,弹出创建新数据源对话框,在其中选择数据源的驱动程序为</FONT><FONT size=3>Microsoft Access Driver(*.mdb)</FONT><FONT face=宋体 size=3>,然后按下完成按钮。</P>< align=justify>接下来,系统会调用</FONT><FONT face="宋体, MS Song" size=3>Access2000</FONT><FONT face=宋体 size=3>的</FONT><FONT face="宋体, MS Song" size=3>ODBC</FONT><FONT face=宋体 size=3>数据源安装对话框,如图</FONT><FONT face="宋体, MS Song" size=3>14-2</FONT><FONT face=宋体 size=3>所示。在其中输入数据源的名称</FONT><FONT face="宋体, MS Song" size=3>MP3CollectDSN</FONT><FONT face=宋体 size=3>,并通过“选择”按钮选择数据库“</FONT><FONT face="宋体, MS Song" size=3>MP3Collect\MP3Collect.mdb</FONT><FONT face=宋体 size=3>”,设置完成后,按下“确定”按钮,新的数据源</FONT><FONT face="宋体, MS Song" size=3>MP3CollectDSN</FONT><FONT face=宋体 size=3>就创建好了。</P>< align=justify>下面还要为</FONT><FONT face="宋体, MS Song" size=3>MP3Collect.mdb</FONT><FONT face=宋体 size=3>数据库创建和配置据库别名。前面提到过,别名是</FONT><FONT face="宋体, MS Song" size=3>BDE</FONT><FONT face=宋体 size=3>引入的重要概念。在</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>的数据库访问元件中,很多元件都需要指定一个数据库的名称,这个名称通常就是数据库别名。别名的作用和</FONT><FONT face="宋体, MS Song" size=3>ODBC</FONT><FONT face=宋体 size=3>数据源的作用很类似,它也定义了数据库的一些连接属性,如数据库类型、路径、连接参数等等。基于</FONT><FONT face="宋体, MS Song" size=3>BDE</FONT><FONT face=宋体 size=3>的数据库应用程序可以通过简单地指定数据库的别名,就可以和数据库建立起连接。</P>< align=justify>创建别名可以通过</FONT><FONT face="宋体, MS Song" size=3>BDE</FONT><FONT face=宋体 size=3>管理器来完成。在</FONT><FONT face="宋体, MS Song" size=3>Windows</FONT><FONT face=宋体 size=3>的控制面板中找到并打开</FONT><FONT face="宋体, MS Song" size=3>BDE</FONT><FONT face=宋体 size=3>管理器,如图</FONT><FONT face="宋体, MS Song" size=3>14-3</FONT><FONT face=宋体 size=3>所示。管理器的左边是</FONT><FONT face="宋体, MS Song" size=3>Database</FONT><FONT face=宋体 size=3>选项页和</FONT><FONT face="宋体, MS Song" size=3>Configuration</FONT><FONT face=宋体 size=3>选项页,前者用于创建和维护</FONT><FONT face="宋体, MS Song" size=3>BDE</FONT><FONT face=宋体 size=3>数据库别名,后者用于配置</FONT><FONT face="宋体, MS Song" size=3>BDE</FONT><FONT face=宋体 size=3>驱动程序。在</FONT><FONT face="宋体, MS Song" size=3>Database</FONT><FONT face=宋体 size=3>选项页中,我们看到,数据源</FONT><FONT face="宋体, MS Song" size=3>MP3CollectDSN</FONT><FONT face=宋体 size=3>也位于其中,说明</FONT><FONT face="宋体, MS Song" size=3>ODBC</FONT><FONT face=宋体 size=3>数据源同样可以作为</FONT><FONT face="宋体, MS Song" size=3>BDE</FONT><FONT face=宋体 size=3>数据库别名来使用。不过为了说明别名的使用方法,心铃决定创建一个新的别名</FONT><FONT face="宋体, MS Song" size=3>MP3Collect</FONT><FONT face=宋体 size=3>。</P><P align=justify>在</FONT><FONT face="宋体, MS Song" size=3>Database</FONT><FONT face=宋体 size=3>选项页中调出关联菜单,在其中选择“</FONT><FONT face="宋体, MS Song" size=3>New...</FONT><FONT face=宋体 size=3>”菜单命令,在弹出的“</FONT><FONT face="宋体, MS Song" size=3>New Database Alias</FONT><FONT face=宋体 size=3>”中选择数据库驱动程序名称为“</FONT><FONT face="宋体, MS Song" size=3>Microsoft Access Driver(*.mdb)</FONT><FONT face=宋体 size=3>”,然后确定。这时</FONT><FONT face="宋体, MS Song" size=3>Database</FONT><FONT face=宋体 size=3>选项页中多了一项别名,我们将其名称改为</FONT><FONT face="宋体, MS Song" size=3>MP3Collect</FONT><FONT face=宋体 size=3>。</FONT><FONT face="宋体, MS Song" size=3>BDE</FONT><FONT face=宋体 size=3>管理器的右边显示了新别名的定义,在其中的</FONT><FONT face="宋体, MS Song" size=3>ODBC DSN</FONT><FONT face=宋体 size=3>栏中输入</FONT><FONT face="宋体, MS Song" size=3>MP3CollectDSN</FONT><FONT face=宋体 size=3>,其它的项目采用缺省配置,然后选择菜单命令“</FONT><FONT face="宋体, MS Song" size=3>Object-&gt;Apply</FONT><FONT face=宋体 size=3>”保存数据库别名</FONT><FONT face="宋体, MS Song" size=3>MP3Collect</FONT><FONT face=宋体 size=3>的设置,为了验证别名设置是否正确,还可以选择菜单命令“</FONT><FONT face="宋体, MS Song" size=3>Object-&gt;Open</FONT><FONT face=宋体 size=3>”来打开</FONT><FONT face="宋体, MS Song" size=3>MP3Collect</FONT><FONT face=宋体 size=3>,如果打开正确,则说明别名设置是正确的,以后就可以在</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>应用程序中使用别名</FONT><FONT face="宋体, MS Song" size=3>MP3Collect</FONT><FONT face=宋体 size=3>了。最后,用菜单命令“</FONT><FONT face="宋体, MS Song" size=3>Object-&gt;Close</FONT><FONT face=宋体 size=3>”关闭打开的数据库别名。</P><UL></FONT><B><FONT size=3><P align=justify><LI>MP3Collect</FONT><FONT face=宋体 size=3>的窗体设计 <p></LI></UL></B><P align=justify>完成上面的准备工作之后,我们就可以开始设计新的</FONT><FONT face="宋体, MS Song" size=3>MP3Collect</FONT><FONT face=宋体 size=3>了。首先在</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>中新建一个工程(也可在原有工程上改,不过最好要做一个备份),工程名称仍然采用</FONT><FONT face="宋体, MS Song" size=3>MP3Collect</FONT><FONT face=宋体 size=3>。工程中的主窗体名称为</FONT><FONT face="宋体, MS Song" size=3>MainForm</FONT><FONT face=宋体 size=3>,主窗体类名称为</FONT><FONT face="宋体, MS Song" size=3>TMainForm</FONT><FONT face=宋体 size=3>。</P><P align=justify>新的窗体和第一版的窗体具有同样的界面风格。其中,窗体的上半部分与第一版完全一样,有三个编辑框</FONT><FONT face="宋体, MS Song" size=3>edtFileName</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>edtSongName</FONT><FONT face=宋体 size=3>和</FONT><FONT face="宋体, MS Song" size=3>edtSingerName</FONT><FONT face=宋体 size=3>,用于输入记录信息和查询条件,有七个命令按钮</FONT><FONT face="宋体, MS Song" size=3>btnFilename</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>btnAdd</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>btnModify</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>btnDelete</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>btnFind</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>btnShowAll</FONT><FONT face=宋体 size=3>和</FONT><FONT face="宋体, MS Song" size=3>btnExit</FONT><FONT face=宋体 size=3>,一个循环播放选项框</FONT><FONT face="宋体, MS Song" size=3>chkLoop</FONT><FONT face=宋体 size=3>,以及一个媒体播放器控件</FONT><FONT face="宋体, MS Song" size=3>MediaPlayer1</FONT><FONT face=宋体 size=3>。其余的非可视元件如</FONT><FONT face="宋体, MS Song" size=3>Timer1</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>OpenDialog1</FONT><FONT face=宋体 size=3>和</FONT><FONT face="宋体, MS Song" size=3>PopupMenu1</FONT><FONT face=宋体 size=3>等也与第一版中完全一样。</P><P align=justify>窗体中的记录显示控件由原来的</FONT><FONT face="宋体, MS Song" size=3>ListView1</FONT><FONT face=宋体 size=3>改为数据库控制元件</FONT><FONT face="宋体, MS Song" size=3>DBGrid1</FONT><FONT face=宋体 size=3>。并新添了数据库控件</FONT><FONT face="宋体, MS Song" size=3>Database1</FONT><FONT face=宋体 size=3>(</FONT><FONT face="宋体, MS Song" size=3>VCL</FONT><FONT face=宋体 size=3>类为</FONT><FONT face="宋体, MS Song" size=3>TDatabase</FONT><FONT face=宋体 size=3>)、数据表控件</FONT><FONT face="宋体, MS Song" size=3>Table1</FONT><FONT face=宋体 size=3>(</FONT><FONT face="宋体, MS Song" size=3>VCL</FONT><FONT face=宋体 size=3>类为</FONT><FONT face="宋体, MS Song" size=3>TTable1</FONT><FONT face=宋体 size=3>)、数据查询控件</FONT><FONT face="宋体, MS Song" size=3>Query1</FONT><FONT face=宋体 size=3>(</FONT><FONT face="宋体, MS Song" size=3>VCL</FONT><FONT face=宋体 size=3>类为</FONT><FONT face="宋体, MS Song" size=3>TQuery</FONT><FONT face=宋体 size=3>)和数据源控件</FONT><FONT face="宋体, MS Song" size=3>DataSource1</FONT><FONT face=宋体 size=3>(</FONT><FONT face="宋体, MS Song" size=3>VCL</FONT><FONT face=宋体 size=3>类为</FONT><FONT face="宋体, MS Song" size=3>TDataSource</FONT><FONT face=宋体 size=3>)。</P><P align=justify>放置好各种元件之后,还要设置元件的属性。这里只介绍新添的几个数据库控件的属性,其余的与第一版中的一样。</P><P align=justify>首先设置数据库控件</FONT><FONT face="宋体, MS Song" size=3>Database1</FONT><FONT face=宋体 size=3>,该控件代表了应用程序与某个数据库的连接,使程序获得对整个数据库的访问权。设置其</FONT><FONT face="宋体, MS Song" size=3>Database Name</FONT><FONT face=宋体 size=3>属性为</FONT><FONT face="宋体, MS Song" size=3>MP3Collect</FONT><FONT face=宋体 size=3>,指定其连接的数据库为</FONT><FONT face="宋体, MS Song" size=3>BDE</FONT><FONT face=宋体 size=3>别名</FONT><FONT face="宋体, MS Song" size=3>MP3Collect</FONT><FONT face=宋体 size=3>,由于别名中已经定义了连接的各种参数,所以</FONT><FONT face="宋体, MS Song" size=3>Database1</FONT><FONT face=宋体 size=3>的</FONT><FONT face="宋体, MS Song" size=3>DriveName</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>AliasName</FONT><FONT face=宋体 size=3>等属性均不需要进行设置。另外设置其</FONT><FONT face="宋体, MS Song" size=3>LoginPromote</FONT><FONT face=宋体 size=3>属性设为</FONT><FONT face="宋体, MS Song" size=3>false</FONT><FONT face=宋体 size=3>,表示连接时不要弹出登录对话框,登录对话框是用于在与数据库建立连接时提示用户输入用户名和口令的,在本例中并没有为数据库设置口令,所以不需要它。最后,将</FONT><FONT face="宋体, MS Song" size=3>Database1</FONT><FONT face=宋体 size=3>的</FONT><FONT face="宋体, MS Song" size=3>Connected</FONT><FONT face=宋体 size=3>属性设为真,表示与数据库建立起连接。</P><P align=justify>接下来设置数据表控件</FONT><FONT face="宋体, MS Song" size=3>Table1</FONT><FONT face=宋体 size=3>。该控件是最基本的数据库访问控件,它代表了实际的数据表对象,其中封装了对数据表的操作,如创建数据表,定义字段、索引,以及添加、修改、删除记录等。我们的程序中使用该控件主要是用于添加、修改和删除记录等操作。选中</FONT><FONT face="宋体, MS Song" size=3>Table1</FONT><FONT face=宋体 size=3>控件后,可以在对象监视器看到它的属性非常多,其中大部分都可以采用缺省值,需要设置的有以下三个:在</FONT><FONT face="宋体, MS Song" size=3>DatabaseName</FONT><FONT face=宋体 size=3>属性中,点击右侧的下拉式列表框,选择别名</FONT><FONT face="宋体, MS Song" size=3>MP3Collect</FONT><FONT face=宋体 size=3>;在</FONT><FONT face="宋体, MS Song" size=3>TableName</FONT><FONT face=宋体 size=3>属性栏中选择数据表</FONT><FONT face="宋体, MS Song" size=3>MP3Info</FONT><FONT face=宋体 size=3>,并在其</FONT><FONT face="宋体, MS Song" size=3>IndexName</FONT><FONT face=宋体 size=3>属性中选取索引</FONT><FONT face="宋体, MS Song" size=3>ID</FONT><FONT face=宋体 size=3>;设置</FONT><FONT face="宋体, MS Song" size=3>Active</FONT><FONT face=宋体 size=3>属性为</FONT><FONT face="宋体, MS Song" size=3>true</FONT><FONT face=宋体 size=3>。至于其它属性,请有兴趣学习数据库开发的朋友参考相关资料。</P><P align=justify> </P><P align=justify>由于篇幅所限,其余几个数据库控件的属性设置,以及功能代码的实现就留到下一讲中。本讲的内容涉及到数据库的许多概念,初次接触的朋友可能会感到比较难懂和枯燥,建议感兴趣的朋友们多结合实例,充分理解这些概念。</P><B><P align=justify> </P><P align=justify>名词解释:</P><P align=justify>数据表:</B>一组相关数据的集合,类似于表格,它的每一行称为一条记录,每一列称为一个字段。在关系数据库中,数据表是真正存储数据的地方。</P><B><P align=justify>记录:</B>在数据库中,记录是一个专有名词,它是数据表的单一入口,每条记录由几个字段组成。</P><B><P align=justify>字段:</B>记录中一个特定的数据项目,数据表中的每一列定义了字段的数据类型和数据宽度等属性。</P><B><P align=justify>索引:</B>数据库中为加快对某一字段的查询而保存的特殊信息。</P><B><P align=justify>记录集:</B>应用程序访问数据库时获得的一组数据集合,它可以是一个表中的全部数据,也可以是表的一个子集,或是几个表的合集。</P></FONT><B><FONT size=3><P align=justify>BDE</FONT><FONT face=宋体 size=3>:</B></FONT><FONT size=3>Borland</FONT><FONT face=宋体 size=3>公司开发的数据库引擎,是</FONT><FONT size=3>Delphi</FONT><FONT face=宋体 size=3>以及</FONT><FONT size=3>CBuilder</FONT><FONT face=宋体 size=3>应用程序访问数据的核心。</P><B><P align=justify>数据源:</B>数据源是</FONT><FONT face="宋体, MS Song" size=3>ODBC</FONT><FONT face=宋体 size=3>标准中的一个概念,它为某一个具体的数据库指定一个名称,数据源中定义了数据库的类型、所使用的驱动程序、所处的路径等信息。</P><B><P align=justify>别名:</B>别名用于基于</FONT><FONT face="宋体, MS Song" size=3>BDE</FONT><FONT face=宋体 size=3>的数据库应用程序中,它的作用与</FONT><FONT face="宋体, MS Song" size=3>ODBC</FONT><FONT face=宋体 size=3>数据源很类似。设置和维护数据库别名一般是通过工具软件</FONT><FONT face="宋体, MS Song" size=3>BDE</FONT><FONT face=宋体 size=3>管理器来完成。</P></FONT>
作者: 韩冰    时间: 2005-1-26 01:33
<b><FONT face=宋体 size=6> </FONT></b>< align=center>简单数据库查询操作</P><FONT face=宋体 size=3>< align=justify>上一讲我们学习了数据库编程的基础知识,并对</FONT><FONT face="宋体, MS Song" size=3>MP3Collect</FONT><FONT face=宋体 size=3>进行了一番改造,使其具有数据库访问能力。在本讲中,我们首先设置三个数据库元件</FONT><FONT face="宋体, MS Song" size=3>Query1</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>DataSource1</FONT><FONT face=宋体 size=3>和</FONT><FONT face="宋体, MS Song" size=3>DBGrid1</FONT><FONT face=宋体 size=3>的属性,接下来学习如何通过</FONT><FONT face="宋体, MS Song" size=3>Query</FONT><FONT face=宋体 size=3>控件实现简单的数据库查询操作。</P><UL><B>< align=justify><LI>设置控件属性
2 H: _- I, c3 E' J</LI></UL></B></FONT><FONT size=3>< align=justify>Query1</FONT><FONT face=宋体 size=3>控件的用途是查询数据库,获取可以显示在窗体中的数据。</FONT><FONT size=3>Query</FONT><FONT face=宋体 size=3>控件和</FONT><FONT size=3>Table</FONT><FONT face=宋体 size=3>控件一样,它们都是从</FONT><FONT size=3>VCL</FONT><FONT face=宋体 size=3>类</FONT><FONT size=3>TDataSet</FONT><FONT face=宋体 size=3>(数据集元件)中继承来的,都代表数据库中一组记录的集合。不同的是,</FONT><FONT size=3>Table</FONT><FONT face=宋体 size=3>控件代表库中实际存在的一个数据表对象,而</FONT><FONT size=3>Query</FONT><FONT face=宋体 size=3>控件则代表一次查询的结果。</FONT><FONT size=3>Query</FONT><FONT face=宋体 size=3>控件支持通过</FONT><FONT size=3>SQL</FONT><FONT face=宋体 size=3>进行查询,因此比</FONT><FONT size=3>Table</FONT><FONT face=宋体 size=3>控件具有更大的灵活性,它可以同时访问多个数据表,可以灵活访问数据表中的行和列,可以实现十分复杂的条件查询。</P></FONT><FONT size=3>< align=justify>SQL</FONT><FONT face=宋体 size=3>的全称是结构化查询语言,它是一种标准的数据库查询语言,具有自己的关键字(</FONT><FONT size=3>SQL</FONT><FONT face=宋体 size=3>中的关键字是不分大小写的,</FONT><FONT size=3>SELECT</FONT><FONT face=宋体 size=3>和</FONT><FONT size=3>Select</FONT><FONT face=宋体 size=3>的作用是相同的)和语法,典型的</FONT><FONT size=3>SQL</FONT><FONT face=宋体 size=3>查询语句如下所示:</P></FONT><FONT size=3>< align=justify>SELECT [</FONT><FONT face=宋体 size=3>字段名</FONT><FONT size=3>] FROM [</FONT><FONT face=宋体 size=3>数据表名</FONT><FONT size=3>] WHERE [</FONT><FONT face=宋体 size=3>条件子句</FONT><FONT size=3>]</P></FONT><FONT face=宋体 size=3>< align=justify>其中</FONT><FONT face="宋体, MS Song" size=3>SELECT</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>FROM</FONT><FONT face=宋体 size=3>和</FONT><FONT face="宋体, MS Song" size=3>WHERE</FONT><FONT face=宋体 size=3>都是</FONT><FONT face="宋体, MS Song" size=3>SQL</FONT><FONT face=宋体 size=3>的关键字。</FONT><FONT face="宋体, MS Song" size=3>SELECT</FONT><FONT face=宋体 size=3>代表查询操作,“字段名”表示返回的记录集中所包含的字段,字段名可以使用通配符</FONT><FONT face="宋体, MS Song" size=3>*</FONT><FONT face=宋体 size=3>,表示查询的数据表中的所有字段,“数据表名”表示在哪个数据表中进行查询,“条件子句”为查询的条件。</P>< align=justify>了解了</FONT><FONT face="宋体, MS Song" size=3>SQL</FONT><FONT face=宋体 size=3>的基本语法后,下面我们来设置</FONT><FONT face="宋体, MS Song" size=3>Query1</FONT><FONT face=宋体 size=3>控件的</FONT><FONT face="宋体, MS Song" size=3>SQL</FONT><FONT face=宋体 size=3>属性。在对象监视器中双击</FONT><FONT face="宋体, MS Song" size=3>Query1</FONT><FONT face=宋体 size=3>控件的</FONT><FONT face="宋体, MS Song" size=3>SQL</FONT><FONT face=宋体 size=3>属性(该属性为</FONT><FONT face="宋体, MS Song" size=3>TStrings*</FONT><FONT face=宋体 size=3>类型),打开字符串列表编辑器,在其中输入这样两句“</FONT><FONT face="宋体, MS Song" size=3>Select * From MP3Info</FONT><FONT face=宋体 size=3>”和“</FONT><FONT face="宋体, MS Song" size=3>Order by FileName ASC</FONT><FONT face=宋体 size=3>”。注意第二句要另起一行,这样在后面的编程中可以很方便地改变记录的排序方式。这两句合在一起的意思是获取</FONT><FONT face="宋体, MS Song" size=3>MP3Info</FONT><FONT face=宋体 size=3>数据表中的所有记录,并以</FONT><FONT face="宋体, MS Song" size=3>FileName</FONT><FONT face=宋体 size=3>字段为基准按升序方式排序。除了指定</FONT><FONT face="宋体, MS Song" size=3>Query1</FONT><FONT face=宋体 size=3>控件的</FONT><FONT face="宋体, MS Song" size=3>SQL</FONT><FONT face=宋体 size=3>属性外,还要指定它在哪个数据库中进行查询,将其</FONT><FONT face="宋体, MS Song" size=3>Database</FONT><FONT face=宋体 size=3>属性设为别名</FONT><FONT face="宋体, MS Song" size=3>MP3Collect</FONT><FONT face=宋体 size=3>。然后指定其</FONT><FONT face="宋体, MS Song" size=3>Active</FONT><FONT face=宋体 size=3>属性为</FONT><FONT face="宋体, MS Song" size=3>true</FONT><FONT face=宋体 size=3>,其它属性值都接受缺省值。</P></FONT><FONT size=3>< align=justify>DataSource</FONT><FONT face=宋体 size=3>控件从字面上可翻译为数据源控件,不过它与上一讲介绍的</FONT><FONT size=3>ODBC</FONT><FONT face=宋体 size=3>数据源可不是一回事。</FONT><FONT size=3>DataSource</FONT><FONT face=宋体 size=3>控件是一个中间控件,它位于数据集控件(如</FONT><FONT size=3>Table</FONT><FONT face=宋体 size=3>控件或</FONT><FONT size=3>Query</FONT><FONT face=宋体 size=3>控件)和数据控制控件(如</FONT><FONT size=3>DBGrid</FONT><FONT face=宋体 size=3>控件或</FONT><FONT size=3>DBEdit</FONT><FONT face=宋体 size=3>控件)之间,是联系两类控件的桥梁。</FONT><FONT size=3>DataSource</FONT><FONT face=宋体 size=3>控件最重要的属性是它的数据集属性</FONT><FONT size=3>DataSet</FONT><FONT face=宋体 size=3>,在对象浏览器中点击该属性右侧的下拉式列表框,可以看到其中列出了</FONT><FONT size=3>Table1</FONT><FONT face=宋体 size=3>和</FONT><FONT size=3>Query1</FONT><FONT face=宋体 size=3>,我们选中</FONT><FONT size=3>Query1</FONT><FONT face=宋体 size=3>,表示</FONT><FONT size=3>DataSource</FONT><FONT face=宋体 size=3>控件从</FONT><FONT size=3>Query1</FONT><FONT face=宋体 size=3>中获取数据。</P></FONT><FONT size=3>< align=justify>DBGrid</FONT><FONT face=宋体 size=3>控件是一种常用的数据控制元件,它以表格的方式显示记录,表格中的行表示记录,而列表示记录的字段。所有的数据控制元件都必须和某个</FONT><FONT size=3>DataSource</FONT><FONT face=宋体 size=3>控件相关联,才能获取所需要的数据,因此我们在这里将</FONT><FONT size=3>DBGrid1</FONT><FONT face=宋体 size=3>控件的</FONT><FONT size=3>DataSource</FONT><FONT face=宋体 size=3>属性设为</FONT><FONT size=3>DataSource1</FONT><FONT face=宋体 size=3>。指定</FONT><FONT size=3>DBGrid1</FONT><FONT face=宋体 size=3>的数据来源后,我们可以看到</FONT><FONT size=3>DBGrid1</FONT><FONT face=宋体 size=3>的表格中立即显示出相应的记录了。</P>< align=justify>缺省情况下,</FONT><FONT face="宋体, MS Song" size=3>DBGrid1</FONT><FONT face=宋体 size=3>会显示数据集的全部字段,并以字段的名称显示在列标题中,我们可以在设计时通过</FONT><FONT face="宋体, MS Song" size=3>DBGrid</FONT><FONT face=宋体 size=3>控件的列编辑器修改列的数目、标题以及布局等。在对象浏览器中双击</FONT><FONT face="宋体, MS Song" size=3>Columns</FONT><FONT face=宋体 size=3>属性,打开列编辑器,此时列编辑器中的内容还是空的,因此我们在列编辑器中点击鼠标右键,选择关联菜单中的“</FONT><FONT face="宋体, MS Song" size=3>Add All Field</FONT><FONT face=宋体 size=3>”命令,先把数据集中的所有字段添加进来。由于我们不希望将记录的编号显示出来,所以要删除其中的“</FONT><FONT face="宋体, MS Song" size=3>ID</FONT><FONT face=宋体 size=3>”字段。</P>< align=justify>接下来我们来设置各列的列标题。首先选中“</FONT><FONT face="宋体, MS Song" size=3>FileName</FONT><FONT face=宋体 size=3>”列,这时可以在对象浏览器中看到该列的各种属性,其中</FONT><FONT face="宋体, MS Song" size=3>FieldName</FONT><FONT face=宋体 size=3>属性为“</FONT><FONT face="宋体, MS Song" size=3>FileName</FONT><FONT face=宋体 size=3>”,表示该列显示“</FONT><FONT face="宋体, MS Song" size=3>FileName</FONT><FONT face=宋体 size=3>”字段的内容,列对象的</FONT><FONT face="宋体, MS Song" size=3>Title</FONT><FONT face=宋体 size=3>属性为复合属性,展开</FONT><FONT face="宋体, MS Song" size=3>Title</FONT><FONT face=宋体 size=3>属性,将其中的</FONT><FONT face="宋体, MS Song" size=3>Caption</FONT><FONT face=宋体 size=3>子属性改为“文件名称”,然后设置“</FONT><FONT face="宋体, MS Song" size=3>FileName</FONT><FONT face=宋体 size=3>”列的列宽度,其缺省的</FONT><FONT face="宋体, MS Song" size=3>Width</FONT><FONT face=宋体 size=3>属性为</FONT><FONT face="宋体, MS Song" size=3>-1</FONT><FONT face=宋体 size=3>,表示根据字段的宽度自动设置列宽度,我们可以根据窗体的布局为其重新设置一个实际的值。按照同样的方法,我们继续把“</FONT><FONT face="宋体, MS Song" size=3>SongName</FONT><FONT face=宋体 size=3>”、“</FONT><FONT face="宋体, MS Song" size=3>SingerName</FONT><FONT face=宋体 size=3>”的列标题改为“歌曲名称”和“歌手名称”。</P>< align=justify>设置好</FONT><FONT face="宋体, MS Song" size=3>DBGrid1</FONT><FONT face=宋体 size=3>控件的列对象的属性后,接下来还要设置它的</FONT><FONT face="宋体, MS Song" size=3>Options</FONT><FONT face=宋体 size=3>属性,该属性决定了显示记录的方式。展开</FONT><FONT face="宋体, MS Song" size=3>DBGrid1</FONT><FONT face=宋体 size=3>控件的</FONT><FONT face="宋体, MS Song" size=3>Options</FONT><FONT face=宋体 size=3>属性,可以看见其中有十多项选项,将其中的</FONT><FONT face="宋体, MS Song" size=3>dgEditing</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>dgAlwaysShowEdit</FONT><FONT face=宋体 size=3>和</FONT><FONT face="宋体, MS Song" size=3>dgMultiSelect</FONT><FONT face=宋体 size=3>三个选项设为</FONT><FONT face="宋体, MS Song" size=3>false</FONT><FONT face=宋体 size=3>,其余的选项都设为</FONT><FONT face="宋体, MS Song" size=3>true</FONT><FONT face=宋体 size=3>,如此设置可以屏蔽在</FONT><FONT face="宋体, MS Song" size=3>DBGrid</FONT><FONT face=宋体 size=3>中直接修改记录以及同时选中多条记录的功能。另外还可以设置</FONT><FONT face="宋体, MS Song" size=3>DBGrid1</FONT><FONT face=宋体 size=3>的</FONT><FONT face="宋体, MS Song" size=3>ReadOnly</FONT><FONT face=宋体 size=3>属性为</FONT><FONT face="宋体, MS Song" size=3>true</FONT><FONT face=宋体 size=3>,使用户不能在网格中进行添加、修改、删除记录的操作。最后,设置</FONT><FONT face="宋体, MS Song" size=3>DBGrid1</FONT><FONT face=宋体 size=3>的</FONT><FONT face="宋体, MS Song" size=3>opupMenu</FONT><FONT face=宋体 size=3>属性为</FONT><FONT face="宋体, MS Song" size=3>opupMenu1</FONT><FONT face=宋体 size=3>,为其指定关键菜单。</P>< align=justify>现在所有元件的属性都设置好了,下面我们来看看访问数据库的具体方法。为了简洁起见,下面的代码中都没有异常处理措施,读者朋友可以根据第</FONT><FONT face="宋体, MS Song" size=3>13</FONT><FONT face=宋体 size=3>讲的内容自己添加相应的异常处理代码。</P><UL><B>< align=justify><LI>实现查询功能 <p></LI></UL></B></FONT><FONT size=3>< align=justify>Table</FONT><FONT face=宋体 size=3>控件和</FONT><FONT size=3>Query</FONT><FONT face=宋体 size=3>控件都可以实现查询,但</FONT><FONT size=3>Table</FONT><FONT face=宋体 size=3>不支持</FONT><FONT size=3>SQL</FONT><FONT face=宋体 size=3>,只能通过数据表中的索引实现比较简单的检索功能(在后面还会用到</FONT><FONT size=3>Table</FONT><FONT face=宋体 size=3>的查询功能),因此心铃决定用</FONT><FONT size=3>Query1</FONT><FONT face=宋体 size=3>控件进行查询,提供显示在</FONT><FONT size=3>DBGrid1</FONT><FONT face=宋体 size=3>中的数据。</P>< align=justify>所有的查询都是通过设置</FONT><FONT face="宋体, MS Song" size=3>Query1</FONT><FONT face=宋体 size=3>控件的</FONT><FONT face="宋体, MS Song" size=3>SQL</FONT><FONT face=宋体 size=3>属性来完成的。实现显示所有记录的</FONT><FONT face="宋体, MS Song" size=3>SQL</FONT><FONT face=宋体 size=3>语句最简单,即前面给出的</FONT><FONT face="宋体, MS Song" size=3>SQL</FONT><FONT face=宋体 size=3>属性。下面是</FONT><FONT face="宋体, MS Song" size=3>btnShowAllClick</FONT><FONT face=宋体 size=3>事件处理函数的新代码,其中给出了在运行时改变</FONT><FONT face="宋体, MS Song" size=3>Query</FONT><FONT face=宋体 size=3>控件</FONT><FONT face="宋体, MS Song" size=3>SQL</FONT><FONT face=宋体 size=3>属性的方法。</P></FONT><FONT size=3>< align=justify>void __fastcall TMainForm::btnShowAllClick(TObject *Sender)</P>< align=justify>{</P>< align=justify>Query1-&gt;Close();//</FONT><FONT face=宋体 size=3>先关闭上一次查询</P></FONT><FONT size=3>< align=justify>Query1-&gt;SQL-&gt;Clear();//</FONT><FONT face=宋体 size=3>清除原来的</FONT><FONT size=3>SQL</FONT><FONT face=宋体 size=3>语句</P></FONT><FONT size=3>< align=justify>Query1-&gt;SQL-&gt;Add("Select * from MP3Info");//</FONT><FONT face=宋体 size=3>添加一个字符串,</FONT><FONT size=3>SQL</FONT><FONT face=宋体 size=3>属性由多个字符串组合而成</P></FONT><FONT size=3>< align=justify>Query1-&gt;SQL-&gt;Add("Order By FileName ASC");</P>< align=justify>ColumnToSort=0;//</FONT><FONT face=宋体 size=3>记下当前排序的基准列为“</FONT><FONT size=3>FileName</FONT><FONT face=宋体 size=3>”</P></FONT><FONT size=3>< align=justify>m_IsAsc=1;//</FONT><FONT face=宋体 size=3>记下当前排序的方式为升序方式</P></FONT><FONT size=3>< align=justify>Query1-&gt;Open(); //</FONT><FONT face=宋体 size=3>设置好</FONT><FONT size=3>SQL</FONT><FONT face=宋体 size=3>属性后,打开</FONT><FONT size=3>Query1</FONT><FONT face=宋体 size=3>,获取数据并自动更新</FONT><FONT size=3>DBGrid1</P></FONT><FONT face=宋体 size=3>< align=justify>}</P>< align=justify>在改变</FONT><FONT face="宋体, MS Song" size=3>Query1</FONT><FONT face=宋体 size=3>的</FONT><FONT face="宋体, MS Song" size=3>SQL</FONT><FONT face=宋体 size=3>属性之前,首先应将上一次查询关闭。</FONT><FONT face="宋体, MS Song" size=3>SQL</FONT><FONT face=宋体 size=3>属性是一个</FONT><FONT face="宋体, MS Song" size=3>TStrings</FONT><FONT face=宋体 size=3>对象指针,它将多个字符串组成一个完整的</FONT><FONT face="宋体, MS Song" size=3>SQL</FONT><FONT face=宋体 size=3>查询语句,其中的</FONT><FONT face="宋体, MS Song" size=3>Order By</FONT><FONT face=宋体 size=3>是</FONT><FONT face="宋体, MS Song" size=3>SQL</FONT><FONT face=宋体 size=3>中的关键字,表示按照某一个字段进行排序,</FONT><FONT face="宋体, MS Song" size=3>ASC</FONT><FONT face=宋体 size=3>是排序方式关键字,表示升序方式。</FONT><FONT face="宋体, MS Song" size=3>ColumnToSort</FONT><FONT face=宋体 size=3>和</FONT><FONT face="宋体, MS Song" size=3>m_IsAsc</FONT><FONT face=宋体 size=3>是</FONT><FONT face="宋体, MS Song" size=3>MainForm</FONT><FONT face=宋体 size=3>类的成员变量,用于保存排序的基准列号和排序方式,有关排序的内容还要在下一节仔细介绍。设置好</FONT><FONT face="宋体, MS Song" size=3>SQL</FONT><FONT face=宋体 size=3>属性后,调用</FONT><FONT face="宋体, MS Song" size=3>Query</FONT><FONT face=宋体 size=3>控件的</FONT><FONT face="宋体, MS Song" size=3>Open()</FONT><FONT face=宋体 size=3>方法,该方法会通过</FONT><FONT face="宋体, MS Song" size=3>BDE</FONT><FONT face=宋体 size=3>引擎向数据库进行一次查询操作,获取所需的数据,并自动更新</FONT><FONT face="宋体, MS Song" size=3>DBGrid1</FONT><FONT face=宋体 size=3>中显示的数据。</P><P align=justify>条件查询操作需要使用</FONT><FONT face="宋体, MS Song" size=3>SQL</FONT><FONT face=宋体 size=3>语句中的</FONT><FONT face="宋体, MS Song" size=3>WHERE</FONT><FONT face=宋体 size=3>条件子句。查询的原理是依次读取三个条件输入框的内容,如果某一条件输入框不为空,则添加一个查询条件。这里使用的查询条件的语法如下所示:</P></FONT><FONT size=3><P align=justify>[</FONT><FONT face=宋体 size=3>字段名</FONT><FONT size=3>] Like '</FONT><FONT face=宋体 size=3>带通配符的字符串</FONT><FONT size=3>'</P></FONT><FONT face=宋体 size=3><P align=justify>其中</FONT><FONT face="宋体, MS Song" size=3>[</FONT><FONT face=宋体 size=3>字段名</FONT><FONT face="宋体, MS Song" size=3>]</FONT><FONT face=宋体 size=3>为要检查的字段,</FONT><FONT face="宋体, MS Song" size=3>LIKE</FONT><FONT face=宋体 size=3>为</FONT><FONT face="宋体, MS Song" size=3>SQL</FONT><FONT face=宋体 size=3>的关键字,表示将字段内容与“带通配符的字符串”进行比较,看是否符合给定的模式。“带通配符的字符串”需要用单引号包括起来,常用的通配符有“</FONT><FONT face="宋体, MS Song" size=3>%</FONT><FONT face=宋体 size=3>”、“?”等。其中“</FONT><FONT face="宋体, MS Song" size=3>%</FONT><FONT face=宋体 size=3>”表示任意字符串。例如,下面的</FONT><FONT face="宋体, MS Song" size=3>SQL</FONT><FONT face=宋体 size=3>语句表示从</FONT><FONT face="宋体, MS Song" size=3>MP3Info</FONT><FONT face=宋体 size=3>中取出所有</FONT><FONT face="宋体, MS Song" size=3>FileName</FONT><FONT face=宋体 size=3>字段中包括“</FONT><FONT face="宋体, MS Song" size=3>MP3</FONT><FONT face=宋体 size=3>”字样的记录:</P></FONT><FONT size=3><P align=justify>SELECT * FROM MP3Info WHERE FileName Like %MP3%</P></FONT><FONT face=宋体 size=3><P align=justify>另外,在</FONT><FONT face="宋体, MS Song" size=3>MP3Collect</FONT><FONT face=宋体 size=3>中,各个查询条件之间是逻辑与的关系,因此多个查询条件之间要用关键字</FONT><FONT face="宋体, MS Song" size=3>AND</FONT><FONT face=宋体 size=3>进行连接,表示只有符合所有查询条件的记录才是所需要的记录。下面是</FONT><FONT face="宋体, MS Song" size=3>btnFindClick</FONT><FONT face=宋体 size=3>事件处理函数的新代码:</P></FONT><FONT size=3><P align=justify>void __fastcall TMainForm::btnFindClick(TObject *Sender)</P><P align=justify>{</P><P align=justify>Query1-&gt;Close();//</FONT><FONT face=宋体 size=3>首先关闭</FONT><FONT size=3>Query1</P><P align=justify>Query1-&gt;SQL-&gt;Clear();//</FONT><FONT face=宋体 size=3>清除原有的</FONT><FONT size=3>SQL</FONT><FONT face=宋体 size=3>语句</P></FONT><FONT size=3><P align=justify>Query1-&gt;SQL-&gt;Add("Select * from MP3Info");//</FONT><FONT face=宋体 size=3>表示从数据表中</FONT><FONT size=3>MP3Info</FONT><FONT face=宋体 size=3>中查询</P></FONT><FONT size=3><P align=justify>//</FONT><FONT face=宋体 size=3>如果</FONT><FONT size=3>edtFileName</FONT><FONT face=宋体 size=3>不为空,则添加对</FONT><FONT size=3>FileName</FONT><FONT face=宋体 size=3>字段的查询,注意不要漏了其中的单引号</P></FONT><FONT size=3><P align=justify>if(!edtFileName-&gt;Text.IsEmpty())</P><DIR><P align=justify>Query1-&gt;SQL-&gt;Add(" where FileName Like '%"+edtFileName-&gt;Text+"%'");</P></DIR><P align=justify>//</FONT><FONT face=宋体 size=3>如果</FONT><FONT size=3>edtSongName</FONT><FONT face=宋体 size=3>不为空,则添加对</FONT><FONT size=3>SongName</FONT><FONT face=宋体 size=3>字段的查询,由于整个条件子句中只有</P></FONT><FONT size=3><P align=justify>//</FONT><FONT face=宋体 size=3>一个</FONT><FONT size=3>WHERE</FONT><FONT face=宋体 size=3>关键字,多个条件之间需要用</FONT><FONT size=3>AND</FONT><FONT face=宋体 size=3>关键字连接,所以要进行一些特殊处理</P></FONT><FONT size=3><P align=justify>if(!edtSongName-&gt;Text.IsEmpty())</P><P align=justify>{</P><DIR><P align=justify>if(Query1-&gt;SQL-&gt;Count&gt;1)//</FONT><FONT face=宋体 size=3>判断是否已经包含查询条件了</P><DIR></FONT><FONT size=3><P align=justify>Query1-&gt;SQL-&gt;Add(" and ");//</FONT><FONT face=宋体 size=3>如果是,则用</FONT><FONT size=3>AND</FONT><FONT face=宋体 size=3>连接本查询条件</P></DIR></FONT><FONT size=3><P align=justify>else</P><DIR><P align=justify>Query1-&gt;SQL-&gt;Add(" where ");//</FONT><FONT face=宋体 size=3>否则用</FONT><FONT size=3>WHERE</FONT><FONT face=宋体 size=3>引出查询条件</P></DIR></FONT><FONT size=3><P align=justify>Query1-&gt;SQL-&gt;Add("SongName Like '%"+edtSongName-&gt;Text+"%'");//</FONT><FONT face=宋体 size=3>添加一个查询条件</P></DIR><P align=justify>}</P></FONT><FONT size=3><P align=justify>//</FONT><FONT face=宋体 size=3>如果</FONT><FONT size=3>edtSingerName</FONT><FONT face=宋体 size=3>编辑框中不为空,则添加对</FONT><FONT size=3>SingerName</FONT><FONT face=宋体 size=3>字段的查询</P></FONT><FONT size=3><P align=justify>if(!edtSingerName-&gt;Text.IsEmpty())</P><P align=justify>{</P><DIR><P align=justify>if(Query1-&gt;SQL-&gt;Count&gt;1)//</FONT><FONT face=宋体 size=3>判断是否已经包含查询条件了</P><DIR></FONT><FONT size=3><P align=justify>Query1-&gt;SQL-&gt;Add(" and ");//</FONT><FONT face=宋体 size=3>如果是,则用</FONT><FONT size=3>AND</FONT><FONT face=宋体 size=3>连接本查询条件</P></DIR></FONT><FONT size=3><P align=justify>else</P><DIR><P align=justify>Query1-&gt;SQL-&gt;Add(" where ");//</FONT><FONT face=宋体 size=3>否则用</FONT><FONT size=3>WHERE</FONT><FONT face=宋体 size=3>引出查询条件</P></DIR></FONT><FONT size=3><P align=justify>Query1-&gt;SQL-&gt;Add("SingerName Like '%"+edtSingerName-&gt;Text+"%'");//</FONT><FONT face=宋体 size=3>添加一个查询条件</P></DIR><P align=justify>}</P></FONT><FONT size=3><P align=justify>Query1-&gt;SQL-&gt;Add(" Order By FileName ASC");//</FONT><FONT face=宋体 size=3>添加排序子句</P></FONT><FONT size=3><P align=justify>ColumnToSort=0;//</FONT><FONT face=宋体 size=3>记下当前排序的基准列为“</FONT><FONT size=3>FileName</FONT><FONT face=宋体 size=3>”</P></FONT><FONT size=3><P align=justify>m_IsAsc=1;//</FONT><FONT face=宋体 size=3>记下当前排序的方式为升序方式</P></FONT><FONT size=3><P align=justify>Query1-&gt;Open();</P></FONT><FONT face=宋体 size=3><P align=justify>}</P><UL><B><P align=justify><LI>实现排序 <p></LI></UL></B><P align=justify>前面我们已经用到了</FONT><FONT face="宋体, MS Song" size=3>SQL</FONT><FONT face=宋体 size=3>语言的排序子句,排序子句是由关键词</FONT><FONT face="宋体, MS Song" size=3>Order By</FONT><FONT face=宋体 size=3>引出的,其后跟一个或多个字段,表示以某个字段为基准进行排序,如果有多个字段,则先按第一个字段进行排序,如果出现第一个字段的内容相同,再按第二个字段排序,依此类推。另外还可以用</FONT><FONT face="宋体, MS Song" size=3>ASC</FONT><FONT face=宋体 size=3>(升序方式)和</FONT><FONT face="宋体, MS Song" size=3>DESC</FONT><FONT face=宋体 size=3>(降序方式)规定其排序的方式。</P><P align=justify>我们在</FONT><FONT face="宋体, MS Song" size=3>TMainForm</FONT><FONT face=宋体 size=3>中添加了一个成员变量</FONT><FONT face="宋体, MS Song" size=3>m_IsAsc</FONT><FONT face=宋体 size=3>,用于保存当前排序的方式,注意应在窗体的初始化函数</FONT><FONT face="宋体, MS Song" size=3>FormCreate</FONT><FONT face=宋体 size=3>中将</FONT><FONT face="宋体, MS Song" size=3>m_IsAsc</FONT><FONT face=宋体 size=3>初始化为</FONT><FONT face="宋体, MS Song" size=3>1</FONT><FONT face=宋体 size=3>。下面是菜单命令</FONT><FONT face="宋体, MS Song" size=3>mnuSortByFileName</FONT><FONT face=宋体 size=3>的命令处理函数:</P></FONT><FONT size=3><P align=justify>void __fastcall TMainForm::mnuSortByFileNameClick(TObject *Sender)</P><P align=justify>{</P><P align=justify>if(ColumnToSort!=0)//</FONT><FONT face=宋体 size=3>如果以前不是按</FONT><FONT size=3>FileName</FONT><FONT face=宋体 size=3>字段排序,则改为按</FONT><FONT size=3>FileName</FONT><FONT face=宋体 size=3>字段排序</P><P align=justify>{</P><DIR></FONT><FONT size=3><P align=justify>Query1-&gt;Close();</P><P align=justify>Query1-&gt;SQL-&gt;Delete(Query1-&gt;SQL-&gt;Count-1);//</FONT><FONT face=宋体 size=3>清除原来的排序子句</P></FONT><FONT size=3><P align=justify>Query1-&gt;SQL-&gt;Add("Order By FileName ASC");//</FONT><FONT face=宋体 size=3>添加新的排序子句</P></FONT><FONT size=3><P align=justify>ColumnToSort=0;//</FONT><FONT face=宋体 size=3>记下当前排序的基准列为“</FONT><FONT size=3>FileName</FONT><FONT face=宋体 size=3>”</P></FONT><FONT size=3><P align=justify>m_IsAsc=1; //</FONT><FONT face=宋体 size=3>记下当前排序的方式为升序方式</P></FONT><FONT size=3><P align=justify>Query1-&gt;Open();</P></DIR></FONT><FONT face=宋体 size=3><P align=justify>}</P></FONT><FONT size=3><P align=justify>else //</FONT><FONT face=宋体 size=3>否则切换排序的方式</P><P align=justify>{</P><DIR></FONT><FONT size=3><P align=justify>Query1-&gt;Close();</P><P align=justify>Query1-&gt;SQL-&gt;Delete(Query1-&gt;SQL-&gt;Count-1);</P><P align=justify>if(m_IsAsc)</P><DIR><P align=justify>Query1-&gt;SQL-&gt;Add("Order By FileName DESC");//</FONT><FONT face=宋体 size=3>如果原来是升序,改为降序</P></DIR></FONT><FONT size=3><P align=justify>else</P><DIR><P align=justify>Query1-&gt;SQL-&gt;Add("Order By FileName Asc");//</FONT><FONT face=宋体 size=3>如果原来是降序,改为升序</P></DIR></FONT><FONT size=3><P align=justify>m_IsAsc=1-m_IsAsc;//</FONT><FONT face=宋体 size=3>改变</FONT><FONT size=3>m_IsAsc</FONT><FONT face=宋体 size=3>的值,反映排序方式的改变</P></FONT><FONT size=3><P align=justify>Query1-&gt;Open();//</FONT><FONT face=宋体 size=3>打开</FONT><FONT size=3>Query1</P></DIR></FONT><FONT face=宋体 size=3><P align=justify>}</P><P align=justify>}</P><P align=justify>另外两个排序菜单命令的处理函数</FONT><FONT face="宋体, MS Song" size=3>mnuSortBySongNameClick</FONT><FONT face=宋体 size=3>和</FONT><FONT face="宋体, MS Song" size=3>mnuSortBySingerNameClick</FONT><FONT face=宋体 size=3>的实现方法与</FONT><FONT face="宋体, MS Song" size=3>mnuSortByFileNameClick</FONT><FONT face=宋体 size=3>很类似,就交给读者朋友自己完成吧。</P><P align=justify>最后,还要响应</FONT><FONT face="宋体, MS Song" size=3>DBGrid1</FONT><FONT face=宋体 size=3>的</FONT><FONT face="宋体, MS Song" size=3>OnTitleClick</FONT><FONT face=宋体 size=3>事件,允许用户通过单击</FONT><FONT face="宋体, MS Song" size=3>DBGrid1</FONT><FONT face=宋体 size=3>的列标题来改变排序的方式。下面是</FONT><FONT face="宋体, MS Song" size=3>DBGrid1TitleClick</FONT><FONT face=宋体 size=3>函数的新代码:</P></FONT><FONT size=3><P align=justify>void __fastcall TMainForm:BGrid1TitleClick(TColumn *Column)</P><P align=justify>{</P><DIR><P align=justify>switch(Column-&gt;Index)//</FONT><FONT face=宋体 size=3>用户点击的列号</P></DIR><P align=justify>{</P><DIR></FONT><FONT size=3><P align=justify>case 0://</FONT><FONT face=宋体 size=3>如果是第一列,则按</FONT><FONT size=3>FileName</FONT><FONT face=宋体 size=3>进行排序</P></FONT><FONT size=3><P align=justify>mnuSortByFileNameClick(NULL);</P><P align=justify>break;</P></DIR><P align=justify>case 1: //</FONT><FONT face=宋体 size=3>如果是第二列,则按</FONT><FONT size=3>SongName</FONT><FONT face=宋体 size=3>进行排序</P><DIR></FONT><FONT size=3><P align=justify>mnuSortBySongNameClick(NULL);</P><P align=justify>break;</P><P align=justify>case 2: //</FONT><FONT face=宋体 size=3>如果是第三列,则按</FONT><FONT size=3>SingerName</FONT><FONT face=宋体 size=3>进行排序</P></FONT><FONT size=3><P align=justify>mnuSortBySingerNameClick(NULL);</P><P align=justify>break;</P></DIR></FONT><FONT face=宋体 size=3><P align=justify>}</P><P align=justify>}</P><P align=justify>本讲我们学习了利用</FONT><FONT face="宋体, MS Song" size=3>Query</FONT><FONT face=宋体 size=3>控件和</FONT><FONT face="宋体, MS Song" size=3>SQL</FONT><FONT face=宋体 size=3>语句实现简单数据库查询的方法,</FONT><FONT face="宋体, MS Song" size=3>SQL</FONT><FONT face=宋体 size=3>实际上是数据库编程的核心内容之一,因此心铃建议想进一步学习数据库开发的读者朋友一定要掌握好</FONT><FONT face="宋体, MS Song" size=3>SQL</FONT><FONT face=宋体 size=3>的语法和用法。在下一讲中,我们将学习简单的数据库编辑操作,即添加、修改和删除记录的方法。</P></FONT>
作者: 韩冰    时间: 2005-1-26 01:34
<b><FONT face=宋体 size=6> </FONT></b>< align=center>简单数据库编辑操作</P><FONT face=宋体 size=3>< align=justify>上一讲我们学习了利用</FONT><FONT face="宋体, MS Song" size=3>Query1</FONT><FONT face=宋体 size=3>控件和</FONT><FONT face="宋体, MS Song" size=3>SQL</FONT><FONT face=宋体 size=3>语句实现简单数据库查询的方法,在本讲中,我们将要学习如何利用</FONT><FONT face="宋体, MS Song" size=3>Table1</FONT><FONT face=宋体 size=3>控件来实现添加、修改、删除记录等数据库编辑操作。</P><UL><B>< align=justify><LI>获取当前记录
7 n% C0 ^2 O, G3 t: r</LI></UL></B>< align=justify>在上一讲中我们曾经比较过</FONT><FONT face="宋体, MS Song" size=3>Query</FONT><FONT face=宋体 size=3>控件和</FONT><FONT face="宋体, MS Song" size=3>Table</FONT><FONT face=宋体 size=3>控件的异同,并指出</FONT><FONT face="宋体, MS Song" size=3>Query</FONT><FONT face=宋体 size=3>控件是通过</FONT><FONT face="宋体, MS Song" size=3>SQL</FONT><FONT face=宋体 size=3>语句来操作数据库的,</FONT><FONT face="宋体, MS Song" size=3>SQL</FONT><FONT face=宋体 size=3>语句除了可以实现查询外,也可以通过关键字</FONT><FONT face="宋体, MS Song" size=3>INSERT</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>UPDATE</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>DELETE</FONT><FONT face=宋体 size=3>来实现添加、修改和删除记录的操作,但是这一类</FONT><FONT face="宋体, MS Song" size=3>SQL</FONT><FONT face=宋体 size=3>语句对初学者来说有一定难度,而</FONT><FONT face="宋体, MS Song" size=3>Table</FONT><FONT face=宋体 size=3>控件提供有</FONT><FONT face="宋体, MS Song" size=3>Insert</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>Edit</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>Delete</FONT><FONT face=宋体 size=3>等方法,实现简单的数据库编辑操作比</FONT><FONT face="宋体, MS Song" size=3>Query</FONT><FONT face=宋体 size=3>控件更为容易,因此心铃决定以</FONT><FONT face="宋体, MS Song" size=3>Table</FONT><FONT face=宋体 size=3>控件为例来介绍进行数据库编辑操作的方法。</P></FONT><FONT size=3>< align=justify>MP3Collect</FONT><FONT face=宋体 size=3>使用的</FONT><FONT size=3>Query1</FONT><FONT face=宋体 size=3>和</FONT><FONT size=3>Table1</FONT><FONT face=宋体 size=3>是两个独立的控件,用户看到窗体上的数据是由</FONT><FONT size=3>Query1</FONT><FONT face=宋体 size=3>提供的,怎样才能让</FONT><FONT size=3>Table1</FONT><FONT face=宋体 size=3>控件知道用户当前操作的是哪一条记录呢?</P>< align=justify>为了解决这个问题,我们需要先学习一些基础知识。数据集控件(</FONT><FONT face="宋体, MS Song" size=3>Table</FONT><FONT face=宋体 size=3>或</FONT><FONT face="宋体, MS Song" size=3>Query</FONT><FONT face=宋体 size=3>)除了提供一组记录集合之外,还保存了一个称为光标(</FONT><FONT face="宋体, MS Song" size=3>Cursor</FONT><FONT face=宋体 size=3>)的指针,用于指向当前记录,程序可以通过调用</FONT><FONT face="宋体, MS Song" size=3>TDataSet</FONT><FONT face=宋体 size=3>类的</FONT><FONT face="宋体, MS Song" size=3>First()</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>Next()</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>rior()</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>MoveBy()</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>Last()</FONT><FONT face=宋体 size=3>等方法控制记录光标的移动。</P>< align=justify>如果数据集控件与某个数据控制控件相关联,则还可以通过数据控制控件来移动记录光标,例如,</FONT><FONT face="宋体, MS Song" size=3>MP3Collect</FONT><FONT face=宋体 size=3>主窗体上的</FONT><FONT face="宋体, MS Song" size=3>Query1</FONT><FONT face=宋体 size=3>控件和</FONT><FONT face="宋体, MS Song" size=3>DBGrid1</FONT><FONT face=宋体 size=3>控件建立了关联(通过</FONT><FONT face="宋体, MS Song" size=3>DataSource1</FONT><FONT face=宋体 size=3>控件),当用户在</FONT><FONT face="宋体, MS Song" size=3>DBGrid1</FONT><FONT face=宋体 size=3>中选择不同的行时,同时也会把</FONT><FONT face="宋体, MS Song" size=3>Query1</FONT><FONT face=宋体 size=3>的记录光标移到相应的位置上。</P>< align=justify>无论用哪种方式改变了数据集控件的当前记录光标,都会触发数据集控件的</FONT><FONT face="宋体, MS Song" size=3>AfterScroll</FONT><FONT face=宋体 size=3>事件。因此,我们要为</FONT><FONT face="宋体, MS Song" size=3>Query1</FONT><FONT face=宋体 size=3>控件添加</FONT><FONT face="宋体, MS Song" size=3>AfterScroll</FONT><FONT face=宋体 size=3>事件的处理函数</FONT><FONT face="宋体, MS Song" size=3>Query1AfterScroll</FONT><FONT face=宋体 size=3>,在其中获取当前记录的内容并显示在三个编辑框中,同时在</FONT><FONT face="宋体, MS Song" size=3>MediaPlayer1</FONT><FONT face=宋体 size=3>中打开相应的音乐文件,另外还要利用</FONT><FONT face="宋体, MS Song" size=3>Table</FONT><FONT face=宋体 size=3>控件的</FONT><FONT face="宋体, MS Song" size=3>FindKey()</FONT><FONT face=宋体 size=3>方法将</FONT><FONT face="宋体, MS Song" size=3>Table1</FONT><FONT face=宋体 size=3>的记录光标调整到相同的记录上。</P>< align=justify>前一讲中介绍过,</FONT><FONT face="宋体, MS Song" size=3>Table</FONT><FONT face=宋体 size=3>控件也具有一定的查询能力,</FONT><FONT face="宋体, MS Song" size=3>FindKey()</FONT><FONT face=宋体 size=3>就是它的查询方法之一,其原理是利用数据表的索引进行快速的检索操作。查询的步骤如下:首先设置</FONT><FONT face="宋体, MS Song" size=3>Table</FONT><FONT face=宋体 size=3>控件的</FONT><FONT face="宋体, MS Song" size=3>IndexName</FONT><FONT face=宋体 size=3>属性。在窗体设计阶段,我们已经将</FONT><FONT face="宋体, MS Song" size=3>Table1</FONT><FONT face=宋体 size=3>控件的</FONT><FONT face="宋体, MS Song" size=3>IndexName</FONT><FONT face=宋体 size=3>属性设为</FONT><FONT face="宋体, MS Song" size=3>ID</FONT><FONT face=宋体 size=3>,选择</FONT><FONT face="宋体, MS Song" size=3>ID</FONT><FONT face=宋体 size=3>作为</FONT><FONT face="宋体, MS Song" size=3>Table1</FONT><FONT face=宋体 size=3>的索引,是因为每个记录的</FONT><FONT face="宋体, MS Song" size=3>ID</FONT><FONT face=宋体 size=3>值是唯一的,不用担心会检索出重复的记录。在运行时确认</FONT><FONT face="宋体, MS Song" size=3>Table1</FONT><FONT face=宋体 size=3>处于打开的状态,然后调用其</FONT><FONT face="宋体, MS Song" size=3>FindKey()</FONT><FONT face=宋体 size=3>方法,查找数据表中</FONT><FONT face="宋体, MS Song" size=3>ID</FONT><FONT face=宋体 size=3>值与</FONT><FONT face="宋体, MS Song" size=3>Query1</FONT><FONT face=宋体 size=3>控件的当前记录</FONT><FONT face="宋体, MS Song" size=3>ID</FONT><FONT face=宋体 size=3>值相等的记录,同时将</FONT><FONT face="宋体, MS Song" size=3>Table1</FONT><FONT face=宋体 size=3>的光标移到新的记录上。下面就是</FONT><FONT face="宋体, MS Song" size=3>Query1AfterScroll</FONT><FONT face=宋体 size=3>的实现代码。</P></FONT><FONT size=3>< align=justify>void __fastcall TMainForm:uery1AfterScroll(TDataSet *DataSet)</P>< align=justify>{</P>< align=justify>if(Query1-&gt;State==dsBrowse )//</FONT><FONT face=宋体 size=3>如果</FONT><FONT size=3>Query1</FONT><FONT face=宋体 size=3>控件当前处于记录浏览状态</P>< align=justify>{</P><DIR></FONT><FONT size=3>< align=justify>if(!Query1-&gt;IsEmpty())//</FONT><FONT face=宋体 size=3>如果</FONT><FONT size=3>Query1</FONT><FONT face=宋体 size=3>的数据集不为空</P>< align=justify>{</P><DIR></FONT><FONT size=3>< align=justify>//</FONT><FONT face=宋体 size=3>声明</FONT><FONT size=3>TVarRec</FONT><FONT face=宋体 size=3>类型的变量数组,</FONT><FONT size=3>FindKey()</FONT><FONT face=宋体 size=3>方法使用该类型的数组作为参数。</P></DIR></DIR></FONT><FONT size=3>< align=justify>TVarRec KeyValues[1]; </P>< align=justify>//</FONT><FONT face=宋体 size=3>获得</FONT><FONT size=3>Query1</FONT><FONT face=宋体 size=3>控件的当前记录的</FONT><FONT size=3>ID</FONT><FONT face=宋体 size=3>字段内容,并赋给</FONT><FONT size=3>KeyValues</FONT><FONT face=宋体 size=3>数组中的第一个元素</P><DIR><DIR></FONT><FONT size=3>< align=justify>KeyValues[0]=Query1-&gt;FieldByName("ID")-&gt;AsInteger;</P>< align=justify>if(!Table1-&gt;Active) //</FONT><FONT face=宋体 size=3>如果</FONT><FONT size=3>Table1</FONT><FONT face=宋体 size=3>还未打开,将其打开</P><DIR><DIR></FONT><FONT size=3>< align=justify>Table1-&gt;Active =true;</P></DIR></DIR></DIR></DIR>< align=justify>Table1-&gt;FindKey(KeyValues,0);//</FONT><FONT face=宋体 size=3>调用</FONT><FONT size=3>FindKey()</FONT><FONT face=宋体 size=3>方法,查找并定位新的记录光标</P></FONT><FONT size=3>< align=justify>//</FONT><FONT face=宋体 size=3>获取</FONT><FONT size=3>Query1</FONT><FONT face=宋体 size=3>控件当前记录的各个字段内容,并赋给相应的编辑框</P><DIR><DIR></FONT><FONT size=3>< align=justify>edtFileName-&gt;Text=Query1-&gt;FieldByName("FileName")-&gt;AsString;</P>< align=justify>edtSongName-&gt;Text=Query1-&gt;FieldByName("SongName")-&gt;AsString;</P>< align=justify>edtSingerName-&gt;Text=Query1-&gt;FieldByName("SingerName")-&gt;AsString;</P></DIR></DIR>< align=justify>//</FONT><FONT face=宋体 size=3>在</FONT><FONT size=3>MediaPlayer1</FONT><FONT face=宋体 size=3>中打开相应的音乐文件</P><DIR><DIR></FONT><FONT size=3>< align=justify>MediaPlayer1-&gt;FileName=Query1-&gt;FieldByName("FileName")-&gt;AsString;</P>< align=justify>MediaPlayer1-&gt;Open();</P></DIR></FONT><FONT face=宋体 size=3><P align=justify>}</P></DIR><P align=justify>}</P><P align=justify>}</P><UL><B><P align=justify><LI>移动当前记录 <p></LI></UL></B><P align=justify>为了实现向前、向后浏览和连续播放的功能,我们需要通过程序控制数据集的光标移动。其中,向前移动一条记录使用</FONT><FONT face="宋体, MS Song" size=3>TDataSet</FONT><FONT face=宋体 size=3>类的</FONT><FONT face="宋体, MS Song" size=3>Prior()</FONT><FONT face=宋体 size=3>方法,向后移动一条记录使用</FONT><FONT face="宋体, MS Song" size=3>Next()</FONT><FONT face=宋体 size=3>方法,移动到第一条记录使用</FONT><FONT face="宋体, MS Song" size=3>First()</FONT><FONT face=宋体 size=3>方法,移动到最后一条记录使用</FONT><FONT face="宋体, MS Song" size=3>Last()</FONT><FONT face=宋体 size=3>方法。</FONT><FONT face="宋体, MS Song" size=3>TDataSet</FONT><FONT face=宋体 size=3>类还提供了两个布尔类型的属性</FONT><FONT face="宋体, MS Song" size=3>Bof</FONT><FONT face=宋体 size=3>和</FONT><FONT face="宋体, MS Song" size=3>Eof</FONT><FONT face=宋体 size=3>,用于确定当前的记录是否是数据集中的第一个记录或最后一个记录。下面给出用户点击</FONT><FONT face="宋体, MS Song" size=3>MediaPlayer</FONT><FONT face=宋体 size=3>的</FONT><FONT face="宋体, MS Song" size=3>Next</FONT><FONT face=宋体 size=3>和</FONT><FONT face="宋体, MS Song" size=3>Prev</FONT><FONT face=宋体 size=3>按钮时的事件处理代码(完整的事件处理函数参见第</FONT><FONT face="宋体, MS Song" size=3>11</FONT><FONT face=宋体 size=3>讲):</P><DIR></FONT><FONT size=3><P align=justify>case Mplayer::btNext: //</FONT><FONT face=宋体 size=3>如果用户点击</FONT><FONT size=3>Next</FONT><FONT face=宋体 size=3>按钮,播放下一首</FONT><FONT size=3>MP3</FONT><FONT face=宋体 size=3>文件</P><DIR></FONT><FONT size=3><P align=justify>EnableButtons(false);//</FONT><FONT face=宋体 size=3>使记录操作按钮失效</P></FONT><FONT size=3><P align=justify>Query1-&gt;Next();//</FONT><FONT face=宋体 size=3>使</FONT><FONT size=3>Query1</FONT><FONT face=宋体 size=3>控件的记录光标向后移动一条记录</P></FONT><FONT size=3><P align=justify>if(Query1-&gt;Eof)//</FONT><FONT face=宋体 size=3>如果</FONT><FONT size=3>Query1</FONT><FONT face=宋体 size=3>控件的</FONT><FONT size=3>Eof</FONT><FONT face=宋体 size=3>属性为真,则表示已到了最后一个记录</P><DIR><DIR></FONT><FONT size=3><P align=justify>Query1-&gt;First();//</FONT><FONT face=宋体 size=3>循环到当前数据集的第一个记录</P></DIR></DIR></FONT><FONT size=3><P align=justify>m_bIsPlaying=true; //</FONT><FONT face=宋体 size=3>设置</FONT><FONT size=3>m_bIsPlaying</FONT><FONT face=宋体 size=3>标志</P></FONT><FONT size=3><P align=justify>DoDefault=false; //</FONT><FONT face=宋体 size=3>不执行缺省的按钮事件</P></FONT><FONT size=3><P align=justify>PlayTheSong();//</FONT><FONT face=宋体 size=3>执行打开</FONT><FONT size=3>MP3</FONT><FONT face=宋体 size=3>文件、播放</FONT><FONT size=3>MP3</FONT><FONT face=宋体 size=3>文件等操作</P></FONT><FONT size=3><P align=justify>Timer1-&gt;Enabled=true; //</FONT><FONT face=宋体 size=3>打开定时器</P></FONT><FONT size=3><P align=justify>break;</P></DIR><P align=justify>case Mplayer::btPrev: //</FONT><FONT face=宋体 size=3>如果用户点击</FONT><FONT size=3>Prev</FONT><FONT face=宋体 size=3>按钮,播放上一首</FONT><FONT size=3>MP3</FONT><FONT face=宋体 size=3>文件</P><DIR></FONT><FONT size=3><P align=justify>EnableButtons(false);</P><P align=justify>Query1-&gt;Prior();//</FONT><FONT face=宋体 size=3>使</FONT><FONT size=3>Query1</FONT><FONT face=宋体 size=3>控件的记录光标向前移动一条记录</P></FONT><FONT size=3><P align=justify>if(Query1-&gt;Bof)//</FONT><FONT face=宋体 size=3>如果</FONT><FONT size=3>Query1</FONT><FONT face=宋体 size=3>控件的</FONT><FONT size=3>Bof</FONT><FONT face=宋体 size=3>属性为真,则表示已到了第一个记录</P><DIR><DIR></FONT><FONT size=3><P align=justify>Query1-&gt;Last();//</FONT><FONT face=宋体 size=3>循环到当前数据集的最后一个记录</P></DIR></DIR></FONT><FONT size=3><P align=justify>m_bIsPlaying=true;</P><P align=justify>DoDefault=false;</P><P align=justify>PlayTheSong();</P><P align=justify>Timer1-&gt;Enabled=true;</P></DIR></DIR><P align=justify>break;</P><P align=justify>Timer1</FONT><FONT face=宋体 size=3>的时间事件处理函数如下所示:</P></FONT><FONT size=3><P align=justify>void __fastcall TMainForm::Timer1Timer(TObject *Sender)</P><P align=justify>{</P><P align=justify>if(MediaPlayer1-&gt;Position == MediaPlayer1-&gt;Length) //</FONT><FONT face=宋体 size=3>如果已经播放到一个文件的末尾</P><P align=justify>{</P><DIR></FONT><FONT size=3><P align=justify>//</FONT><FONT face=宋体 size=3>检测</FONT><FONT size=3>chkLoop</FONT><FONT face=宋体 size=3>是否处于选中状态,以及媒体播放器是否处于播放状态</P></FONT><FONT size=3><P align=justify>if(chkLoop-&gt;Checked &amp;&amp; m_bIsPlaying)</P></FONT><FONT face=宋体 size=3><P align=justify>{</P><DIR></FONT><FONT size=3><P align=justify>Query1-&gt;Next();//</FONT><FONT face=宋体 size=3>使</FONT><FONT size=3>Query1</FONT><FONT face=宋体 size=3>控件的记录光标向后移动一条记录</P></FONT><FONT size=3><P align=justify>if(Query1-&gt;Eof)//</FONT><FONT face=宋体 size=3>如果</FONT><FONT size=3>Query1</FONT><FONT face=宋体 size=3>控件的</FONT><FONT size=3>Eof</FONT><FONT face=宋体 size=3>属性为真,则表示已到了最后一个记录</P><DIR><DIR></FONT><FONT size=3><P align=justify>Query1-&gt;First();//</FONT><FONT face=宋体 size=3>循环到当前数据集的第一个记录</P></DIR></DIR></DIR><P align=justify>}</P></FONT><FONT size=3><P align=justify>else</P></FONT><FONT face=宋体 size=3><P align=justify>{</P><DIR></FONT><FONT size=3><P align=justify>EnableButtons(true);//</FONT><FONT face=宋体 size=3>使记录操作按钮有效</P></FONT><FONT size=3><P align=justify>Timer1-&gt;Enabled =false;//</FONT><FONT face=宋体 size=3>关闭定时器</P></DIR><P align=justify>}</P></DIR><P align=justify>}</P><P align=justify>}</P><UL><B><P align=justify><LI>添加记录 <p></LI></UL></B></FONT><FONT size=3><P align=justify>TTable</FONT><FONT face=宋体 size=3>控件类提供了两种添加记录的方法,它们是</FONT><FONT size=3>Insert()</FONT><FONT face=宋体 size=3>和</FONT><FONT size=3>Append()</FONT><FONT face=宋体 size=3>。其中</FONT><FONT size=3>Insert()</FONT><FONT face=宋体 size=3>方法在当前记录处添加一条新的记录,而</FONT><FONT size=3>Append()</FONT><FONT face=宋体 size=3>则是在数据表的最后添加一条新记录,在</FONT><FONT size=3>MP3Collect</FONT><FONT face=宋体 size=3>中我们要使用的是前者。</P></FONT><FONT size=3><P align=justify>Insert()</FONT><FONT face=宋体 size=3>方法向数据表中添加一条空白的记录,并使</FONT><FONT size=3>Table</FONT><FONT face=宋体 size=3>控件处于记录添加状态。接下来设置新记录的各个字段值,利用</FONT><FONT size=3>TTable</FONT><FONT face=宋体 size=3>类的</FONT><FONT size=3>FieldByName()</FONT><FONT face=宋体 size=3>方法可以获取当前记录的各个字段对象。</FONT><FONT size=3>VCL</FONT><FONT face=宋体 size=3>为字段提供了封装类</FONT><FONT size=3>TField</FONT><FONT face=宋体 size=3>,根据字段不同的数据类型,</FONT><FONT size=3>TField</FONT><FONT face=宋体 size=3>类又提供了</FONT><FONT size=3>As****</FONT><FONT face=宋体 size=3>属性,用于读写其字段值。在</FONT><FONT size=3>MP3Info</FONT><FONT face=宋体 size=3>数据表中,</FONT><FONT size=3>FileName</FONT><FONT face=宋体 size=3>、</FONT><FONT size=3>SongName</FONT><FONT face=宋体 size=3>、</FONT><FONT size=3>SingerName</FONT><FONT face=宋体 size=3>都是文本类型,因此使用</FONT><FONT size=3>TField</FONT><FONT face=宋体 size=3>类的</FONT><FONT size=3>AsString</FONT><FONT face=宋体 size=3>属性来读写它们的内容。</P><P align=justify>设置好新记录的各个字段值后,需要调用</FONT><FONT face="宋体, MS Song" size=3>Table</FONT><FONT face=宋体 size=3>控件的</FONT><FONT face="宋体, MS Song" size=3>Post()</FONT><FONT face=宋体 size=3>方法将此次操作保存到数据库中,如果用户放弃了这次操作,也可以调用</FONT><FONT face="宋体, MS Song" size=3>Cancel()</FONT><FONT face=宋体 size=3>方法取消这次添加操作。</FONT><FONT face="宋体, MS Song" size=3>Post()</FONT><FONT face=宋体 size=3>和</FONT><FONT face="宋体, MS Song" size=3>Cancel()</FONT><FONT face=宋体 size=3>都可以结束记录添加状态,使</FONT><FONT face="宋体, MS Song" size=3>Table</FONT><FONT face=宋体 size=3>控件恢复成记录浏览状态。</P><P align=justify>下面给出“添加”按钮的命令响应函数</FONT><FONT face="宋体, MS Song" size=3>btnAddClick()</FONT><FONT face=宋体 size=3>的新代码,另外一个同时添加多条记录的函数</FONT><FONT face="宋体, MS Song" size=3>mnuAddClick()</FONT><FONT face=宋体 size=3>留给读者朋友自己完成。</P></FONT><FONT size=3><P align=justify>void __fastcall TMainForm::btnAddClick(TObject *Sender)</P><P align=justify>{</P><P align=justify>if(edtFileName-&gt;Text.IsEmpty())//</FONT><FONT face=宋体 size=3>判断文件名编辑框中是否为空</P><P align=justify>{</P><DIR></FONT><FONT size=3><P align=justify>Application-&gt;MessageBox("</FONT><FONT face=宋体 size=3>文件名称不能为空,请重新输入文件名称!</FONT><FONT size=3>","MP3Collect",MB_OK);</P><P align=justify>edtFileName-&gt;SetFocus();//</FONT><FONT face=宋体 size=3>令文件名编辑框获得键盘输入焦点</P></FONT><FONT size=3><P align=justify>return;</P></DIR></FONT><FONT face=宋体 size=3><P align=justify>}</P></FONT><FONT size=3><P align=justify>Table1-&gt;Insert();//</FONT><FONT face=宋体 size=3>添加一条空白记录</P></FONT><FONT size=3><P align=justify>Table1-&gt;FieldByName("FileName")-&gt;AsString=edtFileName-&gt;Text;//</FONT><FONT face=宋体 size=3>设置</FONT><FONT size=3>FileName</FONT><FONT face=宋体 size=3>字段</P></FONT><FONT size=3><P align=justify>Table1-&gt;FieldByName("SongName")-&gt;AsString=edtSongName-&gt;Text;//</FONT><FONT face=宋体 size=3>设置</FONT><FONT size=3>SongName</FONT><FONT face=宋体 size=3>字段</P></FONT><FONT size=3><P align=justify>Table1-&gt;FieldByName("SingerName")-&gt;AsString=edtSingerName-&gt;Text;//</FONT><FONT face=宋体 size=3>设置</FONT><FONT size=3>SingerName</FONT><FONT face=宋体 size=3>字段</P></FONT><FONT size=3><P align=justify>Table1-&gt;Post();//</FONT><FONT face=宋体 size=3>保存这次添加操作所作的修改</P></FONT><FONT size=3><P align=justify>RefreshQuery();//</FONT><FONT face=宋体 size=3>更新</FONT><FONT size=3>Query</FONT><FONT face=宋体 size=3>控件中的数据,同时也更新窗体中的显示</P><P align=justify>}</P><P align=justify>在成功地添加了记录之后,还需要更新窗体上显示的数据,也就是要更新</FONT><FONT face="宋体, MS Song" size=3>Query1</FONT><FONT face=宋体 size=3>控件中的数据。由于在进行添加、修改、删除记录等操作之后同样要进行这一步骤,我们为</FONT><FONT face="宋体, MS Song" size=3>MainForm</FONT><FONT face=宋体 size=3>窗体类添加了一个新的成员函数</FONT><FONT face="宋体, MS Song" size=3>RefreshQuery()</FONT><FONT face=宋体 size=3>来完成这一工作。更新</FONT><FONT face="宋体, MS Song" size=3>Query1</FONT><FONT face=宋体 size=3>的方法比较简单,只需要先关闭一次,再重新打开就可以。为了保证在更新后还能恢复正确的记录光标位置,我们利用了数据集控件的书签对象(</FONT><FONT face="宋体, MS Song" size=3>Bookmark</FONT><FONT face=宋体 size=3>)来保存和恢复记录光标位置。</FONT><FONT face="宋体, MS Song" size=3>RefreshQuery()</FONT><FONT face=宋体 size=3>函数如下所示:</P></FONT><FONT size=3><P align=justify>void __fastcall TMainForm::RefreshQuery()</P><P align=justify>{</P><P align=justify>TBookmark * bm=(TBookmark *)Query1-&gt;GetBookmark();//</FONT><FONT face=宋体 size=3>获取当前</FONT><FONT size=3>Query1</FONT><FONT face=宋体 size=3>控件的书签对象</P></FONT><FONT size=3><P align=justify>Query1-&gt;Close();//</FONT><FONT face=宋体 size=3>先关闭</FONT><FONT size=3>Query1</P><P align=justify>Query1-&gt;Open();//</FONT><FONT face=宋体 size=3>再重新打开</FONT><FONT size=3>Query1</FONT><FONT face=宋体 size=3>,即可更新其中的数据</P></FONT><FONT size=3><P align=justify>Query1-&gt;GotoBookmark(bm);//</FONT><FONT face=宋体 size=3>利用书签对象恢复记录光标的位置</P></FONT><FONT size=3><P align=justify>Query1-&gt;FreeBookmark(bm);//</FONT><FONT face=宋体 size=3>释放书签对象</P><P align=justify>}</P><UL><B><P align=justify><LI>修改记录和删除记录 <p></LI></UL></B><P align=justify>由于前面已经为</FONT><FONT face="宋体, MS Song" size=3>Table1</FONT><FONT face=宋体 size=3>控件和</FONT><FONT face="宋体, MS Song" size=3>Query1</FONT><FONT face=宋体 size=3>控件的光标位置作了同步调整,因此可以保证在</FONT><FONT face="宋体, MS Song" size=3>Table1</FONT><FONT face=宋体 size=3>中修改和删除的记录是用户当前所选择的记录。</P><P align=justify>修改记录的步骤是:首先调用</FONT><FONT face="宋体, MS Song" size=3>Table1</FONT><FONT face=宋体 size=3>控件的</FONT><FONT face="宋体, MS Song" size=3>Edit()</FONT><FONT face=宋体 size=3>方法,使其处于记录修改状态,再设置当前记录的各个字段值,设置方法与添加记录中一样,接下来调用</FONT><FONT face="宋体, MS Song" size=3>Table1</FONT><FONT face=宋体 size=3>控件的</FONT><FONT face="宋体, MS Song" size=3>Post()</FONT><FONT face=宋体 size=3>方法保存这次修改,并关闭记录修改状态,回复到记录浏览状态,最后调用</FONT><FONT face="宋体, MS Song" size=3>RefreshQuery()</FONT><FONT face=宋体 size=3>函数更新显示数据。</P><P align=justify>删除记录的操作最简单,只要调用</FONT><FONT face="宋体, MS Song" size=3>Table1</FONT><FONT face=宋体 size=3>控件的</FONT><FONT face="宋体, MS Song" size=3>Delete ()</FONT><FONT face=宋体 size=3>方法就可以删除其当前的数据记录。</P><P align=justify>下面是“修改”和“删除”按钮的命令响应函数的实现代码:</P></FONT><FONT size=3><P align=justify>void __fastcall TMainForm::btnModifyClick(TObject *Sender) //</FONT><FONT face=宋体 size=3>“修改”按钮的命令响应函数</P><P align=justify>{</P></FONT><FONT size=3><P align=justify>Table1-&gt;Edit();//</FONT><FONT face=宋体 size=3>使</FONT><FONT size=3>Table1</FONT><FONT face=宋体 size=3>控件处于记录编辑状态</P></FONT><FONT size=3><P align=justify>Table1-&gt;FieldByName("FileName")-&gt;AsString=edtFileName-&gt;Text;//</FONT><FONT face=宋体 size=3>修改</FONT><FONT size=3>FileName</FONT><FONT face=宋体 size=3>字段</P></FONT><FONT size=3><P align=justify>Table1-&gt;FieldByName("SongName")-&gt;AsString=edtSongName-&gt;Text;//</FONT><FONT face=宋体 size=3>修改</FONT><FONT size=3>SongName</FONT><FONT face=宋体 size=3>字段</P></FONT><FONT size=3><P align=justify>Table1-&gt;FieldByName("SingerName")-&gt;AsString=edtSingerName-&gt;Text;//</FONT><FONT face=宋体 size=3>修改</FONT><FONT size=3>SingerName</FONT><FONT face=宋体 size=3>字段</P></FONT><FONT size=3><P align=justify>Table1-&gt;Post();//</FONT><FONT face=宋体 size=3>保存这次操作所作的修改</P></FONT><FONT size=3><P align=justify>RefreshQuery();</P></FONT><FONT face=宋体 size=3><P align=justify>}</P></FONT><FONT size=3><P align=justify>void __fastcall TMainForm::btnDeleteClick(TObject *Sender) //</FONT><FONT face=宋体 size=3>“删除”按钮的命令响应函数</P><P align=justify>{</P></FONT><FONT size=3><P align=justify>Table1-&gt;Delete();//</FONT><FONT face=宋体 size=3>删除当前记录</P></FONT><FONT size=3><P align=justify>RefreshQuery();//</FONT><FONT face=宋体 size=3>更新</FONT><FONT size=3>Query</FONT><FONT face=宋体 size=3>控件中的数据,同时也更新窗体中的显示</P><P align=justify>}</P><P align=justify> </P><P align=justify>到现在为此,我们对</FONT><FONT face="宋体, MS Song" size=3>MP3Collect</FONT><FONT face=宋体 size=3>的改造也已基本完成,第二版的</FONT><FONT face="宋体, MS Song" size=3>MP3Collect</FONT><FONT face=宋体 size=3>程序已经具备了第一版的全部功能,并且解决第一版存在的一些潜在问题。数据库编程其实是一个相当复杂的课题,讲座中介绍的内容仅仅是九牛一毛,读者朋友们必须多学习、多动手实践方可真正掌握好数据库编程。</P></FONT>
作者: 韩冰    时间: 2005-1-26 01:37
<b><FONT face=宋体 size=6> </FONT></b>< align=center>实现简单的数据报表</P><FONT face=宋体 size=3>< align=justify>在前两讲中我们已经学习了对数据库进行查询和读写操作的基本方法,本讲中我们将为</FONT><FONT face="宋体, MS Song" size=3>MP3Collect</FONT><FONT face=宋体 size=3>小程序添加另一项与数据库操作有关的新功能:数据报表打印功能。</P>< align=justify>打印数据报表是开发数据库类应用程序过程中经常遇到的问题,特别是在商务类的应用软件中,单位领导或者客户关心的不仅仅是显示在计算机屏幕上的数据,更重要的是打印出来的整齐清晰的报表。</P>< align=justify>设计一个好的数据报表应该遵循这样几个原则:首先要了解用户需要得到什么样的数据,数据库中的记录可能有成千上万条,打印出来的应该是经过提炼、精简的,其中将涉及到数据库的查询、统计、分组、排序等操作;第二个要点是关于报表的布局设计,其设计原则是整齐有序、美观大方,在某些应用场合,如财会类的应用软件中,报表的设计需要遵循固定的格式。第三点是将数据与报表结合起来,实现数据报表的生成与打印。</P><UL><B>< align=justify><LI>使用数据报表向导 ' J9 @2 m# l/ ?" ^
</LI></UL></B>< align=justify>从前面的介绍中我们可以看出,实现数据报表的功能还是颇为复杂的。好在</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>充分考虑到了数据报表的重要性,在其集成开发环境中提供了许多现成的数据报表控件,因此大大方便了数据报表的设计与实现。另外,</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>还提供有专门的数据报表向导,利用向导可以在几分钟内完成一个简单的数据报表的设计。</P>< align=justify>下面我们首先学习如何使用</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>的数据报表向导。在</FONT><FONT face="宋体, MS Song" size=3>MP3Collect</FONT><FONT face=宋体 size=3>工程中使用菜单命令“</FONT><FONT face="宋体, MS Song" size=3>File-&gt;New...</FONT><FONT face=宋体 size=3>”,在弹出的新建对象对话框中选择“</FONT><FONT face="宋体, MS Song" size=3>Business</FONT><FONT face=宋体 size=3>”页,并双击其中的“</FONT><FONT face="宋体, MS Song" size=3>Quick Report Wizard</FONT><FONT face=宋体 size=3>”图标。这时会弹出如图</FONT><FONT face="宋体, MS Song" size=3>17-1</FONT><FONT face=宋体 size=3>所示的新数据报表向导对话框,在其中选择报表的样式为“</FONT><FONT face="宋体, MS Song" size=3>List Report</FONT><FONT face=宋体 size=3>”,然后按下“</FONT><FONT face="宋体, MS Song" size=3>Start Wizard</FONT><FONT face=宋体 size=3>”按钮启动向导。</P>< align=justify>向导接下来会显示如图</FONT><FONT face="宋体, MS Song" size=3>17-2</FONT><FONT face=宋体 size=3>所示的参数设置对话框。“</FONT><FONT face="宋体, MS Song" size=3>Alias or directory</FONT><FONT face=宋体 size=3>”一栏用于指定数据库,我们在下拉列表框中选择数据库别名</FONT><FONT face="宋体, MS Song" size=3>MP3Collect</FONT><FONT face=宋体 size=3>。“</FONT><FONT face="宋体, MS Song" size=3>Table Name</FONT><FONT face=宋体 size=3>”一栏用于指定表,我们选择</FONT><FONT face="宋体, MS Song" size=3>MP3Info</FONT><FONT face=宋体 size=3>。这时,数据表</FONT><FONT face="宋体, MS Song" size=3>MP3Info</FONT><FONT face=宋体 size=3>中的四个字段</FONT><FONT face="宋体, MS Song" size=3>ID</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>FileName</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>SongName</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>SingerName</FONT><FONT face=宋体 size=3>自动出现在</FONT><FONT face="宋体, MS Song" size=3>Avaliable fields</FONT><FONT face=宋体 size=3>(可用的字段)列表框中,它的右侧是</FONT><FONT face="宋体, MS Song" size=3>Selected fields</FONT><FONT face=宋体 size=3>(选中的字段)列表框,两个列表框中间有四个箭头按钮,用来在两个列表框之间移动字段。在本例中我们只希望打印歌曲名称和歌手名称两项内容,因此将</FONT><FONT face="宋体, MS Song" size=3>SongName</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>SingerName</FONT><FONT face=宋体 size=3>两个字段选入</FONT><FONT face="宋体, MS Song" size=3>Selected fields</FONT><FONT face=宋体 size=3>列表框。设置好显示的数据内容后,按下“</FONT><FONT face="宋体, MS Song" size=3>Finish</FONT><FONT face=宋体 size=3>”按钮,创建报表完毕,这时我们可以看到,工程中新添了一个报表窗体</FONT><FONT face="宋体, MS Song" size=3>Form1</FONT><FONT face=宋体 size=3>,如图</FONT><FONT face="宋体, MS Song" size=3>17-3</FONT><FONT face=宋体 size=3>所示,该窗体上的各个控件的用途及使用方法在下一节中详细介绍。现在我们先来看一下报表窗体运行的效果,用鼠标右键单击窗体中的空白部分,在关联菜单中选择</FONT><FONT face="宋体, MS Song" size=3>review</FONT><FONT face=宋体 size=3>命令,可以对报表进行打印预览,如图</FONT><FONT face="宋体, MS Song" size=3>17-4</FONT><FONT face=宋体 size=3>所示。打印预览是以所见即所得的方式显示报表输出到打印机的效果,在预览窗口的上方有一排快捷按钮,可以进行切换预览方式、浏览不同的页面等操作,其中还有两个打印机形状的按钮,一个用于设置打印机,另一个则是执行打印命令,完成向打印机的输出。预览完毕后可以点击工具条上的</FONT><FONT face="宋体, MS Song" size=3>Close</FONT><FONT face=宋体 size=3>按钮关闭预览窗口。</P>< align=justify>从这个例子中我们可以看出,使用报表向导来创建报表时,只需要指定数据库、数据表、报表中输出的字段名,就可以生成一个简单的数据报表。下面我们就来仔细了解一下报表窗体上的各个组成部分,并在向导生成的报表基础上稍加修改,使之更加满足我们的要求。</P><UL><B>< align=justify><LI>常用的数据报表元件 <p></LI></UL></B>< align=justify>图</FONT><FONT face="宋体, MS Song" size=3>17-3</FONT><FONT face=宋体 size=3>所示的数据报表窗体中,</FONT><FONT face="宋体, MS Song" size=3>TTable</FONT><FONT face=宋体 size=3>控件</FONT><FONT face="宋体, MS Song" size=3>Table1</FONT><FONT face=宋体 size=3>是我们所熟悉的,它指向</FONT><FONT face="宋体, MS Song" size=3>MP3Collect</FONT><FONT face=宋体 size=3>数据库中的</FONT><FONT face="宋体, MS Song" size=3>MP3Info</FONT><FONT face=宋体 size=3>数据表,其作用是提供打印报表所需要的数据。窗体上的其它控件都属于</FONT><FONT face="宋体, MS Song" size=3>QuickReport</FONT><FONT face=宋体 size=3>控件。</FONT><FONT face="宋体, MS Song" size=3>QuickReport</FONT><FONT face=宋体 size=3>是由</FONT><FONT face="宋体, MS Song" size=3>QuSoft AS</FONT><FONT face=宋体 size=3>公司开发的第三方软件产品,它以一组元件的形式集成在</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>中,能够帮助</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>编程人员以可视化的方法快速开发数据报表应用程序,目前</FONT><FONT face="宋体, MS Song" size=3>CBuilder 5.0</FONT><FONT face=宋体 size=3>中采用的是</FONT><FONT face="宋体, MS Song" size=3>QuickReport 3.0</FONT><FONT face=宋体 size=3>版本。</P>< align=justify>在元件面板中找到</FONT><FONT face="宋体, MS Song" size=3>QReport</FONT><FONT face=宋体 size=3>元件栏,我们可以看到其中包含了二十几个元件,利用这些元件,可以使报表输出各种类型的数据,如图像、图形、数值、文本、</FONT><FONT face="宋体, MS Song" size=3>HTML</FONT><FONT face=宋体 size=3>格式的文本等,并控制报表各个部分的输出效果,如大小、字体、颜色、对齐方式等。在设计报表时我们会发现,设计报表和设计程序窗体十分相似,报表中常用的一些元件,如</FONT><FONT face="宋体, MS Song" size=3>TQRLabel</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>TQRMemo</FONT><FONT face=宋体 size=3>等元件与普通的窗体元件如</FONT><FONT face="宋体, MS Song" size=3>TLabel</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>TMemo</FONT><FONT face=宋体 size=3>等在名称和用途上也有一定的对应关系。报表元件与普通窗体元件之间的最重要的差别在于:普通窗体元件具有与用户交互的功能,它们能够接收用户的输入,而报表元件则只是负责输出,输出的结果可能是在打印机上(如果选择了打印报表操作)也可能是在屏幕上(如果选择了打印预览操作)。</P>< align=justify>在</FONT><FONT face="宋体, MS Song" size=3>QuickReport</FONT><FONT face=宋体 size=3>元件组中,最重要的元件是</FONT><FONT face="宋体, MS Song" size=3>TQuickRep</FONT><FONT face=宋体 size=3>控件,它是实现报表的基础,可以控制报表的生成和打印,它还是其它</FONT><FONT face="宋体, MS Song" size=3>QuickReport</FONT><FONT face=宋体 size=3>控件的容器,因此</FONT><FONT face="宋体, MS Song" size=3>TQuickRep</FONT><FONT face=宋体 size=3>是在</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>中实现数据报表功能必不可少的控件。在向导生成的</FONT><FONT face="宋体, MS Song" size=3>Form1</FONT><FONT face=宋体 size=3>窗体中,我们可以看到,</FONT><FONT face="宋体, MS Song" size=3>TQuickRep</FONT><FONT face=宋体 size=3>控件对象</FONT><FONT face="宋体, MS Song" size=3>QuickRep1</FONT><FONT face=宋体 size=3>为一个白色背景、带有网格和标尺的矩形。该矩形充满整个窗体的客户区,它代表的是打印输出的纸张大小,</FONT><FONT face="宋体, MS Song" size=3>QuickRep1</FONT><FONT face=宋体 size=3>内部有一个蓝色虚线的方框,表示可打印区域。在可打印区域内部,我们可以看到用黑色虚线框起的三个长条形区域,每一个长条形区域称为一个</FONT><FONT face="宋体, MS Song" size=3>Band</FONT><FONT face=宋体 size=3>。不同的</FONT><FONT face="宋体, MS Song" size=3>Band</FONT><FONT face=宋体 size=3>将</FONT><FONT face="宋体, MS Song" size=3>TQuickRep</FONT><FONT face=宋体 size=3>控件内部分为不同的区域,例如标题栏区(</FONT><FONT face="宋体, MS Song" size=3>Title</FONT><FONT face=宋体 size=3>)用于显示报表的标题,如果报表由多页组成,则只显示在第一页上;列标题栏区(</FONT><FONT face="宋体, MS Song" size=3>ColumnHeader</FONT><FONT face=宋体 size=3>)显示列标题,如果报表由多页组成,它会显示在每一页的表格上方;明细栏区(</FONT><FONT face="宋体, MS Song" size=3>Detail</FONT><FONT face=宋体 size=3>)则显示具体的数据,虽然在设计阶段只显示了一行内容,但在输出时会根据实际记录的数量显示出多行来,形成一个表格。</FONT><FONT face="宋体, MS Song" size=3>TQuickRep</FONT><FONT face=宋体 size=3>控件中定义了六种</FONT><FONT face="宋体, MS Song" size=3>Band</FONT><FONT face=宋体 size=3>区域,除了刚才提到的三种,还有页眉栏(</FONT><FONT face="宋体, MS Song" size=3>ageHeader</FONT><FONT face=宋体 size=3>)、页脚栏(</FONT><FONT face="宋体, MS Song" size=3>ageFooter</FONT><FONT face=宋体 size=3>)、合计栏(</FONT><FONT face="宋体, MS Song" size=3>Summary</FONT><FONT face=宋体 size=3>),</FONT><FONT face="宋体, MS Song" size=3>TQuickRep</FONT><FONT face=宋体 size=3>控件的</FONT><FONT face="宋体, MS Song" size=3>Bands</FONT><FONT face=宋体 size=3>属性决定了显示哪些</FONT><FONT face="宋体, MS Song" size=3>Band</FONT><FONT face=宋体 size=3>区域。</FONT><FONT face="宋体, MS Song" size=3>TQuickRep</FONT><FONT face=宋体 size=3>控件的属性</FONT><FONT face="宋体, MS Song" size=3>DataSet</FONT><FONT face=宋体 size=3>属性决定了它与自己内部的其它报表控件的数据来源。与前两讲介绍的数据访问控件不同的是,数据报表控件可以直接从</FONT><FONT face="宋体, MS Song" size=3>TDataSet</FONT><FONT face=宋体 size=3>类的控件中获取数据,而不需要</FONT><FONT face="宋体, MS Song" size=3>TDataSource</FONT><FONT face=宋体 size=3>控件作为中转。</P>< align=justify>在本例中,</FONT><FONT face="宋体, MS Song" size=3>QuickRep1</FONT><FONT face=宋体 size=3>的</FONT><FONT face="宋体, MS Song" size=3>DataSet</FONT><FONT face=宋体 size=3>属性设为</FONT><FONT face="宋体, MS Song" size=3>Table1</FONT><FONT face=宋体 size=3>,表示数据来源为</FONT><FONT face="宋体, MS Song" size=3>MP3Collect</FONT><FONT face=宋体 size=3>数据库中的</FONT><FONT face="宋体, MS Song" size=3>MP3Info</FONT><FONT face=宋体 size=3>数据表。除了上述属性之外,</FONT><FONT face="宋体, MS Song" size=3>TQuickRep</FONT><FONT face=宋体 size=3>控件的其它重要属性还包括有</FONT><FONT face="宋体, MS Song" size=3>Frame</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>Options</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>age</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>rintSettings</FONT><FONT face=宋体 size=3>等等,其中</FONT><FONT face="宋体, MS Song" size=3>Frame</FONT><FONT face=宋体 size=3>属性定义了报表的四周是否有边框,以及边框的样式(大部分</FONT><FONT face="宋体, MS Song" size=3>QuickReport</FONT><FONT face=宋体 size=3>报表控件都有</FONT><FONT face="宋体, MS Song" size=3>Frame</FONT><FONT face=宋体 size=3>属性,用于定义边框),</FONT><FONT face="宋体, MS Song" size=3>Options</FONT><FONT face=宋体 size=3>属性定义了一些用于显示的选项,</FONT><FONT face="宋体, MS Song" size=3>age</FONT><FONT face=宋体 size=3>属性定义了打印纸张的大小、纸型、页边距等,该属性和输出打印机的设置有关,</FONT><FONT face="宋体, MS Song" size=3>rintSettings</FONT><FONT face=宋体 size=3>属性则定义了打印的范围、打印的份数等参数。</P>< align=justify>在</FONT><FONT face="宋体, MS Song" size=3>TQuickRep</FONT><FONT face=宋体 size=3>控件中,需要显示的</FONT><FONT face="宋体, MS Song" size=3>Band</FONT><FONT face=宋体 size=3>区域自动显示为</FONT><FONT face="宋体, MS Song" size=3>TQuickRep</FONT><FONT face=宋体 size=3>控件内部的一个黑色虚线矩形,该矩形实际上是一个</FONT><FONT face="宋体, MS Song" size=3>TQRBand</FONT><FONT face=宋体 size=3>控件。</FONT><FONT face="宋体, MS Song" size=3>TQRBand</FONT><FONT face=宋体 size=3>控件封装了报表中不同</FONT><FONT face="宋体, MS Song" size=3>Band</FONT><FONT face=宋体 size=3>区域的属性和方法,其属性</FONT><FONT face="宋体, MS Song" size=3>BandType</FONT><FONT face=宋体 size=3>决定了该</FONT><FONT face="宋体, MS Song" size=3>Band</FONT><FONT face=宋体 size=3>区域的类型。</FONT><FONT face="宋体, MS Song" size=3>QuickRep1</FONT><FONT face=宋体 size=3>中的三个</FONT><FONT face="宋体, MS Song" size=3>Band</FONT><FONT face=宋体 size=3>对象的类型分别为</FONT><FONT face="宋体, MS Song" size=3>rbColumnHeader</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>rbDetail</FONT><FONT face=宋体 size=3>和</FONT><FONT face="宋体, MS Song" size=3>rbPageFooter</FONT><FONT face=宋体 size=3>。</FONT><FONT face="宋体, MS Song" size=3>TQRBand</FONT><FONT face=宋体 size=3>控件可以用来控制各个栏目区域的大小和位置,例如,如果我们加大</FONT><FONT face="宋体, MS Song" size=3>DetailBand1</FONT><FONT face=宋体 size=3>的高度,就可以加大报表表格中行的间距,利用</FONT><FONT face="宋体, MS Song" size=3>TQRBand</FONT><FONT face=宋体 size=3>控件对象还可以实现其它一些显示上的特殊效果,朋友们可以多试一试各种不同设置的效果。不过心铃认为</FONT><FONT face="宋体, MS Song" size=3>TQRBand</FONT><FONT face=宋体 size=3>对象的主要作用应该是作为其它报表控件的容器。</P>< align=justify>前面已经说过,报表</FONT><FONT face="宋体, MS Song" size=3>QuickRep1</FONT><FONT face=宋体 size=3>被划分为三个</FONT><FONT face="宋体, MS Song" size=3>Band</FONT><FONT face=宋体 size=3>区域,分别是列标题区</FONT><FONT face="宋体, MS Song" size=3>ColumnHeaderBand1</FONT><FONT face=宋体 size=3>、明细区</FONT><FONT face="宋体, MS Song" size=3>DetailBand1</FONT><FONT face=宋体 size=3>和页脚区</FONT><FONT face="宋体, MS Song" size=3>ageFooterBand1</FONT><FONT face=宋体 size=3>。</P>< align=justify>列标题区</FONT><FONT face="宋体, MS Song" size=3>ColumnHeaderBand1</FONT><FONT face=宋体 size=3>内包括两个</FONT><FONT face="宋体, MS Song" size=3>TQRLabel</FONT><FONT face=宋体 size=3>控件,分别显示“</FONT><FONT face="宋体, MS Song" size=3>SongName</FONT><FONT face=宋体 size=3>”和“</FONT><FONT face="宋体, MS Song" size=3>SingerName</FONT><FONT face=宋体 size=3>”两个字符串。</FONT><FONT face="宋体, MS Song" size=3>TQRLabel</FONT><FONT face=宋体 size=3>控件用于显示固定的文本字符串,它在报表中作用与</FONT><FONT face="宋体, MS Song" size=3>Label</FONT><FONT face=宋体 size=3>控件在普通窗体中的作用是相似的(注意不要在报表中使用普通窗体控件,它们不会在预览或打印结果中显示出来)。</FONT><FONT face="宋体, MS Song" size=3>TQRLabel</FONT><FONT face=宋体 size=3>控件的属性也很好理解,与普通</FONT><FONT face="宋体, MS Song" size=3>Label</FONT><FONT face=宋体 size=3>控件相比,它多了一个</FONT><FONT face="宋体, MS Song" size=3>Frame</FONT><FONT face=宋体 size=3>复合属性,该属性定义了字符串的四周是否显示边框,以及边框的样式等。“</FONT><FONT face="宋体, MS Song" size=3>SongName</FONT><FONT face=宋体 size=3>”和“</FONT><FONT face="宋体, MS Song" size=3>SingerName</FONT><FONT face=宋体 size=3>”两个</FONT><FONT face="宋体, MS Song" size=3>TQRLabel</FONT><FONT face=宋体 size=3>对象的</FONT><FONT face="宋体, MS Song" size=3>Frame</FONT><FONT face=宋体 size=3>属性中就定义为显示下边框,因此我们在预览效果(图</FONT><FONT face="宋体, MS Song" size=3>17-4</FONT><FONT face=宋体 size=3>)中可以看到列标题下方有一根直线把列标题与报表明细内容区分开来。</P>< align=justify>明细区</FONT><FONT face="宋体, MS Song" size=3>DetailBand1</FONT><FONT face=宋体 size=3>包含两个</FONT><FONT face="宋体, MS Song" size=3>TQRExpr</FONT><FONT face=宋体 size=3>对象</FONT><FONT face="宋体, MS Song" size=3>QRExpr2</FONT><FONT face=宋体 size=3>和</FONT><FONT face="宋体, MS Song" size=3>QRExpr3</FONT><FONT face=宋体 size=3>。</FONT><FONT face="宋体, MS Song" size=3>TQRExpr</FONT><FONT face=宋体 size=3>控件是</FONT><FONT face="宋体, MS Song" size=3>QuickReport</FONT><FONT face=宋体 size=3>数据报表特有的控件,它没有普通的窗体控件与之对应,该控件的引入大大方便了数据报表的设计。</FONT><FONT face="宋体, MS Song" size=3>TQRExpr</FONT><FONT face=宋体 size=3>控件的名称从字面上翻译就是数据报表表达式控件,顾名思义,该控件中可以定义一个表达式,输出的是以文本方式显示的表达式结果。该表达式可以由常量(如数字或字符串常量)、数据字段以及</FONT><FONT face="宋体, MS Song" size=3>QuickReport</FONT><FONT face=宋体 size=3>支持的一些标准变量(如日期、时间、页码等等)组成,表达式支持的运算包括加、减、乘、除、比较运算、逻辑运算等等,表达式中还支持一些简单的函数调用(如</FONT><FONT face="宋体, MS Song" size=3>SUM()</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>AVERAGE()</FONT><FONT face=宋体 size=3>等等),可见</FONT><FONT face="宋体, MS Song" size=3>TQRExpr</FONT><FONT face=宋体 size=3>控件具有较强的数据处理能力。</P></FONT><FONT size=3>< align=justify>QRExpr2</FONT><FONT face=宋体 size=3>和</FONT><FONT size=3>QRExpr3</FONT><FONT face=宋体 size=3>中的表达式比较简单,只定义了要显示的字段名称。如果要构造较为复杂的表达式,可以在对象监视器中双击</FONT><FONT size=3>TQRExpr</FONT><FONT face=宋体 size=3>对象的</FONT><FONT size=3>Expression</FONT><FONT face=宋体 size=3>属性,调出其表达式向导对话框,利用向导构造出符合语法要求的表达式。</P>< align=justify>页脚区</FONT><FONT face="宋体, MS Song" size=3>ageFooterBand1</FONT><FONT face=宋体 size=3>只包含一个</FONT><FONT face="宋体, MS Song" size=3>TQRExpr</FONT><FONT face=宋体 size=3>对象</FONT><FONT face="宋体, MS Song" size=3>QRExpr1</FONT><FONT face=宋体 size=3>,其</FONT><FONT face="宋体, MS Song" size=3>Expression</FONT><FONT face=宋体 size=3>属性字义了它显示的内容为页码数,另外它的</FONT><FONT face="宋体, MS Song" size=3>AlignToBand</FONT><FONT face=宋体 size=3>属性设为了</FONT><FONT face="宋体, MS Song" size=3>true</FONT><FONT face=宋体 size=3>,</FONT><FONT face="宋体, MS Song" size=3>Alignment</FONT><FONT face=宋体 size=3>属性设为</FONT><FONT face="宋体, MS Song" size=3>taRightJustify</FONT><FONT face=宋体 size=3>,表示它将以右对齐的方式显示。</P><UL><B>< align=justify><LI>完成数据报表功能 <p></LI></UL></B><P align=justify>我们已经对数据报表窗体及其上的数据报表控件有了一定的了解,下面我们就来对其报表窗体做一些小小的修改,让它变得美观一些,然后我们在程序的主窗体中加上一些代码,让</FONT><FONT face="宋体, MS Song" size=3>MP3Collect</FONT><FONT face=宋体 size=3>能够调用数据报表。</P><P align=justify>首先,我们把</FONT><FONT face="宋体, MS Song" size=3>Form1</FONT><FONT face=宋体 size=3>的</FONT><FONT face="宋体, MS Song" size=3>Name</FONT><FONT face=宋体 size=3>属性改为</FONT><FONT face="宋体, MS Song" size=3>ReportForm</FONT><FONT face=宋体 size=3>,窗体类名称改为</FONT><FONT face="宋体, MS Song" size=3>TReportForm</FONT><FONT face=宋体 size=3>,并将此单元保存为</FONT><FONT face="宋体, MS Song" size=3>Report.cpp</FONT><FONT face=宋体 size=3>(窗体文件与头文件分别保存为</FONT><FONT face="宋体, MS Song" size=3>Report.dfm</FONT><FONT face=宋体 size=3>和</FONT><FONT face="宋体, MS Song" size=3>Report.h</FONT><FONT face=宋体 size=3>)。接下来,我们把</FONT><FONT face="宋体, MS Song" size=3>ReportForm</FONT><FONT face=宋体 size=3>窗体上的</FONT><FONT face="宋体, MS Song" size=3>Table1</FONT><FONT face=宋体 size=3>控件删除,并重新添加一个</FONT><FONT face="宋体, MS Song" size=3>TQuery</FONT><FONT face=宋体 size=3>控件</FONT><FONT face="宋体, MS Song" size=3>Query1</FONT><FONT face=宋体 size=3>,</FONT><FONT face="宋体, MS Song" size=3>Query1</FONT><FONT face=宋体 size=3>的</FONT><FONT face="宋体, MS Song" size=3>Database</FONT><FONT face=宋体 size=3>属性设为别名</FONT><FONT face="宋体, MS Song" size=3>MP3Collect</FONT><FONT face=宋体 size=3>,</FONT><FONT face="宋体, MS Song" size=3>SQL</FONT><FONT face=宋体 size=3>属性为“</FONT><FONT face="宋体, MS Song" size=3>SELECT * FROM MP3Info Order by FileName ASC</FONT><FONT face=宋体 size=3>”。然后指定其</FONT><FONT face="宋体, MS Song" size=3>Active</FONT><FONT face=宋体 size=3>属性为</FONT><FONT face="宋体, MS Song" size=3>true</FONT><FONT face=宋体 size=3>,其它属性值都接受缺省值。</P><P align=justify>我们把</FONT><FONT face="宋体, MS Song" size=3>QuickRep1</FONT><FONT face=宋体 size=3>的</FONT><FONT face="宋体, MS Song" size=3>DataSet</FONT><FONT face=宋体 size=3>属性指向新的数据来源</FONT><FONT face="宋体, MS Song" size=3>Query1</FONT><FONT face=宋体 size=3>,并修改其</FONT><FONT face="宋体, MS Song" size=3>Bands</FONT><FONT face=宋体 size=3>属性,将其中的子属性</FONT><FONT face="宋体, MS Song" size=3>HasTitle</FONT><FONT face=宋体 size=3>设为</FONT><FONT face="宋体, MS Song" size=3>true</FONT><FONT face=宋体 size=3>,表示增加报表标题的显示。此时,</FONT><FONT face="宋体, MS Song" size=3>ColumnHeaderBand1</FONT><FONT face=宋体 size=3>前面会自动插入一个新的</FONT><FONT face="宋体, MS Song" size=3>TQRBand</FONT><FONT face=宋体 size=3>控件对象</FONT><FONT face="宋体, MS Song" size=3>TitleBand1</FONT><FONT face=宋体 size=3>,我们将其高度调整到合适的位置,然后在其中添加一个</FONT><FONT face="宋体, MS Song" size=3>TQRLabel</FONT><FONT face=宋体 size=3>控件对象</FONT><FONT face="宋体, MS Song" size=3>QRLabel3</FONT><FONT face=宋体 size=3>,并把</FONT><FONT face="宋体, MS Song" size=3>QRLabel3</FONT><FONT face=宋体 size=3>的</FONT><FONT face="宋体, MS Song" size=3>Alignment</FONT><FONT face=宋体 size=3>属性设为</FONT><FONT face="宋体, MS Song" size=3>taCenter</FONT><FONT face=宋体 size=3>,</FONT><FONT face="宋体, MS Song" size=3>AlignToBand</FONT><FONT face=宋体 size=3>属性设为了</FONT><FONT face="宋体, MS Song" size=3>true</FONT><FONT face=宋体 size=3>,表示居中对齐于标题栏的中间,另外还要把</FONT><FONT face="宋体, MS Song" size=3>QRLabel3</FONT><FONT face=宋体 size=3>的</FONT><FONT face="宋体, MS Song" size=3>Caption</FONT><FONT face=宋体 size=3>属性设为“</FONT><FONT face="宋体, MS Song" size=3>MP3</FONT><FONT face=宋体 size=3>音乐宝库——查询结果”,字体设置为“宋体”,大小为</FONT><FONT face="宋体, MS Song" size=3>20</FONT><FONT face=宋体 size=3>。</P><P align=justify>接下来我们把</FONT><FONT face="宋体, MS Song" size=3>ColumnHeaderBand1</FONT><FONT face=宋体 size=3>中的</FONT><FONT face="宋体, MS Song" size=3>QRLabel1</FONT><FONT face=宋体 size=3>和</FONT><FONT face="宋体, MS Song" size=3>QRLabel2</FONT><FONT face=宋体 size=3>控件的</FONT><FONT face="宋体, MS Song" size=3>Caption</FONT><FONT face=宋体 size=3>属性分别修改为“歌曲名称”和“歌手名称”,并把</FONT><FONT face="宋体, MS Song" size=3>PageFooterBand1</FONT><FONT face=宋体 size=3>中的</FONT><FONT face="宋体, MS Song" size=3>QRExpr1</FONT><FONT face=宋体 size=3>控件的</FONT><FONT face="宋体, MS Song" size=3>Expression</FONT><FONT face=宋体 size=3>属性修改为“</FONT><FONT face="宋体, MS Song" size=3>'</FONT><FONT face=宋体 size=3>第</FONT><FONT face="宋体, MS Song" size=3> ' + PageNumber+'</FONT><FONT face=宋体 size=3>页</FONT><FONT face="宋体, MS Song" size=3>'</FONT><FONT face=宋体 size=3>”,把缺省的英文单词改为中文。最后将</FONT><FONT face="宋体, MS Song" size=3>QRLabel1</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>QRLabel2</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>QRExpr1</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>QRExpr2</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>QRExpr3</FONT><FONT face=宋体 size=3>的字体都改为“宋体”,大小改为</FONT><FONT face="宋体, MS Song" size=3>10</FONT><FONT face=宋体 size=3>。在上述过程中,还需要调整各个</FONT><FONT face="宋体, MS Song" size=3>Band</FONT><FONT face=宋体 size=3>区域的高度以适应新的字体高度。</P><P align=justify>做好这一系列调整之后,我们接着要在</FONT><FONT face="宋体, MS Song" size=3>MainForm</FONT><FONT face=宋体 size=3>中添加调用报表窗体的代码。由于</FONT><FONT face="宋体, MS Song" size=3>MainForm</FONT><FONT face=宋体 size=3>窗体上的控件布局已经比较紧凑了,如果再添加新的命令按钮,需要进行的调整就比较大,因此我们不再向</FONT><FONT face="宋体, MS Song" size=3>MainForm</FONT><FONT face=宋体 size=3>窗体中添加新按钮,而是通过添加关联菜单命令的方式来增加打印报表的命令。为此,我们在</FONT><FONT face="宋体, MS Song" size=3>MainForm</FONT><FONT face=宋体 size=3>窗体上的</FONT><FONT face="宋体, MS Song" size=3>PopupMenu1</FONT><FONT face=宋体 size=3>中添加一个菜单项</FONT><FONT face="宋体, MS Song" size=3>mnuReport</FONT><FONT face=宋体 size=3>,其</FONT><FONT face="宋体, MS Song" size=3>Caption</FONT><FONT face=宋体 size=3>属性为“打印报表”,</FONT><FONT face="宋体, MS Song" size=3>OnClick</FONT><FONT face=宋体 size=3>事件处理函数为</FONT><FONT face="宋体, MS Song" size=3>mnuReportClick()</FONT><FONT face=宋体 size=3>,该函数的代码实现如下所示:</P></FONT><FONT size=3><P align=justify>void __fastcall TMainForm::mnuReportClick(TObject *Sender)</P><P align=justify>{</P><P align=justify>ReportForm-&gt;Query1-&gt;Close();</P><P align=justify>ReportForm-&gt;Query1-&gt;SQL-&gt;Clear();</P><P align=justify>ReportForm-&gt;Query1-&gt;SQL-&gt;AddStrings(Query1-&gt;SQL);</P><P align=justify>ReportForm-&gt;Query1-&gt;Open();</P><P align=justify>ReportForm-&gt;QuickRep1-&gt;Preview();</P></FONT><FONT face=宋体 size=3><P align=justify>}</P><P align=justify>该函数主要完成以下几个步骤,首先关闭报表窗体的查询控件</FONT><FONT face="宋体, MS Song" size=3>Query1</FONT><FONT face=宋体 size=3>,清除其中原有的</FONT><FONT face="宋体, MS Song" size=3>SQL</FONT><FONT face=宋体 size=3>属性,然后将其</FONT><FONT face="宋体, MS Song" size=3>SQL</FONT><FONT face=宋体 size=3>属性设置成与主窗体上</FONT><FONT face="宋体, MS Song" size=3>Query1</FONT><FONT face=宋体 size=3>控件的</FONT><FONT face="宋体, MS Song" size=3>SQL</FONT><FONT face=宋体 size=3>属性一致,再打开报表窗体的查询控件</FONT><FONT face="宋体, MS Song" size=3>Query1</FONT><FONT face=宋体 size=3>。这样做的目的是保证报表中显示的数据与主窗体中显示的内容一致。函数最后调用报表窗体上</FONT><FONT face="宋体, MS Song" size=3>QuickRep1</FONT><FONT face=宋体 size=3>控件的</FONT><FONT face="宋体, MS Song" size=3>Preview()</FONT><FONT face=宋体 size=3>方法启动打印预览窗口(如图</FONT><FONT face="宋体, MS Song" size=3>17-5</FONT><FONT face=宋体 size=3>所示),用户在该窗口中就可以完成打印报表的操作。</P><P align=justify> </P><P align=justify>本讲介绍了如何利用</FONT><FONT face="宋体, MS Song" size=3>QuickReport</FONT><FONT face=宋体 size=3>控件来实现数据报表的功能,这里介绍的仅仅是最基本的方法,用到的</FONT><FONT face="宋体, MS Song" size=3>QuickReport</FONT><FONT face=宋体 size=3>控件也只有少数几个,如果要设计更复杂的数据报表,朋友们还需要进一步学习各种</FONT><FONT face="宋体, MS Song" size=3>QuickReport</FONT><FONT face=宋体 size=3>控件的用法。</P><P align=justify> </P><P align=justify> </P></FONT>
作者: 韩冰    时间: 2005-1-26 01:38
<b><FONT face=宋体 size=6> </FONT></b>< align=center>注册表和动态连接库</P><FONT face=宋体 size=3>< align=justify>前面我们通过例子已经学习了</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>数据库编程的基础知识,本讲我们将学习关于注册表和动态连接库编程方面的知识。</P><UL><B>< align=justify><LI>对注册表编程 / p* H2 p3 H7 n% z, R( x, T
</LI></UL></B>< align=justify>应用程序保存信息的常用方法有三种,第一种是保存在文件中,第二种是保存在数据库中,第三种则是保存在系统注册表中。到目前为止,我们已经实践了前面两种方法,下面我们就来看看如何使用注册表。</P>< align=justify>注册表是</FONT><FONT face="宋体, MS Song" size=3>Windows</FONT><FONT face=宋体 size=3>系统中保存系统配置信息以及应用程序运行参数的地方,注册表也是系统最重要的组成部分之一,如果注册表遭到了破坏,系统功能就会出现混乱,轻则使应用软件不能正确工作,重则会导致系统崩溃。正因为注册表的重要性,使它有一种神秘的色彩,不少参考书上都建议用户不要操作注册表,似乎稍有不慎就会造成巨大损失。其实,对于编程人员来说,注册表可不是什么禁区,相反,它很适合于应用程序保存一些少量的、关键的配置信息。</P>< align=justify>在</FONT><FONT face="宋体, MS Song" size=3>Windows</FONT><FONT face=宋体 size=3>系统中,我们可以通过</FONT><FONT face="宋体, MS Song" size=3>Regedit.exe</FONT><FONT face=宋体 size=3>(</FONT><FONT face="宋体, MS Song" size=3>Windows 9x</FONT><FONT face=宋体 size=3>)或</FONT><FONT face="宋体, MS Song" size=3>Regedit32.exe</FONT><FONT face=宋体 size=3>(</FONT><FONT face="宋体, MS Song" size=3>Windows NT</FONT><FONT face=宋体 size=3>)来查看和修改注册表中的内容。运行</FONT><FONT face="宋体, MS Song" size=3>Regedit</FONT><FONT face=宋体 size=3>打开注册表,我们可以很清楚地看到,注册表的信息是以树形结构组织在一起的,如图</FONT><FONT face="宋体, MS Song" size=3>18-1</FONT><FONT face=宋体 size=3>,在“我的电脑”下有六个根注册项:</FONT><FONT face="宋体, MS Song" size=3>HKEY_CLASSES_ROOT</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>HKEY_CURRENT_USER</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>HKEY_LOCAL_MACHINE</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>HKEY_USERS</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>HKEY_CURRENT_CONFIG</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>HKEY_DYN_DATA</FONT><FONT face=宋体 size=3>。每个根注册项下面都有数量不等的子注册项,每一个子注册项又称为一个主键,主键的下面还可以有下一层主键,六个根注册项以及不同层次的主键一起形成类似文件目录的树形结构。注册表的每个主键可以定义若干个值,缺省的是默认值,除此之外还可以定义其它关键字的值,值的类型有三种:字符串值、二进制值和</FONT><FONT face="宋体, MS Song" size=3>DWORD</FONT><FONT face=宋体 size=3>型值。</P>< align=justify>下面我们为</FONT><FONT face="宋体, MS Song" size=3>MP3Collect</FONT><FONT face=宋体 size=3>程序添加注册表读写的功能,把用户输入的查询条件保存在注册表中,即每次启动时自动读取以前在注册表中保存的查询条件,并将满足初始查询条件的记录显示出来,当用户进行一次查找操作时,程序又将新的查询条件写入到注册表中。</P>< align=justify>为了实现这个功能,我们先手工在注册表的</FONT><FONT face="宋体, MS Song" size=3>HKEY_CURRENT_USER</FONT><FONT face=宋体 size=3>根注册项下的</FONT><FONT face="宋体, MS Song" size=3>Software</FONT><FONT face=宋体 size=3>主键下新建一个主键</FONT><FONT face="宋体, MS Song" size=3>MP3Collect</FONT><FONT face=宋体 size=3>,并为该主键创建三个字符串值:</FONT><FONT face="宋体, MS Song" size=3>FileName</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>SongName</FONT><FONT face=宋体 size=3>和</FONT><FONT face="宋体, MS Song" size=3>SingerName</FONT><FONT face=宋体 size=3>。</P></FONT><FONT size=3>< align=justify>CBuilder</FONT><FONT face=宋体 size=3>对注册表的操作主要是通过</FONT><FONT size=3>VCL</FONT><FONT face=宋体 size=3>类</FONT><FONT size=3>TRegistry</FONT><FONT face=宋体 size=3>实现的。使用</FONT><FONT size=3>TRegistry</FONT><FONT face=宋体 size=3>类需要包含头文件</FONT><FONT size=3>Registry.hpp</FONT><FONT face=宋体 size=3>。</FONT><FONT size=3>TRegistry</FONT><FONT face=宋体 size=3>的属性只有五个,分别是</FONT><FONT size=3>Access</FONT><FONT face=宋体 size=3>、</FONT><FONT size=3>CurrentKey</FONT><FONT face=宋体 size=3>、 </FONT><FONT size=3>CurrentPath</FONT><FONT face=宋体 size=3>、</FONT><FONT size=3>LazyWrite</FONT><FONT face=宋体 size=3>和</FONT><FONT size=3>RootKey</FONT><FONT face=宋体 size=3>,其中</FONT><FONT size=3>CurrentKey</FONT><FONT face=宋体 size=3>和</FONT><FONT size=3>CurrentPath</FONT><FONT face=宋体 size=3>是只读属性,分别表示当前主键和当前键所有的路径,另外,</FONT><FONT size=3>Access</FONT><FONT face=宋体 size=3>是访问权限属性,</FONT><FONT size=3>LazyWrite</FONT><FONT face=宋体 size=3>指定进行写操作时真正写入注册表的时间,</FONT><FONT size=3>RootKey</FONT><FONT face=宋体 size=3>属性指定一个根,为后续的操作指定一个注册表子集。</P>< align=justify>使用</FONT><FONT face="宋体, MS Song" size=3>TRegistry</FONT><FONT face=宋体 size=3>类进行注册表操作的一般步骤如下:首先创建一个</FONT><FONT face="宋体, MS Song" size=3>TRegistry</FONT><FONT face=宋体 size=3>对象,然后指定其</FONT><FONT face="宋体, MS Song" size=3>RootKey</FONT><FONT face=宋体 size=3>属性,定义一个有效的子集。接下来利用</FONT><FONT face="宋体, MS Song" size=3>TRegistry::OpenKey</FONT><FONT face=宋体 size=3>方法打开一个注册表主键,该方法以主键的路径作为参数,如果打开成功,就可以进行读写操作。对不同类型的注册表键值,</FONT><FONT face="宋体, MS Song" size=3>TRegistry</FONT><FONT face=宋体 size=3>提供了不同的读写函数,例如读、写字符串值分别使用方法:</FONT><FONT face="宋体, MS Song" size=3>ReadString</FONT><FONT face=宋体 size=3>和</FONT><FONT face="宋体, MS Song" size=3>WriteString</FONT><FONT face=宋体 size=3>。</P>< align=justify>在</FONT><FONT face="宋体, MS Song" size=3>MP3Collect</FONT><FONT face=宋体 size=3>中,为了实现注册表读写功能,我们要为</FONT><FONT face="宋体, MS Song" size=3>TMainForm</FONT><FONT face=宋体 size=3>类添加两个成员函数</FONT><FONT face="宋体, MS Song" size=3>ReadRegistrys</FONT><FONT face=宋体 size=3>和</FONT><FONT face="宋体, MS Song" size=3>WriteRegistrys</FONT><FONT face=宋体 size=3>。在窗体初始化函数</FONT><FONT face="宋体, MS Song" size=3>FormCreate</FONT><FONT face=宋体 size=3>中调用</FONT><FONT face="宋体, MS Song" size=3>ReadRegistrys</FONT><FONT face=宋体 size=3>,并调用</FONT><FONT face="宋体, MS Song" size=3>btnFindClick</FONT><FONT face=宋体 size=3>函数,使</FONT><FONT face="宋体, MS Song" size=3>Query1</FONT><FONT face=宋体 size=3>控件按照所获取的条件进行查询。另外,要在</FONT><FONT face="宋体, MS Song" size=3>btnFindClick</FONT><FONT face=宋体 size=3>函数和</FONT><FONT face="宋体, MS Song" size=3>btnShowAllClick</FONT><FONT face=宋体 size=3>函数中调用</FONT><FONT face="宋体, MS Song" size=3>WriteRegistrys</FONT><FONT face=宋体 size=3>函数将最新的查询条件存入注册表中。</FONT><FONT face="宋体, MS Song" size=3>ReadRegistrys</FONT><FONT face=宋体 size=3>和</FONT><FONT face="宋体, MS Song" size=3>WriteRegistrys</FONT><FONT face=宋体 size=3>函数的实现代码分别如下:</P></FONT><FONT size=3>< align=justify>void __fastcall TMainForm::ReadRegistrys() {</P>< align=justify>TRegistry *Registry = new TRegistry; //</FONT><FONT face=宋体 size=3>创建一个</FONT><FONT size=3>TRegistry</FONT><FONT face=宋体 size=3>对象</P></FONT><FONT size=3>< align=justify>Registry-&gt;RootKey=HKEY_CURRENT_USER; //</FONT><FONT face=宋体 size=3>指定</FONT><FONT size=3>TRegistry</FONT><FONT face=宋体 size=3>对象的根</P></FONT><FONT size=3>< align=justify>Registry-&gt;OpenKey("Software\\MP3Collect",TRUE); //</FONT><FONT face=宋体 size=3>打开主键</FONT><FONT size=3>Software\\MP3Collect</P>< align=justify>edtFileName-&gt;Text=Registry-&gt;ReadString("FileName"); //</FONT><FONT face=宋体 size=3>读值</P></FONT><FONT size=3>< align=justify>edtSongName-&gt;Text=Registry-&gt;ReadString("SongName");</P>< align=justify>edtSingerName-&gt;Text=Registry-&gt;ReadString("SingerName");</P>< align=justify>Registry-&gt;CloseKey(); //</FONT><FONT face=宋体 size=3>关闭主键</P></FONT><FONT size=3>< align=justify>delete Registry; //</FONT><FONT face=宋体 size=3>释放对象</P>< align=justify>}</P></FONT><FONT size=3>< align=justify>void __fastcall TMainForm::WriteRegistrys(AnsiString sFileName,AnsiString sSongName,AnsiString sSingerName) {</P>< align=justify>TRegistry *Registry = new TRegistry;</P>< align=justify>Registry-&gt;RootKey=HKEY_CURRENT_USER;</P>< align=justify>Registry-&gt;OpenKey("Software\\MP3Collect",TRUE);</P>< align=justify>Registry-&gt;WriteString("FileName",sFileName);</P>< align=justify>Registry-&gt;WriteString("SongName",sSongName);</P>< align=justify>Registry-&gt;WriteString("SingerName",sSingerName);</P>< align=justify>Registry-&gt;CloseKey();</P>< align=justify>delete Registry;</P></FONT><FONT face=宋体 size=3><P align=justify>}</P><UL><B><P align=justify><LI>动态连接库的特点 <p></LI></UL></B><P align=justify>动态连接库(</FONT><FONT face="宋体, MS Song" size=3>DLL</FONT><FONT face=宋体 size=3>)是一个包含有函数和数据(资源)的可执行模块,它不能象</FONT><FONT face="宋体, MS Song" size=3>EXE</FONT><FONT face=宋体 size=3>文件那样直接运行,需要由其它可执行模块(一个</FONT><FONT face="宋体, MS Song" size=3>EXE</FONT><FONT face=宋体 size=3>或</FONT><FONT face="宋体, MS Song" size=3>DLL</FONT><FONT face=宋体 size=3>)在运行时调用它,</FONT><FONT face="宋体, MS Song" size=3>Windows</FONT><FONT face=宋体 size=3>才会装载它,其中的代码才能被执行,数据才能被引用。</P><P align=justify>在</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>中进行编译连接时,程序调用的</FONT><FONT face="宋体, MS Song" size=3>DLL</FONT><FONT face=宋体 size=3>不会被嵌入到最终的</FONT><FONT face="宋体, MS Song" size=3>EXE</FONT><FONT face=宋体 size=3>文件中,只有在</FONT><FONT face="宋体, MS Song" size=3>EXE</FONT><FONT face=宋体 size=3>文件启动时或运行过程中,</FONT><FONT face="宋体, MS Song" size=3>DLL</FONT><FONT face=宋体 size=3>的内容才会被动态地加载到内存中,这就是它称为动态连接库的原因。除了动态连接库外,还有静态连接库,这一类的文件在进行连接时,其中的函数和数据会直接嵌入到</FONT><FONT face="宋体, MS Song" size=3>EXE</FONT><FONT face=宋体 size=3>文件中,连接结束后,静态库就成为了</FONT><FONT face="宋体, MS Song" size=3>EXE</FONT><FONT face=宋体 size=3>的一部分,不会再改变,因而称为静态连接库。</P></FONT><FONT size=3><P align=justify>DLL</FONT><FONT face=宋体 size=3>提供了一种应用程序模块化的方法,它可以使得功能模块容易更改和重用。当几个应用程序同时使用一个</FONT><FONT size=3>DLL</FONT><FONT face=宋体 size=3>时,还可以减少系统开销。另外,</FONT><FONT size=3>DLL</FONT><FONT face=宋体 size=3>文件的格式是独立于编程语言的,</FONT><FONT size=3>CBuilder</FONT><FONT face=宋体 size=3>、</FONT><FONT size=3>VC</FONT><FONT face=宋体 size=3>、</FONT><FONT size=3>VB</FONT><FONT face=宋体 size=3>开发的</FONT><FONT size=3>DLL</FONT><FONT face=宋体 size=3>库在原则上说是可以互相通用。</P></FONT><FONT size=3><P align=justify>DLL</FONT><FONT face=宋体 size=3>中可以定义两种函数,即导出函数(</FONT><FONT size=3>export</FONT><FONT face=宋体 size=3>)和内部函数(</FONT><FONT size=3>internal</FONT><FONT face=宋体 size=3>)。导出函数可以被其它可执行模块调用,而内部函数只能在</FONT><FONT size=3>DLL</FONT><FONT face=宋体 size=3>内部使用。同样的,</FONT><FONT size=3>DLL</FONT><FONT face=宋体 size=3>中也可以导出全局变量和</FONT><FONT size=3>C++</FONT><FONT face=宋体 size=3>对象。</P><UL><B><P align=justify><LI>创建动态连接库 <p></LI></UL></B><P align=justify>为了学习用</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>编写动态连接库的方法,我们来创建一个可以检查软件使用天数的</FONT><FONT face="宋体, MS Song" size=3>DLL</FONT><FONT face=宋体 size=3>,如果用户使用软件超过了允许的试用天数,就弹出一个对话框来提醒用户注册软件,然后自动退出。</P><P align=justify>为了完成这一功能,我们可以使用注册表来保存软件的试用信息和软件的运行天数。按照本讲前面介绍的方法,在</FONT><FONT face="宋体, MS Song" size=3>MP3Collect</FONT><FONT face=宋体 size=3>主键下创建一个</FONT><FONT face="宋体, MS Song" size=3>DWORD</FONT><FONT face=宋体 size=3>类型的键值</FONT><FONT face="宋体, MS Song" size=3>TestUse</FONT><FONT face=宋体 size=3>,它用来表示当前软件是否为试用版,如果是,则该值为</FONT><FONT face="宋体, MS Song" size=3>1</FONT><FONT face=宋体 size=3>,否则为</FONT><FONT face="宋体, MS Song" size=3>0</FONT><FONT face=宋体 size=3>,后面的代码还会在程序第一次运行时自动创建一个二进制值</FONT><FONT face="宋体, MS Song" size=3>BeginTime</FONT><FONT face=宋体 size=3>,用来记录了第一次运行时的日期,我们假定允许用户试用软件</FONT><FONT face="宋体, MS Song" size=3>100</FONT><FONT face=宋体 size=3>天。</P><P align=justify>首先,选择</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>中的菜单命令“</FONT><FONT face="宋体, MS Song" size=3>File-&gt;New...</FONT><FONT face=宋体 size=3>”,在弹出的新建对象对话框中选定其中的“</FONT><FONT face="宋体, MS Song" size=3>DLL Wizard</FONT><FONT face=宋体 size=3>”,确定之后会弹出一个</FONT><FONT face="宋体, MS Song" size=3>DLL</FONT><FONT face=宋体 size=3>向导对话框(图</FONT><FONT face="宋体, MS Song" size=3>18-2</FONT><FONT face=宋体 size=3>),在其中选择源代码类型为</FONT><FONT face="宋体, MS Song" size=3>C++</FONT><FONT face=宋体 size=3>,并且需要使用可视化元件库</FONT><FONT face="宋体, MS Song" size=3>VCL</FONT><FONT face=宋体 size=3>,然后按下“</FONT><FONT face="宋体, MS Song" size=3>OK</FONT><FONT face=宋体 size=3>”按钮即可。新生成的</FONT><FONT face="宋体, MS Song" size=3>DLL</FONT><FONT face=宋体 size=3>工程</FONT><FONT face="宋体, MS Song" size=3>Project1</FONT><FONT face=宋体 size=3>中只有一个</FONT><FONT face="宋体, MS Song" size=3>Unit1.cpp</FONT><FONT face=宋体 size=3>文件,其中有一个函数</FONT><FONT face="宋体, MS Song" size=3>DllEntryPoint()</FONT><FONT face=宋体 size=3>,该函数在</FONT><FONT face="宋体, MS Song" size=3>DLL</FONT><FONT face=宋体 size=3>加载时被调用,相当于应用程序的</FONT><FONT face="宋体, MS Song" size=3>WinMain()</FONT><FONT face=宋体 size=3>函数。我们不对</FONT><FONT face="宋体, MS Song" size=3>DllEntryPoint</FONT><FONT face=宋体 size=3>作任何修改。</P><P align=justify>接下来,再次利用</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>的新建对象对话框创建一个</FONT><FONT face="宋体, MS Song" size=3>AboutBox</FONT><FONT face=宋体 size=3>类型的窗体,并在其上添加有关注册的信息,如图</FONT><FONT face="宋体, MS Song" size=3>18-3</FONT><FONT face=宋体 size=3>所示。该对话框的单元文件被命名为</FONT><FONT face="宋体, MS Song" size=3>Unit2.cpp</FONT><FONT face=宋体 size=3>。</P><P align=justify>下面为这个</FONT><FONT face="宋体, MS Song" size=3>DLL</FONT><FONT face=宋体 size=3>工程添加导出函数</FONT><FONT face="宋体, MS Song" size=3>CheckFunc()</FONT><FONT face=宋体 size=3>。该函数的声明和定义都位于</FONT><FONT face="宋体, MS Song" size=3>Unit1.cpp</FONT><FONT face=宋体 size=3>中。在导出一个函数时,我们一般采用下面的语法:</P></FONT><FONT size=3><P align=justify>extern “C” __declspec(dllexport) __stdcall </FONT><FONT face=宋体 size=3>函数名称(函数参数)</FONT><FONT size=3>;</P></FONT><FONT face=宋体 size=3><P align=justify>这样的声明方式不仅指明了函数为一个</FONT><FONT face="宋体, MS Song" size=3>DLL</FONT><FONT face=宋体 size=3>导出函数,而且指明了它的调用规则为</FONT><FONT face="宋体, MS Song" size=3>__stdcall</FONT><FONT face=宋体 size=3>,命名规则为</FONT><FONT face="宋体, MS Song" size=3>C</FONT><FONT face=宋体 size=3>语言。按照</FONT><FONT face="宋体, MS Song" size=3>C</FONT><FONT face=宋体 size=3>语言而不是</FONT><FONT face="宋体, MS Song" size=3>C++</FONT><FONT face=宋体 size=3>来导出函数,可以避免因</FONT><FONT face="宋体, MS Song" size=3>C++</FONT><FONT face=宋体 size=3>名字修饰而造成的不兼容问题。下面是修改后的</FONT><FONT face="宋体, MS Song" size=3>Unit1.cpp</FONT><FONT face=宋体 size=3>的完整代码:</P></FONT><FONT size=3><P align=justify>#include &lt;vcl.h&gt;</P><P align=justify>#include &lt;windows.h&gt;</P><P align=justify>#pragma hdrstop</P><P align=justify>#include &lt;Registry.hpp&gt;</P><P align=justify>USEFORM("Unit2.cpp",AboutBox);</P><P align=justify>#include "unit2.h"</P><P align=justify>extern TAboutBox *AboutBox;</P><P align=justify>#pragma argsused</P><P align=justify>extern "C" __declspec(dllexport) long __stdcall CheckFunc();//</FONT><FONT face=宋体 size=3>声明导出函数</FONT><FONT size=3>CheckFunc</FONT><FONT face=宋体 size=3>()</P></FONT><FONT size=3><P align=justify>int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void* lpReserved) //DLL</FONT><FONT face=宋体 size=3>的入口</P><P align=justify>{</FONT><FONT size=3><FONT face="宋体, MS Song"> return 1;}</FONT></P><P align=justify> </P><P align=justify>long __stdcall CheckFunc() { //</FONT><FONT face=宋体 size=3>导出函数</FONT><FONT size=3>CheckFunc</P><P align=justify>TRegistry *Registry =new TRegistry;</P><P align=justify>Registry-&gt;RootKey=HKEY_CURRENT_USER;</P><P align=justify>Registry-&gt;OpenKey("Software\\MP3Collect",TRUE);</P><P align=justify>short bIsTest=Registry-&gt;ReadDword("TestUse");//</FONT><FONT face=宋体 size=3>读入</FONT><FONT size=3>TestUse</FONT><FONT face=宋体 size=3>值,查看本程序是否为试用版本</P></FONT><FONT size=3><P align=justify>TDateTime tNow,tBegin;</P><P align=justify>tNow=TDateTime::CurrentDate();//</FONT><FONT face=宋体 size=3>获取当前日期</P></FONT><FONT size=3><P align=justify>long returnVal=1; //</FONT><FONT face=宋体 size=3>缺省的返回值为</FONT><FONT size=3>1</FONT><FONT face=宋体 size=3>,即没有超过试用期</P></FONT><FONT size=3><P align=justify>//</FONT><FONT face=宋体 size=3>如果为试用版本,则要查看注册表中</FONT><FONT size=3>BeginTime</FONT><FONT face=宋体 size=3>值是否已经存在,如果不存在表示这是程序</P></FONT><FONT size=3><P align=justify>//</FONT><FONT face=宋体 size=3>第一次运行,于是将当前的日期写入注册表中;如果存在则并检查试用期是否已到</P></FONT><FONT size=3><P align=justify>if(bIsTest) {</P><DIR><P align=justify>if(!Registry-&gt;ValueExists("BeginTime"))</P><DIR><P align=justify>Registry-&gt;WriteDate("BeginTime",tNow);</P></DIR><P align=justify>else {</P><DIR><P align=justify>tBegin=Registry-&gt;ReadDate("BeginTime");//</FONT><FONT face=宋体 size=3>读出</FONT><FONT size=3>BeginTime</FONT><FONT face=宋体 size=3>值</P></FONT><FONT size=3><P align=justify>if(tNow&gt;tBegin+100) { //</FONT><FONT face=宋体 size=3>检查是否超过</FONT><FONT size=3>100</FONT><FONT face=宋体 size=3>天试用期</P><DIR><DIR></FONT><FONT size=3><P align=justify>returnVal=0;//</FONT><FONT face=宋体 size=3>超过试用期时的返回值</P></FONT><FONT size=3><P align=justify>AboutBox=new TAboutBox(NULL);//</FONT><FONT face=宋体 size=3>创建并显示注册信息对话框</P></FONT><FONT size=3><P align=justify>AboutBox-&gt;ShowModal();</P><P align=justify>delete AboutBox;</P></DIR></DIR></FONT><FONT face=宋体 size=3><P align=justify>}</P></DIR><P align=justify>}</P></DIR><P align=justify>}</P></FONT><FONT size=3><P align=justify>Registry-&gt;CloseKey();//</FONT><FONT face=宋体 size=3>关闭注册表键</P></FONT><FONT size=3><P align=justify>delete Registry;//</FONT><FONT face=宋体 size=3>释放</FONT><FONT size=3>Registry</FONT><FONT face=宋体 size=3>对象</P></FONT><FONT size=3><P align=justify>return returnVal;//</FONT><FONT face=宋体 size=3>返回检查结果</P><P align=justify>}</P><P align=justify>将修改后的</FONT><FONT face="宋体, MS Song" size=3>DLL</FONT><FONT face=宋体 size=3>工程</FONT><FONT face="宋体, MS Song" size=3>Project1</FONT><FONT face=宋体 size=3>保存在与</FONT><FONT face="宋体, MS Song" size=3>MP3Collect</FONT><FONT face=宋体 size=3>工程相同的目录中,然后对</FONT><FONT face="宋体, MS Song" size=3>Project1</FONT><FONT face=宋体 size=3>进行编译、连接,生成的结果是一个动态连接库</FONT><FONT face="宋体, MS Song" size=3>Project1.DLL</FONT><FONT face=宋体 size=3>和它的导入库</FONT><FONT face="宋体, MS Song" size=3>Project1.LIB</FONT><FONT face=宋体 size=3>。</P><UL><B><P align=justify><LI>使用动态连接库 <p></LI></UL></B></FONT><FONT size=3><P align=justify>DLL</FONT><FONT face=宋体 size=3>的导入库中并没有实际代码,只包含有</FONT><FONT size=3>DLL</FONT><FONT face=宋体 size=3>导出函数和数据的相关信息,进行连接时,</FONT><FONT size=3>CBuilder</FONT><FONT face=宋体 size=3>的连接器需要导入库来定位相关的函数,以便生成</FONT><FONT size=3>EXE</FONT><FONT face=宋体 size=3>文件。通过导入库来使用</FONT><FONT size=3>DLL</FONT><FONT face=宋体 size=3>是一种十分简单方便的办法,其好处在于:编程时可以象调用普通外部函数一样调用从</FONT><FONT size=3>DLL</FONT><FONT face=宋体 size=3>中导入的函数,连接器将完成对</FONT><FONT size=3>DLL</FONT><FONT face=宋体 size=3>导出函数的定位工作,生成的</FONT><FONT size=3>EXE</FONT><FONT face=宋体 size=3>文件在启动时,</FONT><FONT size=3>Windows</FONT><FONT face=宋体 size=3>会自动加载所需要的</FONT><FONT size=3>DLL</FONT><FONT face=宋体 size=3>文件,这种加载方式也称为隐式加载。如果不采用导入库,则需要在程序代码中通过调用</FONT><FONT size=3>LoadLibray</FONT><FONT face=宋体 size=3>函数来显式地加载所需要的</FONT><FONT size=3>DLL</FONT><FONT face=宋体 size=3>模块。</P><P align=justify>下面仍以</FONT><FONT face="宋体, MS Song" size=3>MP3Collect</FONT><FONT face=宋体 size=3>为例,我们来看看通过导入库使用</FONT><FONT face="宋体, MS Song" size=3>DLL</FONT><FONT face=宋体 size=3>的方法。前面说过,</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>在编辑连接</FONT><FONT face="宋体, MS Song" size=3>DLL</FONT><FONT face=宋体 size=3>工程时,会自动生成该</FONT><FONT face="宋体, MS Song" size=3>DLL</FONT><FONT face=宋体 size=3>的导入库</FONT><FONT face="宋体, MS Song" size=3>.LIB</FONT><FONT face=宋体 size=3>文件。如果某个</FONT><FONT face="宋体, MS Song" size=3>DLL</FONT><FONT face=宋体 size=3>没有相应的</FONT><FONT face="宋体, MS Song" size=3>LIB</FONT><FONT face=宋体 size=3>文件,</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>在其</FONT><FONT face="宋体, MS Song" size=3>Bin</FONT><FONT face=宋体 size=3>目录下提供了一个</FONT><FONT face="宋体, MS Song" size=3>IMPLIB.EXE</FONT><FONT face=宋体 size=3>工具,可以为</FONT><FONT face="宋体, MS Song" size=3>DLL</FONT><FONT face=宋体 size=3>文件生成相应的导入库。</P><P align=justify>打开</FONT><FONT face="宋体, MS Song" size=3>MP3Collect</FONT><FONT face=宋体 size=3>工程,通过</FONT><FONT face="宋体, MS Song" size=3>View-&gt;Project Manager</FONT><FONT face=宋体 size=3>菜单命令打开其工程管理器,在工程管理器中将导入库</FONT><FONT face="宋体, MS Song" size=3>Project1.LIB</FONT><FONT face=宋体 size=3>文件添加到工程</FONT><FONT face="宋体, MS Song" size=3>MP3Collect</FONT><FONT face=宋体 size=3>中去。在使用</FONT><FONT face="宋体, MS Song" size=3>DLL</FONT><FONT face=宋体 size=3>库中的任何函数之前,还需要对引用的函数进行声明,声明语法如下:</P></FONT><FONT size=3><P align=justify>extern “C” __declspec(dllimport) __stdcall </FONT><FONT face=宋体 size=3>函数名称(函数参数)</FONT><FONT size=3>;</P></FONT><FONT face=宋体 size=3><P align=justify>然后就可以象使用普通的外部函数那样使用</FONT><FONT face="宋体, MS Song" size=3>DLL</FONT><FONT face=宋体 size=3>导出的函数了。</P></FONT><FONT size=3><P align=justify>CheckFunc()</FONT><FONT face=宋体 size=3>函数的声明和调用的代码如下所示:</P></FONT><FONT size=3><P align=justify>extern "C" __declspec(dllimport) long __stdcall CheckFunc();</P><P align=justify>void __fastcall TMainForm::FormCreate(TObject *Sender) {</P><P align=justify>if(CheckFunc()==0){//</FONT><FONT face=宋体 size=3>调用</FONT><FONT size=3>DLL</FONT><FONT face=宋体 size=3>库函数</FONT><FONT size=3>CheckFunc</FONT><FONT face=宋体 size=3>进行试用期检查,如果超过,则退出程序</P><DIR></FONT><FONT size=3><P align=justify>PostMessage(Handle,WM_CLOSE,0,0);</P><P align=justify>return;</P></DIR></FONT><FONT face=宋体 size=3><P align=justify>}</P></FONT><FONT size=3><P align=justify>//</FONT><FONT face=宋体 size=3>如果检查正确,则继续其它的初始化工作</P><P align=justify>}</P><P align=justify> </P></FONT>
作者: 韩冰    时间: 2005-1-26 01:40
<b><FONT face=宋体 size=6> </FONT></b>< align=center>使用<FONT face="宋体, MS Song" size=6>ActiveX</FONT><FONT face=宋体 size=6>控件</P></FONT><FONT face=宋体 size=3>< align=justify>上一讲中我们学习编写和使用</FONT><FONT face="宋体, MS Song" size=3>DLL</FONT><FONT face=宋体 size=3>的基本方法,</FONT><FONT face="宋体, MS Song" size=3>DLL</FONT><FONT face=宋体 size=3>实际上是程序模块化和实现代码重用的方式之一,但是由于种种原因,</FONT><FONT face="宋体, MS Song" size=3>DLL</FONT><FONT face=宋体 size=3>的可重用性并不是最佳的,经常会出现版本冲突问题。为此,微软提出了一种新的</FONT><FONT face="宋体, MS Song" size=3>Windows</FONT><FONT face=宋体 size=3>编程技术——</FONT><FONT face="宋体, MS Song" size=3>ActiveX</FONT><FONT face=宋体 size=3>技术,它可以比</FONT><FONT face="宋体, MS Song" size=3>DLL</FONT><FONT face=宋体 size=3>更好地解决二进制级的代码重用问题。</P><UL><B>< align=justify><LI>什么是</FONT><FONT face="宋体, MS Song" size=3>ActiveX</FONT><FONT face=宋体 size=3>控件 & ^$ W' S& y- z
</LI></UL></B></FONT><FONT size=3>< align=justify>ActiveX</FONT><FONT face=宋体 size=3>技术是从</FONT><FONT size=3>OLE</FONT><FONT face=宋体 size=3>技术发展而来的。</FONT><FONT size=3>OLE</FONT><FONT face=宋体 size=3>原意是对象链接和嵌入,后来被扩展成为了组件与分布式编程体系结构,并改称为</FONT><FONT size=3>ActiveX</FONT><FONT face=宋体 size=3>。</FONT><FONT size=3>ActiveX</FONT><FONT face=宋体 size=3>技术包括有组件对象模型(</FONT><FONT size=3>COM</FONT><FONT face=宋体 size=3>)、进程间编组(</FONT><FONT size=3>Marshaling</FONT><FONT face=宋体 size=3>)、结构化存储(</FONT><FONT size=3>Structured Storage</FONT><FONT face=宋体 size=3>)、对象一致性(</FONT><FONT size=3>Object Persistence</FONT><FONT face=宋体 size=3>)、统一数据传输(</FONT><FONT size=3>Uniform Data Transfer</FONT><FONT face=宋体 size=3>)、自动化(</FONT><FONT size=3>Automation</FONT><FONT face=宋体 size=3>)等等大量内容,其中的核心是组件对象模型</FONT><FONT size=3>COM</FONT><FONT face=宋体 size=3>。</FONT><FONT size=3>COM</FONT><FONT face=宋体 size=3>定义了一种统一的接口调用方式,从而使得</FONT><FONT size=3>COM</FONT><FONT face=宋体 size=3>组件能够独立于编程语言和操作系统平台,并解决了长期困扰软件开发的版本冲突问题。</FONT><FONT size=3>COM</FONT><FONT face=宋体 size=3>非常基础,</FONT><FONT size=3>ActiveX</FONT><FONT face=宋体 size=3>技术的其它内容都是在它的上面开发出来的。</P></FONT><FONT size=3>< align=justify>ActiveX</FONT><FONT face=宋体 size=3>控件是</FONT><FONT size=3>ActiveX</FONT><FONT face=宋体 size=3>技术的一种,以前也叫做</FONT><FONT size=3>OLE</FONT><FONT face=宋体 size=3>控件,或者称为</FONT><FONT size=3>OCX</FONT><FONT face=宋体 size=3>控件,这是因为它一般都存放在扩展名为</FONT><FONT size=3>.OCX</FONT><FONT face=宋体 size=3>的文件中。尽管整套</FONT><FONT size=3>ActiveX</FONT><FONT face=宋体 size=3>技术的理论相当庞大并且非常复杂,但</FONT><FONT size=3>ActiveX</FONT><FONT face=宋体 size=3>控件使用起来要简单得多,特别是有了在</FONT><FONT size=3>CBuilder</FONT><FONT face=宋体 size=3>中使用</FONT><FONT size=3>VCL</FONT><FONT face=宋体 size=3>控件的经验和基础,我们会发现</FONT><FONT size=3>ActiveX</FONT><FONT face=宋体 size=3>控件使用起来与</FONT><FONT size=3>VCL</FONT><FONT face=宋体 size=3>控件十分类似。</FONT><FONT size=3>ActiveX</FONT><FONT face=宋体 size=3>控件也提供了属性、方法和事件,用于对控件的操作和完成特定的功能,并且一旦将某个</FONT><FONT size=3>ActiveX</FONT><FONT face=宋体 size=3>控件安装到</FONT><FONT size=3>CBuilder</FONT><FONT face=宋体 size=3>中后,我们就可以在</FONT><FONT size=3>CBuilder</FONT><FONT face=宋体 size=3>集成开发环境中方便地使用</FONT><FONT size=3>ActiveX</FONT><FONT face=宋体 size=3>控件了,元件面板、对象监视器等工具对</FONT><FONT size=3>ActiveX</FONT><FONT face=宋体 size=3>控件都有效。</P>< align=justify>由于</FONT><FONT face="宋体, MS Song" size=3>ActiveX</FONT><FONT face=宋体 size=3>控件为代码提供了良好的封装特性,并且具有良好的对象一致性,使得程序易于升级和保持兼容性,因此不论是商业软件还是共享软件中,</FONT><FONT face="宋体, MS Song" size=3>ActiveX</FONT><FONT face=宋体 size=3>控件应用得都十分广泛。</FONT><FONT face="宋体, MS Song" size=3>ActiveX</FONT><FONT face=宋体 size=3>控件还具有独立于语言、平台和机器的特点,因此它在</FONT><FONT face="宋体, MS Song" size=3>Internet</FONT><FONT face=宋体 size=3>上也得到了广泛的应用。</P>< align=justify>下面我们将对</FONT><FONT face="宋体, MS Song" size=3>MP3Collect</FONT><FONT face=宋体 size=3>程序进行一番改造,用</FONT><FONT face="宋体, MS Song" size=3>ActiveX</FONT><FONT face=宋体 size=3>控件</FONT><FONT face="宋体, MS Song" size=3>Windows Media Player</FONT><FONT face=宋体 size=3>代替原来的</FONT><FONT face="宋体, MS Song" size=3>VCL</FONT><FONT face=宋体 size=3>播放控件</FONT><FONT face="宋体, MS Song" size=3>TMediaPlayer</FONT><FONT face=宋体 size=3>,来学习使用</FONT><FONT face="宋体, MS Song" size=3>ActiveX</FONT><FONT face=宋体 size=3>控件的方法。</P><UL><B>< align=justify><LI>怎样安装</FONT><FONT face="宋体, MS Song" size=3>ActiveX</FONT><FONT face=宋体 size=3>控件 <p></LI></UL></B>< align=justify>我们准备在例子中使用的是微软提供的</FONT><FONT face="宋体, MS Song" size=3>ActiveX</FONT><FONT face=宋体 size=3>控件</FONT><FONT face="宋体, MS Song" size=3>Windows Media Player</FONT><FONT face=宋体 size=3>(后面简称为</FONT><FONT face="宋体, MS Song" size=3>WMediaPlayer</FONT><FONT face=宋体 size=3>),该控件集成在</FONT><FONT face="宋体, MS Song" size=3>Win98</FONT><FONT face=宋体 size=3>第二版以上的系统中。需要注意的是,不同版本的</FONT><FONT face="宋体, MS Song" size=3>WMediaPlayer</FONT><FONT face=宋体 size=3>控件的功能稍有不同,特别是最新的</FONT><FONT face="宋体, MS Song" size=3>WMediaPlayer 7.0</FONT><FONT face=宋体 size=3>与其它版本在用户界面上有很大区别,为了便于对照讲座学习,心铃建议大家使用</FONT><FONT face="宋体, MS Song" size=3>6.xx</FONT><FONT face=宋体 size=3>版本。从媒体播放器程序的帮助菜单中选择“关于”命令,就可以查看</FONT><FONT face="宋体, MS Song" size=3>WMediaPlayer</FONT><FONT face=宋体 size=3>控件的版本。</P>< align=justify>除了少数几个之外,大部分</FONT><FONT face="宋体, MS Song" size=3>ActiveX</FONT><FONT face=宋体 size=3>控件对</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>来说是属于第三方控件,不能在元件面板上直接找到,因此在使用这些控件之前,必须先把它们安装到</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>中。安装步骤如下:</P>< align=justify>首先,选择菜单命令</FONT><FONT face="宋体, MS Song" size=3>Component-&gt;Import ActiveX Control</FONT><FONT face=宋体 size=3>,启动导入</FONT><FONT face="宋体, MS Song" size=3>ActiveX</FONT><FONT face=宋体 size=3>控件对话框(图</FONT><FONT face="宋体, MS Song" size=3>19-1</FONT><FONT face=宋体 size=3>)。该对话框上方的列表框中列出了系统内已注册的所有</FONT><FONT face="宋体, MS Song" size=3>ActiveX</FONT><FONT face=宋体 size=3>控件,在其中找到“</FONT><FONT face="宋体, MS Song" size=3>Windows Media Player</FONT><FONT face=宋体 size=3>”控件并选中它,这时,控件的</FONT><FONT face="宋体, MS Song" size=3>OCX</FONT><FONT face=宋体 size=3>文件名会自动显示在列表框下的文本框中,为</FONT><FONT face="宋体, MS Song" size=3>MSDXM.OCX</FONT><FONT face=宋体 size=3>,而“</FONT><FONT face="宋体, MS Song" size=3>Class name</FONT><FONT face=宋体 size=3>”中显示了要生成的控件类名称,因为缺省给出的类名称与</FONT><FONT face="宋体, MS Song" size=3>VCL</FONT><FONT face=宋体 size=3>的</FONT><FONT face="宋体, MS Song" size=3>TMediaPlayer</FONT><FONT face=宋体 size=3>控件相冲突,因此我们将其改为</FONT><FONT face="宋体, MS Song" size=3>TWMediaPlayer</FONT><FONT face=宋体 size=3>。“</FONT><FONT face="宋体, MS Song" size=3>alette Page</FONT><FONT face=宋体 size=3>”用于指定安装后的控件显示在元件面板的哪一个元件栏中,我们选择其中的</FONT><FONT face="宋体, MS Song" size=3>ActiveX</FONT><FONT face=宋体 size=3>元件栏。“</FONT><FONT face="宋体, MS Song" size=3>Unit dir name</FONT><FONT face=宋体 size=3>”和“</FONT><FONT face="宋体, MS Song" size=3>Search path</FONT><FONT face=宋体 size=3>”是安装控件时所需的路径设置,一般不需要改变,接受缺省值就可以了。确认了上述设置后,按“</FONT><FONT face="宋体, MS Song" size=3>Install...</FONT><FONT face=宋体 size=3>”按钮开始安装。</P>< align=justify>接着</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>会弹出一个对话框,要求我们选择安装新控件的包,我们可以从已有的包工程(</FONT><FONT face="宋体, MS Song" size=3>.bpk</FONT><FONT face=宋体 size=3>文件)中选择一个,也可以新建一个包工程。这里我们接受缺省设置,将</FONT><FONT face="宋体, MS Song" size=3>TWMediaPlayer</FONT><FONT face=宋体 size=3>安装到</FONT><FONT face="宋体, MS Song" size=3>dclusr50.bpk</FONT><FONT face=宋体 size=3>(该文件是包文件</FONT><FONT face="宋体, MS Song" size=3>dclusr50.bpl</FONT><FONT face=宋体 size=3>的工程文件,</FONT><FONT face="宋体, MS Song" size=3>dclusr50.bpl</FONT><FONT face=宋体 size=3>是用于包含用户元件的包文件)中,然后按下确定按钮,这时</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>提示需要重建</FONT><FONT face="宋体, MS Song" size=3>dclusr50.bpk</FONT><FONT face=宋体 size=3>工程,确定后,</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>就开始编译连接</FONT><FONT face="宋体, MS Song" size=3>dclusr50.bpk</FONT><FONT face=宋体 size=3>工程,完成这一过程需要一点时间。如果重建成功,</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>会提示“</FONT><FONT face="宋体, MS Song" size=3>dclusr50.bpl</FONT><FONT face=宋体 size=3>被重新生成,元件面板中的元件已经更新,</FONT><FONT face="宋体, MS Song" size=3>TWMediaPlayer</FONT><FONT face=宋体 size=3>控件被成功注册”,确定之后,我们会发现</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>当前打开的工程为</FONT><FONT face="宋体, MS Song" size=3>dclusr50.bpk</FONT><FONT face=宋体 size=3>,应先保存</FONT><FONT face="宋体, MS Song" size=3>dclusr50.bpk</FONT><FONT face=宋体 size=3>,然后再重新打开原来的</FONT><FONT face="宋体, MS Song" size=3>MP3Collect</FONT><FONT face=宋体 size=3>工程,我们可以发现元件面板的</FONT><FONT face="宋体, MS Song" size=3>ActiveX</FONT><FONT face=宋体 size=3>元件页中新增了</FONT><FONT face="宋体, MS Song" size=3>WMediaPlayer</FONT><FONT face=宋体 size=3>控件的图标。在某些情况下,新增</FONT><FONT face="宋体, MS Song" size=3>ActiveX</FONT><FONT face=宋体 size=3>控件的图标可能没有显示出来,此时我们可以在</FONT><FONT face="宋体, MS Song" size=3>Component</FONT><FONT face=宋体 size=3>菜单中选择</FONT><FONT face="宋体, MS Song" size=3>Install Package</FONT><FONT face=宋体 size=3>命令,并在弹出的对话框中把</FONT><FONT face="宋体, MS Song" size=3>Borland User Components</FONT><FONT face=宋体 size=3>(即</FONT><FONT face="宋体, MS Song" size=3>dclusr50.bpl</FONT><FONT face=宋体 size=3>)选中到设计时包文件和运行时包文件中即可。</P>< align=justify>安装好了一个</FONT><FONT face="宋体, MS Song" size=3>ActiveX</FONT><FONT face=宋体 size=3>控件之后,如果用了一段时间又想将它删除应该怎么办呢?一种方法是通过</FONT><FONT face="宋体, MS Song" size=3>Component-&gt;Configure Palette</FONT><FONT face=宋体 size=3>菜单命令,调出元件面板属性对话框并找到相应元件栏的相应控件,通过“</FONT><FONT face="宋体, MS Song" size=3>Hide</FONT><FONT face=宋体 size=3>”按钮将其隐藏起来,以后需要的时候还可以用同样的方法让它重新显示在元件面板上。第二种方法较为彻底,需要修改当初安装控件的包工程。以刚才添加的</FONT><FONT face="宋体, MS Song" size=3>WMediaPlayer</FONT><FONT face=宋体 size=3>控件为例,打开</FONT><FONT face="宋体, MS Song" size=3>dclusr50.bpk</FONT><FONT face=宋体 size=3>包工程,这时会显示包的工程属性(图</FONT><FONT face="宋体, MS Song" size=3>19-2</FONT><FONT face=宋体 size=3>),我们可以看出文件名中包含了控件名称,如</FONT><FONT face="宋体, MS Song" size=3>MediaPlayer_OCX.cpp</FONT><FONT face=宋体 size=3>和</FONT><FONT face="宋体, MS Song" size=3>MediaPlayer_OCX.dcr</FONT><FONT face=宋体 size=3>封装了</FONT><FONT face="宋体, MS Song" size=3>WMediaPlayer</FONT><FONT face=宋体 size=3>控件,我们只需把这两个文件从包工程中删除,然后重新编译生成</FONT><FONT face="宋体, MS Song" size=3>dclusr50.bpk</FONT><FONT face=宋体 size=3>,就可以从包中彻底删除</FONT><FONT face="宋体, MS Song" size=3>WMediaPlayer</FONT><FONT face=宋体 size=3>控件了。</P><UL><B>< align=justify><LI>用</FONT><FONT face="宋体, MS Song" size=3>Windows Media Player</FONT><FONT face=宋体 size=3>控件改造</FONT><FONT size=3><FONT face="宋体, MS Song">MP3Collect </FONT><p></LI></UL></B></FONT><FONT face=宋体 size=3>< align=justify>安装好</FONT><FONT face="宋体, MS Song" size=3>WMediaPlayer</FONT><FONT face=宋体 size=3>控件之后,我们要用它代替原来程序中的</FONT><FONT face="宋体, MS Song" size=3>VCL</FONT><FONT face=宋体 size=3>元件</FONT><FONT face="宋体, MS Song" size=3>Media Player</FONT><FONT face=宋体 size=3>,来实现播放</FONT><FONT face="宋体, MS Song" size=3>MP3</FONT><FONT face=宋体 size=3>音乐的功能,修改后的</FONT><FONT face="宋体, MS Song" size=3>MP3Collect</FONT><FONT face=宋体 size=3>程序如图</FONT><FONT face="宋体, MS Song" size=3>19-3</FONT><FONT face=宋体 size=3>所示。在进行改造之前,心铃建议大家先把原来的工程做一个备份,这样如果在修改过程中出现了错误,容易进行比对查找。</P>< align=justify>我们先把</FONT><FONT face="宋体, MS Song" size=3>MainForm</FONT><FONT face=宋体 size=3>上原有的</FONT><FONT face="宋体, MS Song" size=3>MediaPlayer1</FONT><FONT face=宋体 size=3>控件删除,并在空出来的位置上新增加一个</FONT><FONT face="宋体, MS Song" size=3>WMediaPlayer</FONT><FONT face=宋体 size=3>控件</FONT><FONT face="宋体, MS Song" size=3>WMediaPlayer1</FONT><FONT face=宋体 size=3>。由于</FONT><FONT face="宋体, MS Song" size=3>WMediaPlayer</FONT><FONT face=宋体 size=3>控件能够播放视频,因此控件上带有视频输出区域,我们需要适当调整控件的大小,使得视频区域隐藏起来。</P>< align=justify>前面说过,当</FONT><FONT face="宋体, MS Song" size=3>ActiveX</FONT><FONT face=宋体 size=3>控件安装成功后,可以象使用普通</FONT><FONT face="宋体, MS Song" size=3>VCL</FONT><FONT face=宋体 size=3>控件一样使用它。但是使用</FONT><FONT face="宋体, MS Song" size=3>ActiveX</FONT><FONT face=宋体 size=3>控件时常会遇到帮助文档不全的问题,特别是从网上下载的一些共享</FONT><FONT face="宋体, MS Song" size=3>ActiveX</FONT><FONT face=宋体 size=3>控件,由于帮助文档很少,常常让人“望</FONT><FONT face="宋体, MS Song" size=3>X</FONT><FONT face=宋体 size=3>兴叹”。心铃在使用</FONT><FONT face="宋体, MS Song" size=3>WMediaPlayer</FONT><FONT face=宋体 size=3>控件时也遇到这个问题,该控件是由微软编写的,</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>中并没有相关的帮助,幸好经过多次搜索后,心铃终于从微软的</FONT><FONT face="宋体, MS Song" size=3>latform SDK</FONT><FONT face=宋体 size=3>中找到了一些帮助,根据这些帮助,心铃在下面的表格中对</FONT><FONT face="宋体, MS Song" size=3>WMediaPlayer</FONT><FONT face=宋体 size=3>控件需要设置的主要属性的大致含义进行了介绍,其中可能会有理解不是十分准确的地方,请朋友们注意这一点。</P><B>< align=center>表19-1:WMediaPlayer1控件主要属性的设置</P></B></FONT><TABLE cellSpacing=1 cellPadding=7 width=607 border=1><TR><TD vAlign=top width="30%"><FONT face=宋体 size=3>< align=justify>属性名称</FONT></P></TD><TD vAlign=top width="12%"><FONT face=宋体 size=3>< align=justify>设置值</FONT></P></TD><TD vAlign=top width="58%"><FONT face=宋体 size=3>< align=justify>解释</FONT></P></TD></TR><TR><TD vAlign=top width="30%"><FONT size=3>< align=justify>AutoRewind</FONT></P></TD><TD vAlign=top width="12%"><FONT size=3>< align=justify>False</FONT></P></TD><TD vAlign=top width="58%"><FONT face=宋体 size=3>< align=justify>禁止播放完毕后自动回到起始点的功能</FONT></P></TD></TR><TR><TD vAlign=top width="30%"><FONT size=3>< align=justify>AutoStart</FONT></P></TD><TD vAlign=top width="12%"><FONT size=3>< align=justify>false</FONT></P></TD><TD vAlign=top width="58%"><FONT face=宋体 size=3>< align=justify>禁止打开文件后自动播放的功能</FONT></P></TD></TR><TR><TD vAlign=top width="30%"><FONT size=3>< align=justify>Mute</FONT></P></TD><TD vAlign=top width="12%"><FONT size=3><P align=justify>false</FONT></P></TD><TD vAlign=top width="58%"><FONT face=宋体 size=3><P align=justify>取消静音状态</FONT></P></TD></TR><TR><TD vAlign=top width="30%"><FONT size=3><P align=justify>PreviewMode</FONT></P></TD><TD vAlign=top width="12%"><FONT size=3><P align=justify>false</FONT></P></TD><TD vAlign=top width="58%"><FONT face=宋体 size=3><P align=justify>关闭预览模式</FONT></P></TD></TR><TR><TD vAlign=top width="30%"><FONT size=3><P align=justify>SendErrorEvents</FONT></P></TD><TD vAlign=top width="12%"><FONT size=3><P align=justify>true</FONT></P></TD><TD vAlign=top width="58%"><FONT face=宋体 size=3><P align=justify>产生错误时发送错误事件</FONT></P></TD></TR><TR><TD vAlign=top width="30%"><FONT size=3><P align=justify>SendKeyboardEvents</FONT></P></TD><TD vAlign=top width="12%"><FONT size=3><P align=justify>true</FONT></P></TD><TD vAlign=top width="58%"><FONT face=宋体 size=3><P align=justify>用户在控件上按键时发送键盘事件</FONT></P></TD></TR><TR><TD vAlign=top width="30%"><FONT size=3><P align=justify>SendMouseClickEvents</FONT></P></TD><TD vAlign=top width="12%"><FONT size=3><P align=justify>true</FONT></P></TD><TD vAlign=top width="58%"><FONT face=宋体 size=3><P align=justify>用户在控件上点击鼠标时发送鼠标点击事件</FONT></P></TD></TR><TR><TD vAlign=top width="30%"><FONT size=3><P align=justify>SendMouseMoveEvents</FONT></P></TD><TD vAlign=top width="12%"><FONT size=3><P align=justify>true</FONT></P></TD><TD vAlign=top width="58%"><FONT face=宋体 size=3><P align=justify>用户在控件上移动鼠标时发送鼠标移动事件</FONT></P></TD></TR><TR><TD vAlign=top width="30%"><FONT size=3><P align=justify>SendOpenStateChangeEvents</FONT></P></TD><TD vAlign=top width="12%"><FONT size=3><P align=justify>true</FONT></P></TD><TD vAlign=top width="58%"><FONT face=宋体 size=3><P align=justify>打开状态发生变化时发送</FONT><FONT face="宋体, MS Song" size=3>OpenStateChange</FONT><FONT face=宋体 size=3>事件</FONT></P></TD></TR><TR><TD vAlign=top width="30%"><FONT size=3><P align=justify>SendPlayStateChangeEvents</FONT></P></TD><TD vAlign=top width="12%"><FONT size=3><P align=justify>true</FONT></P></TD><TD vAlign=top width="58%"><FONT face=宋体 size=3><P align=justify>播放状态发生变化时发送</FONT><FONT face="宋体, MS Song" size=3>PlayStateChange</FONT><FONT face=宋体 size=3>事件</FONT></P></TD></TR><TR><TD vAlign=top width="30%"><FONT size=3><P align=justify>ShowAudioControls</FONT></P></TD><TD vAlign=top width="12%"><FONT size=3><P align=justify>true</FONT></P></TD><TD vAlign=top width="58%"><FONT face=宋体 size=3><P align=justify>显示音量控件</FONT></P></TD></TR><TR><TD vAlign=top width="30%"><FONT size=3><P align=justify>ShowControls</FONT></P></TD><TD vAlign=top width="12%"><FONT size=3><P align=justify>true</FONT></P></TD><TD vAlign=top width="58%"><FONT face=宋体 size=3><P align=justify>显示播放控件等</FONT></P></TD></TR><TR><TD vAlign=top width="30%"><FONT size=3><P align=justify>ShowDisplay</FONT></P></TD><TD vAlign=top width="12%"><FONT size=3><P align=justify>false</FONT></P></TD><TD vAlign=top width="58%"><FONT face=宋体 size=3><P align=justify>不显示信息窗口</FONT></P></TD></TR><TR><TD vAlign=top width="30%"><FONT size=3><P align=justify>ShowGotoBar</FONT></P></TD><TD vAlign=top width="12%"><FONT size=3><P align=justify>false</FONT></P></TD><TD vAlign=top width="58%"><FONT face=宋体 size=3><P align=justify>不显示跳转栏</FONT></P></TD></TR><TR><TD vAlign=top width="30%"><FONT size=3><P align=justify>ShowHint</FONT></P></TD><TD vAlign=top width="12%"><FONT size=3><P align=justify>true</FONT></P></TD><TD vAlign=top width="58%"><FONT face=宋体 size=3><P align=justify>显示提示信息</FONT></P></TD></TR><TR><TD vAlign=top width="30%"><FONT size=3><P align=justify>ShowPositionControls</FONT></P></TD><TD vAlign=top width="12%"><FONT size=3><P align=justify>true</FONT></P></TD><TD vAlign=top width="58%"><FONT face=宋体 size=3><P align=justify>显示向前、向后浏览按钮</FONT></P></TD></TR><TR><TD vAlign=top width="30%"><FONT size=3><P align=justify>ShowStatusBar</FONT></P></TD><TD vAlign=top width="12%"><FONT size=3><P align=justify>false</FONT></P></TD><TD vAlign=top width="58%"><FONT face=宋体 size=3><P align=justify>不显示状态栏</FONT></P></TD></TR><TR><TD vAlign=top width="30%"><FONT size=3><P align=justify>ShowTracker</FONT></P></TD><TD vAlign=top width="12%"><FONT size=3><P align=justify>true</FONT></P></TD><TD vAlign=top width="58%"><FONT face=宋体 size=3><P align=justify>显示播放位置滑动条</FONT></P></TD></TR></TABLE><FONT face=宋体 size=3><P align=justify>设置好控件的属性后,还要对代码进行修改,将原来由</FONT><FONT face="宋体, MS Song" size=3>MediaPlayer1</FONT><FONT face=宋体 size=3>控件实现的功能改为由</FONT><FONT face="宋体, MS Song" size=3>WMediaPlayer1</FONT><FONT face=宋体 size=3>实现。</P><P align=justify>用</FONT><FONT face="宋体, MS Song" size=3>WMediaPlayer</FONT><FONT face=宋体 size=3>控件播放一个媒体文件的基本方法是:首先将文件名赋给</FONT><FONT face="宋体, MS Song" size=3>WMediaPlayer1</FONT><FONT face=宋体 size=3>的</FONT><FONT face="宋体, MS Song" size=3>FileName</FONT><FONT face=宋体 size=3>属性,再调用其</FONT><FONT face="宋体, MS Song" size=3>Open</FONT><FONT face=宋体 size=3>方法打开该文件。由于</FONT><FONT face="宋体, MS Song" size=3>Open</FONT><FONT face=宋体 size=3>方法不等待打开成功就会返回,所以不能够马上进行下一步</FONT><FONT face="宋体, MS Song" size=3>Play</FONT><FONT face=宋体 size=3>操作,而需要等待事件</FONT><FONT face="宋体, MS Song" size=3>OnOpenStateChange</FONT><FONT face=宋体 size=3>,在该事件的处理函数中判断文件是否打开正确,如果打开正确,则可以进一步调用其</FONT><FONT face="宋体, MS Song" size=3>Play</FONT><FONT face=宋体 size=3>函数进行播放。下面给出函数</FONT><FONT face="宋体, MS Song" size=3>PlayTheSong</FONT><FONT face=宋体 size=3>和</FONT><FONT face="宋体, MS Song" size=3>OnOpenStateChange</FONT><FONT face=宋体 size=3>事件处理函数的实现代码:</P></FONT><FONT size=3><P align=justify>void __fastcall TMainForm:layTheSong() </FONT><FONT face=宋体 size=3>{</P></FONT><FONT size=3><P align=justify>WMediaPlayer1-&gt;FileName=DBGrid1-&gt;DataSource-&gt;DataSet-&gt;FieldByName("FileName")-&gt;AsString;</P><P align=justify>WMediaPlayer1-&gt;Open(WMediaPlayer1-&gt;FileName);</P><P align=justify>m_bIsPlaying=true;//</FONT><FONT face=宋体 size=3>设置</FONT><FONT size=3>m_bIsPlaying</FONT><FONT face=宋体 size=3>标志,表示打开成功后进行播放操作</P><P align=justify>}</P></FONT><FONT size=3><P align=justify>void __fastcall TMainForm::WMediaPlayer1OpenStateChange(TObject *Sender,long bytesSent, long bytesRemaining) </FONT><FONT face=宋体 size=3>{</P></FONT><FONT size=3><P align=justify>//OpenState</FONT><FONT face=宋体 size=3>为</FONT><FONT size=3>6</FONT><FONT face=宋体 size=3>表示打开正确,</FONT><FONT size=3>m_bIsPlaying</FONT><FONT face=宋体 size=3>为真表示下一步应该进行播放操作</P></FONT><FONT size=3><P align=justify>if(WMediaPlayer1-&gt;OpenState==6 &amp;&amp; m_bIsPlaying) {//</FONT><FONT face=宋体 size=3>两个条件同时满足时开始播放。</P><DIR></FONT><FONT size=3><P align=justify>m_bIsPlaying=false;</P><P align=justify>WMediaPlayer1-&gt;Play();</P></DIR></FONT><FONT face=宋体 size=3><P align=justify>}</P><P align=justify>}</P><P align=justify>在播放过程中,我们还需要根据播放状态的变化将一些命令按钮设置成有效或无效。这一功能在</FONT><FONT face="宋体, MS Song" size=3>OnPlayStateChange</FONT><FONT face=宋体 size=3>事件中完成。播放到文件结尾处时,</FONT><FONT face="宋体, MS Song" size=3>WMediaPlayer</FONT><FONT face=宋体 size=3>控件会产生</FONT><FONT face="宋体, MS Song" size=3>OnEndOfStream</FONT><FONT face=宋体 size=3>事件,我们可以在这一事件中判断是否需要循环播放,如果是则播放下一首。</P></FONT><FONT size=3><P align=justify>void __fastcall TMainForm::WMediaPlayer1PlayStateChange(TObject *Sender, long bytesSent, long bytesRemaining) </FONT><FONT face=宋体 size=3>{</P></FONT><FONT size=3><P align=justify>if(bytesRemaining==2)// bytesRemaining</FONT><FONT face=宋体 size=3>为</FONT><FONT size=3>2</FONT><FONT face=宋体 size=3>表示播放开始</P><DIR></FONT><FONT size=3><P align=justify>EnableButtons(false); //</FONT><FONT face=宋体 size=3>使记录操作按钮失效</P></DIR></FONT><FONT size=3><P align=justify>else if(bytesRemaining==0)// bytesRemaining</FONT><FONT face=宋体 size=3>为</FONT><FONT size=3>0</FONT><FONT face=宋体 size=3>表示播放结束</P><DIR></FONT><FONT size=3><P align=justify>EnableButtons(true); //</FONT><FONT face=宋体 size=3>使记录操作按钮失效</P></DIR><P align=justify>}</P></FONT><FONT size=3><P align=justify>void __fastcall TMainForm::WMediaPlayer1EndOfStream(TObject *Sender, long bytesTotal) </FONT><FONT face=宋体 size=3>{</P></FONT><FONT size=3><P align=justify>TDataSet * pDS=DBGrid1-&gt;DataSource-&gt;DataSet;</P><P align=justify>if(chkLoop-&gt;Checked){</P><DIR><P align=justify>pDS-&gt;Next();</P><DIR><P align=justify>if(pDS-&gt;Eof) pDS-&gt;First();</P></DIR><P align=justify>PlayTheSong();</P></DIR></FONT><FONT face=宋体 size=3><P align=justify>}</P></FONT><FONT size=3><P align=justify>else EnableButtons(true);</P></FONT><FONT face=宋体 size=3><P align=justify>}</P><P align=justify>当</FONT><FONT face="宋体, MS Song" size=3>Query1</FONT><FONT face=宋体 size=3>控件当前记录发生改变时,在</FONT><FONT face="宋体, MS Song" size=3>WMediaPlayer1</FONT><FONT face=宋体 size=3>中打开相应文件的实现代码如下:</P></FONT><FONT size=3><P align=justify>void __fastcall TMainForm:uery1AfterScroll(TDataSet *DataSet) </FONT><FONT face=宋体 size=3>{</P></FONT><FONT size=3><P align=justify>if(Query1-&gt;State==dsBrowse ) </FONT><FONT face=宋体 size=3>{</P><DIR></FONT><FONT size=3><P align=justify>TDataSet * pDS=DBGrid1-&gt;DataSource-&gt;DataSet ;</P><P align=justify>if(!pDS-&gt;IsEmpty()) </FONT><FONT face=宋体 size=3>{</P><DIR></FONT><FONT size=3><P align=justify>//</FONT><FONT face=宋体 size=3>定位</FONT><FONT size=3>Table1</FONT><FONT face=宋体 size=3>控件,并在编辑框中显示相应的记录信息</P></FONT><FONT size=3><P align=justify>…//</FONT><FONT face=宋体 size=3>(此处同以前的代码,故省略)</P></FONT><FONT size=3><P align=justify>m_bIsPlaying=false;//</FONT><FONT face=宋体 size=3>打开成功后不播放。</P></FONT><FONT size=3><P align=justify>WMediaPlayer1-&gt;FileName =Query1-&gt;FieldByName("FileName")-&gt;AsString;</P><P align=justify>WMediaPlayer1-&gt;Open(WMediaPlayer1-&gt;FileName);//</FONT><FONT face=宋体 size=3>打开媒体文件</P><P align=justify>}</P></DIR></DIR><P align=justify>}</P><P align=justify>}</P><P align=justify> </P><P align=justify>本讲我们学习</FONT><FONT face="宋体, MS Song" size=3>ActiveX</FONT><FONT face=宋体 size=3>控件的基本使用方法,可以说,</FONT><FONT face="宋体, MS Song" size=3>ActiveX</FONT><FONT face=宋体 size=3>控件使用起来并不复杂,但这项技术本身涉及到非常多的概念,朋友们在使用</FONT><FONT face="宋体, MS Song" size=3>ActiveX</FONT><FONT face=宋体 size=3>控件的过程中如果遇到问题,最好多查阅相关资料,特别是开发者提供的开发文档。</P><P align=justify>另外,由于中华网对个人主页服务器进行了调整,心铃原来告诉大家的讲座下载地址有一些变化,请需要电子文档的朋友使用新地址去下载:</FONT><a href="http://ctprwindwind.at.china.com/" target="_blank" ><FONT face="宋体, MS Song" size=3>http://ctprwindwind.at.china.com/</FONT></A><FONT face=宋体 size=3>。</P></FONT>
作者: 韩冰    时间: 2005-1-26 01:41
<b><FONT face=宋体 size=6> </FONT></b>< align=center>安装程序的制作</P><FONT face=宋体 size=3>< align=justify>经过前面十九讲的学习,我们已经初步掌握了</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>编程的基本知识,而且亲自动手设计和编写了一个小软件</FONT><FONT face="宋体, MS Song" size=3>MP3Collect</FONT><FONT face=宋体 size=3>,通常一个软件开发完毕后,为了方便用户使用,一般都需要制作相应的安装程序,本讲中我们就来学习如何利用</FONT><FONT face="宋体, MS Song" size=3>InstallShield</FONT><FONT face=宋体 size=3>来制作安装程序。</P><UL></FONT><B><FONT size=3>< align=justify><LI>InstallShield Express</FONT><FONT face=宋体 size=3>简介
7 U: I* C; q; H; ?' B' h/ M</LI></UL></B>< align=justify>要让应用程序在目标机器上顺利运行,除了需要基本的可执行文件之外,还需要一系列支持文件和一个合适的运行环境,其中支持文件包括有程序要调用的动态链接库、控件、相关数据文件等等,运行环境包括注册表配置、数据库配置等等,这些是发布程序时需要配置的几项主要内容。原则上来说,拷贝文件和配置工作都可以通过手工来完成,但这一过程相当复杂,没有用户会喜欢采用这种方式来安装程序,为此,我们需要使用专门的制作安装程序的软件(可简称为“发布软件”)来制作一个使用简便的安装程序,例如</FONT><FONT face="宋体, MS Song" size=3>InstallShield Express</FONT><FONT face=宋体 size=3>。</P></FONT><FONT size=3>< align=justify>InstallShield</FONT><FONT face=宋体 size=3>是一个专业开发发布软件的公司,它为许多著名的编程工具提供了专门的发布软件,如</FONT><FONT size=3>InstallShield For VC</FONT><FONT face=宋体 size=3>、</FONT><FONT size=3>InstallShield Express For VB</FONT><FONT face=宋体 size=3>、</FONT><FONT size=3>InstallShield Express For CBuilder</FONT><FONT face=宋体 size=3>、</FONT><FONT size=3>InstallShield Express For Delphi</FONT><FONT face=宋体 size=3>等,另外还有通用的</FONT><FONT size=3>InstallShield Express</FONT><FONT face=宋体 size=3>,目前最新版本为</FONT><FONT size=3>3.01</FONT><FONT face=宋体 size=3>,感兴趣的朋友可以到其主页(</FONT><a href="http://www.installshield.com/" target="_blank" ><FONT size=3>http://www.installshield.com</FONT></A><FONT face=宋体 size=3>)去了解最新产品的情况。</P></FONT><FONT size=3>< align=justify>InstallShield Express For CBuilder</FONT><FONT face=宋体 size=3>是</FONT><FONT size=3>InstallShield</FONT><FONT face=宋体 size=3>公司为</FONT><FONT size=3>CBuilder</FONT><FONT face=宋体 size=3>量身定做的发布软件,随</FONT><FONT size=3>CBuilder</FONT><FONT face=宋体 size=3>软件包一起发行。不同版本的</FONT><FONT size=3>CBuilder</FONT><FONT face=宋体 size=3>所带的</FONT><FONT size=3>InstallShield Express</FONT><FONT face=宋体 size=3>使用方法很类似而且相互兼容,考虑到不少读者朋友手上的</FONT><FONT size=3>CBuilder 5.0</FONT><FONT face=宋体 size=3>光盘中并没有最新的</FONT><FONT size=3>InstallShield Express For CBuilder 5.0</FONT><FONT face=宋体 size=3>,因此心铃就以</FONT><FONT size=3>InstallShield Express For CBuilder 4.0</FONT><FONT face=宋体 size=3>为例来介绍制作安装程序的过程,不过心铃使用的</FONT><FONT size=3>InstallShield Express For CBuilder 4.0</FONT><FONT face=宋体 size=3>并非企业版,因此功能上有一些限制,但基本上还是能够满足我们的要求。</P><UL><B>< align=justify><LI>创建安装工程 <p></LI></UL></B>< align=justify>由于第</FONT><FONT face="宋体, MS Song" size=3>19</FONT><FONT face=宋体 size=3>讲中的</FONT><FONT face="宋体, MS Song" size=3>MP3Collect</FONT><FONT face=宋体 size=3>使用了</FONT><FONT face="宋体, MS Song" size=3>ActiveX</FONT><FONT face=宋体 size=3>控件,而</FONT><FONT face="宋体, MS Song" size=3>ActiveX</FONT><FONT face=宋体 size=3>控件的安装比较复杂,</FONT><FONT face="宋体, MS Song" size=3>InstallShield Express for CBuilder 4.0</FONT><FONT face=宋体 size=3>中没有提供简单的方法用于安装</FONT><FONT face="宋体, MS Song" size=3>ActiveX</FONT><FONT face=宋体 size=3>控件,实现起来比较困难。另外,在程序中发布</FONT><FONT face="宋体, MS Song" size=3>ActiveX</FONT><FONT face=宋体 size=3>控件,特别是第三方的</FONT><FONT face="宋体, MS Song" size=3>ActiveX</FONT><FONT face=宋体 size=3>控件时涉及到许可证问题,也比较复杂。因此,下面我们就以第</FONT><FONT face="宋体, MS Song" size=3>19</FONT><FONT face=宋体 size=3>讲以前的</FONT><FONT face="宋体, MS Song" size=3>MP3Collect</FONT><FONT face=宋体 size=3>为例来制作安装程序。</P>< align=justify>首先运行</FONT><FONT face="宋体, MS Song" size=3>InstallShield Express For CBuilder 4.0</FONT><FONT face=宋体 size=3>,程序启动后会弹出一个对话框,用户可以在其中选择创建一个新的安装程序工程或是打开一个已有的工程,在这里我们选择创建一个新的工程,并在随后的“</FONT><FONT face="宋体, MS Song" size=3>New Project</FONT><FONT face=宋体 size=3>”对话框中输入工程名称</FONT><FONT face="宋体, MS Song" size=3>MP3Collect</FONT><FONT face=宋体 size=3>和工程路径“</FONT><FONT face="宋体, MS Song" size=3>MP3Collect\MP3CollectSetup</FONT><FONT face=宋体 size=3>”,然后按下“</FONT><FONT face="宋体, MS Song" size=3>Create</FONT><FONT face=宋体 size=3>”按钮,</FONT><FONT face="宋体, MS Song" size=3>InstallShield Express For CBuilder</FONT><FONT face=宋体 size=3>就会在相应的目录下创建一个空白的安装工程。</P><UL><B>< align=justify><LI>设置安装工程参数 <p></LI></UL></B>< align=justify>新工程如图</FONT><FONT face="宋体, MS Song" size=3>20-1</FONT><FONT face=宋体 size=3>所示,实际上是一个安装程序的模板。模板中共分为</FONT><FONT face="宋体, MS Song" size=3>9</FONT><FONT face=宋体 size=3>大项内容,其中前</FONT><FONT face="宋体, MS Song" size=3>6</FONT><FONT face=宋体 size=3>项为参数设置项,包括了发布应用程序涉及到的各个方面的内容。每一大项下面都有若干小选项,单击每个小项左边的箭头按钮可以对该项内容进行设置。新工程中所有设置项目都为初始的缺省值,而用户修改过的项目左边会出现一个红色的“<FONT face="Wingdings 2"></FONT> ”作为标记。</P></FONT><FONT size=3>< align=justify>InstallShield Express For CBuilder</FONT><FONT face=宋体 size=3>采用向导的形式来帮助用户设置安装工程中的各项参数,每一个大项的内容都是一个设置对话框,每一个小项则是对话框中的一个选项页。</P>< align=justify>首先设置“</FONT><FONT face="宋体, MS Song" size=3>Setup the visual Design</FONT><FONT face=宋体 size=3>”,这里主要设置安装程序的外观。</FONT><FONT face="宋体, MS Song" size=3>App Info</FONT><FONT face=宋体 size=3>中可设置要发布软件的名称、版本、公司以及缺省的安装目录,其中,我们将缺省安装目录设为:</FONT><FONT face="宋体, MS Song" size=3>&ltrogramFilesDir&gt;\MP3Collect</FONT><FONT face=宋体 size=3>。这里的“</FONT><FONT face="宋体, MS Song" size=3>&ltrogramFilesDir&gt;</FONT><FONT face=宋体 size=3>”是</FONT><FONT face="宋体, MS Song" size=3>InstallShield Express</FONT><FONT face=宋体 size=3>定义的目录标识符之一,代表目标机器的“</FONT><FONT face="宋体, MS Song" size=3>rogram Files</FONT><FONT face=宋体 size=3>”目录。使用目录标识符可以很好地适应不同系统的差异,让安装程序具有较好的灵活性。常用的目录标识符还有</FONT><FONT face="宋体, MS Song" size=3>&lt;INSTALLDIR&gt;</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>&lt;WINDIR&gt;</FONT><FONT face=宋体 size=3>等等,分别代表目标机器的最终程序安装目录和</FONT><FONT face="宋体, MS Song" size=3>Windows</FONT><FONT face=宋体 size=3>系统所在目录。在</FONT><FONT face="宋体, MS Song" size=3>Main Window</FONT><FONT face=宋体 size=3>选项页中,我们可以指定安装程序主窗口的背景图片、文字,以及</FONT><FONT face="宋体, MS Song" size=3>LOGO</FONT><FONT face=宋体 size=3>图片、背景颜色等。</FONT><FONT face="宋体, MS Song" size=3>Features</FONT><FONT face=宋体 size=3>选项中可以指定是否需要自动卸载功能,我们应将其选中。</P>< align=justify>第二步设置“</FONT><FONT face="宋体, MS Song" size=3>Sepecify InstallShield Objects for Borland C++ Builder</FONT><FONT face=宋体 size=3>”。这一项内容是整个工程设置中的重点,也是专门针对</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>应用程序的特点进行设置的地方。单击其中的某个选项按钮打开设置向导对话框,如图</FONT><FONT face="宋体, MS Song" size=3>20-2</FONT><FONT face=宋体 size=3>所示。在</FONT><FONT face="宋体, MS Song" size=3>General</FONT><FONT face=宋体 size=3>选项页中列出了需要安装的各种对象,如是否安装</FONT><FONT face="宋体, MS Song" size=3>BDE</FONT><FONT face=宋体 size=3>、是否需要运行时包文件以及安装哪些包文件等。由于</FONT><FONT face="宋体, MS Song" size=3>MP3Collect</FONT><FONT face=宋体 size=3>程序使用了</FONT><FONT face="宋体, MS Song" size=3>BDE</FONT><FONT face=宋体 size=3>进行数据库访问,所以应该选中</FONT><FONT face="宋体, MS Song" size=3>BDE</FONT><FONT face=宋体 size=3>选项,同时还应该选中</FONT><FONT face="宋体, MS Song" size=3>BDE Control Panel Files</FONT><FONT face=宋体 size=3>选项,该项内容会在目标系统的控制面板中安装</FONT><FONT face="宋体, MS Song" size=3>BDE Administrator</FONT><FONT face=宋体 size=3>,便于管理数据库别名。另外,</FONT><FONT face="宋体, MS Song" size=3>MP3Collect</FONT><FONT face=宋体 size=3>程序使用了数据库控件和</FONT><FONT face="宋体, MS Song" size=3>QuickReport</FONT><FONT face=宋体 size=3>报表控件,所以还要选中相应的包文件,此外还需要选择“</FONT><FONT face="宋体, MS Song" size=3>Use Packages</FONT><FONT face=宋体 size=3>”、“</FONT><FONT face="宋体, MS Song" size=3>RTL</FONT><FONT face=宋体 size=3>”和“</FONT><FONT face="宋体, MS Song" size=3>Standard VCL Packages</FONT><FONT face=宋体 size=3>”等选项。</P>< align=justify>当我们选中</FONT><FONT face="宋体, MS Song" size=3>BDE</FONT><FONT face=宋体 size=3>选项时,</FONT><FONT face="宋体, MS Song" size=3>InstallShield Express</FONT><FONT face=宋体 size=3>会自动弹出</FONT><FONT face="宋体, MS Song" size=3>BDE</FONT><FONT face=宋体 size=3>安装向导,第一步选择</FONT><FONT face="宋体, MS Song" size=3>BDE</FONT><FONT face=宋体 size=3>安装类型,我们在这里选择“完全安装”。第二步决定是否创建数据库别名,因为程序中使用了数据库别名“</FONT><FONT face="宋体, MS Song" size=3>MP3Collect</FONT><FONT face=宋体 size=3>”,因此在这里也要新建一个别名“</FONT><FONT face="宋体, MS Song" size=3>MP3Collect</FONT><FONT face=宋体 size=3>”,接着</FONT><FONT face="宋体, MS Song" size=3>InstallShield Express</FONT><FONT face=宋体 size=3>会询问是否要兼容</FONT><FONT face="宋体, MS Song" size=3>16</FONT><FONT face=宋体 size=3>位系统,这里设为不需要。第三步要对别名进行配置,如图</FONT><FONT face="宋体, MS Song" size=3>20-3</FONT><FONT face=宋体 size=3>所示,配置方法是在“</FONT><FONT face="宋体, MS Song" size=3>Alias Name</FONT><FONT face=宋体 size=3>”中选择“</FONT><FONT face="宋体, MS Song" size=3>MP3Collect</FONT><FONT face=宋体 size=3>”,在“</FONT><FONT face="宋体, MS Song" size=3>ath</FONT><FONT face=宋体 size=3>”中输入别名对应的实际数据库路径名为“</FONT><FONT face="宋体, MS Song" size=3>&lt;INSTALLDIR&gt;\MP3Collect.mdb</FONT><FONT face=宋体 size=3>”,在“</FONT><FONT face="宋体, MS Song" size=3>Type</FONT><FONT face=宋体 size=3>”中选择别名的类型为“</FONT><FONT face="宋体, MS Song" size=3>Microsoft Access Driver(*.mdb)</FONT><FONT face=宋体 size=3>”,图</FONT><FONT face="宋体, MS Song" size=3>20-3</FONT><FONT face=宋体 size=3>最下面一栏用于输入别名的其它参数,参数的格式为“</FONT><FONT face="宋体, MS Song" size=3>Keyname=Value</FONT><FONT face=宋体 size=3>”,各种参数的含义请朋友参考</FONT><FONT face="宋体, MS Song" size=3>BDE Administrator</FONT><FONT face=宋体 size=3>中的别名定义,我们在这里指定一条参数为“</FONT><FONT face="宋体, MS Song" size=3>ODBC DSN=MP3CollectDSN</FONT><FONT face=宋体 size=3>”。</P>< align=justify>到此就完成了对数据库别名的设置,如果以后还需要修改,仍可在图</FONT><FONT face="宋体, MS Song" size=3>20-2</FONT><FONT face=宋体 size=3>所示的对话框中按“</FONT><FONT face="宋体, MS Song" size=3>Settings...</FONT><FONT face=宋体 size=3>”按钮重新设置。</FONT><FONT face="宋体, MS Song" size=3>InstallShield Objects</FONT><FONT face=宋体 size=3>对话框中的</FONT><FONT face="宋体, MS Song" size=3>Advance</FONT><FONT face=宋体 size=3>选项页会根据用户在</FONT><FONT face="宋体, MS Song" size=3>General</FONT><FONT face=宋体 size=3>选项页中所作的选择,自动列出安装相应对象所需要的文件。由于心铃使用的是较早版本的</FONT><FONT face="宋体, MS Song" size=3>InstallShield Express</FONT><FONT face=宋体 size=3>,所以其中列出的许多</FONT><FONT face="宋体, MS Song" size=3>DLL</FONT><FONT face=宋体 size=3>和</FONT><FONT face="宋体, MS Song" size=3>BPL</FONT><FONT face=宋体 size=3>文件都是</FONT><FONT face="宋体, MS Song" size=3>4.0</FONT><FONT face=宋体 size=3>版本的,还需要在下一个设置中进行修改。</P>< align=justify>第三项设置为“</FONT><FONT face="宋体, MS Song" size=3>Specify Components and Files</FONT><FONT face=宋体 size=3>”。这里有三个选项页。其中主要用到的是</FONT><FONT face="宋体, MS Song" size=3>Groups</FONT><FONT face=宋体 size=3>选项页。</FONT><FONT face="宋体, MS Song" size=3>Groups</FONT><FONT face=宋体 size=3>选项页中将安装到目标机器的所有文件分成了几组(即几个文件夹),如图</FONT><FONT face="宋体, MS Song" size=3>20-4</FONT><FONT face=宋体 size=3>所示。除了</FONT><FONT face="宋体, MS Song" size=3>rogram Files</FONT><FONT face=宋体 size=3>文件夹用来安装应用程序之外,其余几个文件夹是根据前面一步的设置而得到的,我们还可以根据需要增加、删除文件夹和修改文件夹中的文件。</P>< align=justify>首先选中</FONT><FONT face="宋体, MS Song" size=3>rogram Files</FONT><FONT face=宋体 size=3>文件夹,然后利用“</FONT><FONT face="宋体, MS Song" size=3>Insert Files</FONT><FONT face=宋体 size=3>”按钮向其中添加</FONT><FONT face="宋体, MS Song" size=3>MP3Collect.exe</FONT><FONT face=宋体 size=3>和</FONT><FONT face="宋体, MS Song" size=3>MP3Collect.mdb</FONT><FONT face=宋体 size=3>。在</FONT><FONT face="宋体, MS Song" size=3>System Files</FONT><FONT face=宋体 size=3>文件夹中,我们要将</FONT><FONT face="宋体, MS Song" size=3>4.0</FONT><FONT face=宋体 size=3>版本的</FONT><FONT face="宋体, MS Song" size=3>DLL</FONT><FONT face=宋体 size=3>和</FONT><FONT face="宋体, MS Song" size=3>BPL</FONT><FONT face=宋体 size=3>文件改成其对应的</FONT><FONT face="宋体, MS Song" size=3>5.0</FONT><FONT face=宋体 size=3>版本库文件,修改后的</FONT><FONT face="宋体, MS Song" size=3>System Files</FONT><FONT face=宋体 size=3>文件夹包括下列文件:</FONT><FONT face="宋体, MS Song" size=3>BORLNDMM.DLL</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>qrpt50.bpl</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>vcl50.bpl</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>vcldb50.bpl</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>vclx50.bpl</FONT><FONT face=宋体 size=3>、</FONT><FONT face="宋体, MS Song" size=3>cc3250mt.dll</FONT><FONT face=宋体 size=3>和</FONT><FONT face="宋体, MS Song" size=3>vclbde50.bpl</FONT><FONT face=宋体 size=3>。其余两个文件夹</FONT><FONT face="宋体, MS Song" size=3>BDE/IDAPI Files</FONT><FONT face=宋体 size=3>和</FONT><FONT face="宋体, MS Song" size=3>BDE/IDAPI CNF File</FONT><FONT face=宋体 size=3>则可以基本不动。选中某个文件夹后,按下“</FONT><FONT face="宋体, MS Song" size=3>roperties</FONT><FONT face=宋体 size=3>”按钮还可以查看和修改每个文件夹的属性,包括名称、文件更新方式和目标平台等,一般接受缺省值即可。</P>< align=justify>第四项设置内容为用户界面设置。</FONT><FONT face="宋体, MS Song" size=3>InstallShield Express</FONT><FONT face=宋体 size=3>将整个安装过程分为几个步骤,每一个步骤有一个用户界面,设置对话框的右边显示了用户界面的预览效果,用户可以选择需要其中的哪几个步骤,并设置其中的一些参数。心铃在其中选择了</FONT><FONT face="宋体, MS Song" size=3>Welcome</FONT><FONT face=宋体 size=3>信息、许可证、选择目录、选择开始菜单文件夹、开始拷贝文件、进度指示以及安装完毕几个步骤。</P>< align=justify>第五项设置注册表。首先在“</FONT><FONT face="宋体, MS Song" size=3>Registry-Keys</FONT><FONT face=宋体 size=3>”选项页中,在</FONT><FONT face="宋体, MS Song" size=3>HKEY_CURRENT_USER</FONT><FONT face=宋体 size=3>下添加一个主键:</FONT><FONT face="宋体, MS Song" size=3>Software\MP3Collect</FONT><FONT face=宋体 size=3>,选中该键后,再在“</FONT><FONT face="宋体, MS Song" size=3>Registry-Values</FONT><FONT face=宋体 size=3>”选项页中添加四个键值“</FONT><FONT face="宋体, MS Song" size=3>FileName</FONT><FONT face=宋体 size=3>”、“</FONT><FONT face="宋体, MS Song" size=3>SongName</FONT><FONT face=宋体 size=3>”、“</FONT><FONT face="宋体, MS Song" size=3>SingerName</FONT><FONT face=宋体 size=3>”和“</FONT><FONT face="宋体, MS Song" size=3>TestUse</FONT><FONT face=宋体 size=3>”,其中前三个为</FONT><FONT face="宋体, MS Song" size=3>String</FONT><FONT face=宋体 size=3>类型,内容为空字符串,第四个为</FONT><FONT face="宋体, MS Song" size=3>DWORD</FONT><FONT face=宋体 size=3>类型,内容为</FONT><FONT face="宋体, MS Song" size=3>1</FONT><FONT face=宋体 size=3>。</P>< align=justify>最后一项设置为“</FONT><FONT face="宋体, MS Song" size=3>Select Folder and Icon</FONT><FONT face=宋体 size=3>”,用于为应用程序在开始菜单中创建一个快捷方式。</FONT><FONT face="宋体, MS Song" size=3>General</FONT><FONT face=宋体 size=3>选项页用指定程序快捷方式的命令参数,我们设置“</FONT><FONT face="宋体, MS Song" size=3>Run Command</FONT><FONT face=宋体 size=3>”为“</FONT><FONT face="宋体, MS Song" size=3>[Program Files]\MP3Collect.exe</FONT><FONT face=宋体 size=3>”。</FONT><FONT face="宋体, MS Song" size=3>Advance</FONT><FONT face=宋体 size=3>选项页用于指定快捷菜单项的位置,我们设置“</FONT><FONT face="宋体, MS Song" size=3>Start In</FONT><FONT face=宋体 size=3>”为“</FONT><FONT face="宋体, MS Song" size=3>[Program Files]</FONT><FONT face=宋体 size=3>”,“</FONT><FONT face="宋体, MS Song" size=3>Icon</FONT><FONT face=宋体 size=3>”为</FONT><FONT face="宋体, MS Song" size=3>MP3Collect.exe</FONT><FONT face=宋体 size=3>的图标,“</FONT><FONT face="宋体, MS Song" size=3>Folder</FONT><FONT face=宋体 size=3>”为“</FONT><FONT face="宋体, MS Song" size=3>rograme Menu Folder</FONT><FONT face=宋体 size=3>”。</P><UL><B><P align=justify><LI>生成安装程序和运行安装程序 <p></LI></UL></B><P align=justify>安装工程中的最后三项用于生成安装程序和进行安装试运行。前面的参数都设置好了之后,可以单击</FONT><FONT face="宋体, MS Song" size=3>Disk Builder</FONT><FONT face=宋体 size=3>制作安装程序。制作前我们可以选择程序发布用的介质,如使用软盘发布可选择</FONT><FONT face="宋体, MS Song" size=3>1.44M</FONT><FONT face=宋体 size=3>,这样制作过程中会自动按照</FONT><FONT face="宋体, MS Song" size=3>1.44M</FONT><FONT face=宋体 size=3>为最大限度制作安装盘。这里我们选择介质类型为</FONT><FONT face="宋体, MS Song" size=3>CD-ROM</FONT><FONT face=宋体 size=3>,让所有安装文件都生成到同一个目录下。选择好介质后按“</FONT><FONT face="宋体, MS Song" size=3>Build</FONT><FONT face=宋体 size=3>”按钮就可以开始制作了,如果制作过程中没有错误,就可以进行下一步工作:测试安装。</P><P align=justify>单击</FONT><FONT face="宋体, MS Song" size=3>Test Run</FONT><FONT face=宋体 size=3>按钮就可以进行测试安装,以检查是否正确。不过根据心铃的经验,由于开发机器上本来就安装有</FONT><FONT face="宋体, MS Song" size=3>CBuilder 5.0</FONT><FONT face=宋体 size=3>,所以一般运行都不会出错,最好在一台没有安装过</FONT><FONT face="宋体, MS Song" size=3>CBuilder 5.0</FONT><FONT face=宋体 size=3>的机器上进行安装测试,这样才能及时发现和解决问题。</P><P align=justify>按照上述步骤生成的安装程序安装到一台新的机器后,还不能马上运行</FONT><FONT face="宋体, MS Song" size=3>MP3Collect.exe</FONT><FONT face=宋体 size=3>,原因是还缺少数据源的配置。由于心铃使用的不是完全版的</FONT><FONT face="宋体, MS Song" size=3>InstallShield Express for CBuilder 4.0</FONT><FONT face=宋体 size=3>,其中缺少自动配置</FONT><FONT face="宋体, MS Song" size=3>ODBC</FONT><FONT face=宋体 size=3>数据源的功能,所以安装完毕后,还要按照第十四讲的方法配置一遍</FONT><FONT face="宋体, MS Song" size=3>ODBC</FONT><FONT face=宋体 size=3>数据源</FONT><FONT face="宋体, MS Song" size=3>MP3CollectDSN</FONT><FONT face=宋体 size=3>,并利用控制面板中的</FONT><FONT face="宋体, MS Song" size=3>BDE Administrator</FONT><FONT face=宋体 size=3>工具重新配置别名</FONT><FONT face="宋体, MS Song" size=3>MP3Collect</FONT><FONT face=宋体 size=3>,使其指向</FONT><FONT face="宋体, MS Song" size=3>ODBC</FONT><FONT face=宋体 size=3>数据源</FONT><FONT face="宋体, MS Song" size=3>MP3CollectDSN</FONT><FONT face=宋体 size=3>。进行完这个步骤之后,</FONT><FONT face="宋体, MS Song" size=3>MP3Collect</FONT><FONT face=宋体 size=3>才能在目标机器上正常运行。如果朋友们的程序需要配置</FONT><FONT face="宋体, MS Song" size=3>ODBC</FONT><FONT face=宋体 size=3>数据源,建议大家选用</FONT><FONT face="宋体, MS Song" size=3>InstallShield Express 3.01</FONT><FONT face=宋体 size=3>或其它具有配置功能的发布软件。</P><B><P align=justify> </P></B><P align=justify>到现在为止,二十讲的</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>讲座已经结束了,心铃对</FONT><FONT face="宋体, MS Song" size=3>CBuilder</FONT><FONT face=宋体 size=3>也是在不断的学习和探索之中,因此在讲座中难免有各种不足和错误的地方,希望朋友们能够谅解,欢迎大家批评指正,谢谢。</P></FONT>




欢迎光临 数学建模社区-数学中国 (http://www.madio.net/) Powered by Discuz! X2.5