高职高专现代停息技术系列教材

Size: px
Start display at page:

Download "高职高专现代停息技术系列教材"

Transcription

1 高职高专计算机技能型紧缺人才培养规划教材计算机软件技术专业 Delphi 程序设计基础 张世明 编 人民邮电出版社

2 高职高专计算机技能型紧缺人才培养 规划教材编委会 主任武马群 副主任王泰峰徐民鹰王晓丹 编 委 ( 以姓氏笔画为序 ) 马 伟 安志远 向 伟 刘 兵 吴卫祖 吴宏雷 余明辉 张晓蕾 张基宏 贺 平 柳 青 赵英杰 施晓秋 姜 锐 耿 壮 郭 勇 曹 炜 蒋方纯 潘春燕

3 丛书出版前言 目前, 人才问题是制约我国软件产业发展的关键 为加大软件人才培养力度和提高软件人才培养质量, 教育部继在 2003 年确定北京信息职业技术学院等 35 所高职院校试办示范性软件职业技术学院后, 又同时根据 教育部等六部门关于实施职业院校制造业和现代服务业技能型紧缺人才培养培训工程的通知 ( 教职成 [2003]5 号 ) 的要求, 组织制定了 两年制高等职业教育计算机应用与软件技术专业领域技能型紧缺人才培养指导方案 示范性软件职业技术学院与计算机应用与软件技术专业领域技能型紧缺人才培养工作, 均要求在较短的时间内培养出符合企业需要 具有核心技能的软件技术人才, 因此, 对目前高等职业教育的办学模式和人才培养方案等做较大的改进和全新的探索已经成为学校的当务之急 据此, 我们认为做一套符合上述一系列要求的切合学校实际的教学方案尤为重要 遵照教育部提出的以就业为导向, 高等职业教育从专业本位向职业岗位和就业为本转变的指导思想, 根据目前高等职业教育院校日益重视学生将来的就业岗位, 注重培养毕业生的职业能力的现状, 我们联合北京信息职业技术学院等几十所高职院校和普拉内特计算机技术 ( 北京 ) 有限公司 福建星网锐捷网络有限公司 北京索浪计算机有限公司等软件企业共同组建了计算机应用与软件技术专业领域技能型紧缺人才培养教学方案研究小组 ( 以下简称研究小组 ) 研究小组对承担计算机应用与软件技术专业领域技能型紧缺人才培养培训工作的 79 所院校的专业设置情况做了细致的调研, 并调查了几十所高职院校计算机相关专业的学生就业情况以及目前软件企业的人才市场需求状况, 确定首批开发目前在高职院校开设比较普遍的计算机软件技术 计算机网络技术 计算机多媒体技术和计算机应用技术等 4 个专业方向的教学方案 同时, 为贯彻教育部提出的要与软件企业合作开展计算机应用与软件技术专业领域技能型紧缺人才培养培训工作的精神, 使高等职业教育培养出的软件技术人才符合企业的需求, 研究小组与许多软件企业的专家们进行了反复研讨, 了解到目前高职院校的毕业生的实际动手能力和综合应用知识方面较弱, 他们和企业需求的软件人才有着较大的差距, 到企业后不能很快独当一面, 企业需要投入一定的成本和时间进行项目培训 针对这种情况, 研究小组在教学方案中增加了 综合项目实训 模块, 以求强化学生的实际动手能力和综合应用前期所学知识的能力, 探索将企业的岗前培训内容前移到学校的教学中的实验之路, 以此增强毕业生的就业竞争力 在上述工作的基础上, 研究小组于 2004 年多次组织召开了包括企业专家 教育专家 学校任课教师在内的各种研讨会和方案论证会, 对各个专业按照 岗位群 核心技能 知识点 课程设置 各课程应掌握的技能 各教材的内容 一步步进行了认真的分析和研讨 : 列出各专业的岗位群及核心技能 针对教育部提出的以就业为导向, 根据目前高职高专院校日益关心学生将来的就业岗位的现状, 在前期大量调研的基础上, 首先提炼各个专业的岗位群 如对某专业的岗位群进行研究时, 首先罗列此专业的各个岗位, 以便能正确了解

4 每个岗位的职业能力, 再根据职业能力进行有意义的合并, 形成各个专业的岗位群, 再对每个岗位群总结和归纳出其核心技能 根据岗位群及核心技能做出教学方案 在岗位群及核心技能明确的前提下, 列出此岗位应该掌握的知识点, 再依据这些知识点推出应该学习的课程 学时数 课程之间的联系 开课顺序并进行必要的整合, 最终形成一套科学完整的教学方案 为配合学校对技能型紧缺人才的培养工作, 在研究小组开发上述 4 个专业的教学方案的基础上, 我们组织编写了这套包含计算机软件技术 计算机网络技术 计算机多媒体技术及计算机应用技术等 4 个专业的教材 本套教材具有以下特点 : 注重专业整体策划的内涵 对各专业系列教材按照 岗位群 核心技能 知识点 课程设置 各课程应掌握的技能 各教材的内容 的思路组织开发教材 按照 理论够用为度 的原则, 对各个专业的基础课进行了按需重新整合 各专业教材突出了实训的比例, 注重案例教学 每本教材都配备了实验 实训的内容, 部分专业的教材配备了综合项目实训, 使学生通过模拟具体的软件开发项目了解软件企业的运行环境, 体验软件的规范化 标准化 专业化和规模化的开发流程 为了方便教学, 我们免费为选用本套教材的老师提供部分专业的整体教学方案及教学相关资料 所有教材的电子教案 部分教材的习题答案 部分教材中实例制作过程中用到的素材 部分教材中实例的制作效果以及一些源程序代码 本套教材以各个专业的岗位群为出发点, 注重专业整体策划, 试图通过对系列教材的整体构架, 探索一条培养技能型紧缺人才的有效途径 经过近两年的艰苦探索和工作, 本套教材终于正式出版了, 我们衷心希望, 各位关心高等职业教育的读者能够对本套教材的不当之处给予批评指正, 提出修改意见, 也热切盼望从事高等职业教育的教师以及软件企业的技术专家和我们联系, 共同探讨计算机应用与软件技术专业的教学方案和教材编写等相关问题 来信请发至 panchunyan@ptpress.com.cn

5 编者的话 目前, Windows 应用程序开发工具种类很多, 而 Delphi 的开发环境是目前面向对象和控件开发性能最好的工具之一 它使用 Microsoft Windows 图形用户界面的许多先进特性和设计思想, 采用了可重复利用 完整的 面向对象的程序语言, 拥有当今世界上最快 最好的编译器, 功能强大 对于广大的程序开发人员来讲, 使用 Delphi 开发应用软件, 无疑会大大提高编程效率 本书对利用 Delphi 进行编程提供了一个基础的指导和参考 读者阅读本书不需要预先具有任何编程经验, 但如果对 Pascal C C++ 或者 Visual Basic 等有所了解, 那么将会对本书的学习非常有益 本书将 Delphi 技术从入门到提高逐步地进行讲解, 同时对 Delphi 的 Object Pascal 语言和可视化组件进行了说明, 读者将学会如何为各种应用程序创建切实可行又简洁漂亮的用户界面 边学边做 是学习一种编程工具的最有效方法, 希望读者在阅读本书的过程中能够上机实践 每学完一个例子, 尝试着改变或者添加一点东西, 并改变一些代码, 这样将能帮助读者尽快地掌握 Delphi 的编程方法, 并同时体验进步和成功的乐趣 凡章节 习题和实训中加 * 号的部分, 难度较高, 为选学内容 本书由上海第二工业大学张世明主编, 在编写过程中得到了陶霖教授的指点和帮助 由于编写时间仓促, 本书错误与不妥之处在所难免, 恳请读者批评指正 作者电子邮件地址为 :delphiline@sina.com 或 delphiline@sohu.com 编 者 2005 年 2 月

6 目 录 第 1 章 Delphi 集成开发环境 Delphi 主窗口 标题栏 菜单栏 工具栏 组件板 Delphi 窗体窗口 窗体窗口 窗体文件 代码编辑器窗口 代码编辑器窗口组成 删除字符 单词和行 复制 移动和删除块 查找和替换字符串 对象查看器窗口 对象查看器窗口组成 设置属性 添加事件 项目管理器 项目组成 项目管理器窗口 项目管理 项目编译和运行 Delphi 程序设计过程 习题...21 第 2 章 Delphi 的编程语言 保留字和标识符 保留字和标准指令符 标识符 注释 控制台程序中的屏幕输入和输出 数据类型... 25

7 2 Delphi 程序设计基础 简单数据类型 字符串类型 结构类型 指针类型 过程与函数类型 可变类型 常量和变量的定义 常量 变量 类型常量 运算符和表达式 运算符 表达式 语句 简单语句 结构语句 条件语句 循环语句 转向语句 过程与函数 标准过程与函数 用户自定义过程和函数的定义...48 习题...55 第 3 章窗体设计 Delphi 窗体 窗体与窗口 窗体属性 窗体事件 设计窗体 新建窗体 设置窗体属性 添加组件 编辑组件 设置组件属性 Tab 顺序 创建顺序 窗体网格 保存文件... 65

8 目录 窗体模板 运行时改变窗体 运行时设置属性 运行时创建组件 MDI 程序 MDI 窗体 创建子窗体 MDI 的属性和方法 MDI 的菜单设计 习题...77 第 4 章 Delphi 的基本组件 文本型组件 Label 组件 StaticText 组件 按钮型组件 Button 组件 BitBtn 组件 RadioButton 组件 CheckBox 组件 按钮型组件实例 编辑型组件 Edit 组件 MaskEdit 组件 SpinEdit 组件 UpDown 组件 Memo 组件 RichEdit 组件 编辑型组件实例 列表框型组件 ListBox 组件 CheckListBox 组件 ComboBox 组件 列表框型组件实例 滑块型组件 ScrollBar 组件 TrackBar 组件 滑块型组件实例 容器型组件

9 4 Delphi 程序设计基础 GroupBox 组件 Panel 组件 ScrollBox 组件 习题 第 5 章菜单设计 菜单设计简介 菜单结构 菜单命令项的作用 菜单设计器 主菜单设计 打开主菜单设计器 菜单命令项的添加 菜单命令项的分组 菜单命令项的热键 菜单命令项的调整 创建级联菜单 菜单命令响应 运行时设置菜单 菜单命令项灰显 菜单命令项隐藏 改变菜单命令项文本 菜单命令项单选标记 菜单命令项复选标记 创建动态菜单 图形菜单 菜单命令项图标 图形菜单命令项 * 菜单模板 插入菜单模板 创建菜单模板 删除菜单模板 快捷菜单设计 快捷菜单的设计 快捷菜单的响应 控制菜单设计 * 控制菜单设计 控制菜单响应 习题...129

10 目录 5 第 6 章对话框设计 公共对话框 打开 对话框组件 保存 对话框组件 字体 对话框组件 颜色 对话框组件 打印 对话框组件 打印设置 和 页面设置 对话框 查找 对话框组件 替换 对话框组件 标准对话框 消息框 输入框 习题 第 7 章工具栏和状态栏设计 快捷按钮 工具栏设计 用面板构成工具栏 使用工具栏组件 使用 CoolBar 组件 使用控件栏组件 状态栏设计 状态栏的基本属性 显示状态及提示信息 习题 第 8 章数据库编程 数据库系统概述 数据库管理系统 (DBMS) 关系数据库 (Relational Database) 数据库应用程序 Delphi 数据库的体系结构 BDE 组件 TTable 组件介绍 TQuery 组件介绍 ADO 组件 TADOConnection 组件...189

11 6 Delphi 程序设计基础 TADOCommand 组件 TADODataSet 组件 TADOTable 组件 数据控制组件简介 TDBGrid 组件 TDBNavigator 组件 TDBText 组件 TDBEdit 组件 TDBMemo 组件 TDBImage 组件 TDBListBox 组件 TDBComboBox 组件 TDBCheckBox 组件 TDBRadioGroup 组件 TDBLookupListBox 组件 TDBLookupComboBox 组件 TDBCtrlGrid 组件 TDBRichEdit 组件 TDBChart 组件 习题 第 9 章报表与图表 QuickReport 组件 QuickReport 概述 TQuickRep 组件 TQRSubDetail 组件 TQRBand 组件 TQRChildBand 组件 TQRGroup 组件 TQRLabel 组件 TQRDBText 组件 TQRExpr 组件 TQRsysData 组件 TQRMemo 组件 TQRRichText 组件 TQRDBRichText 组件 TQRShape 组件 TQRImage 组件 TQRDBImage 组件...221

12 目录 TQRComposite 组件 TQRPreview 组件 QuickReport 报表实例 图表 DBChart 组件 图表应用实例 习题 第 10 章实训 实训 1 Delphi 集成开发环境操作 Delphi 集成开发环境操作 实训报告 实训 2 Delphi 编程语言训练 编写对象 Pascal 应用程序 函数和过程的编写和调用 函数和过程的编写和调用, 尝试窗体编程方法 实训报告 实训 3 Delphi 窗体设计 建立窗体, 在窗体中添加和设置组件 建立 MDI 窗体, 并对子窗体进行管理 实训报告 实训 4 Delphi 组件应用 设计由按钮类组件实现的功能窗体 设计由列表类组件实现的功能窗体 按需求将各种组件灵活组合, 实现功能窗体 实训报告 实训 5 Delphi 菜单设计 设计窗体菜单 (1) 设计窗体菜单 (2) 实训报告 实训 6 对话框设计 对话框的设计和使用 实训报告 实训 7 工具栏 状态栏设计 建立窗体工具栏 状态栏 实训报告 实训 8 数据库编程 设计数据表结构 设计数据表编辑窗体

13 8 Delphi 程序设计基础 设计数据表查询窗体 实训报告 实训 9 报表设计 熟悉 Delphi 报表设计 实训报告

14 第 1 章 Delphi 集成开发环境 Delphi 是 Borland 公司推出的基于 Object Pascal 语言的可视化集成开发环境 利用 Delphi 编程, 可以快速 高效地开发出基于 Windows 环境的各类程序, 尤其在数据库 网络和系统工具等方面,Delphi 更是一个十分理想的开发平台 本书使用的 Delphi 版本是 Delphi 7 本章主要介绍 Delphi 集成开发环境的一些基础知识和开发 Delphi 程序的一般过程, 包括 : Delphi 主窗口 Delphi 窗体窗口 代码编辑器窗口 对象查看器 项目管理器 Delphi 程序设计过程 Delphi 是一个集成开发环境, 从程序设计 代码编辑 程序调试, 到最后形成发布程序的全部工作都可以在这个集成环境中完成 为了帮助用户迅速高效地开发应用程序,Delphi 提供了许多功能强大的开发工具和丰富的菜单命令 本章将对 Delphi 集成环境中的各个组成部分作一个概要的描述 Delphi 集成开发环境界面分为 4 个部分, 分别是主窗口 窗体窗口 代码编辑器窗口和对象查看器窗口, 如图 1-1 所示 主窗口 窗体窗口 对象查看器窗口 代码编辑器窗口 图 1-1 Delphi 集成开发环境界面

15 2 Delphi 程序设计基础 1.1 Delphi 主窗口 Delphi 主窗口如图 1-2 所示, 由标题栏 菜单栏 工具栏和组件板组成, 它是打开其他窗口和退出 Delphi 集成环境的管理者 图 1-2 Delphi 主窗口 标题栏主窗口顶部的水平长条称为标题栏 标题栏提供了 Delphi 7 和项目文件名两部分信息 如果载入的是一个新建的项目,Delphi 会提供缺省项目名 Project1, 标题栏就会显示 Delphi 7 - Project1 当 Delphi 环境处于不同的状态时, 标题栏还会显示相应信息 标题栏右边有 3 个按钮, 用于控制窗口的最小化 最大化和关闭 而单击最左侧的小图标, 可弹出窗口控制菜单, 用鼠标单击就可完成某些操作 菜单栏标题栏的下面是菜单栏, 它集合了 Delphi 的各项命令和工具, 包括 File( 文件 ) Edit ( 编辑 ) Search( 搜索 ) View( 视图 ) Project( 项目 ) Run( 运行 ) Component( 组件 ) Database( 数据库 ) Tools( 工具 ) Window( 窗口 ) 和 Help( 帮助 ) 等 11 项菜单 表 1-1 列出了 Delphi 各项菜单的功能 表 1-1 Delphi 各菜单功能 菜 单 功 能 File 含有新建 打开和保存 Delphi 应用程序中各个项目和文件的命令 Edit 提供了编辑代码和窗体组件的各种命令, 如删除 复制和粘贴等 Search 搜索 替换和定位字符串命令 View 打开 Delphi 环境各个窗口与项目中的窗体和单元文件等 Project 管理 编译和配置项目文件 Run 调试应用程序, 如设置断点 单步执行等 Component 用于建立和安装组件以及定制自己的组件板 Database 开发数据库应用程序的各种工具 Tools Delphi 环境设置和一些 Delphi 外挂工具 Window 切换指定窗口为活动窗口 Help Delphi 帮助文件 工具栏 工具栏把一些常用的菜单命令以图标按钮的方式显示出来, 以便于快速访问 Delphi 提

16 第 1 章 Delphi 集成开发环境 3 供了六个工具栏共二十余个图标按钮, 只要把鼠标在按钮上停留一会儿, 就会弹出关于此按钮功能的提示 组件板工具栏的右侧为组件板 组件板是 Delphi 的核心, 因为 Delphi 主要特点就是使用组件进行程序设计, 所以必须掌握各种组件的功能和使用方法 组件板包括许多选项卡, 单击某选项卡就可以看到该选项卡包含的组件, 图 1-2 中显示了 Standard 选项卡包含的组件 Delphi 7 共预定义了三十多个组件板选项卡, 一般情况下无法全部显示出来 可以单击组件板右边的箭头按钮来左右移动组件板的选项卡标签 组件板用来选取要添加到窗体上的各种组件, 每个选项卡上有一排相关组件的图标, 选取要用的图标后, 在窗体的某位置上单击, 就可以把它放置到窗体上 表 1-2 列出了常用组件板选项卡的说明 表 1-2 组件板选项卡 名称说明 Standard Additiona1 Win32 System Data Access Data Controls ADO InterBase Midas Internet Express Internet FastNet Decision Cube Qreport Dialogs Win3.1 Samples ActiveX Servers 标准的 Windows 控件和菜单自定义的控件 32 位 Windows 的常用组件进行系统级访问控制的组件和控件, 包括定时器 DDE 等非可视化的组件, 用来访问数据库 数据库表 查询和报表可视化的数据访问控件使用 ADO 对象链接数据库的组件链接 InterBase 数据库的控件, 不需要 BDE 和 ADO 用于多层分布式应用服务的各种控件用来建立 Web 服务器 / 多级数据库应用的客户机程序的组件用来建立 Web 服务器应用程序的对象为应用程序提供一系列 Internet 访问协议总结数据库中信息的控件, 用来分析数据库中的数据用于创建内嵌报表的快速报表的组件 Windows 的常用对话框与 Delphi 1.0 项目兼容的组件自制的组件例子, 包括进度指示器 颜色网格等 ActiveX 控件的例子封装 COM 服务器 1.2 Delphi 窗体窗口 窗体窗口也称表单窗口 窗体窗口是用于设计应用程序的界面, 在大多数情况下, 窗体 是用户的主要操作对象

17 4 Delphi 程序设计基础 窗体窗口窗体窗口的顶端水平条是窗体的标题栏, 结构与主窗口的标题栏相似, 由图标 窗体名称和用于控制窗体的最小化 最大化 关闭的按钮组成 窗体窗口的标题栏显示了窗体的当前标题 一般新窗体会用缺省名字 Form1 命名 当然, 用户可以通过对象查看器设置窗体的标题等属性 窗体是窗口的设计界面, 用户可以往窗体中添加各种组件, 然后再对组件的属性进行设置 这样可使整个应用程序的编辑过程可视化 易掌握 窗体文件每一个窗体都有相应的窗体文件 (.DRM), 它保存着窗体和窗体内各个组件的属性, 而且每个窗体都有一个单元文件, 用于编写窗体事件处理过程 窗体文件和单元文件被 Delphi 自动保存在同一个目录下 用鼠标右键单击窗体网格工作区, 会打开一个快捷菜单 该菜单包含了设计窗体时所需的各种常用命令 选择 View as Text 命令即可看到以.DFM 为扩展名的窗体文件 窗体文件列出了窗体的类名 (TForm1) 以及窗体各属性的值, 同时还列出了窗体中包括的组件以及组件的属性值 用户每修改一次窗体, 窗体文件都会有所反应 当然, 也可直接通过修改窗体文件来设置属性, 只不过因太复杂, 很少采用罢了 在窗体文件空白处单击鼠标右键, 将打开一个快捷菜单, 从中选择 View as Form 命令即可恢复窗体的图形化显示 1.3 代码编辑器窗口 窗体设计完成后, 就要开始编辑代码来响应窗体及其组件的事件了 代码编辑通常在代码编辑器窗口进行 下面介绍代码编辑器窗口以及如何进行代码编辑 代码编辑器窗口组成代码编辑器窗口的标题栏显示当前单元文件的文件名, 缺省名为 Unit1.pas 代码编辑器窗口分为左右两部分, 左边是单元浏览器窗口, 右边是单元代码窗口 单元浏览器窗口以树形列出了单元的构成, 主要包括以下 3 项内容 单元使用的类 ( 如 TForm1), 树形分叉中是类的数据成员和过程成员 ; 单元使用的变量和常量 (Variables/Constants), 树形分叉中是单元中使用的变量和常量 ; 单元链接的单元 (Uses), 树形分叉下是链接的单元名称 单元代码窗口是进行代码编辑的窗口 由于一个应用程序可以有多个单元文件, 所以单元代码窗口可以有多个选项卡, 每个选项卡标明一个被打开的单元文件名 代码编辑器窗口除了显示单元文件 (.pas) 外, 也可以显示当前项目的项目文件 (.DPR) 在启动 Delphi 后, 代码编辑器窗口通常被窗体窗口覆盖, 可以单击 View 菜单中的 Toggle Form/Unit 命令, 或单击工具栏上的 Toggle Form/Unit 按钮, 以切换代码编辑

18 第 1 章 Delphi 集成开发环境 5 器窗口和窗体窗口 删除字符 单词和行删除操作又可分为删除字符 删除单词和删除行, 下面分别加以介绍 1. 删除字符删除字符主要用如下方法 用 Backspace 键删除光标左边的一个字符 用 Del 键删除光标右边的一个字符 2. 删除单词按组合键 Ctrl+T 可删除光标右边的一个单词 3. 删除行用组合键 Ctrl+Y 可删除光标所在的行 复制 移动和删除块用户可将一段代码定义成块, 然后对块进行复制 移动和删除操作, 这样可提高效率, 达到事半功倍的效果 1. 定义块定义一个块有两种方式 : 用键盘和用鼠标 如果要用键盘定义一个块, 首先将光标移到所要定义的块首, 按住 Shift 键, 用箭头键将光标移到要定义块的块尾 然后松开 Shift 键即可 而用鼠标定义一个块, 将鼠标移到想要定义块的块首, 按住鼠标左键不放, 拖动鼠标到要定义块的块尾, 松开鼠标左键即可 2. 复制块定义了一个块后, 用 Edit 菜单下的 Copy 命令将块复制到剪贴板上, 然后用 Edit 菜单下的 Paste 命令复制到光标所在的位置 3. 移动块在定义一个块后, 单击块并按住鼠标左键不放, 可将块拖放到所需要的任意位置 4. 删除块在块定义好以后, 可用两种方法将块删除 第一种方法是使用 Edit 菜单下的 Cut 命令, 将块剪切到剪贴板上, 用户可用 Edit 菜单下的 Paste 命令将它复制到光标所在的位置 第二种方法是用 Delete 命令或 Delete 键, 这会将块直接删除, 而不会将块剪切到剪贴板上 查找和替换字符串为了方便用户查找和替换字符串,Delphi 专门提供了一个 Search 菜单 下面具体介绍如何查找和替换字符串 1. 查找字符串要查找一个特定的字符串, 可单击 Search 菜单下的 Find 命令, 打开 Find Text 对话框, 如图 1-3(a) 所示

19 6 Delphi 程序设计基础该对话框有 Find 和 Find in Files 两个选项卡, 缺省为 Find 选项卡 在该选项卡的 Text to find 编辑框内输入所要查找的字符串 在 Find Text 对话框中有若干选项可以确定字符串的查找方式, 其含义见表 1-3 表 1-3 字符串的查找方式 Options tions 选项组 选项含义 Case sensitive 复选框 Whole words only 复选框 对字符串的大小写作严格检查 查找独立的单词, 而不是查找一个单词的部分 当查找到某个匹配的字符串后, 光标将停留在该处, 并将被找到的字符串高亮显示 如 果用户还要查找下一个匹配字符串, 可使用 Search 菜单下的 Search Again 命令继续进 行查找 Regular expressions 复选框将查找文本当作正规表达式处理 在正规表达式中可以包含一些通配符, 如以 * 表示任意的字符串,? 表示任意一个字符, \ 表示将其后面的字符作为一般字符处理, \* 表示在字符串内的 * 不是通配符, 只是一般字符 Sc Scop ope 选项组 Global 单选按钮 Selected text 单选按钮 Dir irection ection 选项组 Forward 单选按钮 Backward 单选按钮 Ori Origin in 选项组 对整个文件进行查找 只在被选中的文本中查找字符 在进行该项查找时, 应先定义一个块 从当前光标处向后进行查找直到文件末或块尾 从当前光标处向前进行查找直到文件头或块首 From cursor 单选按钮从当前光标处向前或向后查找 ( 方向由 Direction 选项组确定 ) Entire scope 单选按钮 从头至尾对整个文件或块进行查找 除了在当前文件中查找指定字符串外, Find Text 对话框还提供一个 Find in Files 选 项卡, 用于在同一项目下的多个文件中查找指定字符串, 如图 1-3(b) 所示 (a) 图 1-3 Find Text 对话框 (b) 在选项卡的 Text to find 编辑框中输入要查找的字符串, 设置各查找选项后, 单击 0K

20 第 1 章 Delphi 集成开发环境 7 按钮进行查找 选项卡上 Options 选项组各选项的含义同 Find 选项卡相同, 其他选项 的含义见表 1-4 表 1-4 在文件中查找字符串的方式 选 项 含 义 Wh Where ere 选项组 Search all files in project 单选按钮 在当前项目的所有文件中进行查找 Search all open files 单选按钮 在当前所打开的所有文件中进行查找 Search in directories 单选按钮 用户自己设置查找路径 查找路径在下一个选项组中设置 Se Search Directory Options tions 选项组 Browse 按钮 设置查找路径 Include subdirectories 复选框 对所设路径下的子目录也进行查找 2. 替换字符串替换字符串和查找字符串操作相似, 单击 Search 菜单中的 Replace 命令, 打开 Replace Text 对话框, 如图 1-4 所示 在 Replace with 编辑框中输入用来替换被查找到的字符串 但在单击 OK 按钮前, 请注意如下两点 Prompt on replace 复选框 : 选中该复选框时, 在替换字符串之前会给出一个提示, 让用户确定是否替换被选中的字符串 Replace All 按钮 : 连续替换所遇到的每一 图 1-4 Replace Text 对话框 个匹配的字符串 如果选择了 Prompt on replace 复选框, 则每次都会给出一个提示 3. 渐近查找 Delphi 还提供了一种特殊的查找方式, 称为渐近查找 要使用渐近查找, 可单击 Search 菜单下的 Incremental Search 命令, 这时在状态栏上会出现 Searching for: 字样, 提示用户输入要查找的字符串 每当用户输入一个字符, 代码编辑器都将光标停留在自当前光标起所遇到的第一个匹配的字符串上, 并将它高亮显示 用户可以不断地输入其他字符, 代码编辑器会随着输入字符的增多自动搜寻最匹配的字符串, 直到找到用户所需要的字符串为止 4. 查找特定行用 Search 菜单下的 Go to Line Number 命令可根据用户所输入的行号查找该行 在未输入行号前, 代码编辑器会自动把当前光标所在行的行号放入对话框中的 Enter new line number 编辑框, 待输入一个新行号后, 单击 OK 按钮, 光标将被置在新行号所指定的新行的源代码行首 1.4 对象查看器窗口 窗体窗口的左侧为对象查看器窗口, 它的功能是设置窗体 组件的属性, 并为窗体 组

21 8 Delphi 程序设计基础 件添加事件的响应处理过程, 如图 1-5 所示 标题栏 对象选择列表框 属性选项卡 事件选项卡 图 1-5 对象查看器窗口 对象查看器窗口组成对象查看器窗口由标题栏 对象选择列表框 属性选项卡和事件选项卡组成 标题栏 : 显示 Object Inspector 字样 对象选择列表框 : 为一下拉列表框, 列表框中是可供选择的窗体以及当前窗体上放置的所有组件 用户可从中选择要设置属性或要添加事件的窗体或组件 属性选项卡 : 标签名为 Properties 的选项卡 用于设置当前组件的属性, 随对象选择列表框中的所选组件而发生变化 属性选项卡是一个两列的表格, 左列是属性标题, 右列是属性值 只有选择了属性标题, 才可以设置属性值 事件选项卡 : 标签名为 Events 的选项卡 用于为当前组件添加各种响应事件 ( 如单击 拖曳等 ), 也随着对象选择器窗口中的所选组件而发生变化 事件选项卡同样为一个两列的表格, 左列是事件名称, 右列是事件处理过程, 缺省时事件的处理过程为空, 在空格处双击则可以为当前组件添加事件, 并进入代码编辑器窗口 设置属性从窗体上选择组件, 或从对象选择列表框中选择窗体或组件, 使之成为当前组件, 就可以用对象查看器的属性选项卡来设置其属性了 根据属性标题的情况, 设置属性可分为 4 种情况 第 1 种情况是用鼠标单击属性标题后, 直接在属性值编辑框中输入属性的数值或字符串, 如 Name Caption Left Top 等属性, 如图 1-6(a) 所示 注意 : 如果输入的属性值不符合要求, 例如, 在应输入数值的属性中输入了字符串,Delphi 将给出报错信息 第 2 种情况是属性值由 Delphi 提供可选项 这时, 用鼠标单击属性标题后, 属性值马上变成一个下拉列表框, 用户可从中选择所需要的属性值 可选项分两种, 一种是文字可选项, 如 Border Style Enabled 等属性 ; 另一种是图形加文字形式的可选项, 如 Color Cursor 等属性 图 1-6(b) 和图 1-6(c) 显示了这两种可选项的属性值形式

22 第 1 章 Delphi 集成开发环境 9 (a) (b) (c) (d) 图 1-6 对象查看器属性选项卡 第 3 种情况是通过对话框来设置属性值 对于 Font Color 等属性, 单击属性标题后, 属性值右端会出现一个带 的按钮, 单击该按钮, 即可打开一个相应的对话框, 在对话框中选择所需值, 即可设置属性值, 如图 1-6(d) 所示 第 4 种情况是属性带有子属性 在这种属性的属性标题前, 一般会有一个 + 号, 单击该 + 号, 将展开子属性, 同时 + 号变成 号 此时即可依次对各子属性进行设置, 如图 1-6(d) 所示 添加事件从窗体上选择一个组件, 或从对象选择器中选择一个窗体或组件, 使之成为当前组件, 就可以用对象查看器的事件选项卡来添加事件了 添加事件一般是选定组件后, 单击对象查看器的事件选项卡中要添加的事件名称, 再在其右侧输入事件的响应函数名称, 然后按 Enter 键即可 提示 : 如果单击要添加的事件后, 在其右侧编辑框中双击鼠标, 将为事件采用缺省事件处理过程名, 同时进入代码编辑窗口 缺省事件处理过程名是组件名和事件名去除 On 后合并而成的字符串, 如 Button1 组件的 OnClick 事件的缺省事件处理过程名是 Button1Click 1.5 项目管理器 Delphi 用项目 (Project) 来管理用户开发的应用程序中的各个文件, 有序的管理可以极大地提高应用程序开发的质量和速度 大多数情况下, 一个应用程序由一个项目构成, 也可以是包括多个项目的项目组, 甚至可以由多个项目组构成 例如, 创建一个有两个项目的应用程序, 其中一个用来创建应用程序所需的动态链接库, 而另一个则用来产生应用程序的可执行文件 项目组成 Delphi 为每个项目建立了相当数目的文件 这些文件中, 一部分是在设计阶段产生的,

23 10 Delphi 程序设计基础如项目文件 (.DPR) 单元文件 (.PAS) 和窗体文件 (.DFM) 等 还有一些则是在编译阶段产生的, 如对象映射文件 (.DSM) 编译单元文件 (.DCU) 等 当然, 项目中还包括一些非 Delphi 生成的文件, 如位图 图标 鼠标指针等资源文件 这些文件, 一部分要由用户保存时命名 相当一部分文件由 Delphi 自动产生, 这些文件的命名主要取决于用户为项目和窗体所取的名称, 以及 Delphi 和系统欲定义的文件扩展名 这些文件构成了一个完整项目, 但经常打交道的文件并不多, 主要是项目文件 (.DPR) 单元文件 (.PAS) 窗体文件 (.DFM) 以及一些资源文件 前面已经介绍了窗体文件, 这里着重介绍一下单元文件和项目文件 1. 单元文件单元文件是组成应用源代码的主要部分, 无论是窗体事件处理过程还是单独的源代码都保存在单元文件中 单元文件可以分为 : 有窗体文件和无窗体文件两种 每当用户在项目中新建一个窗体, 例如使用 File 菜单的 New Form 命令新建窗体, 都会自动产生一个单元文件 如果用户需要产生一个无窗体文件, 可以使用 File 菜单中的 New Unit 命令 下面给出一个典型的有窗体的单元文件的结构 unit Unit1; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TForm1 = class(tform) Button1: TButton; procedure Button1Click(Sender: TObject); private { Private declarations } public { Public declarations } var Form1: TForm1; implementation {$R *.DFM}

24 procedure TForm1.Button1Click(Sender: TObject); 第 1 章 Delphi 集成开发环境 11 end. 代码首句指出了单元名, 单元名必须与单元文件名保持一致 如果保存时文件名变为 Myunit.PAS, 则首句相应变为 : unit Myunit 代码的 uses 语句指出了单元文件在编译时要链接哪些单元, 如 Windows Messages SysUtils Classes Graphics Controls Forms Dialogs StdCtrls 等, 因为这些单元中包含了编程中所调用的一些函数 对象等 type 语句为窗体的类声明 类声明中包括了窗体中的组件和事件响应过程名 如语句 : Button1: TButton; 指出了组件类型 (Tbutton) 和组件的 Name 属性 (Button1), 除处理 Name 属性外, 设置其他属性不会影响单元文件源代码 添加新的事件处理过程对单元文件的影响最大, 每为一个事件定义一个处理过程, 窗体的类型定义下就会多出一行, 执行部分中就会加入一个空白处理过程, 窗体文件中也会相应存入一些信息 例如, 上面 type 语句下定义了一处理过程 : procedure TForm1.Button1Click(Sender: TObject); 而在实现部分 (implementation) 中, 出现了一空白处理过程 : procedure TForm1.Button1Click(Sender: TObject); 用户可在 和 end 之间添加自己的事件处理代码 2. 项目文件项目文件对应用至关重要, 由 Delphi 自动建立, 一般用户不需要改变它 项目文件是真正意义上的 Pascal 源代码文件, 它描述了整个应用程序的结构及启动代码 : program Project1; uses Forms, Unit1 in 'Unit1.pas' {Form1}; {$R *.RES}

25 12 Delphi 程序设计基础 Application.Initialize; Application.CreateForm(TForm1, Form1); Application.Run; end. 用户可以通过 Project 菜单的 View Source 命令来查看该文件 代码首行给出了项目名称 : program Project1; uses 语句中列出了组成项目的单元文件, 其中有些单元文件还有相应的窗体文件 编译项目时,Delphi 将首先编译各个单元文件及其相应的窗体文件, 然后再将其链接成可执行文件 例如 : Unit1 in 'Unit1.pas' {Form1}; 语句说明项目包含了单元文件 Unit1.pas, 而后面的括号对 {Form1} 则说明单元文件有相应的窗体文件 Form1.DFM 接下来是编译指令 {$R *.RES}, 表示把项目中所有资源文件全包括进来 和 end 之间的代码段所起的作用是初始化应用程序 创建表单和启动应用程序 项目管理器窗口使用项目管理器窗口可以了解项目的构成, 以及方便地对项目进行管理 选择 View 菜单的 Project Manager 命令, 可以打开项目管理器窗口 Project Manager 窗口, 如图 1-7 所示, 它用来管理当前项目中的组成文件 在项目管理器中列出了当前项目中的各个单元文件和窗体文件, 用户可以对它们进行操作 图 1-7 项目管理器窗口 项目管理器窗口由标题栏 工具栏 项目显示窗口和状态栏 4 部分组成 1. 标题栏标题栏列出了项目管理器的英文名称 Project Manager 2. 工具栏工具栏中包含一个 Project Selector 下拉列表框 ( 从项目中选择需管理的项目 ), 以及 3 个快捷按钮 : New 按钮 ( 往项目组中新增项目 ) Remove 按钮 ( 从项目组中删除选定项目 ) 和 Activate 按钮 ( 激活项目 ) 3. 项目显示窗口

26 第 1 章 Delphi 集成开发环境 13 项目管理器根据项目文件中的内容, 在下面显示窗口中列出了组成项目的所有窗体文件和单元文件 ( Files 列 ) 以及它们的路径 ( Path 列 ) 注意 : 项目管理器只列出 Delphi 自己添加的文件, 用户手动添加的文件在项目管理器中得不到反映 4. 状态栏状态栏一般缺省为不可见 如果要显示状态栏, 可以在窗口中单击右键, 打开一快捷菜单, 从中选取 Status Bar 命令 状态栏显示的是项目显示窗口中当前文件的完整路径 下面介绍如何用项目管理器来进行项目管理 项目管理器的作用主要是用来往应用程序中新增项目或项目组, 和从应用程序中删除项目或项目组 另外, 利用项目管理器还可以激活项目组中的某个项目为当前项目 如果要往应用程序中新增项目或项目组, 执行如下操作 (1) 单击工具栏上的 New 按钮, 打开 New Items 对话框, 并选择 New 选项卡, 如图 1-8 所示 图 1-8 New Items 对话框 (2) 执行如下操作之一 : 1 如果要新增项目, 单击 Application 图标 ; 2 如果要新增项目组, 单击 Project Group 图标 (3) 单击 OK 按钮 如果要从应用程序中删除项目或项目组, 在项目管理器中选定要删除的项目或项目组, 然后单击工具栏上的 Remove 按钮即可 对于有多个项目或项目组的应用程序而言, 经常需要使用激活功能 例如, 应用程序包括 Project1 Project2 两个项目 如果当前项目为 Project2, 而想编辑 Project1, 此时就得激活 Project1 方法是选定 Project1 后单击 [Activate] 按钮 项目管理前面介绍了如何利用项目管理器新增或删除项目及项目组以及激活项目, 下面介绍如何往某个项目中增加 删除文件, 以及如何保存项目中的文件 1. 给项目添加文件给项目添加文件可分为两种情况 : 第一种情况是往项目中添加新的窗体或单元文件, 第二种情况是往项目中添加已经存在的文件 对于第一种情况, 往项目中添加的新窗体或新单

27 14 Delphi 程序设计基础元文件, 可以单击 File 菜单中的 New 级联菜单下的 Form 命令或 Unit 命令 直接单击工具栏中 New Form 按钮, 可往项目中添加一个新窗体 往项目中新添窗体或单元文件后,Delphi 会自动修改项目文件中的 uses 语句, 将新添加的窗体或单元文件加进来 对于第二种情况, 往项目中添加已经存在的文件, 可以执行如下操作 (1) 单击 Project 菜单中的 Add to Project 命令, 或单击工具栏上 Add File to Project 按钮, 打开 Add to Project 对话框, 如图 1-9 所示 图 1-9 Add to Project 对话框 (2) 选择所需的文件, 例如, 选择单元文件 Unit5_1.pas (3) 单击 打开 按钮 这样, 就将选定文件添加到当前项目中 此时 Delphi 并没有把该文件移动到项目文件所在的目录中, 也没有将该文件复制到项目所在的目录中, 只是在项目文件的 uses 语句中声明了所增加的文件的名称及其目录 这样, 编译项目时, 就能将该文件链接 2. 从项目中删除文件从项目中删除文件后,Delphi 并没有将文件从硬盘上删除, 只是修改了项目文件中的 uses 语句, 将要删除的文件从该语句中去掉而已 如果要从项目中删除文件, 可执行如下操作 (1) 单击 Project 菜单中的 Remove From Project 命令, 或单击工具栏上 Remove File From Project 按钮, 打开 Remove From Project 对话框, 如图 1-10(a) 所示 (2) 选择要删除的文件 (3) 单击 OK 按钮 另外, 可利用项目管理器从项目中删除文件 在项目管理器中, 鼠标右键单击要删除的单元文件, 将打开一个快捷菜单, 从中选择 Remove From Project 命令即可, 如图 1-10(b) 所示 3. 查看文件

28 第 1 章 Delphi 集成开发环境 15 如果要查看项目中的某窗体或文件的源代码, 根据需要, 可以采取如下方法

29 16 Delphi 程序设计基础 (a) 图 1-10 Remove From Project (b) 如果要查看某个单元文件的源代码, 可以单击 View 菜单的 Units 命令或工具栏中的 View Unit 按钮, 打开 View Unit 对话框, 如图 1-11 所示 然后从列表框中选择要查看的单元文件 再单击 OK 按钮 如果要查看某个窗体, 可以单击 View 菜单的 Forms 命令或工具栏中的 View Form 按钮, 打开 View Form 对话框, 如图 1-12 所示 然后从列表框中选择要查看的窗体 再单击 OK 按钮 图 1-11 View Unit 对话框图 1-12 View Form 对话框 打开项目管理器窗口, 鼠标右键单击要查看的窗体或单元文件, 将打开一个快捷菜单, 从中选择 Open 命令, 即可查看到选定的窗体或选定单元文件的源代码 如果当前窗口为窗体窗口或窗体对应的单元文件源代码, 而用户正好想查看窗体对应的单元文件或单元文件对应的窗体, 可单击 View 菜单的 Toggle Form/Unit 命令, 或直接在工具栏上单击 Toggle Form/Unit 按钮 4. 保存项目及其文件 Delphi 提供了许多保存命令, 用户可以根据需要来选择使用 如果要保存当前文件, 单击 File 菜单中的 Save 命令, 或单击工具栏上 Save 按钮 如果该文件是新文件,Delphi 将打开一个 Save Unitl As 对话框, 提示用户输入新

30 第 1 章 Delphi 集成开发环境 17 文件名, 如图 1-13 所示 图 1-13 Save As 对话框 如果要将当前文件以新文件名存储, 单击 File 菜单中的 Save As 命令, 打开一个 Save As 对话框, 然后输入新文件名, 单击 保存 按钮即可 如果要保存项目中所有文件, 单击 File 菜单中的 Save All 命令, 或单击工具栏中 Save All 按钮 如果项目中有新文件,Delphi 将打开一个 Save As 对话框, 提示用户输入新文件名 如果要将当前项目以新名称存储, 单击 File 菜单中的 Save Project As 命令, 打开一个 Save Project As 对话框, 然后输入新项目名, 单击 保存 按钮即可 项目编译和运行运行应用程序前, 首先得对应用程序进行编译 Delphi 提供了多种编译方式, 供用户在不同情况下选用 1. 编译链接单击 Project 菜单的 Compile 项目名 命令, 将编译当前项目自上一次编译以来修改过的文件, 并将项目中所有文件链接成可执行文件, 该命令的热键为 Ctrl+F9 项目的编译过程为 :Delphi 首先将项目中各单元文件编译成以.DCU 为扩展名的编译单元文件, 然后开始编译项目文件, 最后将编译好的文件链接成可执行文件 如果用户想了解 Delphi 编译过程中的信息, 可执行如下操作 : (1) 单击 Tools 菜单的 Environment Options 命令, 打开 Environment Options 对话框, 并选择 Preferences 选项卡 (2) 在 Compiling and Running 选项组中选择 Show compiling progress 复选框 (3) 单击 OK 按钮 这样, 每次用户编译项目时, 就会出现一个 Compiling 消息框, 显示项目的编译过程, 如图 1-14 所示

31 18 Delphi 程序设计基础 2. 重建项目重建项目的意思是指重新编译项目中所有的文件, 包括单元文件和项目文件, 并重新建立生成可执行文件所需的一系列文件 当用户不能确定是否有文件被遗漏编译, 或想更新编译单元文件 (.DCU) 和可执行文件 (.EXE) 时, 可采取这一种编译模式 如果要重建项目, 选择 Project 菜单中的 Build 项目名 命令即可 3. 只编译文件 图 1-14 Compiling 消息框 所谓只编译文件, 是指只对项目中的文件进行编译, 而不链接它们 这种编译模式通常 用于检查文件中的语法错误 如果只编译文件, 可选择 Project 菜单中的 Syntax check 项目名 命令 4. 查看编译信息 编译完当前项目后, 还可以单击 Project 菜单中的 Information for 项目名 命令, 打开 Information 消息框, 来查看编译后的信息, 如图 1-15 所示 消息框中提供的信息见 表 1-5 表 1-5 Source compiled Code size Data size Initial stack size File size Status 栏 Information 消息框信息被编译的源代码总数编译后的可执行代码大小存储全局变量所需的内存大小存储局部变量所需的内存大小编译输出文件的大小显示上一次编译是否成功 图 1-15 Information 消息框 5. 编译所有项目 对于有多个项目或项目组的应用程序, 经常一次编译并链接所有项目, 从而一次性生成 可执行文件

32 第 1 章 Delphi 集成开发环境 19 要编译所有项目, 单击 Project 菜单的 Compile All Projects 命令即可 6. 重建所有项目重建所有项目本质上与重建项目并没有什么不同, 只不过是针对多个项目操作而已 重建所有项目使用的命令是 Project 菜单的 Build All Projects 命令 7. 运行若程序没有语法错误, 编译后可直接在 Delphi 集成环境中运行, 运行方法是使用 Run 菜单的 Run 命令, 或单击工具栏中的 Run 按钮, 或直接按 F9 功能键 通过简略地介绍 Delphi 集成开发环境的各个组成部分, 读者对它的开发工具有了一个大概的了解, 并学习了一些基本的使用方法 在 Delphi 的学习过程中, 还可以通过帮助文件来解决问题 当然,Delphi 集成开发环境是一个综合的整体, 只有全面灵活地掌握和使用, 才能开发出理想 高效的应用程序来 1.6 Delphi 程序设计过程 Delphi 程序设计是可视化的, 大多数开发的程序界面风格类似于其他 Windows 应用程序 在开发过程中, 基本上以一个项目文件管理一组窗体单元文件, 而各个窗体根据功能需要, 安排了不同的组件, 运行时通过这些组件与用户交互, 这些组件所要实现的功能由其背后的事件 ( 程序代码 ) 实现 在 Delphi 中创建应用程序的过程一般如下 第 1 步 : 创建新的项目和窗体 使用 File 菜单中 New 级联菜单下的 Application 菜单命令, 创建新的项目和窗体 第 2 步 : 在窗体中加入组件 在组件选项板中选定需要的组件, 然后在窗体的适当位置单击 接着可以适当地安排窗体和窗体上的组件 第 3 步 : 设置窗体和组件的属性 根据程序需求在对象编辑器中设置组件的属性, 包括组件的大小 颜色 位置 标题文字 特征等 这些属性也可以通过程序动态地设置和修改 第 4 步 : 编写事件处理程序 在对象编辑器中选择指定组件的事件项, 进入代码编辑窗口, 编写程序代码, 以实现相应功能 第 5 步 : 保存项目文件和单元文件 使用 File 菜单中 Save All 命令, 保存项目 单元等文件 第 6 步 : 编译 调试和运行程序 使用 Run 菜单中 Run 命令运行应用程序 若出现问题或程序的运行结果达不到预期的结果, 还可以使用 Delphi 提供的调试器来调试 修改, 直到满意为止 例 1-1 在 Delphi 集成开发环境中编写 Windows 应用程序 程序实现的功能是在应用程序的窗体中显示时钟 运行时显示的界面如图 l-16(b) 所示 具体实现过程如下 (1) 进入 Delphi 集成开发环境

33 20 Delphi 程序设计基础可以通过 Windows 的 开始 菜单来运行 Delphi, 如 开始 程序 Borland Delphi 7 Delphi 7 (2) 创建项目为了集中管理各个文件, 我们可以创建一个 项目 进行统一管理 1 创建项目文件夹为了单独存放与项目有关的文件, 先创建一个文件夹 ( 可以通过 Windows 环境中的资源管理器来实现 ) 如 C:\Mypro 2 创建一个新的项目在 Delphi 集成开发环境中通过 File 菜单中 New 级联菜单下的 Application 命令创建一个新的应用程序,Delphi 会自动创建项目文件及相关的其他文件 3 保存项目及相关文件使用 File 菜单中 Save All 命令将保存与项目有关的所有文件 此时首先会弹出 Save Unit1 As 对话框, 定位到目录 C:\Mypro 后, 输入文件名 Unit1_1, 点击 确定 按钮, 接着会弹出 Save Project1 As 对话框 这时目录自动定位到 C:\Mypro 中, 输入文件名 Project1_1, 点击 确定 按钮 (3) 向窗体中添加组件为了在 Form1 窗体中显示文字, 可以添加一个标签 (Label) 组件 标签组件是组件栏的 Standard 组件夹中的第 4 个组件 可以将鼠标移动到 Standard 组件夹中的第 4 个组件上, 稍停一下后会出现一个内容显示为 Label 的提示窗口 单击鼠标左键, 然后移动鼠标到 Form1 窗体中再单击一下左键, 标签组件就被添加到窗体中了 为了每隔 1 秒将显示的内容改变一次, 采用同样的方法, 往 Form1 窗体中添加一个定时器 (Timer) 组件 定时器组件是 System 组件夹中的第 1 个组件 在程序运行的过程中, 定时器组件并不在窗体中显示, 所以将定时器组件随便放置在窗体中的某个位置就可以了 为了可以关闭显示, 添加一个按钮 (Button) 组件, 按钮组件在 Standard 组件夹中的第 7 个位置, 采用同样方法, 将其添加到窗体中 (4) 设置组件属性在 Form1 窗体中选中标签组件, 然后在对象编辑器窗口中设置标签组件的主要属性, 见表 1-6 表 1-6 例 1-1 中标签组件的属性设置 属性属性值 Alignment AutoSize Caption Font Name tacenter False ( 空串, 删除原 Label1) 黑体, 粗体, 初号 Label1 注意 : 改变字体属性时, 可以单击组合框右面的省略号 ( ) 按钮, 在弹出的 字体 对话框中设置字体 大小和颜色等 也可以展开 Font 属性, 对子属性进行设置

34 第 1 章 Delphi 集成开发环境 21 设置好组件的属性后 可以改变窗体的大小 : 将鼠标移动到窗体的边缘时, 鼠标的形状会变成双箭头模式, 然后按下鼠标左键进行拖动就可以改变窗体的大小 然后, 再在 Form1 窗体中选中按钮组件, 在对象编辑器窗口中将按钮的 Caption 属性设置为 开 / 关 定制好的窗体如图 1-16(a) 所示 (5) 添加代码 1 在 Form1 窗体中选中定时器组件, 然后选中对象编辑器窗口中的事件 (Events) 页, 为定时器组件添加 OnTimer 事件的处理过程 只要双击 OnTimer 栏右面的组合框, 系统就会自动添加该事件的处理过程, 并自动定位到相应的代码处 在 TForm1.Timer1Timer 处理过程中添加以下代码 : procedure TForm1.Timer1Timer(Sender: TObject); var // 变量说明 DateTime : TDateTime; str : string; DateTime := Time; // 取得当前日期和时间 str := TimeToStr(DateTime); // 转换时间成字符串 Label1.Caption := str; // 显示时间字符 { 注意 : 这些语句也可直接用下列语句代替 : label1.caption := TimeToStr(Time); } (a) 图 1-16 显示时钟 (b) 2 同样, 在 Form1 窗体中选中按钮组件, 然后选中对象编辑器窗口中的事件 (Events) 页, 为按钮组件添加单击 (OnClick) 事件的处理过程 ( 即运行时, 单击按钮所要运行的功能程序 ) 双击 OnClick 栏右面的组合框, 进入代码编辑器, 给按钮组件添加单击事件 : procedure TForm1.Button1Click(Sender: TObject); Label1.Visible:=not Label1.Visible; (6) 运行程序通过 Run 菜单的 Run 命令运行程序 如果程序没有编译和链接, 则程序在运行前

35 22 Delphi 程序设计基础系统会自动进行编译和链接 运行结果如图 1-16(b) 所示 说明 : 例 1-1 通过定时器每秒执行一次 TForm1.Timer1Timer 处理过程, 在该处理过程中, 通过 Label1.Caption := str; 语句将组件 Label1 的 Caption 属性改变, 也就是将窗体中显示的内容每秒改变了一次 而按钮的单击事件是通过 Label1.Visible:=not Label1.Visible; 将 Label1 组件的 Visible 属性在 True 和 False 中间切换, 以达到开关的目的 程序中 // 和 {} 符号代表注释文本 读者可以自己尝试进行以下工作 1 改变窗体中显示内容交替的频率 可以通过设置定时器的 Interval 属性来实现 2 改变窗体标题栏的内容 如可以将 Form1 的 Caption 属性由 Form1 改为 小闹铃 3 改变窗体的大小 显示内容 字体和颜色等 4 有兴趣的读者还可以让程序在运行过程中发出声音, 这样提示的效果会更明显 这可以在 TForm1.Timer1Timer 过程的后部添加如下一条语句来实现 : procedure TForm1.TTimer1Timer(Sender:TObject); Beep; // 发声 习 题 1.Delphi 的集成开发环境主要由哪几部分组成? 各部分的功能是怎样的? 2.Delphi 集成开发环境的界面分为哪 4 个部分? 3. 对象查看器的功能是什么? 4. 怎样修改窗体或组件的属性? 5. 一个 Delphi 应用程序的源文件有哪些? 运行后又生成了哪些文件? 各文件的含义是什么?

36 第 2 章 Delphi 的编程语言 Delphi 开发应用程序时的实质性工作是编写功能代码, 而编写功能代码的基础是 Object Pascal( 对象 Pascal) 语言 对象 Pascal 程序设计语言是在 Pascal 语言的基础上发展起来的, 它继承了 Pascal 语言语法严谨 数据结构丰富等优点, 同时融入了面向对象的语法要素, 成 为了一个完善的面向对象编程语言 Delphi 并不是一种计算机语言, 而是一个基于对象 Pascal 语言的 Windows 应用程序开发工具系统 因此, 要能够使用 Delphi 开发出一个完整的应用 程序, 必须熟悉和掌握对象 Pascal 语言的语法和使用方法 本章主要介绍 : 保留字和标识符 对象 Pascal 的数据类型 常量和变量的定义 运算符和表达式 语句 过程与函数 保留字和标准指令符 2.1 保留字和标识符 对象 Pascal 语言中规定了一批英文单词, 赋予了它们特定的含义, 在进行程序设计时不能 被重新定义或进行它用, 这些单词称为保留字 对象 Pascal 语言中规定的保留字有如下 65 个 and array as asm case class const constructor destructor dispinterface div do downto else end except exports file finalization finally for function goto if implementation in inherited initialization inline interface is label library mod nil not object of or out packed procedure program property raise record repeat resourcestring set shl shr string then threadvar to try type unit until uses var while with xor 注意 : 对象 Pascal 语言是不区分大小写的, 所以像 And AND and 等都被看作是保留字 此外, 对象 Pascal 语言中还定义了 39 个指令字 (Directives), 它们也具有特殊的含义 ;

37 第 2 章 Delphi 的编程语言 24 如果由用户重新定义了这些指令字, 在作用域内它们就失去了原来的意义 这些指令字如下 absolute abstract assembler automated cdecl contains default dispid dynamic export external far forward implements index message name near nodefault overload override package pascal private protected public published read readonly register reintroduce requires resident safecall stdcall stored virtual write writeonly 尽管 private protected public published 和 automated 都是指令字, 也应该将它们当作保留字来看待, 不要定义与它们同名的标识符 同样,at 和 on 也具有特殊的含义, 也不要定义与它们同名的标识符 在 Delphi 集成开发环境的代码编辑器中, 保留字和指令字将以粗体显示 在定义标识符的时候不要定义与这些以粗体显示的保留字和指令字一样的单词 标识符标识符是用来标识 ( 表示 ) 程序 过程 函数 类型 符号常量 变量 对象等的名字的符号 对象 Pascal 语言中规定, 标识符由字母 A~Z a~z 下划线和数字 0~9 组成, 标识符的命名有以下 3 条限制 : (1) 首字符必须是字母或下划线, 不能是数字 ; (2) 标识符不能和保留字相同 ; (3) 缺省状态下,Delphi 只认为标识的前 255 个组成字符是有意义的 在对象 Pascal 语言中, 标识符也不区分大小写, 所以标识符 Myname MyName myname myname 和 MYNAME 被认为是同一个标识符 总体上来说, 这是 Pascal 的一大优点, 因为在大小写敏感的语言中, 许多语法错误是由不正确的大小写引起的 注意 :Pascal 语言的大小写不敏感特性也有例外, 如控件包中的 Register 过程必须以大写字母 R 开始, 一些 API 函数调用参数也必须按要求大小写等 保持大写使用的一致性是值得提倡的好习惯, 尽量保持大写使用的一致性, 可以提高代码的可读性 一个常用的方法是将每个标识符的第一个字母大写, 标识符若由几个词组合而成 ( 中间不能插入空格 ), 每个词的第一个字母应大写, 比如 : MyLongIdentifier MyVeryLongAndAlmostStupidIdentifier 注释为了使程序更加易读, 通常要为程序添加注释, 即对程序模块 语句或命令作文字解释 运行时, 这些文字不会作为命令的一部分而被执行, 因而不会影响原来的程序 有时, 在调试的过程中, 也可以用注释的方法对部分命令作暂时的 删除, 以缩小调试范围 对象 Pascal 语言中的注释有下面 3 种形式 :

38 25 Delphi 程序设计基础 组合符号 { 与 } 的成对使用表示它们之间的内容为注释部分 ; 组合符号 (* 与 *) 的成对使用表示它们之间的内容为注释部分 ; 符号 // 的单个使用表示所在行的该符号之后的内容为注释 注意 : 注释符 { 与 } (* 与 *) 在使用时不支持注释的嵌套, 而且必须成 对使用 即不允许形如 { { } } 或 (* (* *) *), 但允许形如 (* { } *) 的结构 建议对于单行和少量几行的注释使用符号 //, 对于大块注释使用 { 与 } 或 (* 与 *) 有时可以利用注释在代码中形成一个醒目的标志 比如利用注释符号形成一个矩形方 框, 在其中可以添加一些重要的说明文字 如果在注释符 { 或 (* 后紧接着的是一个美元符号 $, 表示该句是一个编译 器指令, 它与普通的注释不同, 通常用来对编译过程进行设置 比如下面的例 2-1 中的第二 句就是一个编译器指令 由于 Delphi 集成开发环境中的代码编辑器在显示不同类型的代码时通过使用不同的颜色 来加以区别, 所以在编程的过程中, 只要注意文件中代码的颜色, 一般就不会错误地使用注 释符了 例 2-1 说明了注释的用法 例 2-1 注释的用法 program Project2_1; {$APPTYPE CONSOLE} // 编译器指令 ///////////////////////////////////////////////// /////// 本例程用来说明注释符的使用 ///// ///////////////////////////////////////////////// { 下面的这条语句将字符串 1 和 字符串 2 紧接着在屏幕上输出 } Writeln('String0' (* 字符串 1*) +'String1'); // 字符串 2 Writeln(' 按下回车键 <Enter> 退出 '); Readln; end. 运行结果如下 : String0String1 上面的注释文字 (* 字符串 1*) 实际上位于语句 Writeln( String0 + Stringl ); 之间, 但 是对编译结果没有影响 因为在编译的时候, 编译器会忽略所有的注释 控制台程序中的屏幕输入和输出 在介绍可视化编程方法前, 我们采用 read write 来进行屏幕输入 输出 1. 输入语句格式

39 第 2 章 Delphi 的编程语言 26 read(< 变量表 >); 或 readln(< 变量表 >); 变量表里面变量与变量之间用逗号隔开 ;readln 表示下一个语句将从下一行开始操作 ; 输入时, 整型或实型用空格或回车隔开, 字符型之间无需分隔, 一个接一个输入 2. 输出语句格式 write(< 变量表 >); 或 writeln(< 变量表 >); 变量表里面变量与变量之间用逗号隔开 ;writeln 表示从下一行开始显示 ; 变量表中可 对 real 或 integer 类型的数据限定显示宽度, 如 write('a=',a:2:0) 即指定 a 显示宽度为 2 位, 小数 0 位 例如, 在屏幕上显示 9 9 乘法表, 运行结果如图 2-1 所示 program Project2_1eg; {$APPTYPE CONSOLE} // 设置为控制台程序 var i,n:integer; for i:=1 to 9 do for n:=1 to i do write(i*n:3); writeln; readln; end. 图 乘法表 2.2 数据类型 对象 Pascal 语言的数据类型比较丰富, 图 2-2 中列举了一些预定义好的数据类型 此外, 还可以通过数据类型声明语句在预定义数据类型的基础上定义新的数据类型 下面对图 2-2 中的数据类型进行介绍 简单数据类型 有序数据类型 实数数据类型 整数类型字符类型布尔类型枚举类型子界类型 简单数据类型简单数据类型 (Simple) 包括有序数据类型 (ordinal) 和实数数据类型 (real) 有序数据类型包括下面的一些数据类型 1. 整数类型整数类型 (integer) 包括了表 2-1 中的各种类型 数据类型 字符串类型集合类型数组类型记录类型结构类型文件类型类类型类引用类型接口类型指针类型过程与函数类型可变类型图 2-2 对象 Pascal 语言的数据类型

40 27 Delphi 程序设计基础 表 2-1 对象 Pascal 语言中的整数类型 整数类型 数值范围 格 式 Integer ~ 带符号 32 位 Cardinal 或 Longword 0~ 无符号 32 位 Shortint 128~127 带符号 8 位 Smallint 32768~32767 带符号 l6 位 Longint ~ 带符号 32 位 Int ~ 带符号 64 位 Byte 0~255 无符号 8 位 Word 0~65535 无符号 l6 位 2. 字符类型 基本的字符类型 (Character) 包括 AnsiChar 和 WideChar 两种 AnsiChar 类型的数据具 有一个字节, 与扩展的 ANSI 字符集对应 WideChar 类型的数据为双字节, 与 Unicode 字符 集对应 Unicode 字符集的前 256 个字符与 ANSI 字符集的相同 通用的字符类型为 Char, 与 AnsiChar 类型相同 此外, 可以使用函数 Chr 返回一个整型数对应的字符, 也可以使用函数 Ord 返回一个字 符的序数 例 2-2 将整数值为 0~127 的字符在屏幕上输出 程序清单如下 : Program Project2_2; {$APPTYPE CONSOLE} Var I:Integer; for I:=0 to 127 do Write(Chr(I)); // 将 0~127 的整数以 ASCII 码的形式输出 Writeln; Writeln(' 按下回车键 <Enter> 退出 '); Readln; end. 一般来说, 对字母 数字或符号, 用代表它们的符号来表示较好 ; 而涉及到特殊字符时 用数字符号较好 下面列出了常用的特殊字符 #9 或 chr(9): 跳格 (Tab 键 ); #10 或 chr(10): 换行 ; #13 或 chr(13): 回车 (Enter 键 ) 3. 布尔类型 布尔类型 (Boolean) 包括以下 4 种 :Boolean ByteBool WordBool 和 LongBool 其中 Boolean 和 ByteBool 为单字节,WordBool 为双字节,LongBool 为四字节 对象 Pascal 语言 预定义了两个常量标识符 False 和 True, 可以为 Boolean 类型的数据赋值为 False 或 True, 对 应的序数值为 0 和 1 当 ByteBool WordBool 和 LongBool 类型的数据为 0 时, 可以认为是 False; 当不为 0 时, 可以认为是 True 4. 枚举类型 枚举类型 (enumerated) 是一种用户自定义类型, 它的定义由一组有序的标识符组成

41 第 2 章 Delphi 的编程语言 28 注意 : 类型的声明使用保留字 Type 枚举类型定义形式如下 : type 类型名称 =( 值 1, 值 2,, 值 n); 例如 : type Weekdays=(Sunday,Monday,Tuesday,Wednsday,Thursday,Friday,Saturday); Colors=(mcRed,mcGreen,mcBlue); Shapes=(Square,Rectangle,Circle,Ellipse); // 类型定义当在程序中定义了枚举类型时, 可按如下形式声明变量 : var Mycolor:Colors; // 变量声明也可以不预先用 Type 定义, 而是直接按如下方法定义枚举类型变量 : var Mycolor:(mcRed,mcGreen,mcBlue); Delphi VCL( 可视控件库 ) 在很多地方用了枚举类型 例如, 窗体边框类型定义如下 : type TFormBorderStyle = (bsnone, bssingle, bssizeable, bsdialog, bssizetoolwin, bstoolwindow); 当属性值是枚举类型时, 可以从 Object Inspector 对话框显示的下拉列表框中选值, 如图 2-3 所示 5. 子界类型 图 2-3 Object Inspector 对话框中的枚举类型属性 子界类型 (subrange) 为某个有序类型的子集 子界类型也是一种用户自定义类型, 它规定了值域的上界和下界及取值的类型 子界类型的定义格式如下 : type 类型名称 = 值域下界.. 值域上界 ; 例如 : type SomeNum=1..255; Caps='A'.. 'Z'; // 类型定义如果定义了变量 Num 为 Somenum 类型 : var Num:SomeNum; 则变量 Num 的值只能在 1~255 之间 ; 若在程序中 Num 的值小于 1 或大于 255 均为非法情况 定义子界类型时应注意以下几点 (1) 上界和下界必须属同一顺序类型, 上界序号必须大于下界序号 下面的用法不合法 : type Age= ; Letter=0.. 'z';

42 29 Delphi 程序设计基础 Letter1='z'.. 'a'; Num=10..1; (2) 子界类型的上 下界的类型定义了子界的基类型 如 : 由于 1 和 255 为整数类型的常量, 所以 SomeNum 类型的基类型为整数 ;A 和 Z 为字符型的常量, 所以 Caps 的基类型为字符型 (3) 如果子界类型的基类型是枚举类型, 则应该在定义子界类型之前先定义枚举类型, 如 : type TColors=(Red,Blue,Green,Yellow,Orange,Purple,White,Black); TMyColors=Green..White; 其中 TMyColors 包括了 Green Yellow Orange Purple 和 White 6. 实数类型实数类型定义了一个能用浮点数表示的数字集合 对象 Pascal 语言中的实数数据类型见表 2-2 表 2-2 对象 Pascal 语言中的实数数据类型 实数类型 范 围 有效位数 字 节 数 Real Single Double Extended Comp l 19 8 Currency Real 其中 Real48 Single Double Extended Comp Currency 为基本类型,Real 为一般类型 字符串类型和传统 Pascal 语言不同, 对象 Pascal 语言专门提供了预定义的字符串数据类型, 可以方便地表示字符串, 实现存储 处理字符串等操作 字符串类型 (String) 主要包括表 2-3 中的 3 种类型 表 2-3 对象 Pascal 语言中的字符串类型 字符串类型 最大长度 存储空间 说 明 ShortString 到 256 字节 为了和以前的版本兼容 AnsiString ~ 字节到 2GB 动态分配内存 WideString ~ 字节到 2GB 使用 Unicode 字符集 WideString 类型与 AnsiString 类似只不过是基于 WideChar 字符类型 (Unicode 字符集 ), 用来存储 Unicode 字符 对象 Pascal 引入这种类型, 主要是为了支持 OLE 编程 可以用如下方式来声明相应的字符串变量 : var

43 第 2 章 Delphi 的编程语言 30 Str1:ShortString; Str2:AnsiString; Str3:WideString; 但在一般情况下, 当我们声明一个变量为字符串类型时使用 String 保留字 例如 : var MyStr:String; 缺省时,String 类型就是 AnsiString 类型 在 Delphi 中, 众多组件的属性使用了 String 类型, 如每个组件的 Caption 属性 Edit 组件中的 Text 属性等 同时 Delphi 中封装了众多的 String 类型字符串的操作过程和函数 因此应尽量使用 String 类型 结构类型结构类型 (Struct) 包括集合类型 (set) 数组类型 (array) 记录类型 (record) 文件类型 (file) 类类型 (class) 类引用类型 (class reference) 和接口类型 (interface) 等 这里我们依次介绍前 4 种类型 1. 集合类型一个集合由集合成员组成, 集合的成员元素是无序的 集合的另一个特点是无重复元素 集合操作的重点是判定一个元素是否属于该集合, 而不是元素在集合中的次序和出现的频率 集合类型 (set) 的类型定义方法如下 : type 类型名称 =set of 元素类型 ; 例如 : type TSomeInts=1..250; // 基本类型为子界类型 TIntSet=set of TSomeInts; // 定义集合类型 TACopyOfByte=set of Byte; TSuit=set of (Club,Diamond,Heart,Spade); TACopyOfChar=set of Char; 集合类型表示一组值, 该组值由集合所依据的有序类型定义 定义集合的常用有序类型不多, 一般为枚举类型或子界类型 如果子界类型取值为 1..3, 那么基于它的集合类型值可以是 1, 或 2, 或 3, 或 1 和 2, 或 1 和 3, 或 2 和 3, 或取所有 3 个数 或一个数也没有 一个变量通常包含该类型对应的一个值, 而集合类型可以不包含值, 包含一个值 两个值 三个值, 或更多值, 它甚至可以包含定义范围内所有的值 下面定义一个集合 : type Letters = set of Uppercase; 现在可以用上面的类型来定义变量, 并把原始类型的值赋给变量 为了在集合中表示一组值, 需要用逗号将值隔开, 最后用方括号结尾 下例显示了多值 单值和空值的变量赋值 : var Letters1, Letters2, Letters3: Letters;

44 31 Delphi 程序设计基础 Letters1 := ['A', 'B', 'C']; Letters2 := ['K']; Letters3 := []; 在 Delphi 中, 许多组件对象的属性被定义成集合类型, 比如窗体对象的 BorderIcons 属性就被定义为集合类型 : type TBorderIcon=(biSystemMenu,biMinimize,biMaximize,biHelp); TBorderIcons=set of TborderIcon; Property BorderIcons: TborderIcons; 实际上, 给定的窗口中可以没有图标, 也可以有一个或多个图标 用对象查看器设置时 ( 如图 2-4 所示 ), 双击属性名, 或单击属性左边的加号, 自行选择, 从而添加或删除集合中的值 2. 数组类型数组类型 (array) 的数据为某一类相同类型的元素按一定的顺序组成的序列, 包括静态数组和动态数 组两种 (1) 静态数组 图 2-4 对象查看器中的集合类型属性 静态数组就是传统 Pascal 语言中的数组类型 在程序初始化时给静态数组分配内存空间, 所以静态数组必须具有确定的大小, 其元素的数据类型也必须是确定的 静态数组的定义方式如下 : type 数组类型名 =array [ 下标类型 ] of 基类型 // 一维数组 或 数组类型名 =array [ 下标类型 1,, 下标类型 n] of 基类型 // 多维数组 例如 : type MyArray=array [1..100] of Char; // 一维数组 Tmatrix1=array [1..10] of array [1..50] of Real; // 二维数组 Tmatrix2=array [1..10,1..50] of Real; // 与上面的二维数组相同 数组类型定义了一组指定类型的元素序列, 在方括号中填入下标值就可访问数组中的元 素 定义数组时, 方括号也用来指定可能的下标值 例如, 下面的代码中定义了一个有 24 个整数的数组 : type DayTemperatures = array [1..24] of Integer; 在数组定义时, 需要在方括号中填入一个子界类型的值, 或者用两个有序类型的常量定 义一个新的子界类型, 子界类型指定了数组的有效索引 由于子界类型指定了数组下标值的 上界和下界, 那么下标就不必像 C C++ Java 和其他语言那样必须从零开始 和其他数据类型一样, 仅仅声明了数组类型并没有真正建立一个数组实例, 所以必须声 明一个该类型的变量, 来真正申请一段内存空间, 以便使用数组来实现数据的存取和其他操

45 第 2 章 Delphi 的编程语言 32 作 例如 : var MyStr:MyArray; MyEx:Tmatrix1; 数组类型可在声明变量时直接声明, 如 : var tst1:array [0..50] of real; 使用数组时, 经常需要编写的程序代码就是访问数组中的元素 静态数组中元素的访问是通过数组的下标进行的 访问数组中元素的一般形式为 : 数组变量名 [ 下标表达式 ] // 一维数组数组变量名 [ 下标表达式 1,, 下标表达式 n] // 多维数组例 : var a:array [1..8] of real; i:integer; for i:=1 to 8 do a[i]:=i/2; for i:=7 downto 1 do a[i+1]:=a[i]; 在 Delphi 中, 许多组件对象的属性被定义成数组类型, 比如 ListBox 控件的 Items 属性 (2) 动态数组对象 Pascal 语言自 Delphi 4.0 以后引进了动态数组类型, 它不需要在声明时指定大小, 因此为我们在程序中动态地开辟存储空间提供了方便的途径 动态数组的定义方式如下 : type 数组类型名 =array of 基类型 ; // 一维数组数组类型名 =array of array of array of 基类型 // 多维数组例如 : type MyFlexibleArray=array of Real; // 定义动态数组可以通过过程 Setlength 来为动态数组指定空间大小, 例如 : SetLength(MyFlexibleArray,20); // 为动态数组指定空间大小其中数组 MyFlexibleArray 的下标值为 0~19 3. 记录类型记录类型 (record) 可以由不同类型的元素组成, 这些元素称为域 在记录类型中为每个域指定了一个名称和数据类型 数据类型可以是对象 Pascal 语言中预定义的类型, 也可以是程序员自定义的类型 记录类型的定义方式如下 : type 记录类型名 =record 域名 1: 类型 1; 域名 2: 类型 2;

46 33 Delphi 程序设计基础域名 n: 类型 n; 记录类型定义中列出了所有域, 每个域对应一个域名, 通过域名可以访问它 例 2-3 记录类型的定义与使用,with 语句的使用 program Project2_3; {$APPTYPE CONSOLE} type TDateRec=record // 记录类型的定义 Year: Integer; Month: (Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec); Day:1..31; var Record1,Record2,Record3:TDateRec; // 记录类型变量的声明 Record1.Year:=1975; // 给记录中的域赋值 Record1.Month:=Sep; Record1.Day:=13; with Record2 do // 使用 with 语句可以简化代码的输入 Year:=1973; // 相当于 Record2.Year:=1973; Month:=Jul; Day:=21; Record3:=Record1; // 对记录进行复制 end. 例中的 with 语句将在后面进行介绍 该例中没有输入和输出, 所以在运行时没任何现象出现 4. 文件类型文件类型代表物理磁盘文件, 是一个线性序列的数据集 除了文件类型本身, 其他任何类型都可以是它的元素类型 文件类型定义形式如下 : type 文件类型名 =file of 元素类型 ; 元素类型可以是整数 实数等简单类型, 也可以是记录类型这样的复杂类型, 例如 : type TStudent=Record Name:String[8]; Age:Byte; End; StudentFile:File of TStudent;

47 第 2 章 Delphi 的编程语言 34 如果元素类型被忽略, 则是无类型文件, 直接使用底层的 IO 函数打开文件, 并把它当 作二进制文件处理 TextFile 是预定义的类型, 表示一个文本文件 指针类型 指针类型 (pointer) 的变量指向的是内存空间的地址 通常我们真正关心的是某一个地 址的内存中存放的数据, 通过指针可以对所指地址的内存中的数据进行操作 指针类型的定义形式如下 : type 指针类型名 =^ 类型 ; 其中, 指针类型名为任意合法的标识符, ^ 放在类型的前面, 表明声明的类型为一个指针 类型, ^ 后面紧跟的类型确定了指针所指向的类型, 可以是简单类型, 如整型 实型或枚 举型等, 也可以是结构类型, 如数组 集合或记录等 一旦定义了指针变量, 符号把另一个相同类型变量的地址赋给它, 见例 2-4 例 2-4 指针的定义和使用 program Prject2_4; {$APPTYPE CONSOLE} type PInteger=^Integer; // 定义指针类型 Var Y:Shortint; // 短整型 I:Integer; // 整型 Pi:Pinteger; // 整型指针 P:Pointer; // 无类型指针 Y:=2; I:=3; PI:=@I; // 利用整型指针指向整型数据 writeln('i:',pi^); // 显示输出 P:=@Y; // 利用无类型指针指向短整型数据 I:=Integer(P^); // 将无类型指针指向的内容给另一个变量赋值 // 下一语句错误, 故屏蔽掉 //I:=P^; // 不可以直接赋值给变量 writeln('i:',i); PI:= P; // 指针之间进行赋值 writeln('pi^:',pi^); readln; end. 运行结果如下 :

48 35 Delphi 程序设计基础 I:3 I:2 PI^:2 说明 : 运算符放在变量的前面, 将获取变量的地址, 并可以把地址赋值为同样数据类型的指针 把 ^ 运算符放在一个数据类型的前面, 则可以定义该类型的一个指针类型 ; 如果放在一个指针的后面, 则获取该指针指向的地址空间的内容 如果定义了一个指针 P, 那么 P 表示指针所指向的内存地址, 而 P^ 表示内存所存储的实际内容 因此, 在上面的代码中, P^ 与 Y 相等 可以将上面定义 PI 的过程合成为一步 :PI:^Integer 上面还定义了一个无类型的指针 P, 它可以指向任何类型的数据, 但在使用它时要注意进行类型转换, 不可以将所指地址中的内容直接赋值给其他类型的变量 过程与函数类型关于过程与函数类型的用法将在 2.6 节 过程与函数 中介绍 可变类型有时要对一些数据类型变化的数据进行操作, 并且要到运行时才能根据实际情况确定数据的类型, 这时就可以使用可变类型 (Variant) 的数据 这些数据的数据类型可以在运行期间自动改变, 不过它们比固定类型的数据占用更多的空间和更多的操作时间 与 real integer 等类型一样, 可变类型是对象 Pascal 语言中的一种预定义的数据类型, 因此可以使用如下方法来定义一个可变类型的变量 : var 变量名 :Variant; 例如 : var v1,v2,v3,v4:variant; Begin v1:=1; // 整型值 v2:= ; // 实型值 v3:= 'Hello'; // 字符串值 v4:=v1+v2+100; // 实型值 这里需要强调的是, 由于使用可变类型将导致低的代码执行效率, 所以除了编写 OLE COM CORBA 和一些数据库应用程序外, 应尽量使用固定的数据类型 常量 2.3 常量和变量的定义

49 第 2 章 Delphi 的编程语言 36 对于在程序运行期间保持不变的值,Pascal 允许通过常量来声明 声明常量不必特定数据类型, 但需要赋一个初值 编译器会根据所赋初值自动选用合适的数据类型 常量是打算在程序中多次引用的固定量的名字 它是不变的数, 它的值在程序执行期间也不能变 常量定义形式如下 : const 常量名 = 常量值 ; 例如 : Const Pi= ; Thousand = 1000; AuthorName = 'Marco Cantù'; 在声明常量的时候, 等号右边可以使用一些预定义的函数, 如 Abs Addr ArcTan Chr Cos Exp Frac Hi High Int Length Ln Lo Low Odd Ord Pred Round Sin SizeOf Sqr Sqrt Succ Swap 和 Trunc 等 变量变量是一个特定数据实体, 它有预定义的数据类型, 并且可在内存中某个惟一的地址存放指定类型的值 变量可在程序运行的过程中动态地修改, 这是它与常量的最大区别 变量具有 4 个属性, 每个变量都有名字 类型 变量值和占用的内存地址 变量在使用前必须声明, 声明变量时必须指定一种数据类型 变量的定义形式如下 : var 变量名 : 类型名 ; 一旦变量的类型被指定, 你只能对变量执行该变量类型支持的操作 例如, 在判断操作中用布尔值, 在数字表达式中用整型值, 你不能将布尔值和整型值混用 ( 在 C 语言中可以这样 ) 例如 : var Value: Integer; IsCorrect: Boolean; A, B: Char; 使用简单的赋值语句, 可写出下面的代码 : Value := 10; IsCorrect := True; 但下面的语句是不正确的, 因为两个变量数据类型不同 : Value := IsCorrect; // error 把变量的值从一种类型转换到另一种类型往往不难做到, 有些情况下类型转换会自动实现, 不过一般情况下需要调用特殊的系统函数, 通过改变数据内部表示来实现类型转换 例 2-5 求圆柱体体积 program project2_5;

50 37 Delphi 程序设计基础 {$APPTYPE CONSOLE} const pi= ; var h:integer; r,v:real; readln(r); readln(h); v:=pi*sqr(r)*h; writeln(v); readln; end. // 输入半径 // 输入高度 // 求体积,sqr(r) 为 r 的平方 类型常量类型常量不是一个常量, 它是一个全局变量, 只不过在编译时用指定的值预初始化, 使其在程序开始运行时具有指定的初值, 在运行中仍可以修改 类型常量的定义方法如下 : const 名字 : 类型 = 值 ; 例如 : const Left:Integer=40; ReadOnly:Boolean=False; 2.4 运算符和表达式 运算符对象 Pascal not ^ * / div mod and shl shr as + or xor = > < <> <= >= in 和 is 等 按照操作数数目的多少来分, 运算符分为两类 : 单目运算符和双目运算符 not 和 ^ 为单目运算符, 其余的为双目运算符 其中 + 和 也可以作为单目运算符来使用 单目运算符一般放在操作对象的前面, 只有 ^ 可以放在操作对象的后面 双目运算符都放在两个操作数之间 有些运算符是根据给定的操作数的数据类型做相应处理的 例如, 运算符 not 对于整型的操作数来说, 做的是按位取反 ; 对于逻辑类型的操作数来说, 它完成的则是逻辑取反 除了运算符 ^ is 和 in 外, 其余运算符都可以对 Variant 类型的数据进行操作 在复杂的表达式中, 各种运算符的优先级如下 第一级 ( 最高 ):@ not

51 第 2 章 Delphi 的编程语言 38 第二级 :* / div mod and shl shr as 第三级 :+ or xor 第四级 ( 最低 ):= <> < > <= >= in is 尽管各种运算符的优先级比较明确, 但是在具体编程的时候, 并不需要记住所有运算符 的优先级顺序 常见的一些运算符优先级顺序比较好记, 如乘 除运算符的优先级比加 减 运算符的优先级高 在优先级顺序不太明显的地方, 可以多加一些小括号以明确表达式的结 合次序 下面对各种运算符进行具体介绍 1. 算术运算符 算术运算符对浮点数和整数进行加 减 乘 除和取模运算, 见表 2-4 表 2-4 对象 Pascal 语言中的算术运算符 运算符作用操作数类型结果类型运算式举例变量值表达式值 + 两个数相加整型或实型整型或实型 x+y 其中 + 和 运算符还可以作为单目运算符, 放在浮点数或整数前, 分别表示正数和负数 2. 逻辑运算符 x=4 y=3.21 两个数相减整型或实型整型或实型 n l n= * 两个数相乘整型或实型整型或实型 Pi*R Pi=3.14 R=2 / 两个浮点数相除整型或实型实型 x/2 x= div 两个整型数相除整型整型 Value div n Value=7 n=3 mod 取模整型整型 Y mod 6 Y=27 3 逻辑运算符对逻辑类型的操作数进行运算, 运算结果也为逻辑类型, 见表 表 2-5 对象 Pascal 语言中的逻辑运算符 运算符作用举例变量值表达式值 not 逻辑取反运算 not A and or xor 3. 位运算符 逻辑积运算 全真得真, 有假得假 逻辑或运算 全假得假, 有真得真 逻辑异或运算 相异得真, 相同得假 Done and (n>0) A or B A xor B A=true A=false Done=true n=3 Done=false n=3 A=false A=true A=true A=true B=false B=false B=true B=false 位运算符对整型的数据进行按二进制位操作, 所得结果也为整型数据, 见表 2-6 表 2-6 对象 Pascal 语言中的位运算符 ( 举例中变量均为 Byte 型 ) False True True False 运算符作用举例变量值表达式值 not 按位取反 Not x X=3 ( ) 252 ( ) and 按位积 X and Y X=3 y=5 1 ( ) False True False True

52 39 Delphi 程序设计基础 or 按位或 X or Y X=3 y=5 7 ( ) 续表 运 算 符 作 用 举 例 变 量 值 表达式值 xor 按位异或 X xor Y X=3 y=5 6 ( ) shl 按位左移 X shl 2 X=3 10 ( ) shr 按位右移 Y shr 1 Y=6 3 ( ) 4. 字符串运算符 加号 (+) 还可以作为字符串运算符, 它可以将两个字符串联接在一起 如果两个字符串 都是短字符串, 那么在结果字符串长度超过 255 个字符的情况下, 只有前面 255 个字符有效 5. 指针运算符 表 2-7 中的运算符可以对指针类型的数据进行操作 表 2-7 对象 Pascal 语言中的指针运算符 运 算 符 作 用 操作数类型 结果类型 举 例 + 将指针指向的地址增加一个偏移量 指针, 整型 指针 P+I 将指针指向的地址减去一个偏移量 指针, 整型 指针 P Q ^ 取指针指向地址中的内容 指针 指针指向的数据类型 P^ = 判断两个指针是否指向同一个地址 指针 布尔 P=Q <> 判断两个指针是否指向的是不同的地址 指针 布尔 P<>Q 6. 集合运算符集合运算符主要对两个集合进行操作, 判断两个集合之间的关系, 见表 2-8 表 2-8 对象 Pascal 语言中的集合运算符 运 算 符 作 用 操作数类型 结果类型 举 例 + 取两个集合的元素 集合 集合 Setl+Set2 取两个集合不同的元素 集合 集合 S-T * 取两个集合共同的元素 集合 集合 S*T <= 判断左边的集合是否是右边集合的子集 集合 布尔 Q<=MySet >= 判断左边的集合是否是右边集合的母集 集合 布尔 S1>=S2 = 判断两个集合是否相等 集合 布尔 S2=MySet <> 判断两个集合是否不等 集合 布尔 MySet<>S1 in 判断左边的集合是否与右边的集合有从属关系 有序, 集合 布尔 A in Set1 7. 关系运算符 关系运算符可以对两个普通数据类型 类 对象 接口类型或字符串类型的数据进行比 较, 结果数据类型为布尔类型, 见表 2-9 表 2-9 对象 Pascal 语言中的关系运算符 ( 结果类型均为布尔类型 ) 运算符作用举例变量值表达式值 = 判断是否相等 I=Max I=6 max=5 I=7 max=7 <> 判断是否不相等 x<>y X=6 y=5 True False true

53 第 2 章 Delphi 的编程语言 40 X=7 y=7 False 续表 运 算 符 作 用 举 例 变 量 值 表达式值 < 判断是否小于 x<y > 判断是否大于 Len>0 <= 判断是否小于等于 Cnt<=I >= 判断是否大于等于 I>=1 X=3 y=5 X=7 y=7 Len=4 Len=-3 X=3 y=5 X=7 y=7 I=0 I=1 True False True False True True False True 8. 类运算符 类运算符 as 和 is 对类或类的实例进行操作 此外, 关系运算符 = 和 <> 也可以对类进行操作 9.@ 运算符返回一个变量 过程或函数的地址 运算符对一个类的方法进行作用, 则需要指明类的名称, 例如 表达式 表达式是由运算符 运算对象和分隔符组成的序列, 它指明了一个运算 表达式中的运 算对象可以是另外一个表达式 最简单的表达式是变量和常量, 更复杂的表达式则通过将简单表达式通过运算符 函数 调用 强制类型转换结合在一起而构成, 下面的例子都是合法的表达式 : X // 变量, 值为变量的值 15 // 常量, 值为常量本身 Calc(x,y) // 函数调用, 值为函数运算的结果 X*y // 算术运算, 值为两个变量值的乘积 X=1.5 // 逻辑表达式, 如果变量 X 的值为 1.5, 则值为 true, 否则为 false C in Range1 // 逻辑表达式, 如果 C 的值在 Range1 集合内, 值为 true, 否则为 false ['a', 'b'] // 集合, 值为集合本身 char(65) // 强制类型转换, 值为字符 'A' 简单语句 2.5 语句 1. 赋值语句赋值语句的形式如下 : 变量 := 表达式 ; 例如 : y:=0.5; // 将一个常量赋值给一个变量

54 41 Delphi 程序设计基础 Done:=(I>=1) and (I<100); // 将逻辑表达式的结果赋值给一个变量 Huel:=[Blue,Succ(C)]; // 将一个子集赋值给一个变量 I:=Sqr(J) I*K; // 将一个表达式的结果赋值给一个变量 Shortint(MyChar):=122; // 给类型转换后的变量赋值 MyString[I]:= 'A'; // 给数组的一个元素赋值 TmyObject.SomeProperty:=True; // 给对象的属性赋值 2.goto 语句 通过 goto 语句可以在程序中非常方便地从一个地方直接跳转到另一个地方 从结构化程 序设计的角度来考虑, 尽量不要使用 goto 语句 goto 语句的形式如下 : goto 标号 在使用 goto 语句之前, 要首先声明一个标号 标号的声明形式如下 : label 标号 1,, 标号 n; 其中的标号 1~ 标号 n 可以是一个 0~9999 的整数, 也可以是一个标识符 例 2-6 求平方根 program Project2_6; {$APPTYPE CONSOLE} label 10; var x,y:real; readln(x); if x<0 then writeln('can not Solve!'); goto 10; y:=sqrt(x); //sqrt 为求平方根函数 writeln('y=',y:6:2); readln; 10: end 结构语句 1. 复合语句 首尾使用 和 end 括起来一组语句称为复合语句 复合语句可以嵌套使用, 也允许 空的复合语句出现, 也就是在 和 end 之间没有其他语句 例如 :

55 第 2 章 Delphi 的编程语言 42 Z:=X; X:=Y; Y:=Z; 2.with 语句在使用记录类型的变量时, 可以通过 with 语句来简化记录中域引用的写法 在 with 语句中, 引用记录变量的域不再冠以记录变量名 with 语句的形式如下 : with 记录型变量 do 语句 ; 具体用法可以参阅例 2-3 type Date = record Year: Integer; Month: Byte; Day: Byte; var BirthDay: Date; BirthDay.Year := 1997; BirthDay.Month := 2; BirthDay.Day := 14; 可以用 with 语句改进后半部分代码 : with BirthDay do Year := 1995; Month := 2; Day := 14; 如果 with 语句指定的某个变量具有某个字段, 另一个变量也具有该字段, 则在 with 语句中对不指明变量的该字段来说, 所有的操作都是针对 with 语句指定的变量来进行的 如果

56 43 Delphi 程序设计基础要对其他变量的该字段进行操作, 要在 with 语句中指明变量名 对于对象也可以使用 with 语句 条件语句条件语句通过条件检测, 判断是否执行该条件语句中包含的语句 条件语句可有两种基本形式 :if 语句和 case 语句 1.if 语句 if 语句主要实现了判断的功能 具体形式如下 : if 表达式 then 语句 ; 或 if 表达式 then 语句 1 else 语句 2; 对 if then 型语句, 仅当条件满足时, 语句才执行 ; 对 if then else 型语句, 当条件满足时, 执行语句 1, 否则执行语句 2, 在两条语句中选择一条执行 条件用布尔表达式建立 注意 : 在第二种情况下, 语句 1 的最后不能有分号 ; 如果语句 1 是一个复合语句, 则该复合语句的 end 后面也不能有分号 if (x>10) and (y>5) { 关系运算必须用 ()} then z:=x+y { 没有 ; } else z:=2*(x+y); 2.case 语句如果你的 if 语句变得非常复杂, 有时可以用 case 语句代替它 case 语句包括用来选值的表达式 可能值序列或一个取值范围 这些值应该是常量, 并且它们必须惟一, 而且应属于有序类型 Case 语句最后可以带一个 else 语句, 当没有一个标签与选择器的值一致时, 执行 else 语句 case 语句对一个结果的多个分支进行判断, 具体形式如下 : case 选择器表达式 of 情况常量表 1: 语句 1; 情况常量表 n: 语句 n; [else 语句 ;] // 方括号内内容可省略 如果 选择器表达式 的数值等于 情况常量表 1, 则执行 语句 1, 执行完毕后就退出 case 语句 如果 选择器表达式 的数值不等于 情况常量表 1, 则依次向下判断 如

57 第 2 章 Delphi 的编程语言 44 果所有罗列出来的数值都不满足, 就执行 else 语句后面的 语句 else 及其后面的 语句 可以不要 例如 : case Number of 1: Text := 'One'; 2: Text := 'Two'; 3: Text := 'Three'; case MyChar of '+' : Text := 'Plus sign'; ' ' : Text := 'Minus sign'; '*', '/': Text := 'Multiplication or division'; '0'..'9': Text := 'Number'; 'a'..'z': Text := 'Lowercase character'; 'A'..'Z': Text := 'Uppercase character'; else Text := 'Unknown character'; 例 2-7 百分制转五分制 program Project2_7; {$APPTYPE CONSOLE} var n:integer; c:string; readln(n); case n div 10 of 0..5:c:='E'; 6:c:='D'; 7:c:='C'; 8:c:='B'; 9..10:c:='A'; else c:='error'; writeln(c); readln; end.

58 45 Delphi 程序设计基础 循环语句 1.repeat 语句 repeat 语句可以实现循环操作的功能 具体形式如下 : repeat 语句 1; 语句 n; until 循环终止条件表达式 ; 在 循环终止条件表达式 值为 True 之前, 循环执行 语句 1 到 语句 n 例 2-8 计算 n program Project2_8; {$APPTYPE CONSOLE} var i,n,sum:integer; readln(n); sum:=0; i:=0; repeat //repeat 语句开始行 i:=i+1; sum:=sum+i; until i>=n; //repeat 语句结束行 writeln(sum); readln; end. 2.while 语句 while 语句也可以实现循环操作的功能 具体形式如下 : while 循环条件表达式 do 循环体语句 ; 在 循环条件表达式 值为 False 之前, 循环执行 循环体语句 下面将例 2-8 中循环部分的代码改写如下 : while i<n do //while 语句开始行 i:=i+1; sum:=sum+i; //while 语句结束行 3.for 语句 for 语句可以实现循环操作的功能 具体形式如下 : for 循环变量 := 初值 to 终值 do

59 第 2 章 Delphi 的编程语言 46 循环体语句 ; 或 for 循环变量 := 初值 downto 终值 do 循环体语句 ; 其中 循环变量 为一个有序类型的数据, 初值 为 循环变量 的初始值 在第一种形式中, 使用的是保留字 to, 循环变量 从初始值开始逐一增加到 终值 ; 在第二种形式中, 使用的是保留字 downto, 循环变量 从初始值开始逐一递减到 终值 每次执行一次 循环体语句 继续改写例 2-8 中循环部分的代码如下 : for i:=1 to n do //for 语句开始行 sum:=sum+i; //for 语句结束行 转向语句 1.Break( 强制退出循环 ) 语句 Break 语句用于从 For 语句 While 语句或 Repeat 语句中强行退出 例 2-9 例 2-8 中, 当和 >1000 时, 使执行停止 program Project2_9; {$APPTYPE CONSOLE} var i,n,sum:integer; readln(n); sum:=0; i:=0; repeat //repeat 语句开始行 i:=i+1; sum:=sum+i; if (sum>1000) then break; until i>=n; //repeat 语句结束行 writeln(sum); readln; end. 当 sum>1000 时, 从循环中强制退出, 执行 until 后面的语句 2.Continue( 强制缩短循环 ) 语句 Continue 语句用于从 For 语句 While 语句或 Repeat 语句中强行结束本次循环, 开始下一次循环 例 2-10 计算 n,( 例 2-8 中去掉 3 的倍数 ) program Project2_10;

60 47 Delphi 程序设计基础 {$APPTYPE CONSOLE} var i,n,sum:integer; readln(n); sum:=0; i:=0; repeat //repeat 语句开始行 i:=i+1; if (i mod 3=0) then continue; sum:=sum+i; until i>=n; //repeat 语句结束行 writeln(sum); readln; end. 当 i mod 3=0 时, 不执行该语句与 until 语句之间的语句 (sum:=sum+i), 进行下一次循环 3.Exit( 强制退出程序块 ) 语句 Exit 语句用于从当前代码块中退出 若该代码为主程序, 则终止该程序, 若是函数或过程, 则立即退出该过程或函数 4.Halt( 强制终止程序执行 ) 语句 Halt 用于强行终止应用程序的执行, 返回到操作系统, 其语法格式为 : Procedure Halt[( 退出码 :Integer)]; // 注意 Procedure 仅说明该语句为过 // 程类的, 使用时不必写 Procedure, 下同其中 退出码 可以省略 通常在遇到严重错误时, 如非法内存访问 磁盘操作冲突等才使用 Halt 这种非正常退出方式 在退出前, 应关闭当前打开的文件或数据库 断开与服务器的连接 释放所有可以释放的资源, 以免造成不必要的损失 5.Runerror( 停止程序执行并产生运行错误 ) 语句 Runerror 语句终止程序的执行, 并产生运行错误, 其语法为 : Procedure Runerror[( 出错码 :Byte)]; 其中 出错码 的值不大于 255, 默认为 过程与函数 过程与函数是实现一定功能的语句块, 可以在程序的其他地方被调用, 也可以进行递归调用 理论上说, 过程是你要求计算机执行的操作, 函数是能返回值的计算 两者突出的不同点在于 : 函数能返回计算结果, 即有一个返回值, 而过程没有 过程通常作为一个单独的命令语句出现在程序中, 而函数一般作为表达式的一部分 它们都可以带多个给定类型的参数 不过实际上, 现在的函数和过程差别已经不大了, 因为你可以调用函数完成一系列操作,

61 第 2 章 Delphi 的编程语言 48 跳过其返回值 ( 用可选的出错代码或类似的东西代替返回值 ), 也可以通过过程的参数传递计算结果 标准过程与函数 Object Pascal 语言已经对常用的功能和计算做成了过程和函数, 开发人员只要直接调用即可, 这些由 Object Pascal 系统提供的过程和函数, 我们称为标准过程和标准函数 ( 或称系统过程和系统函数 ) 标准过程往往通过各组件的方法来体现, 所以在具体讲各个组件时, 再对它一一描述, 下面我们对常用的标准函数作简单介绍 程序设计语言中的函数概念同数学中一样, 即对参数 ( 相当于自变量 ) 通过函数计算得到函数的结果值 Object Pascal 语言提供多种标准函数, 表 2-10 列出部分常用函数 表 2-10 Object Pascal 语言部分标准函数 算术函数 函数名参数类型结果类型功能 绝对值 abs(x) 同参数 返回 x 的绝对值 平方 sqr(x) 同参数 返回 x 的平方值 平方根 sqrt(x) real 返回 x 的平方根值 正弦 sin(x) real 返回 x 的正弦值,x 为弧度 余弦 cos(x) real 返回 x 的余弦值,x 为弧度 反正切 arctan(x) integer real real 返回 x 的反正切值, 结果为弧度 指数 exp(x) real 返回以 e 为底的幂值, 即 e x 对数 ln(x) real 返回以 e 为底的 x 的自然对数 圆周率 pi real 返回圆周率值 最大值 max(x,y) 同参数 返回 x y 中的最大值 最小值 min(x,y) 同参数 返回 x y 中的最小值 随机数 random(range) integer integer 返回一个 0~range 之间的随机数, 没有参数时, 随机数的范围是 0~1 变量长度 sizeof(x) integer real char boolean integer 返回 x 所占的字节数 类型上界值 high(i) 类型下界值 low(i) 顺序类型 顺序类型名 同参数 获得参数类型的最大值 获得参数类型的最小值 转换函数 序数 ord(x) integer real char integer 取序号, 字符转换成 ASCII 码值 字符 chr(i) integer char ASCII 码值转换成字符 截尾 trunc(x) real integer 取 x 的整数部分 舍入 round(x) real integer 取 x 的四舍五入的值 类型转换函数 StrToInt(c) string integer 将字符串 c 转换成整型 IntToStr(n) integer string 将整型数 n 转换成字符串 StrToFloat(c) string real 将字符串 c 转换成实型 FloatToStr(x) real string 将实型数 x 转换成字符串

62 49 Delphi 程序设计基础 续表 函 数 名 参数类型 结果类型 功 能 顺序函数 前趋 pred(i) integer char 同参数 返回前趋值 后继 succ(i) boolean 同参数 返回后继值 布尔函数奇数 odd(x) integer boolean 判断 x 是否为奇数 行结束 eo1n 无参数 判断是否读入一个回车换行符 虽然标准函数已由系统说明, 用户可以直接使用, 但在使用时, 参数的个数 类型 顺 序必须与系统说明一致 函数的结果类型 ( 函数返回值的类型 ) 只能是简单类型 例如 : abs( 3) // 结果为 3 chr(ord('a')+1) // 结果为 'b' odd(73) // 结果为 true pred(1) // 结果为 0, 参数为整型, 结果也为整型 sqr(4) // 结果为 16 succ('a') // 结果为 'B', 参数为字符型, 结果也为字符型 strtoint(edit1.text) // 将组件 Edit1 的键入值转换成整数型 设 ch 表示一个字符 : chr(ord(ch)+ord('a') ord('a')) // 将 ch 转换成小写字母 用户自定义过程和函数的定义 并不是所有的功能和计算 Object Pascal 都有现成的, 有些功能或计算必须由开发人员自 己实现, 即编写用户自定义过程和函数, 或者有些经常出现的程序段也可以编写成过程或函 数, 反复调用, 这样有利于程序维护 下面我们介绍如何编写过程和函数 过程的定义和调用 1. 过程的定义 过程的定义包括过程原型和过程体的定义 过程定义的形式如下 : procedure 过程名 ( 参数列表 ); 指令符 ; 局部声明块 ; 语句 ; 其中 : 过程名 为一个有效的标识符 参数列表 需要指明参数的个数及其数据类型 指令符 用来指定过程的调用方式, 可以一次设置多个, 使用分号隔开 局部声明块 中定义了该过程中需要使用的一些临时变量, 通常也叫做本地变量

63 第 2 章 Delphi 的编程语言 50 在 与 end 之间是在过程调用时实现特定功能的一系列语句 上面的 参数列表 指令符 局部声明块 和 语句 等为可选部分, 可以不要 2. 过程的调用过程名 ( 参数列表 ); 例 2-11 编制程序解二元一次方程 Ax+By=C Dx+Ey=F 要求解方程组部分用过程语句 分析 : 设 G =A E B D, 根据代数知识, 在 G=0 时, 方程组有无穷多个解, 否则, 有一组确定的解 : x=1/g (C E B F) y=1/g (A F C D) (1) 新建应用程序启动 Delphi, 从 Fi1e 菜单中选取 New Application 命令, 开始一个新的应用文件 (2) 打开 Project1 打开 View 菜单的 Units 菜单项, 选择 Project1, 打开 Project1 (3) 输入程序代码 program Project1; {$APPTYPE CONSOLE} var A,B,C,D,E,F:integer; G,X,Y :real; yes:char; Procedure Solve; G:=A*E B*D; if G<>0 then X:=(C*E B*F)/G; Y:=(A*F C*D)/G; // 解方程的过程定义 //Main Program repeat Readln(A,B,C); Readln(D,E,F); Solve; // 过程的调用 if G=0 then Writeln(' 方程组有无穷多个解!') else Writeln('X=',x:7:2, ', Y=',y:7:2); readln(yes); until yes='n';

64 51 Delphi 程序设计基础 end. (4) 保存程序将文件保存为 Project2_11.dpr (5) 编译运行程序单击工具栏上 Run 按钮即可运行程序 运行后出现的界面如图 2-5 所示 1 输入方程组系数 A,B,C 值, 数值间用空格分隔, 按 Enter 图 2-5 例 2-11 程序运行界面键后再输入方程组系数 D,E,F 值 2 按 Enter 键后求解方程 3 若想退出程序, 按 N 键, 否则重复 1 2 (6) 程序说明这是一个比较简单的程序 它只有全程变量, 没有局部变量, 更没有任何参数 这个程序的执行部分完成三件工作 : 1 输入二元一次方程组的系数值 ; 2 解方程组, 通过过程语句实现 ; 3 输出解方程组的结果 如果退出程序, 按 N 键, 否则按任意键继续解其他方程 这个程序稍加修改后, 可以解三元一次方程组及其他线性方程组 函数的定义和调用 1. 函数的定义函数的定义与过程非常相似, 包括函数原型和函数体的定义 只是使用的保留字不同, 而且多了一个返回值类型 具体形式如下 : function 函数名 ( 参数列表 ): 返回类型 ; 指令符 ; 局部声明块 ; 语句 ; 各部分意义同过程一样 一般可以将函数要返回的数值赋值给 Result 或函数名变量 如果函数体中存在着一些由于判断而产生的分支语句时, 要在每一个分支中设置返回值 2. 函数的调用函数调用的形式为 : 函数名 ( 参数列表 ) 例 2-12 编制 阶乘 函数 分析 :n 的阶乘含义是 : JC(n)=n (n 1) (n 2) 2 1; (1) 新建应用程序启动 Delphi, 从 Fi1e 菜单中选取 New Application 命令, 开始一个新的应用文件 (2) 打开 Project1 打开 View 菜单的 Units 菜单项, 选择 Project1, 打开 Project1 (3) 输入程序

65 第 2 章 Delphi 的编程语言 52 program Project1; {$APPTYPE CONSOLE} var x,jcx:integer; yes:char; function JC(Num:Integer):integer; // 阶乘函数定义 var i,nn:integer; nn:=1; for i:=num Downto 1 do nn:=nn*i; result:=nn; // 注意, 该语句不包括在循环中 repeat Readln(x); jcx:=jc(x); // 函数的调用 Writeln('X=',x,' jc(x)=',jcx); readln(yes); until yes='n'; end. (4) 保存程序将文件保存为 Project2_12.dpr (5) 编译运行程序单击工具栏上 Run 按钮即可运行程序 运行后出现的界面如图 2-6 所示 1 输入一个正整数 2 按 Enter 键后解出 JC 函数 3 若想退出程序, 按 N 键, 否则重复 参数 图 2-6 例 2-12 程序运行界面 1. 参数的作用一般将过程 函数定义时参数列表中的参数称为形参, 将过程 函数调用时参数列表中的参数称为实参 在过程或函数原型中, 多个参数之间用分号隔开, 同一类型的参数可以放在一起, 以逗号隔开 在过程或函数调用的时候, 在过程或函数原型中, 多个参数之间用逗号隔开

66 53 Delphi 程序设计基础一般来说, 形参列表和实参列表完全匹配是指参数的个数一样, 而且顺序排列的数据类型也完全一致 对于普通的函数, 如果编译器发现实参的数据类型与形参的数据类型不匹配, 会将实参的数据类型进行一次或多次的 提升, 比如 : 将 Integer 类型转换为 Double 类型 在 Object Pascal 语言中, 参数可以分为值参数 (Value) 变量参数 (Variable) 常量参数 (Constant) 和外部参数 (Out) 默认为值参数( 传递的为值 ) 值参数总是具有确定的类型, 而其他 3 种参数可以是有类型的, 也可以是无类型的 2. 值参数值参数可以像过程或函数的本地变量一样使用, 其初值来自过程调用时的实参数, 对值参数的修改并不影响实参数 例如 : procedure test(i:integer); // 定义过程 test i:=i*2; procedure TForm1.Button1Click(Sender: TObject); var n:integer; n:=10; test(n); // 调用过程 test Edit1.Text:=inttostr(n); 在调用过程 test(n) 时, 值参数 i 由实参数 n 得到值 10, 然后 i 乘 2 在调用结束后 n 的值保持不变 3. 常量参数常量参数可以像局部的只读变量一样来使用, 其初值来自过程调用时的实参数, 实参数必须是一个表达式 在定义过程 ( 函数 ) 的形参表中的有关形参前加上保留字 CONST 不允许在过程或函数中给常量参数赋值, 并且常量参数不能作为实参数传递给另一个过程或函数 4. 变量参数若要将一个值从过程或函数传递给调用者, 则必须在定义它们时使用变量参数 这时过程或函数调用中的实参数必须是变量的引用 在过程或函数执行期间, 这个变量参数就代表了实参数, 改变了变量参数也就相应地改变了实参数 在被调用的过程 ( 函数 ) 的形参表中有关形参前加上保留字 var procedure test(var i:integer); // 定义过程 test i:=i*2; procedure TForm1.Button1Click(Sender: TObject);

67 第 2 章 Delphi 的编程语言 54 var n:integer; n:=10; test(n); // 调用过程 test Edit1.Text:=inttostr(n); 在调用过程 test(n) 时, 变量参数 i 由实参数 n 得到值 10, 然后 i 乘 2 在调用结束后,n 的值为变量参数 i 的值 数组参数过程或函数中也可以使用数组作为参数, 但不能在数组参数的定义中包含数组下标类型的定义, 可以先进行数组类型的定义, 然后利用该类型来定义数组参数 例如 : Type Tdata=array[1..100] of Integer; Procedure Sort(var a:tdata); 局部变量与全局变量我们已经看到, 过程和函数的作用之一是能够一次编写, 多处使用, 使用者不必再去研究它的功能怎样实现, 只需遵照过程 ( 函数 ) 的调用格式, 即可方便地使用 例 2-13 编写一个程序, 计算 1!+2!+3!+ +n! function jc(n:integer):integer; // 阶乘函数的定义 var i,s:integer; s:=1; for i:=1 to n do s:=s*i; result:=s; var i,n,s:integer // 主程序 readln(n); s:=0; for i:=1 to n do s:=s+jc(i); 在这里, 我们编写了主函数, 并以正确的格式加入和调用函数 jc, 至于 jc 的内部情况, 则不需要我们操心, 只要两部分程序都正确, 整个程序就应当正确, 这就是使用函数的好处

68 55 Delphi 程序设计基础然而, 如果我们仔细考察整个程序, 会对上述观点发生严重的怀疑 : 主函数中的循环使用了循环变量 i,i 从 1 递增到 n, 产生 n 个阶乘值, 并将它们相加 在每次求阶乘时, 函数 jc 要被调用 1 次, 而在 jc 的执行过程中, 循环变量 i 又要经历一轮从 1 开始的变化, 我们不难想象, 整个程序将陷入一片混乱! 怎么办? 是为函数 jc 的使用者规定一批禁止使用的变量名, 包括 i s n, 还是要求使用者必须根据自己的要求去修改 jc 中的变量名? 显然, 两种做法都要严重损害函数的使用价值 实际上,Object Pascal 语言采用限制变量作用范围 ( 作用域 ) 的方法, 从根本上解决了这个问题 Object Pascal 语言有以下的规定 : (1) 在过程 ( 函数 ) 内部声明的变量, 包括形参表中列出的形参, 称为这个过程 ( 函数 ) 的局部变量 ( 或内部变量 ); 在过程 ( 函数 ) 之外声明的变量, 称为全局变量 ( 或外部变量 ) (2) 过程 ( 函数 ) 的局部变量, 只在过程 ( 函数 ) 内部有效, 或者说, 局部变量的作用域, 是其所在的过程 ( 函数 ) (3) 全局变量, 对声明位置以后的所有过程 ( 函数 ) 有效, 或者说, 全局变量的作用域, 是从声明位置开始直到整个程序结束 (4) 如果局部变量的作用域与同名全局变量的作用域重叠, 那么, 在重叠的范围内, 那个全局变量无效 在上面那个 有问题 的程序中, 先后两次声明了变量 i, 一个是主函数的局部变量, 一个则是 jc 的局部变量, 两个函数的执行部分中使用的 i, 都是各自的局部变量, 不会相互干扰 所以, 程序能够产生预想的运行结果 例 2-11 程序中所有变量均为全局变量, 过程 Solve 中直接对全局变量进行运算 其实, 在实际编程方法中, 过程和函数中一般不直接对全局变量进行运算, 而是通过参数列表来进行参数传递, 这样有利于过程和函数的独立性 如例 2-11 的代码可改成如下形式 : program Project2_11b; {$APPTYPE CONSOLE} Procedure Solve(a1,b1,c1,a2,b2,c2:integer;var resux,resuy,g:real); g:=a1*b2 b1*a2; if g<>0 then resux:=(c1*b2 b1*c2)/g; resuy:=(a1*c2 c1*a2)/g; var A,B,C,D,E,F:integer;

69 第 2 章 Delphi 的编程语言 56 G,X,Y :real; yes:char; //Main Program repeat Readln(A,B,C); Readln(D,E,F); Solve(A,B,C,D,E,F,X,Y,G); if G=0 then Writeln(' 方程组有无穷多个解!') else Writeln('X=',x:7:2, ', readln(yes); until yes='n'; end. Y=',y:7:2); 习 题 1.Object Pascal 语言中的数据类型有哪些? 2. 输出 9 9 乘法表, 要求输出格式如图 2-7 所示 3. 输入 2 个实数 x 和 y, 输出 x y x/y 值 4. 输入 3 个整数, 使用嵌套 if 语句将 3 个整数按从小到大的顺序输出 5. 考虑 :exp(y ln(x)) 相当于什么运算? 6. 输入三角形的三条边 a b c, 求该三角形面积 7. 说明 for while 和 repeat 3 种循环语句的区别 8. 任意输入一串字符, 将其中的小写字母转换成大写字母 ( 其他字符不变 ), 并记录小写字母的个数 9. 输入 n 个数, 求数中的最大值与最小值 10. 函数和过程的区别是什么? 图 乘法表输出格式 11. 输入 n(1~9 的整数 ), 用循环和过程输出如下所示的数字塔 ( 这里 n=7) 输入 n(1~9 的整数 ), 输出如下所示的方阵 ( 这里 n=5)

70 57 Delphi 程序设计基础 输入一元二次方程 Ax 2 +Bx+C=0 的系数 A B C, 求解方程根 x1 x2 14*. 输入 n(n<100), 在 1~100 个序号中,1~100 头尾相接, 逢 n 删除, 求最后留下的 1 个的序号值

71 第 3 章 窗体设计 窗体是用户进行程序设计时的窗口, 是程序界面的框架, 是各种组件和控件及其代码的载体 因此, 窗体是 Delphi 程序开发的核心元素 本章主要介绍 : Delphi 窗体 组件 窗体属性 事件 设计窗体 窗体模板 MDI 程序及其设计 3.1 Delphi 窗体 窗体与窗口窗口是屏幕上被边框围住的一部分 窗口有标题, 而且通常有一个控制菜单, 用于移动 关闭 最大化 最小化窗口 在 Windows 中, 绝大多数用户界面都是窗口 因此, 在 Delphi 中, 大多数组件也都是基于窗口的 窗口通常可分为两类 : 主窗口与对话框 Windows 系统能识别窗口, 并为它们的操作调用函数 每当系统中有事件发生,Windows 就把相应的消息发送给对应的窗口, 该窗口通过执行代码产生响应 实际上, 每个窗口都有相应的处理过程用于处理窗口收到的各种消息 在 Delphi 中, 用窗体表示设计时的窗口, 以保持设计过程的可视性 窗体可用于创建主窗口 MDI 程序 对话框 窗体的行为主要依赖于窗口的处理代码, 也依赖于窗体的位置和尺寸属性 Delphi 的其他组件都以窗体为基础进行衍生和继承 应用程序的窗口, 通常可分为以下 3 类 重叠式窗口 : 作为应用程序的主窗口 弹出式窗口 : 通常用于对话框与消息框 只有弹出式窗口才能覆盖其他窗口 弹出式窗口与重叠式窗口非常相似 子窗口 : 通常用于不能移出父窗口客户区中的从属窗口, 如用于创建 MDI 应用程序等 另外, 对话框中的控件也属于子窗口 下面我们从介绍窗口属性开始入手, 逐步学习如何用窗体来设计应用程序 窗体属性窗体是用户设计应用程序界面的地方, 有时也将窗体称作表单 在 Delphi 中, 每个窗体

72 59 Delphi 程序设计基础都有一个窗体文件 (.DRM) 和一个单元文件 (.PAS) 窗体文件保存着窗体和窗体上各个组件的属性 ; 单元文件则是用户编写窗体的事件处理过程的地方 当开始一个新项目或创建一个新窗体时,Delphi 系统以默认的尺寸和标准来初始化窗体 用户可以在设计阶段或运行阶段设置窗体的属性 窗体的常用属性见表 3-1 表 3-1 窗体的常用属性 BorderStyle Caption Height Width Left Top Color BorderIcons ClientHeight ClientWidth Ctl3D Cursor Enabled Font Formstyle 属性说明 ActiveControl Hint ShowHint HorzScrollBar VerScrollBar HelpContext Icon 设置窗体的边界风格, 常用选项有 bsdialog( 对话框边界 ) bsnone( 无边界 ) bssingle( 单线边界 ) 和 bssizeable( 可改变大小的标准边界 )4 种 新窗体的缺省属性值为 bssizeable 也称标题属性, 用于设置显示在窗体标题栏上的文字 缺省时以 Name 属性值命名 设置窗体的高度 设置窗体的宽度 设置窗体左上角的 x 坐标 设置窗体左上角的 y 坐标 设置窗体的背景颜色 具有 4 个子属性 :bssystemmenu biminimize bimaximize 和 bihelp, 这 4 个子属性均只有 True 和 False 两种取值, 分别用于决定窗体是否拥有系统菜单 最小化按钮 最大化按钮和帮助按钮 属性值为 True, 则表示有 ; 反之则表示无 设置用户区的高度, 以像素为单位 设置用户区的宽度, 以像素为单位 有 True 和 False 两种取值, 用于决定窗体是否以三维显示 设置窗体可用的各种光标 决定窗体是否可响应事件, 只有 True 和 False 两种取值 缺省为 True, 表明窗体可响应事件, 这一属性可在运行中改变 决定窗体上所用的字体 字体颜色 字符大小及字体的一些特征, 如粗体 带下划线等等 字体属性有多个子属性, 在进行程序设计时, 这些属性可以单独设置, 也可以在 Object Inspector 中双击 Font 属性激活 Font 对话框, 在 Font 对话框中设置 即窗体风格, 有 4 种选项 :fsnormal( 标准窗口 ) fsstayontop( 窗体总是显示在其他窗体的上面 ) fsmdichild( 多文档界面程序中的子窗口 ) 和 fsmdiform( 多文档界面程序中的主窗口 ) 决定程序运行时初始焦点的控件 可在程序运行时利用该属性设置当前焦点控件, 但在某一时刻, 只能有一个焦点控件 设置窗体的弹出提示文字 决定窗体及窗体中的组件是否会显示 Hint 属性所提供的提示文字 决定窗体水平滚动条的各种属性 决定窗体垂直滚动条的各种属性 提供窗体的上下文帮助文件名 决定窗体被最小化后的显示图标 Menu 决定当前窗体要使用哪个菜单作为主菜单 ( 一个应用程序可有多个菜单资源 ) Name 命名窗体及组件对象, 所有组件都有该属性 该属性在运行时一般不可改变, 否则将产生错误 Position Visible 设置窗体的显示位置, 缺省值为 PoDesigned( 由用户设计决定 ), 另外可取值还有 PoScreenCenter( 将窗体置于屏幕中间 ) 等 决定窗体在运行时是否可见 窗体事件 事件的产生可以来自系统, 也可以来自用户 事件是一种将发生的动作与代码相连的机 制 因此事件是一个方法指针, 它指向某个类实例的方法

73 第 3 章窗体设计 60 从程序设计者的角度来看, 一个事件是一个与某种动作相关联的名字 在程序运行时, 如果发生了指定的事件, 系统就会调用这个过程来处理这个事件 在第 1 章中, 我们已经介绍了如何添加事件的方法, 设计窗体时, 在对象查看器的对象选择器列表框中选定窗体, 然后单击 Events 标签, 对象查看器中就显示出所有窗体的事件 双击属性值栏就会弹出相应事件的代码编辑窗口, 可在其中编写该事件的处理程序 下面就一些常用的事件进行说明 1.Create 和 Destroy 事件当创建窗体时, 就执行 Create 事件 ; 当释放窗体所占用的空间时, 就会执行 Destroy 事件 通常整个程序的初始化工作放在主窗体的 Create 事件中进行处理, 如读入将要用到的图形资源 对数据赋初值等, 而对资源的释放则放在主窗体的 Destroy 事件中进行处理 当创建窗体并且 Visible 属性设置为 True 时, 事件 Create Show Activate Paint 按顺序出现 2.Show 和 Hide 事件 Show 事件和 Hide 事件分别在窗体显示与隐藏时被触发 当窗体的 Visible 属性设置为 True 时, 窗体被显示, 同时触发 Show 事件 ; 当窗体的 Visible 属性设置为 False 时, 窗体被隐藏, 同时触发 Hide 事件 3.Activate 和 Deactivate 事件当激活窗体时, 就触发 Activate 事件, 当窗体不再激活时, 就会触发 Deactivate 事件 4.Click 和 DblClick 事件在窗体上 ( 光标没有在其他组件上 ) 单击, 就会触发 Click 事件 ; 在窗体上双击, 就会触发 DblClick 事件 5.DragDrop 事件在窗体上拖放操作时, 就会产生 DragDrop 事件 该事件过程的基本语法形式为 : procedure TForm.FormDragDrop(Sender,Source:TObject;X,Y:integer); 其中 Source 参数为拖动的对象,Sender 为要拖动到的对象,X 和 Y 为拖放后鼠标的位置坐标 ( 单位是像素 ) 6.KeyDown KeyUp 和 KeyPress 事件在窗体上按下键盘的任一键 (KeyDown) 或释放它 (KeyUp), 就会产生 KeyDown 和 KeyUp 事件 可以对键盘上的所有键, 包括功能键及与 Shift Alt Ctrl 的组合键进行处理 ( 但如果按下的是快捷键或者热键, 则不必编写事件处理程序, 该操作由系统来完成 ) 这两个事件过程的基本语法形式为 : procedure TForm.FormKeyDown(Sender:TObject;var Key:Word; Shift:TShiftState); procedure TForm.FormKeyUp(Sender:TObject;var Key:Word;Shift:TShiftState); Key 参数用来表示所按或释放键的键码 ;Shift 是组合键的状态, 如 Shift 键 (ssshift) Alt 键 (ssalt) Ctrl 键 (ssctrl) 等 在窗体上按下单个的字母键, 就会产生 KeyPress 事件 该事件过程的基本语法形式为 : procedure TForm.FormKeyPress(Sender:TObject;var Key:Char); Key 参数为所按字母键所代表的字符 对非 ASCII 码键及组合键使用 KeyDown 或 KeyUp 事件进行处理

74 61 Delphi 程序设计基础 7.MouseDown MouseUp 和 MouseMove 事件在窗体上按下或释放任一鼠标键时, 就会出现 MouseDown 和 MouseUp 事件 这两个事件过程的基本语法形式为 : procedure TForm.FormMouseDown(Sender:TObject;Button:TMouseButton; Shift:TShiftState; X,Y:Integer); Procedure TForm.FormMouseUp(Sender:TObject; Button:TMouseButton; Shift:TShiftState; X,Y:Integer); Sender 参数指定产生鼠标事件的组件对象 ;Button 参数表示按下哪一键 ;Shift 表示哪一组合键 (Shift Ctrl 及 Alt 键 ) 与鼠标键按下和释放 ;X 和 Y 是鼠标指针的位置坐标 ( 单位是像素 ) 在窗体上移动鼠标, 就会产生 MouseMove 事件 该事件过程的基本语法形式为 : procedure TForm.FormMouseMove(Sender:TObject; Shift:TShiftState;X,Y:Integer); 使用 Shift 参数可以对鼠标键与组件键 (Shift Ctrl 和 Alt) 的组合进行处理 ;X 和 Y 为鼠标指针的位置坐标 ( 单位是像素 ) 8.Resize 事件在调整窗体的大小时, 就会触发 Resize 事件 3.2 设计窗体 Delphi 组件是用户进行窗体设计必不可少的元素 Delphi 组件分为控件和非控件两类 控件也称可见组件, 是指在运行时能以设计时的形状显示出来的组件 ; 非控件也称不可见组件, 是指在运行时不可见或是需要一些代码才能显现的组件 常用的控件有标签 文本框 按钮等, 非控件有菜单设计器组件 计时器组件 对话框组件等 每一个组件都有自己的属性, 有些属性可以在设计或运行时设置, 而有些属性只能在设计时进行设置, 还有一些属性是只读的 下面通过例子来介绍设计窗体的步骤 例 3-1 窗体设计 新建窗体设计窗体的第一步当然是新建空白窗体 单击 New 菜单下的 New Application 命令开始一个新项目, 此时会新建一个名为 Form1 的空白窗体 如果要在当前项目中新建一个空白窗体, 可以单击 File 菜单下的 New Form 命令, 或单击工具栏上的 New Form 按钮 设置窗体属性新建窗体后, 就该设置窗体的属性了 设置窗体属性通常利用 Object Inspector 来进行 在第 1 章曾经详细介绍了如何进行属性的设置, 故不再赘述 这里我们将窗体的 Caption 属性设置为 资料, 字体设置为 宋体 小五号 另外, 可以用鼠标拖动窗体边界来调整窗体大小

75 第 3 章窗体设计 添加组件设置窗体属性后, 就该往窗体中添加组件了 从组件板上往窗体添加组件通常有 3 种方法 : (1) 双击组件板上的组件图标,Delphi 将把组件以缺省的标准和大小放在窗体正中间 (2) 在组件板上单击组件图标, 选中组件, 再在窗体中想放置组件的位置的左上角单击一下窗体,Delphi 将以缺省的大小把组件放置在那里 如果想在添加组件的同时设置组件的大小, 可将组件添加到窗体中后, 单击选中组件, 这时组件四周将会出现 8 个黑色方块的控点 在某一控点上按住鼠标左键, 拖动鼠标, 这时会出现一个矩形方框, 表示调整后组件的大小 如果方框的大小合适, 释放鼠标, 组件会按矩形方框的大小和形状放置在窗体中 注意 : 非控件组件的大小和形状不能任意改变, 它们在窗体中的大小和形状由系统决定 可以往窗体中添加所需的组件, 添加组件时, 如果不知道组件在组件板的哪一个选项卡, 可以单击 View 菜单下的 Component list 命令, 打开一个 Components ( 组件列表 ) 对话框, 如图 3-1 所示 从该对话框中可以找到所需组件 (3) 如果想在窗体上添加多个相同组件, 可按住 Shift 键, 再单击要添加的组件, 把鼠标移到窗体上, 然后每单击一次鼠标即可放置一个组件, 连续单击鼠标, 可以放置多个组件, 直到不想放置为止 最后用鼠标单击组件板上左侧的箭头标志按钮, 就可脱离连续 放置状态 本例向窗体中加入 3 个 Label 组件 Label1~Label3,2 个 Edit 图 3-1 Components 对话框 组件 Edit1 和 Edit2, 一个 RadioGroup 组件 RadioGroup1, 一个 ComboBox 组件 ComboBox1, 一个 UpDown 组件 UpDown1 和 2 个 Button 组件 Button1 和 Button 编辑组件添加组件后, 还要对组件进行适当编辑, 包括选定组件 调整组件大小和位置 对齐组件, 以及对组件进行删除 复制 剪切和粘贴操作 1. 选定组件要编辑组件, 首先得选定组件 选定组件可分为选定单个组件和选定多个组件两种 选定单个组件又有两种情况 : 若组件在窗体最表面 ( 即可见 ), 此时, 单击组件, 该组件四周会出现 8 个黑色小方块的控点表示该组件被选定 若组件被另一个组件完全覆盖, 此时要选定组件, 得先右击覆盖该组件的组件, 打开一快捷菜单, 再选择 Send To Back 命令, 这样可将被覆盖的组件传送到窗体表面, 并选定该组件 或从 Object Inspector 窗口的组件下拉列表中选定该组件的名称 如果要选定多个组件, 可以有如下两种方法 按住鼠标左键, 拖动鼠标, 此时将会出现一个选线矩形框, 使要选定的组件被方框所

76 63 Delphi 程序设计基础包含, 释放鼠标即可 按住 Shift 键, 依次单击要选定的组件 选定多个组件后, 这些组件即形成一整体 可同时进行移动 删除 复制等操作 2. 调整大小要调整组件的大小, 可先选定组件, 将鼠标放在组件周围的某个控点上, 按住鼠标左键并拖动鼠标, 即可改变组件的大小 选定组件后, 按住 Shift 键, 同时按 键可精确调整组件的尺寸 另外, 可以通过在 Object Inspector( 对象查看器 ) 中设置组件的 Height 和 Width 属性来调整组件的大小 3. 调整位置调整组件的位置和调整组件大小的操作基本相同 方法是先选定组件, 在组件 8 个控点形成的方框内按住鼠标左键并拖动鼠标, 就可以将组件拖到所需位置 选定组件后, 按住 Ctrl 键, 同时按 键可精确调整组件的位置 另外, 可通过在 Object Inspector( 对象查看器 ) 中设置组件的 Left 和 Top 属性来调整组件的位置 4. 对齐组件为了使窗体整洁 美观, 经常需要把一系列组件横向对齐或纵向对齐 如果要对齐组件, 可执行如下操作 (1) 选定要对齐的多个组件 (2) 执行如下操作之一, 打开 Alignment 对话框, 如图 3-2 所示 图 3-2 Alignment 对话框图 3-3 Align 工具栏 1 单击 Edit 菜单下的 Align 命令 2 用鼠标右键单击窗体, 打开一快捷菜单, 再选择 Align 命令 (3) 根据需要, 选择如下操作 1 如果要水平对齐 在 Horizontal 选项组中选择对齐方式, 对齐方式有 Left sides ( 左对齐 ) Centers ( 居中对齐 ) Right sides ( 右对齐 ) Space equally ( 水平均匀分布 ) Center in window ( 组件在窗口横向居中 ) 2 如果要垂直对齐 在 Vertical 选项组中选择对齐方式, 对齐方式有 Tops ( 顶端对齐 ) Centers ( 居中对齐 ) Bottoms ( 底端对齐 ) Space equally ( 垂直均匀分布 )

77 第 3 章窗体设计 64 Center in window ( 组件在窗口纵向居中 ) 单选按钮 (4) 单击 OK 按钮 另外, 可以在选定要对齐的组件后, 单击 View 菜单下的 Align Palette 命令, 打开 A1ign 工具栏, 如图 3-3 所示, 再从工具栏单击所需按钮即可 5. 删除组件如果要删除不合适的组件, 可在选定组件后, 按 Delete 键, 或单击 Edit 菜单下的 Delete 命令 删除单个组件和删除多个组件的操作完全相同 如果错删了组件, 可用 Edit 菜单下的 undelete 命令恢复 但如果删除组件后进行了其他编辑工作, 则无法恢复 6. 复制 剪切和粘贴组件复制 剪切和粘贴组件分别使用 Edit 菜单下的 Copy Cut 和 Paste 命令 另外, 可直接在窗体文件中复制 ( 删除 剪切 ) 组件 右击窗体, 可打开一个快捷菜单, 从中选择 View as Text 命令, 可打开窗体文件, 窗体文件中有窗体中所有组件及其属性的描述 将需要复制 ( 删除 剪切 ) 的组件的代码复制 ( 删除 剪切 ), 其实质即是复制 ( 删除 剪切 ) 组件 在窗体文件中复制 ( 删除 剪切 ) 组件完毕后, 鼠标右键单击文件, 打开快捷菜单, 从中选择 View as Form 命令, 即可返回窗体窗口 7. 锁定组件窗体设计好后, 为了确保窗体中的各个组件的位置不会因为不小心而改动, 可以将组件锁定, 组件锁定后窗体就不能再移动或改变大小, 除非解除锁定 如果要锁定组件, 单击 Edit 菜单下的 Lock Controls 命令 再次单击该命令则可解除锁定 设置组件属性对各个组件按需要设置属性, 本例设置内容见表 3-2 表 3-2 例 3-1 组件属性 组 件 属 性 属 性 值 组 件 属 性 属 性 值 Label1 Caption 姓名 : Edit1 Text 空串 Label2 Caption 职称 : Edit2 Text 空串 Label3 Caption 年龄 : UpDown1 Associate Edit2 Button1 Caption 确定 高级工程师 Button2 Caption 取消 RadioGroup1 Items 男女 ComboBox1 Items 工程师助理工程师技术员 各组件属性的意义我们将在第 4 章讲述, 设置完组件属性后, 界面如图 3-4 所示 Tab 顺序 Tab 顺序是指在运行时用 Tab 键将控件组件切换成当前活动组件时所要遵循的顺序 设置 Tab 顺序有两种方法 第一种方法是在 Object Inspector( 对象查看器 ) 上通过设置

78 65 Delphi 程序设计基础组件的 TabOrder 属性值来达到目的 排在第一位的组件的 TabOrder 属性值为 0, 其余依次递增 第二种修改 Tab 顺序的方法是单击 Edit 菜单下的 Tab Order 命令, 或右击窗体, 从快捷菜单中选择 Tab Order 命令, 打开 Tab Order 对话框, 如图 3-5 所示 该对话框以 Tab 顺序将组件依次排列 如果要改变组件的 Tab 顺序, 先选定该组件, 然后单击对话框右边的上下箭头按钮, 移动该组件到适当位置 图 3-4 例 3-1 设计的窗体图 3-5 Tab Order 对话框 创建顺序创建顺序和 Tab 顺序意义相似, 不同的是,Tab 顺序用于控件型组件, 而创建顺序则用于非控件型组件 通常创建顺序决定创建窗体时非控件型组件被创建的顺序 同样, 设置创建顺序的方法是 : 单击 Edit 菜单的 Creation Order 命令, 或鼠标右键单击窗体, 从快捷菜单中选择 Creation Order 命令, 打开 Creation Order 对话框, 界面类似图 3-5 所示的 Tab Order 对话框 该对话框以创建顺序将组件依次排列 如果要改变组件的创建顺序, 先选定该组件, 然后单击对话框右边的上下箭头按钮, 移动该组件到适当位置 窗体网格缺省情况下窗体都带有网格 此时, 移动和改变窗体中组件的位置和大小都要以网格的单元格为单位 这种情况下, 对精确排列 对齐组件有时很不方便, 因此, 有时需要使窗体的网格无效 如果要使网格无效, 单击 Tools 菜单下的 Environment Options 命令, 打开 Environment Options 对话框, 并选择 Designer 选项卡, 如图 3-6 所示 在 Grid options 选项组进行窗体的网格设置, 选项组中选项功能如下 Display grid 复选框 : 使窗体显示网格 Snap to grid 复选框 : 在窗体中移动组件和改变组件的大小都以网格间距为单位, 否则可任意移动组件和改变组件大小 Grid size X 编辑框 : 设置网格单元格的宽 ( 以像素为单位 ) Grid size Y 编辑框 : 设置网格单元格的高 ( 以像素为单位 ) Show component captions 复选框 : 设计时显示非控件型组件的标题 (caption) 选择该项可清楚地识别非控件型组件

79 第 3 章窗体设计 66 图 3-6 Environment Options 对话框 Show designer hints 复选框 : 设计时, 将鼠标移动到某个组件上, 就可以显示该 组件的名称及所属的类 图 3-7 Save Unit As 对话框图 3-8 Save Project As 对话框 保存文件窗体设计完后, 要保存项目文件和单元文件, 以便以后修改 保存单元文件方法是, 单击 File 菜单中 Save As 命令项, 打开 Save Unit As 对话框, 如图 3-7 所示, 选择指定文件夹和文件名, 单击 保存 按钮 保存项目文件方法是, 单击 File 菜单中 Save Project As 命令项, 打开 Save Project As 对话框, 如图 3-8 所示, 选择指定文件夹和文件名, 单击 保存 按钮 将例 3-1 单元文件保存为 Unit3_1.pas, 将项目文件保存为 Project3_1.dpr

80 67 Delphi 程序设计基础 3.3 窗体模板 有一些窗体设计已形成约定俗成的规范, 此时如果每次设计窗体时都重新设计, 不仅浪费时间, 而且难以保证符合规范, 对于这一种情况,Delphi 提供了窗体模板 下面介绍窗体模板的使用 窗体模板位于对象库中 单击 File 菜单中的 New 级联菜单下 Other 命令, 打开 New Items 对话框 ( 即对象库 ), 并选择 Forms 选项卡, 如图 3-9 所示 对象库共提供了 3 种窗体模板, 另外, 还提供了复制 继承 使用 3 种应用窗体模板的方式, 分别对应于对话框底部的 Copy Inherit 和 Use 单选按钮 这 3 种方式的含义如下 复制方式 :Delphi 将把窗体模板文件 (.DFM) 和单元文件 (.PAS) 复制一份, 并以缺省的 Formn.DFM 图 3-9 New Items 对话框 和 Unitn.PAS 来命名所生成的窗体和单元文件 (n 表示某一个数字 ), 将它们放入当前项目中 继承方式 :Delphi 将以窗体模板所定义的类为基类, 派生出一个新的窗体类, 并把派生窗体的 DFM 文件和 PAS 文件用缺省名放入项目中 使用方式 :Delphi 将在项目文件 (.DPR) 中的 Uses 语句中声明窗体模板的单元文件 该窗体并没有复制到项目中 但编译项目时,Delphi 将根据项目文件 (.DPR) 中的声明, 把窗体模板的文件一起编译链接 对象库共提供了 3 种窗体模板, 其功能如下 About Box 模板 : 标准的 About 对话框, 常用于显示应用程序的名称 版本和版权信息等 Dual List Box 模板 : 有两个列表框的窗体, 可在两个列表框之间相互移动选项 Tabbed Pages 模板 : 多页窗体 用户除了可以利用系统提供的窗体模板外, 也可以创建窗体模板 如果要创建窗体模板, 执行如下操作 (1) 新建并设计一个窗体 (2) 鼠标右键单击窗体, 打开一个快捷菜单 (3) 单击 Add to Repository 命令, 打开 Add to Repository 对话框, 如图 3-10 所示 (4) 在 Title 编辑框输入窗体模板的名称 (5) 在 Description 编辑框输入窗体模板的描述 (6) 在 Page 下拉框中选择 Forms (7) 在 Author 编辑框输入作者姓名 (8) 单击 Browser 按钮, 选择窗体模板的图标 (9) 单击 OK 按钮, 保存窗体模板 这样, 下次再打开 New Items 对话框的 Forms 选项卡, 就会发现其中有用户所创

81 第 3 章窗体设计 68 建的窗体模板 图 3-10 Add to Repository 对话框 3.4 运行时改变窗体 窗体和组件的属性可以分为两种情况, 第一种情况是在设计窗体时设定属性, 在运行时不允许修改 ; 第二种情况是可以在设计窗体时设定属性, 也可以在运行时设定属性, 也就是说可以在运行时修改属性值 另外, 还可以根据需要在运行时创建组件 运行时设置属性例 3-2 在运行时设置组件的属性 其创建过程如下 (1) 新建应用程序启动 Delphi, 从 File 菜单中选取 New Application 命令, 开始一个新的应用文件 此时, 应用程序将有一缺省的窗体 Form1 (2) 设置窗体属性窗体的属性见表 3-3 表 3-3 例 3-2 窗体的属性 属 性 属 性 值 Caption 运行时设置属性 Height 304 Left 200 Top 120 Width 302 (3) 向窗体中添加组件窗体中添加 1 个 GroupBox 组件 GroupBox1,3 个按钮组件 Button1 Button2 Button3,1 个 RadioGroup 组件 RadioGroup1,1 个 ColorDialog 组件 ColorDialog1,1 个 FontDialog 组件 FontDialog1 和 1 个 Memo 组件 Memo1 添加组件后窗体布局如图 3-11(a) 所示 (4) 设置组件属性窗体中的组件属性见表 3-4

82 69 Delphi 程序设计基础 表 3-4 组件属性 组 件 名 称 属 性 属 性 值 GroupBox GroupBox1 Caption 改变文本 Button Button1 Caption 颜色 Button2 Caption 字体 Button3 Caption 内容 RadioGroup RadioGroup1 Caption 对齐 ColorDialog ColorDialog1 FontDialog FontDialog1 Memo Memo1 Lines 睡觉大地公公睡觉, 静悄悄 月亮婆婆睡觉, 眯眯笑 老爷爷睡觉, 胡子翘 小娃娃睡觉, 呼噜呼噜, 像只大花猫 (a) 图 3-11 运行时设置属性 (b) (5) 添加事件 窗体 组件添加的事件见表 3-5 表 3-5 组件事件 组 件 事 件 事件响应函数 Button1 OnClick Button1Click Button2 OnClick Button2Click Button3 OnClick Button3Click RadioGroup1 OnClick RadioGroup1Click (6) 编写事件响应代码编写 Button1 Button2 Button3 RadioGroup1 的 OnClick 事件的响应代码 :

83 第 3 章窗体设计 70 procedure TForm1.Button1Click(Sender: TObject); with ColorDialog1 do Color:=Memo1.Color; if Execute then Memo1.Color:=Color; // 设置颜色 procedure TForm1.Button2Click(Sender: TObject); with FontDialog1 do Font:=Memo1.Font; if Execute then Memo1.Font:=Font; // 设置字体 procedure TForm1.Button3Click(Sender: TObject); Memo1.Lines.Text:=' 布娃娃要睡觉 '+chr(13)+chr(13)+ ' 布娃娃,'+chr(13)+' 要睡觉 '+chr(13)+ ' 小棉被,'+chr(13)+' 盖盖好,'+chr(13)+ ' 伸出脚丫 '+chr(13)+' 乘风凉,'+chr(13)+ ' 阿嚏一声,'+chr(13)+' 吓走小花猫 '; // 修正内容 //chr(13) 为回车符 procedure TForm1.RadioGroup1Click(Sender: TObject); // 对齐设置 case RadioGroup1.ItemIndex of 0:Memo1.Alignment:=taLeftJustify; 1:Memo1.Alignment:=taCenter; 2:Memo1.Alignment:=taRightJustify; (7) 保存程序将单元文件保存为 Unit3_2.pas, 将项目文件保存为 Project3_2.dpr

84 71 Delphi 程序设计基础 (8) 编译运行程序单击工具栏上 Run 按钮即可运行程序 运行后 : 单击 颜色 按钮, 在 颜色 对话框中选择黑色, 文本背景色由白色变为黑色 ; 单击 字体 按钮, 在 字体 对话框中选择 10 号大小 白色, 文本字符由 8 号字变为 10 号字 由黑色变为白色 ; 单击 内容 按钮, 文本内容变为 布娃娃要睡觉 ; 单击 居中 单选按钮, 文本排列由左对齐变为居中 其效果如图 3-11(b) 所示 运行时创建组件 Delphi 还允许用户在运行程序时根据需要创建自己的组件 这种方法与在设计时添加组件相比, 具有更大的灵活性, 而且能够节省内存 这是因为, 运行创建的组件可以在不需要时删除 下面仍以例 3-2 来说明, 假设我们预先没有添加 ColorDialog 组件, 而在运行时创建 ColorDialog 组件, 则可将例 3-2 中原来添加的 ColorDialog 组件删除, 将 Button1 的 OnClick 的事件响应函数变为 : procedure TForm1.Button1Click(Sender: TObject); Var ColorDialog1:TColorDialog; ColorDialog1:=TcolorDialog.Create(Form1); with ColorDialog1 do Color:=Memo1.Color; if Execute then Memo1.Color:=Color; ColorDialog1.Free; 从上面的代码可以看出, 运行时创建组件可分为 3 个步骤 : (1) 组件的变量声明, 即用要创建的组件对应的类声明一个组件对象 例程中用组件 ColorDialog 对应的类 TColorDialog 声明了组件对象 ColorDialog1 (2) 创建组件, 即调用该组件类的 Create 方法, 该方法引用的参数表明该组件被谁拥有 例程中的参数为 Form1, 表明该组件创建后由 Form1 窗体拥有 (3) 释放组件, 即调用组件的 Free 方法, 释放掉组件所占的内存 运行时, 同原来效果相同 3.5 MDI 程序 MDI 是 Multiple Document Interface 的缩写, 意思是多文档界面 MDI 程序能够同时打

85 第 3 章窗体设计 72 开多个文档, 例如,Microsoft Word 可以同时编辑多个文本 一个 MDI 程序至少应包括两种类型的 Form: 一个是 父 Form, 它的 FormStyle 属性应当设为 fsmdiform; 另一个是 子 Form, 它的 FormStyle 属性应当设为 fsmdichild 如果 FormStyle 属性设为 fsnormal, 表示是一般 Form MDI 窗体 1. 父 Form MDI 程序需要有一个公共的区域显示多个文档并在这些文档之间切换, 这个公共的区域称为 父 Form 或框架, 在这个框架内被打开的文档称为子窗口 一个 MDI 程序只能有一个 父 Form, 但可以有多个子窗口, 子窗口的类型可以是不同的 可以把项目中任意一个 Form 的 FormStyle 属性指定为 fsmdiform 但是, 如果没有同时把这个 Form 指定为程序的主 Form, 编译将出错 要把一个 Form 指定为主 Form, 可以使用 Project 菜单上的 Options 命令打开 Project Options 对话框, 如图 3-12 所示, 点击 Forms 标签, 在 Main Form 框内选择一个 Form 作为主 Form 反过来, 应用程序的主 Form 的 FormStyle 属性不能设为 fsmdichild 也就是说, 主 Form 不能是 MDI 的子窗口 2. 子 Form 要创建一个 子 Form, 首先要使用 File 菜单上的 New Form 命令向项目中加入一个新的 Form, 把这个 Form 的 FormStyle 特性设为 fsmdichild 项目中任何一个 Form 的 FormStyle 特性可以设为 fsmdichild 不过, 如果同时又把它指定 为程序的主 Form, 编译将出错 可以有多个 子 Form 在一个 父 Form 中打开 创建子窗体 1. 启动时静态建立子窗体 图 3-12 Project Options 对话框 在 Project Options 对话框的 Forms 选项卡上有一个 Auto-create forms 列表框, 凡是出现在这个列表框中的 Form, 在程序启动时将自动创建, 我们称之为静态建立 Auto-create forms 框中列出的是由 Delphi 自动创建的窗体, Available forms 框中列出的是不由 Delphi 自动创建的窗体 如果希望子窗体不在启动时自动建立, 而是在运行期动态创建, 就应当把 子 Form 从 Auto-create forms 列表框中移走, 移到 Available Forms 列表框中 可以从项目文件中体会到它们的区别 假设有两个 Form, 其中 Form1 是 父 Form, Form2 是 子 Form, 如果把 Form2 放在 Auto-create forms 列表中, 该程序运行时 Form2

86 73 Delphi 程序设计基础将自动打开, 项目文件的示例如下 : program Project1; uses Forms, Unit1 in 'Unit1.pas' {Form1}, Unit2 in 'Unit2.pas' {Form2}; {$R *.RES} Application.Initialize; Application.CreateForm(TForm1, Form1); // 语句 1 Application.CreateForm(TForm2, Form2); // 语句 2 Application.Run; end. 如果把 Form2 放在 Available forms 列表中, 该程序运行时 Form2 将不打开, 项目文件中语句 2 将不存在 2. 运行期动态建立子窗体如果一个 子 Form 没有出现在 Auto-create Forms 列表框中, 这意味着必须在运行期动态创建这个 Form 的实体 要在运行期创建子 Form, 程序示例如下 : procedure TmainForm.CreateMDIChild(Const Name:String); var Child:TMDIChild; Child:=TMDIChild.Create(Application); Child.Caption:=Name; procedure TmainForm.FileNewItemClick(Sender:TObject); CreateMDIChild('NONANE'+IntToStr(MDIChildCount+1)); 在实际的 MDI 程序中, 文件 菜单上的 新建 命令一般用于创建子窗体 CreateMDIChild 首先声明一个 TMDIChild 类型的变量, 然后调用 Create 来创建 TMDIChild 类型的一个实体, 并把它赋给 Child 变量, 最后设置这个子窗口的标题 MDI 的属性和方法窗体中有一些专门用于 MDI 的属性和方法, 可以控制子窗口的操作和状态 1.MDI 的主要属性 (1)WindowMenu 属性

87 第 3 章窗体设计 74 在 Word 的主菜单 窗口 的下拉菜单中, 在横线下面显示的是已打开的子窗口标题, 有 的是当前子窗口, 如果要切换子窗口, 只需单击窗口名即可 这项功能在 Delphi 中只需设置主窗口的 WindowMenu 属性为对应的菜单项即可完成, 程序员不用写任何代码 (2)ActiveMDIChild 属性 ActiveMDIChild 为只读属性, 获得当前活动的子窗口 (3)MDIChildren 和 MDIChildCount 属性 MDIChildren 属性保存了主窗口中的所有子窗口, 它是一个数组, 下标类型为整型, 从 0 开始, 表示各子窗口的索引, 元素类型为 TForm, 记录着子窗口的类实例 在 MDIChildren 数组中, 子窗口的顺序与其生成的顺序正好相反, 即 MDIChildren[0] 返回最后生成的子窗口 MDIChildCount 属性记录着子窗口的个数 MDIChildren[MDIChildCount 1] 返回第 1 个生成的子窗口 2.MDI 的主要方法 (1)Next 和 Previous 方法 Next 和 Previous 方法用于改变当前获得焦点的子窗口 Next 将焦点移到下一个子窗口中, Previous 将焦点移到前一个子窗口中 (2)Cascade 和 Tile 方法 Cascade 和 Tile 方法可设置子窗口的级联 分隔排列方式 Cascade 是 MDI 子窗口的一种排列方式, 它使所有子窗口重叠显示, 后面的窗口都只能见到前面窗口的标题栏 Tile 也是 MDI 子窗口的一种排列方式, 它使所有子窗口都可见, 有相同的大小, 且平均分隔主窗口的客户区 (3)ArrangeIcons 方法 ArrangeIcons 方法排列最小化的子窗口图标, 使得它们整齐排列且不互相重叠 MDI 的菜单设计 1. 合并菜单 MDI 的主窗口和子窗口都可以带有自己的菜单 工具栏 状态栏等 程序启动后, 最初只有主窗口被激活, 系统显示主窗口的菜单, 当创建子窗口之后, 系统就将主窗口和子窗口的菜单合并起来显示, 而其他控件仍在各自的窗口上显示 通常主窗口上的菜单用于操纵子窗口或显示子窗口的状态, 子窗口上的菜单仅对子窗口进行有效的操作 合并后各菜单项的显示次序是按照菜单项的 GroupIndex 属性值自动从小到大排列的 GroupIndex 值越小, 菜单项出现越靠左 如果子窗口和主窗口的菜单项中有两个的 GroupIndex 相同, 合并后, 子窗口的菜单项将替换主窗口的菜单项 2. 建立 窗口 菜单建立主窗口的 窗口 菜单, 可以采用以下两种方式 一种是建立 窗口 菜单下 级联 等多个子菜单, 在菜单项的 OnClick 事件处理程序中, 调用窗口的 Cascade 等方法, 按级联等方式排列当前打开的所有子窗口 例如 : FormMain.Cascade; // 级联方式排列子窗口

88 75 Delphi 程序设计基础另一种更快捷的方式是使用 ActionList 组件 将系统定义的 Window 组的 WindowCascade 等行为加入到 ActionList 组件中, 相应的菜单项只要将其 Action 属性值选择某个行为 ( 如 WindowCascadel) 即可, 而不需写程序 下面, 我们通过例子来体会 MDI 程序的应用, 由于例子中一些组件将在以后几章中介绍, 可以不必详细理解, 或可在学完第 7 章后再理解本例中的一些细节 例 3-3 建立 MDI 应用程序 本例介绍如何建立 MDI 应用程序 设计时的 MDI 主窗体与子窗体如图 3-13 所示 操作步骤如下 图 3-13 例 3-3 界面设计 (1) 建立主窗体新建应用程序, 设置窗体的 Name 属性值为 FormMain,FormStyle 属性值为 fsmdiform, 成为 MDI 应用程序的主窗体 添加 MainMenu1 ToolBar1 StatusBar1 等组件, 为相应组件添加菜单项或按钮等, 具体操作省略 (2) 建立子窗体模板执行 File 菜单下 New Form 菜单项新建一个窗体,Name 属性值设置为 FormChild, FormStyle 属性值设置为 fsmdichild, 则它成为 FormMain 的子窗体 添加 RichEditl MainMenu1 等组件, 为 MainMenu1 添加 编辑 等菜单项 将 Project 文件中创建子窗体的语句删除, 或执行 Project 菜单中 Options 菜单项, 选中 FormChild, 执行 > 按钮, 将 FormChild 移到右边的 Available Forms 框中 则在程序启动时, 不会自动创建 FormChild 子窗体, 而必须由程序在运行时动态创建 保存主窗体 子窗体的单元文件分别为 Unit3_3.pas 和 Unit3_3_2.pas (3) 动态建立与释放子窗口在主窗体 FormMain 的单元文件中说明使用子窗体的单元 在主窗体的 文件 菜单中 新建 菜单项上写如下程序, 当执行该菜单项时, 系统将动态创建子窗口, 并将子窗口计数值显示在窗口标题上 implementation uses Unit3_3_2; // 说明使用子窗体的单元 {$R *.dfm}

89 第 3 章窗体设计 76 procedure TForm1.N1Click(Sender: TObject); var achild:tformchild; // 创建子窗口 achild:=tformchild.create(application); achild.caption:=' 文档 '+IntToStr(MDIChildCount); 关闭子窗口时, 必须释放子窗口所占的内存, 而不是让其最小化, 则需在子窗体的 OnClose 事件上写如下程序 : procedure TFormChild.FormClose(Sender: TObject; var Action: TCloseAction); Action:=caFree; (4) 菜单合并主窗体的主菜单中有 文件 查看 窗口 帮助 等菜单项, 将它们的 GroupIndex 属性值分别设为 , 文件 菜单项下有 新建 打开 保存 关闭 等对子窗口的操作 子窗体的主菜单中有 编辑 菜单项, 将它的 GroupIndex 属性值设置为 2 编辑 菜单项下有 剪切 复制 粘贴 等仅用于对子窗口中的文本进行操作的菜单项 运行时, 最初只显示主窗口的菜单项, 当新建子窗口后, 就显示合并起来的 5 个菜单项, 顺序依次是 文件 编辑 查看 窗口 帮助 (5) 在菜单中列出打开的文档将 窗口 菜单项的 Name 属性值设为 Window1, 将主窗体 FormMain 的 WindowMenu 属性值选择为 Window1, 意为将运行时创建的子窗口名挂在 窗口 菜单项之下 (6) 主窗体的 窗口 菜单项设计主窗体上添加 ActionListl 组件, 双击 ActionList, 从右击的快捷菜单中执行 New Standard Action 菜单项, 加入 Window 组的 WindowCascade1 WindowTileHorizontal1 WindowTileVertical1 等方法, 将 窗口 菜单项下的 级联 横向平铺 纵向平铺 的 Action 属性值分别选择为 WindowCascade1 WindowTileHorizontal1 WindowTileVertical1, 则程序运行时, 子窗口可以按级联 横向平铺等方式排列, 如图 3-14 所示 (7) 使用 self 在子窗体的 OnActivate 事件上写如下程序, 如当 图 3-14 例 3-3 运行界面及 窗口 菜单 子窗口激活时, 在主窗口的状态栏上显示 共有多少个子窗口, 当前活动的子窗口是哪个 的信息 procedure TFormChild.FormActivate(Sender: TObject);

90 77 Delphi 程序设计基础 FormMain.StatusBar1.SimpleText:=' 共有 '+IntToStr(FormMain.MDIChildCount) +' 个子窗口, 当前活动的子窗口是 :'+Self.Caption; 注意 : 程序运行时, 打开的多个子窗口是子窗体类 TFormChild 的多个对象, 每个子窗口的标题是动态生成的, 各不相同, 如文档 1 文档 2 等 这时要显示当前活动的子窗口的标题, 必须使用 self.caption 来指代当前被激活的这个对象, 而非别的对象 如果使用 FormChild.Caption, 则显示子窗体的静态标题 FormChild (8) 主窗体的 文件 菜单 文件 菜单中 退出 菜单项用于退出应用程序, 程序如下 : procedure TFormMain.X1Click(Sender: TObject); Close; 文件 菜单中 关闭 菜单项用于关闭当前活动的子窗口, 程序如下 : procedure TFormMain.C1Click(Sender: TObject); self.activemdichild.close; // 关闭当前活动的子窗口 文件 菜单中 打开 菜单项用于打开指定的文件 如果指定的文件已打开, 则将文件所在的子窗口激活, 否则新建子窗口, 这样保证文件不被重复打开 程序如下 : procedure TFormMain.O1Click(Sender: TObject); var achild:tformchild; i:integer; find:boolean; if OpenDialog1.Execute and FileExists(OpenDialog1.FileName) then // 执行打开文件对话框且文件存在时 i:=mdichildcount; // 当前打开的子窗口总数 find:=false; while not find and (i>=0) do // 判断选中文件是否已打开 if MDIChildren ''i''.caption=opendialog1.filename // 如果已打开 then MDIChildren ''i''.show; // 激活相应子窗口 Find:=true; end else

91 第 3 章窗体设计 78 i:=i 1; if not find // 如果选中文件未打开 then achild:=tformchild.create(application); // 创建新的子窗口 achild.richedit1.lines.loadfromfile(opendialog1.filename); achild.caption:=opendialog1.filename; // 子窗口标题为文件名 习 题 1. 应用程序的窗口通常可分为哪几类? 2. 窗体的位置用什么属性表示? 窗体的大小用什么属性表示? 3. 窗体的标题栏内容在什么属性中设置? 4. 如何往窗体中添加组件? 5. 如何在窗体中直接用键盘对组件调整位置和调整大小? 6. 你认为窗体模板可带来什么好处? 7. 在窗体网格中 Grid size X Grid size Y 设置得太大或太小会给界面设计带来什么不便? 8. 举例说明, 你经常使用的应用程序中, 哪些应用程序是一般窗体的? 哪些应用程序是 MDI 窗体的? 9. 在 MDI 窗体中, 如何实现子窗体的静态建立和动态建立? 10. 如何实现在主窗体的菜单中动态显示子窗体标题?

92 第 4 章 Delphi 的基本组件 Delphi 为用户提供了大量组件, 利用这些组件可以提高应用程序的开发效率 除了特殊功能的组件外, 常用组件按作用可分为以下 4 种基本类型 ( 有些组件兼具多种类型特点 ) (1) 命令型组件 用于激活动作, 发出命令 如按钮 位图按钮等 (2) 显示型组件 用于显示数据 如标签 编辑框 复文本编辑框 掩码编辑框 存储框 列表框 组合框等 (3) 选择型组件 用于列出选项供选择 如单选按钮 复选框等 这些组件可用成组框来进行分组 (4) 装饰型组件 用于装饰需求的组件 如位图按钮 几何图形组件 图片组件等 另外, 组件根据可视性可分为控件和非控件两大类 而控件又分为窗口控件和非窗口控件两类 窗口控件指控件在运行时可获得输入焦点 ( 如按钮 编辑框 ) 当用 Tab 键切换时, 输入焦点将在窗口控件中转移 获得输入焦点的窗口组件可接受用户利用鼠标或键盘的输入 非窗口控件指的是运行时不能获得输入焦点的控件, 如标签 成组框等 本章按组件的形式分类, 依次讲解如下内容 : 文本型组件 按钮型组件 编辑型组件 列表框型组件 滑块型组件 容器型组件 4.1 文本型组件 在许多的窗体中我们都见到过文本, 文本的用途主要有两种 : 第一是用于显示一些没有 Caption 属性的组件的功能 作用 ; 第二是显示一段提示信息 Delphi 提供了两个文本型组件 :Label( 标签 ) 组件和 Static Text( 静态文本 ) 组件, 这两个组件的功能基本相同, 只有细微差别 Label 组件 Label( 标签 ) 组件是典型的非窗口控件, 它不能获得输入焦点, 一般用来显示用户不能改变的文字或给一些没有标题属性的组件 ( 如编辑框等 ) 充当标题 标签组件位于组件板的 Standard 选项卡上

93 第 4 章 Delphi 的基本组件 80 创建窗体后, 单击组件板中 Standard 选项卡中的 Label 组件, 图标将凹陷, 此时在窗体上某位置单击鼠标, 窗体上就出现了一个标签组件 Label1, 而且组件四周有 8 个黑色小方块的控点, 用鼠标拖动控点就可调整标签的大小 另外, 将鼠标放在标签 8 个控点形成的方框中间, 拖动鼠标可调整标签的位置 添加标签组件后, 就可以利用对象查看器设置标签属性了 表 4-1 显示了标签组件的一些常见属性 表 4-1 标签常见属性 属 性 数据类型 说 明 Caption String 标签的标题, 即标签的显示内容 FocusControl String 此属性为标签组件独有, 可用来为一些无标题的组件提供快捷键 Autosize Boolean 决定标签是否随字体的变化而自动变动尺寸以配合这些变化 Font TFont 选择标签的字体格式和大小 FocusControl 属性可为无标题的组件提供快捷键 比如, 将 Label1 组件的 FocusControl 属性设为 Edit1, 而 Label1 的 Caption 属性中有快捷键, 则程序运行时, 一按 Label 提供的快捷键, 就能使 Edit1 获得输入焦点 为 Caption 属性设置快捷键的方法是在 Caption 属性的某一字符前加 &, 标签标题中该字符就会出现下划线, 这就是为标签设置的快捷键 例如,Caption 属性为 姓名 (&N) 的按钮, 标签标题则显示为 姓名 (N), 此时可用快捷键 Alt+N 来使用标签的 FocusControl 属性指定的组件获取输入焦点 标签很少单独使用, 一般和其他组件结合使用 在以后的例子中, 我们将逐步结合其他组件来介绍标签的用途 StaticText 组件 StaticText( 静态文本 ) 组件位于组件板的 Additional 选项卡上, 是一个窗口型控件, 用于在窗体上显示文本 静态文本组件功能与标签组件基本相同, 惟一的差别在于静态文本组件是一个窗口型控件, 拥有窗口句柄 因此, 在组件的加速键必须属于窗口型控件的前提下, 应该使用静态文本组件, 而不能使用标签组件 例如, 对于 ActiveX 属性页上的文本, 就应该使用静态文本组件 由于静态文本与标签的作用基本相同, 因此这里不作过多介绍 4.2 按钮型组件 在 Windows 程序的界面设计中, 经常要用到按钮 广义上的按钮分为 4 种 : 普通按钮 (Button) 位图按钮 (BitBtn) 单选按钮 (RadioButton) 和复选框 (CheckBox) 其中普通按钮和位图按钮是执行类按钮, 通常用来启动程序的运行, 尤以普通按钮最为常见 Button 组件 Button( 普通按钮 ) 组件常简称为按钮 ( 以后不作说明 ) 按钮的设置可以分为两部分,

94 81 Delphi 程序设计基础即 外观 和 功能 与大多数组件一样, 必须先设置按钮的外观 创建窗体后, 单击组件板中 Standard 选项卡中的 Button 组件, 图标将凹陷, 此时在窗体上某部位单击鼠标, 窗体上就出现了一个按钮组件 Button1, 而且组件四周有 8 个黑色小方块的控点, 用鼠标拖动控点就可调整按钮的大小 另外, 将鼠标放在按钮八个控点形成的方框中间, 拖动鼠标可调整按钮的位置 然后可以利用对象查看器来设置按钮的属性, 表 4-2 列出了按钮的主要属性 表 4-2 按钮的主要属性 属性数据类型说明 Name String 按钮的名称, 可以在程序中使用它 Caption String 按钮的标题, 就是在按钮上显示的文本, 可以为按钮指定快捷键 ( 在标题文本某一字符前加符号 &) Enabled Boolean 当属性值为 False 时, 按钮被设置为灰显, 即无法单击或选中它 Cancel Boolean 当属性值为 True 时, 无论何时按下 Esc 键, 按钮中 Taborder 值最小的按钮会产生 OnClick 事件, 缺省值为 False Default Boolean 当属性值为 True 时, 按下 Enter 键时, 当前按钮产生 Onclick 事件, 缺省值为 True Hint String 保存着按钮的提示文本, 当鼠标光标停留时, 显示提示文本 ShowHint Boolean 确定是否显示提示文本, 缺省值为 False 提示 : 在 Caption 属性的某一字符前加 &, 按钮标题中该字符就会出现下划线, 这就是为按钮设置快捷键 例如,Caption 属性为 关闭 (&C) 的按钮, 按钮标题则显示为 关闭 (C), 此时可用快捷键 Alt+C 来启动按钮的 OnClick 事件 通常, 通过设置 Button 的 Enabled 属性, 来设置按钮的灰显, 以达到与环境相符的按钮状况 对象查看器的 Property ( 属性 ) 选项卡中还有按钮的其他属性, 用户可根据需要设定 设置完按钮的外观后, 就该设置按钮的功能, 按钮的功能是通过按钮的事件响应来实现的 按钮常用的事件就是 OnClick 事件, 它在鼠标单击按钮时产生, 另外, 通过快捷键 Enter 键 Esc 键也可以产生 OnClick 事件, 按钮通过 OnClick 事件去实现按钮的功能 要给按钮添加 OnClick 事件, 可选择对象查看器的 Events ( 事件 ) 选项卡, 单击 OnClick 事件名, 再在其右边的编辑框中输入事件响应过程名, 再按 Enter 键即可 另外, 双击 OnClick 事件名, 可为按钮添加缺省事件响应名的事件, 并同时打开代码编辑器窗口 缺省事件响应名为组件 Name 属性值加上事件名 On 后面的部分 例如, 名为 Button1 的 OnClick 事件的缺省事件响应名为 Button1Click 此外, 双击窗体中的按钮, 也可为按钮添加具有缺省事件响应名的 OnClick 事件, 并同时打开代码编辑器窗口 BitBtn 组件 BitBtn( 位图按钮 ) 组件可在按钮上同时显示文本和位图, 比一般按钮更加直观 组件位于组件板的 Additional 选项卡上 经过与按钮同样的操作, 在窗体上可放置一个位图按钮 位图按钮除了具有一般按钮所有的属性外, 还有几个特有的属性, 见表 4-3

95 第 4 章 Delphi 的基本组件 82 表 4-3 位图按钮的属性 属性数据类型说明 Kind TBitBtnKind 确定位图按钮的类型, 缺省值为 bkcustom Glyph TBitmap 指定位图按钮上显示的位图 Layout TButtonLayout 决定位图在位图按钮的位置, 有 Left Right Top Bottom 4 个值分别表示位图位于位图按钮的左 右 上 下 Margin Integer 决定位图与位图按钮边界之间的空格数 NumGlyphs TNumGlyphs 指定位图按钮使用的位图的数目, 只能为 , 缺省为 1 Spacing Integer 决定标题与位图按钮边界之间的空格数 Style TButtonstyle 确定位图按钮外观显示方式, 缺省为 bsautodetect 下面着重解释一下 Kind 属性和 NumGlyphs 属性 Kind 属性是 TBitBtnKind 的一个对象,TBitBtnKind 是 Delphi 已定义的枚举类型 : TbitBtnKind=(bkCustom,bkOK,bkCancel,bkHelp,bkYes,bkNo,bkClose,bkAbort,bkRetry,bkIgnore,bkAll) Kind 可以等于枚举类型中的 11 个枚举值的任何值 每一种枚举值表示一种位图按钮类型, 每一种位图按钮都有自己的位图 文本描述和特定的功能 其中,bkCustom 类型由用户自定义位图和文本描述 图 4-1 显示了不同类型的位图按钮 图 4-1 不同类型的位图按钮 属性 NumGlyphs 指定位图按钮使用位图的个数, 取值只能是 1,2,3,4, 最多使用四幅位图 不过, 多幅 (1,2,3,4) 位图保存在同一个位图文件中 实际上,Delphi 是将位图文件中的位图水平等分为多幅 (1,2,3,4) 位图来使用的 4 幅位图作用如下 : 第 1 幅位图在释放按钮时显示 ; 第 2 幅位图在按钮处于禁止状态时显示 ; 第 3 幅位图在单击按钮时显示 ; 第 4 幅位图在按钮凹陷时显示 提示 :NumGlyphs 属性值为 4, 但位图少于 4 幅时, 系统将自动将缺省的位图用第 1 幅位图补齐 只有第 3 幅位图和第 4 幅位图可缺省 当 Kind 属性值为 bkcustom 时, 可给位图按钮指定位图 自定义位图分为位图编辑 装载位图两个步骤 下面分别加以介绍 1. 位图编辑自定义位图按钮的第一步是位图编辑 位图可利用 Delphi 的 Image Editor( 位图编辑器 ) 来进行编辑 当然, 也可利用别的位图编辑工具来进行编辑, 只要最后能生成以.bmp 为扩展名的位图文件即可 2. 装载位图绘制好位图后, 就可以往位图按钮中装载位图了 装载位图有两种方法 : 第一种方法是利用对象查看器在设置属性时装载位图 ; 第二种方法是利用添加事件的方法在运行程序时装载位图

96 83 Delphi 程序设计基础装载位图的第一种方法是设置位图按钮的 BitBtn 属性, 其操作如下 : (1) 在窗体中选定要装载位图的位图按钮 (2) 在对象查看器的 Property 选项卡中单击属性 Glyph 的属性名 (3) 在 G1yph 属性右侧的属性框中单击省略号按钮, 打开 Picture Editor ( 图片编辑器 ) 对话框, 如图 4-2 所示 (4) 单击 Load 按钮, 打开 Load Picture 对话框, 如图 4-3 所示 (5) 选择所需位图 (6) 单击 OK 按钮 图 4-2 Picture Editor ( 图片编辑器 ) 对话框 这样, 就将位图 Bitmap1.bmp 装载到图片编辑器中, 并在图片编辑器中央的预览框中显示图片的预览 图 4-3 Load Picture 对话框 装载位图的第二种方法是为位图按钮添加事件, 动态添加位图 用 Glyph 属性的 LoadFromFile 函数为位图按钮装载位图文件, 该函数的参数为要装载的位图的文件名, 下面给出一个例子 : procedure TForm1.BitBtn1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); BitBtn1.Glyph.LoadFromFile('Bitmap1.bmp'); RadioButton 组件 RadioButton( 单选按钮 ) 组件比较常用, 一般总是成组出现而且相互排斥, 以让用户在

97 第 4 章 Delphi 的基本组件 84 其中选择惟一的一个选项 这就是 单选 的含义 实现单选按钮有两种方法, 一种是使用 RadioButton( 单选按钮 ) 组件, 另一种是使用 RadioGroup( 单选按钮组 ) 组件 1.RadioButton 组件 RadioButton( 单选按钮 ) 组件位于组件板的 Standard 选项卡上 单选按钮一个比较特殊的属性是 Checked 属性, 表示单选按钮是否被选中, 缺省为 False( 未选中 ) 在窗体上放置许多单选按钮时,Delphi 会自动将它们看作一个组, 每次只能选中一个 如果想在窗体上放置两组单选按钮, 可以使用 GroupBox( 成组框 ) 组件或者 RadioGroup( 单选按钮组 ) 组件, 它们也在组件板的 Standard 选项卡上 在用成组框来设置单选按钮组时, 次序是先在窗体上放置成组框, 然后把单选按钮放置到成组框里 这样按钮就属于成组框了, 移动不出来 删除成组框后, 里面的单选按钮也同时删除 2.RadioGroup 组件 RadioGroup( 单选按钮组 ) 组件使用更方便, 因为它只是一个组件, 比使用成组框和单选按钮更简单和直观, 它有 4 个主要属性, 分别是 Caption Columns ItemIndex 和 Items, 见表 4-4 表 4-4 单选按钮组主要属性 属 性 数据类型 说 明 Caption String 单选按钮组的名称 Columns Integer 单选按钮组中的列数 ItemIndex Integer 单选按钮组中当前被选中的单选按钮 Items TStrings 单选按钮组中的单选按钮列表 上面的属性中,Items 是类 TStrings 的对象, 单击 Items 属性右边的属性值编辑框中的省略号按钮, 打开 String List Editor ( 字符串编辑器 ) 窗口, 如图 4-4 所示 每一行字符串表示一个单选按钮的标题, 使用 Enter 键换行 ItemIndex 属性指出选中了哪个单选按钮 例如,ItemIndex 属性为 0 则表明选中单选按钮组中的第一个, 依此类推 下面分别用单选按钮 成组框和单选按钮组等方法在窗体上设置 3 组单选按钮, 如图 4-5 所示 图 4-4 字符串编辑器图 4-5 三种单选按钮组

98 85 Delphi 程序设计基础 CheckBox 组件在单选按钮组中, 我们只能选中一个选项 如果想在一系列的选项中选中一个或多个, 就需要使用 CheckBox( 复选框 ) 组件 复选框组件也位于 Standard 选项卡中 复选框有 4 个比较重要的属性, 如表 4-5 所示 : 表 4-5 复选框属性 属 性 数据类型 说 明 Alignment TLeftRight 控制复选框标题位置 Allowgrayed Boolean 确定复选框是否可以处于灰显 Checked Boolean 确定复选框是否被选中, 缺省为 False State TCheckBoxState 确定复选框状态 ( 选中 未选中 灰显 ) 属性 Alignment 等于 tarightjustify 时, 标题在复选框右边, 等于 taleftjustify 时, 标题在复选框左边, 缺省时为右边 复选框之间互不排斥, 但也可以用分组框把它们归类, 使得窗体的外观整齐易懂 按钮型组件实例例 4-1 设置文本的对齐方式和字体式样 (1) 新建应用程序进入 Delphi 后, 单击 File 菜单的 New Application 命令开始一个新的应用程序 (2) 设置窗体属性窗体属性设置见表 4-6 表 4-6 窗体属性 属性属性值属性属性值 Caption 组件应用 Font 宋体 五号 (3) 添加组件首先往窗体中添加 1 个 Memo 组件 Memo1 1 个 RadioGroup 组件 RaidoGroup1 1 个 GroupBox 组件 GroupBox1, 然后选中 GroupBox1, 往该组件中添加 2 个 CheckBox 组件 CheckBox1 和 CheckBox2, 这样这两个复选框组件就会位于 GroupBox1 中, 最后直接往窗体中添加 2 个 Button 组件 Button1 和 Button2 (4) 设置组件属性组件属性设置见表 4-7 表 4-7 组件属性设置 组件属性属性值备注 Memo1 Lines 蓝科信息 RadioGroup1 Caption 对齐方式 Items ItemIndex 0 左对齐居中右对齐

99 第 4 章 Delphi 的基本组件 86 续表 组 件 属 性 属 性 值 备 注 GroupBox1 Caption 字体样式 CheckBox1 Caption 加粗 位于 GroupBox1 中 CheckBox2 Caption 倾斜 位于 GroupBox1 中 Button1 Caption 应用 Button2 Caption 关闭 Default True 设置完组件属性后, 窗体中组件及其布局如图 4-6 所示 图 4-6 例 4-1 界面 图 4-7 例 4-1 运行效果 (5) 添加组件事件 为按钮 Button1 添加 OnClick 事件, 响应过程为 Button1Click; 为按钮 Button2 添加 OnClick 事件, 响应过程为 Button2Click (6) 编写事件代码 Button1Click 过程的作用是检测单选按钮组和复选框的状态, 从而让 Memo1 组件作出相 应的反应, 其代码如下 : procedure TForm1.Button1Click(Sender: TObject); case RadioGroup1.ItemIndex of // 根据单选按钮组选项设置对齐方式 0:Memo1.Alignment:=taLeftJustify; // 左对齐 1:Memo1.Alignment:=taCenter; // 居中 2:Memo1.Alignment:=taRightJustify; // 右对齐 if CheckBox1.Checked then Memo1.Font.Style:=Memo1.Font.Style+[fsBold] else Memo1.Font.Style:=Memo1.Font.Style [fsbold]; // 文本加粗 // 文本还原 if CheckBox2.Checked then Memo1.Font.Style:=Memo1.Font.Style+[fsItalic] else Memo1.Font.Style:=Memo1.Font.Style [fsitalic]; // 文本倾斜 // 文本还原

100 87 Delphi 程序设计基础 上述过程中使用了 Font 属性的 Style 子属性, 用于设置字体的样式 :fsbold 表示加粗, fsitalic 表示倾斜 Button2Click 过程用来关闭窗口, 其代码如下 : procedure TForm1.Button2Click(Sender: TObject); Close; (7) 保存程序将单元文件保存为 Unit4_1.pas, 将项目文件保存为 Project4_1.dpr (8) 运行程序单击工具栏中 Run 按钮运行程序 运行后, 通过选择 对齐方式 中的单选按钮, 再单击 应用 按钮, 可以控制 Memo1 文本的对齐方式 ; 通过选择 加粗 和 倾斜 复选框, 再单击 应用 按钮, 可以控制 Memo1 文本的字体样式 而单击 关闭 按钮则可以关闭窗口 用户可以通过图 4-7 所做的对比看出应用程序的运行效果 (9) 程序说明程序中, 复选框用成组框进行分组 在编程时, 通过读取成组框中组件的状态来进行相应操作 实际上, 可以直接通过成组框来读取其容纳的组件的状态 成组框组件有一个 Controls 属性, 以数组的形式存储了成组框中的各组件, 用户可以利用该属性来对成组框中各组件进行操作, 这种方法常用在对成组框内组件的组件名不清楚的地方 4.3 编辑型组件 编辑型组件在应用程序中主要用于输入文本 数字或格式化字符串等 编辑型组件都是窗口型控件, 可以获得输入焦点 Delphi 提供了丰富的编辑型组件, 有输入单行文本的 Edit ( 编辑框 ) 组件 输入格式化字符串的 MaskEdit( 掩码编辑框 ) 组件 输入数字的 SpinEdit ( 数字编辑框 ) 组件 输入多行文本的 Memo( 存储框 ) 组件和 RichEdit( 复文本编辑框 ) 组件等 下面分别介绍这些组件的功能以及使用 Edit 组件 Edit( 编辑框 ) 组件常与标签一起使用, 它是一个窗口控件, 可以获得输入焦点 主要用于输入单行文本, 编辑框组件位于组件板的 Standard 选项卡上 1. 常用属性编辑框常用属性有 Text MaxLength 和 ReadOnly 等, 见表 4-8 表 4-8 编辑框常用属性 属性数据类型说明 Text String 在编辑框中出现的文本

101 第 4 章 Delphi 的基本组件 88 续表属性数据类型说明 MaxLength Integer 编辑框的最大字符数, 缺省为 0, 表示不限长度 PasswordChar Char 显示口令字符, 缺省为 #0, 表示正常显示 ReadOnly Boolean 确定编辑框是否只读, 缺省为 False, 表示可读写 IMEMode TImeMode 设置编辑框输入时使用的输入模式 IMEName TImeName 设置用户输入时输入法名称编程时, 常通过编辑框的 Text 属性获取文本字符串 例如, 对于编辑框 Edit1, 可以如此获得编辑框中的字符串 : var thestring:string; thestring:=edit1.text; 如果用 Edit 组件来输入 / 输出数值型数据时, 需对其数值合法性作检验, 使用时用 StrToInt() StrToFloat() IntToStr() 或 FloatToStr() 等进行转换 属性 PasswordChar 可在编辑框中输入字符时, 只显示属性设置的符号, 如 * 等, 从而保证密码的保密性 当 PasswordChar 为 #0 时, 文本字符串正常显示 ; 当 # 后面是除 0 外的其他数字时, 文本字符以该 ASCII 码显示 ; 当 PasswordChar 为某一字符时, 文本字符则以该符号显示 例如, 如果 PasswordChar 为 *, 则将文本字符以 * 显示 属性 IMEMode 指定编辑框所用的输入模式 对于单字节的西文字符, 可以取为 imsalpha; 对于双字节的西文字符, 可取为 imalpha; 对于双字节的中文字符, 可以取为 imchinese 属性 IMEName 指定编辑框所用的输入法名称 例如, 如果使用智能 ABC 输入法, 可将属性值指定为 智能 ABC 输入法 另外, 还可用 SetIme 方法在程序运行时动态地指定输入法名称 2. 常用事件编辑框组件常用的事件有 OnKeyPress 事件 OnChange 事件 OnEnter 事件和 OnExit 事件 在编辑框中输入完文本后, 按一下 Enter 键, 程序就开始执行, 这就是编辑框的 OnKeyPress 事件 编辑框文本发生改变时触发 OnChange 事件 编辑框获得输入焦点时触发 OnEnter 事件 编辑框失去输入焦点时触发 OnExit 事件 MaskEdit 组件 MaskEdit( 掩码编辑框 ) 组件位于组件板的 Additional 选项卡中, 利用它可以设计出许多复杂的输入格式 例如, 输入货币的格式为 $34.90 又如要在编辑框中输入既有数字

102 89 Delphi 程序设计基础又有字母和其他字符的一条消息, 而我们又要把其中的数字取出时也可以使用掩码编辑框 在对象查看器双击 MaskEdit 组件的 EditMask 属性, 将打开 Input Mask Editor ( 掩码格式编辑器 ) 对话框, 如图 4-8 所示 图 4-8 Input Mask Editor 对话框 左上角的 Input Mask 编辑框用于输入掩码格式, 这种格式可以分为三部分, 每两个部分之间用 ; 分开, 如!0000aa/99aa/99aa;1;_ (1) 输入格式的第一部分是掩码本身, 也就是数据的输入格式, 用一些特殊的格式符来表示应输入的字符类型及格式, 比如!0000aa/99aa/99aa 格式字符的含义见表 4-9 表 4-9 掩码格式 格式符含义! (2) 在输入的第二部分只能是 1 或 0 如为 1, 掩码格式中非用户输入的数据和标准分 隔符等作为数据的一部分保存,0 则不保存 (3) 输入格式的第三部分用于表示数据中的空格用什么字符代替 因此, 要在掩码编辑框中输入如 1969 年 07 月 15 日 的数据的格式, 可将掩码格式设 为!0000aa/99aa/99aa;1;_ 数据前的空格将不被保存在数据中, 无 : 表示数据后的空格不被保存,! 只能放在掩码格式的第一个字符处 > 随后的字母均以大写显示, 直到遇到 < 格式符或 <> 格式符 < 随后的字母均以小写显示, 直到遇到 > 格式符或 <> 格式符 <> 不作大小写的转换, 以输入时的形式为准 \ L l A a C c 该格式符之后的那个掩码格式符将作为数据中的普通字符对待 该位置必须有一个字母 该位置只可能是一个字母, 可用光标键跳过, 但不能是其他类型的字符 该位置必须有一个字母或数字 该位置只可能是一个字母或数字 该位置必须有一个字符 该位置只可能是一个字符 0 该位置必须有一个数字 9 该位置只可能是一个数字 # 该位置可能是一个数字或正负号 ; 和 / 标准的分隔符, 可作为数据的一部分, 其中 / 在显示时为 - 形式

103 第 4 章 Delphi 的基本组件 SpinEdit 组件 SpinEdit( 数字编辑框 ) 组件位于组件板的 Sample 选项卡上 它也是一个窗口控件, 可以获得输入焦点 主要用于输入数字, 并可自动增减数字 所谓数字编辑框, 指的是专门用于输入数字的编辑框, 通常在数字编辑框的右侧有一个微调组件 ( 两个垂直叠放在一起的上三角形小按钮和下三角形小按钮 ), 用以将数字编辑框中的数字增加或减少一个指定单位数字 数字编辑框比较常用的属性有 Value Increment 和 ReadOnly 等, 见表 4-10 表 4-10 数字编辑框常用属性 属 性 数据类型 说 明 Value Integer 在数字编辑框中出现的数字 Increment Integer 单击微调按钮时数字每次增加或减小的步长 MaxValue Integer 数字的最大值 MinValue Integer 数字的最小值 MaxLength Integer 数字的最大位数, 缺省为 0 表示不限长度 ReadOnly Boolean 确定编辑框是否只读, 缺省为 False, 表示可读写 编程时, 常通过数字编辑框的 Value 属性获取数值 例如, 对于数字编辑框 SpinEdit1, 可以如此获得编辑框中的数值 : var thevalue:integer; thevalue:=spinedit1.value; 数字编辑框组件常用的事件和编辑框组件完全相同, 也是 OnPress 事件 OnChange 事件 OnEnter 事件和 OnExit 事件等 UpDown 组件在组件板的 Win32 选项卡上有一个 UpDown( 微调 ) 组件, 通过将微调组件和编辑型组件组合在一起, 可形成数字编辑框, 所以又称组合型数字编辑框 用于组合的编辑型组件可以是编辑框 掩码编辑框, 也可以是后面介绍的存储框和复文本编辑框 UpDown 组件的常用属性见表 4-11 表 4-11 UpDown 组件常用属性 属 性 数据类型 说 明 Associate TWinControl 用于组合的编辑型组件 Increment Integer 单击微调按钮时数字每次增加或减小的步长 Max Integer 数字的最大值 Min Integer 数字的最小值 Thousands Boolean 数字是否使用分节号 ( 千分符 )

104 91 Delphi 程序设计基础只要在 UpDown 组件的 Associate 属性中选定要组合的编辑型组件,UpDown 组件就立即和编辑型组件拼合在一起, 形成一个完整的组件 例如, 如果用 Edit1 组件和 UpDown 组件, 则在 UpDown 组件的 Associate 属性中选定 Edit1 即可 要从组合型数字编辑框中读取数字, 则将编辑型组件中的字符读出再转换成数字即可 Memo 组件编辑框只能编辑单行的文本, 如果要编辑多行文本就要使用 Memo 组件了,Memo( 存储框 ) 组件位于组件板的 Standard 选项卡中,Memo 组件可以输入和编辑文本, 可以与剪贴板进行交流, 它有一些与编辑框组件不同的属性 下面介绍 Memo 组件 1. 常用属性 Memo 组件很多属性都与编辑框相同, 如 Font 属性 IMEMode 属性 ReadOnly 属性等 但也有一些属性不尽相同, 表 4-12 列出了 Memo 组件与编辑框不同的一些常用属性 表 4-12 Memo 组件的常用属性 属 性 数据类型 说 明 Alignment TAlign 确定 Memo 中显示文本的对齐方式 Lines TStrings Memo 组件中出现的文本 ScrollBars TScrollStyle 确定 Memo 的滚动条及其样式 WordWrap Boolean 文本到右边界时是否自动换行 WantReturns Boolean 确定文本是否可以插入回车符 WantTabs Boolean 确定文本是否可以插入 Tab 符 设计时, 如果要给 Memo 组件增加一些显示内容, 可以单击 Lines 属性值右侧的省略号按钮, 打开 String List Editor ( 字符编辑器 ) 窗口, 在其中输入文本, 该文本就会出现在 Memo 组件中, 使用 Enter 键强行换行 在程序运行时, 如果要给 Memo 组件增加显示内容, 可以使用 Add 方法 每调用 Add 方法一次, 存储框中就增加一行 Add 方法的语法如下 : Memo 组件名.Lines.Add(' 显示内容 '); 属性 ScrollBars 确定 Memo 组件的滚动条, 属性值为 sshorizontal 表示有水平滚动条 ; ssvertical 表示有垂直滚动条 ;ssboth 表示既有水平滚动条, 也有垂直滚动条 2. 常用方法 Memo 组件中的文本可以剪切 复制和粘贴等, 它们的方法 ( 这里, 方法是指组件的命令 ) 见表 4-13 表 4-13 Memo 组件的常用方法 方法说明 SelText SelLength CutToClipboard CopyToClipboard PasteFromClipboard Memo 组件中被选中的文本 Memo 组件中被选中的文本长度把 Memo 组件中被选中的文本剪切到剪贴板把 Memo 组件中被选中的文本复制到剪贴板把剪贴板的内容粘贴到 Memo 组件中光标位置

105 第 4 章 Delphi 的基本组件 92 下面介绍如何在存储框中选定文本 如果要在存储框 Memo1 中选定文本, 可调用如下语句块 : Memo1.SetFocus; Memo1.SelStart:={ 选定文本的起始位置 }; Memo1.SelLength:={ 选定文本的长度 }; 利用存储框可以很容易地构成一个编辑器 RichEdit 组件 RichEdit( 复文本编辑框 ) 组件与 Memo 组件非常相似, 但 RichEdit 组件中的文本可以有多种字体和颜色, 而 Memo1 组件中的文本却只能有一种格式 显然, 复文本中的 复 指的是多格式的意思 RichEdit 组件位于组件板的 Win32 选项卡上 RichEdit 组件的常用属性与 Memo 组件差不多 之所以复文本编辑框中的文本可以具有多种格式, 是因为 RichEdit 组件有一个 SelAttributes 属性 ( 该属性不能在 Object Inspector 中看到和设置, 只能在程序中动态设置 ), 表示当前选定的文本, 该属性可以用于指定选定文本的字体 颜色等格式 而 Memo 组件虽然可以有选定文本, 但只能通过 Lines 属性来指定文本格式, 而 Lines 属性对 Memo 中的所有文本均有效, 因此 Memo 中文本的格式单一 与 Memo 组件一样, 复文本框组件中选定文本也采用如下语句块 : RichEdit1.SetFocus; RichEdit1.SelStart:={ 选定文本的起始位置 }; RichEdit1.SelLength:={ 选定文本的长度 }; 选定文本后, 就可以用 SelAttributes 属性指代选定文本了 SelAttributes 属性虽然既不是 TFont 类型, 也不是 TColor 类型, 但与它们却完全匹配 因此,SelAttributes 属性可以通过 Assign 方法来获取 TFont 对象和 TColor 对象中的字体和颜色,TFont 对象和 TColor 对象也能通过自己的 Assign 方法来获取 SelAttributes 中的字体和颜色 另外, 复文本编辑框还有一个 DefAttributes 属性, 表示 RichEdit 组件的缺省属性, 其用法与 SelAttributes 属性完全相同 编辑型组件实例例 4-2 制作一 书籍介绍 界面, 在其中可以输入书籍介绍文字, 并可以设置字体样式 (1) 新建应用程序单击 File 菜单的 New Application 命令开始一个新的应用程序 (2) 设置窗体属性窗体属性设置见表 4-14 表 4-14 窗体属性 属性属性值 Caption Font 书籍介绍 宋体 五号 (3) 添加组件

106 93 Delphi 程序设计基础往窗体中添加 5 个 Label 组件 Label1~Label5 1 个 Edit 组件 Edit1 1 个 MaskEdit 组件 EditMaskl 1 个 SpinEdit 组件 SpinEdit1 1 个 Memo 组件 Memo1 1 个 RichEdit 组件 RichEditl 2 个 CheckBox 组件 CheckBox1 和 CheckBox2 1 个 RadioGroup 组件 RadioGroup1 (4) 设置组件属性组件属性设置见表 4-15 表 4-15 组件属性设置 组 件 属 性 属 性 值 属 性 属 性 值 Label1 Caption 书名 (&N) FocusControl Edit1 Label2 Caption 出版日期 (&D) FocusControl MaskEdit1 Label3 Caption 版本 (&V) 第 版 FocusControl SpinEdit1 Label4 Caption 摘要 (&C) FocusControl Memo1 Label5 Caption 精彩选段 (&B) FocusControl RichEdit1 Edit1 IMEName 智能 ABC 输入法 IMEMods imchinese MaskEdit1 IMEName 智能 ABC 输入法 IMEMode ImChinese EditMask!0000 年 99 月 99 日 ;1;_ SpinEdit MaxValue 20 MinValue 1 Value 1 Memo1 Lines 数据库管理系统以 RichEdit1 Lines 数据库设计的 CheckBox1 Caption 加粗 CheckBox2 Caption 倾斜 RadioGroup1 Caption 字体式样 Items 标题正文提示注释 设置完组件属性后, 窗体中组件及其布局如图 4-9 所示 图 4-9 例 4-2 组件布局图 4-10 例 4-2 运行效果

107 第 4 章 Delphi 的基本组件 94 (5) 添加组件事件 按表 4-16 给组件添加事件 表 4-16 组件事件 组 件 事 件 响应过程 CheckBox1 OnClick CheckBox1Click CheckBox2 OnClick CheckBox2C1ick RadioGroup1 OnClick RadioGroup1Click RichEdit1 OnEnter RichEdit1Enter (6) 编写事件代码 CheckBox1Click 过程的作用是将存储框中文本的字体加粗, 其代码如下 : procedure TForm1.CheckBox1Click(Sender: TObject); if CheckBox1.Checked then Memo1.Font.Style:=Memo1.Font.Style+[fsBold] // 文本加粗 else Memo1.Font.Style:=Memo1.Font.Style [fsbold]; // 文本还原 CheckBox2Click 过程的作用是将存储框中文本的字体倾斜, 其代码如下 : procedure TForm1.CheckBox2Click(Sender: TObject); if CheckBox2.Checked then Memo1.Font.Style:=Memo1.Font.Style+[fsItalic] // 文本倾斜 else Memo1.Font.Style:=Memo1.Font.Style [fsitalic]; // 文本还原 RadioGroup1Click 过程的作用是将复文本编辑框中选定文本的字体设置成指定字体式 样, 其代码如下 : procedure TForm1.RadioGroup1Click(Sender: TObject); var font:tfont; font:=tfont.create; font.assign(richedit1.selattributes); if RichEdit1.SelLength>0 then case RadioGroup1.ItemIndex of 0: // 标题 font.style:=font.style+[fsbold];

108 95 Delphi 程序设计基础 font.size:=16; 1: // 正文 font.size:=12; 2: // 提示 font.size:=12; font.style:=font.style+[fsitalic]+[fsbold]; 3: // 注释 font.size:=10; font.style:=font.style+[fsunderline]; RichEdit1.SelAttributes.Assign(font); RichEdit1Enter 过程的作用是每当重新进入 RichEdit1, 复原 RadioGroup1 状态, 其代码如下 : procedure TForm1.RichEdit1Enter(Sender: TObject); RadioGroup1.ItemIndex:= 1; (7) 保存程序将单元文件保存为 Unit4_2.pas, 将项目文件保存为 Project4_2.dpr (8) 运行程序单击工具栏中 Run 按钮运行程序 运行后, 可以往各编辑框中输入文本 格式化字符串和数字, 往存储框中输入文本 选择存储框右侧的 加粗 倾斜 复选框可以将存储中的文本的字体加粗 倾斜显示 ; 往复文本编辑框中输入文本, 然后选定复文本编辑框中的文本后, 再选择其右侧的 字体式样 单选按钮, 可以将选定文本变成指定字体式样显示 用户可以通过图 4-10 所示对比看出应用程序的运行效果 图中明显可以看出存储框和复文本编辑框的不同 4.4 列表框型组件 如果要从很多选项中选择一项或多项, 此时用单选按钮组或复选框组就不太合适了, 因为这经常要占据非常大的空间, 需要比较大的窗体 此时, 最好的办法是使用列表框, 列表框可以在较小的空间中容纳大量的选项, 利用列表框, 用户还可以方便地增删选项, 这都是单选按钮组或复选框组所不能达到的

109 第 4 章 Delphi 的基本组件 96 下面介绍三种列表框型组件 :ListBox( 列表框 ) 组件 CheckListBox( 复选列表框 ) 组件和 ComboBox( 组合框 ) 组件 ListBox 组件 ListBox( 列表框 ) 组件位于组件板的 Standard 选项卡上 利用列表框, 用户可以用鼠标选择一个或多个选项, 甚至可以随时增加或删除某些选项 1. 常用属性列表框有一些常用属性, 见表 4-17 表 4-17 列表框属性 属 性 数据类型 说 明 ExtendedSelect Boolean 确定用户是否可以选择连续的多个选项, 缺省为 False Items TStrings 列表框中的选项列表 ItemIndex Integer 列表框中当前被选中的选项 MultiSelected Boolean 确定列表框是否可以多项选择, 缺省为 False SelCount Integer 返回选中项目个数, 如果 MultiSelected 为 False, 则为 1 Selected Boolean 确定列表框中某个项目是否被选中 Sorted Boolean 确定列表框中的内容是否按字母顺序排列, 缺省为 False 属性 ExtendedSelect 和 MultiSelected 的缺省值为 False, 此时列表框只能进行单项选择 ; 当 MultiSelected 属性为 True 时, 可以进行多项选择 ; 当属性 ExtendedSelect 也为 True 时, 在单击选项的同时按下 Ctrl 键可以选择多个不连续的选项, 也可以在单击选项后按下 Shift 键单击另一个选项, 这样可以选中这两个选项之间的所有选项 Items 是类 TStrings 的对象, 单击 Items 属性右边的属性值编辑框中的省略号按钮, 打开 String List Editor ( 字符串编辑器 ) 窗口, 如图 4-4 所示 每一行字符串表示一个选项, 使用 Enter 键换行 2. 常用操作下面介绍列表框中常用的操作 在列表框中, 选项都存储在 Items 属性中,Items 为 TStrings 类型 每一选项都是一 String 类型, 都有一个索引号 选项索引号和字符串只要知道一个, 就可求得另一个 知道选项字符串, 索引号可以通过 Items 属性的 IndexOf 方法来获取, 语法如下 ( 假定组件为 ListBox1): ListBox1.Items.IndexOf(' 选项字符串 '); 要知道一选项是否被选定, 可通过列表框的 Checked 属性来判断 列表框的 Checked 属性是一布尔数组, 记录着每一列表项的状态 因此通过 ListBox1.Checked[ 索引号 ] ( 假定组件为 ListBox1) 的方式来判断该选项是否被选定, 若为 True, 则被选定, 否则未被选定 而知道选项索引号, 选项字符串可通过 Items 属性的数组性质来获取, 语法如下 ( 假定组件为 ListBox1): ListBox1.Items 选项索引号 ; 要获取在列表框中选定选项索引号, 直接使用 ItemIndex 属性 另外, 还可以设置选项选定, 语法如下 ( 假定组件为 ListBox1):

110 97 Delphi 程序设计基础 ListBox1.ItemIndex:= 索引号 ; 列表框中插入 添加 删除选项, 分别使用 Items 属性的 Insert Add Delete 方法, 其语法如下 ( 假定组件为 ListBox1): ListBox1.Items.Insert( 插入位置, ' 选项字符串 '); ListBox1.Items.Add(' 选项字符串 '); ListBox1.Delete( 选项索引号 ); CheckListBox 组件对于列表框, 选定一项选项后, 选项被加亮 列表框也允许同时选定多项选项, 这些选项同时加亮 为了方便用户选定选项,Delphi 用一个新的组件扩展了列表框 CheckListBox ( 复选列表框 ) 组件, 在列表框各选项前有一复选框, 用复选框的状态表明该选项的选定状态 : 选定 取消还是灰显 复选列表框对于多项选择和状态选择非常有用 复选列表框位于组件板的 Additional 选项卡上 复选列表框的大部分属性与列表框完全相同 这里仅介绍不同的几个 AllowGrayed 属性, 该属性为 True 时, 每一列表项可有选择 取消 灰显 3 种状态 ; 若为 False, 则只有选择 取消两种状态 判断复选列表框中选项状态分两种情况 : 第一种情况是 AllowGrayed 属性为 False, 此时每一列表项可有选择 取消两种状态, 因此通过 CheckListBox1.Checked[ 索引号 ] ( 假定组件为 CheckListBox1) 的方式来判断该选项是否被选定, 若为 True, 则被选定, 否则未被选定 第二种情况是 AllowGrayed 属性为 True, 此时每一列表项可有选择 取消 灰显 3 种状态, 应通过 CheckListBox1.State[ 索引号 ] ( 假定组件为 CheckListBox1) 的方式来判断选项的状态 : 若为 cbunchecked, 表明处于取消状态 ; 若为 cbchecked, 表明处于选择状态 ; 若为 cbgrayed, 表明处于灰显状态 ComboBox 组件在窗体上, 列表框 复选列表框通常要占据很大一块空间, 而使用 ComboBox( 组合框 ) 组件就只要一行就够了 另外, 组合框带有一个编辑框, 用户可以在其中输入 一般情况下, 组合框只显示这个编辑框, 当用户单击该编辑框右边的下拉箭头时, 就会显示一个包含所有选项的下拉列表 实际上, 从名称也可以看出, 组合框相当于两种组件的组合, 这两种组件就是列表框与编辑框 组合框位于组件板的 Standard 选项卡上 组合框与列表框有相似之处, 都能包含多个选项, 但也有一些独特的属性, 组合框的常用属性见表 4-18 表 4-18 组合框常用属性 属 性 数据类型 说 明 Text String 编辑框中的字符串 SelText String 被选中的字符串 SelStart Integer 被选中字符串的起始位置 SelLength Integer 被选中字符串的长度 Style TComboBoxStyle 确定组合框的样式

111 第 4 章 Delphi 的基本组件 98 对于 ComboBox 组件的 Style 属性,Delphi 提供了以下 5 种属性值 csdropdown: 普通的组合框, 带有一个编辑框和下拉列表 csdropdownlist: 与 csdropdown 相似, 但不能在编辑框中输入文本 cssimple: 只有一个编辑框和列表框, 该列表框不是下拉式的 csownerdrawfixed: 下拉列表中各选项高度由 ItemHeight 属性决定 各选项常为图 形对象, 只能通过选择下拉列表中某选项改变编辑框中的内容, 而不能在编辑框中直接输入 csownerdrawvariable: 下拉列表中各选项及编辑框的高度可变, 各选项常为图形对 象, 只能通过下拉列表中的某选项改变编辑框中的内容, 不能在编辑框中直接输入 组合框与列表框有一个很大的区别就是它不能进行多项选择 组合框中选定的内容存储 在其 Text 属性中, 因此可通过其 Text 属性读取组合框中选定选项 其余操作如添加选项 插入选项和删除选项基本上与列表框的相同 在介绍编辑框时, 曾经介绍编辑框中输入完文本后, 按 Enter 键, 编辑框就开始调用其 OnKeyPress 事件 由于组合框中包含有编辑框, 因此在 csdropdown cssimple 两种样式下, 可通过组合框的编辑框的 OnKeyPress 事件来执行相关操作, 通常是执行添加选项的操作 列表框型组件实例 例 4-3 制作一 品牌调查 界面, 可对所列品牌进行选择 (1) 新建应用程序 单击 File 菜单的 New Application 命令开始一个新的应用程序 (2) 设置窗体属性 窗体属性设置见表 4-19 表 4-19 窗体属性 属性属性值属性属性值 Caption 品牌调查 Font 宋体 五号 (3) 添加组件往窗体中添加 4 个 Label 组件 Label1~Label4 1 个 ListBox 组件 ListBox1 1 个 CheckListBox 组件 CheckListBox1 1 个 ComboBox 组件 ComboBox1 1 个 RichEdit 组件 RichEdit1, 以及 3 个 Button 组件 Button1~Button3 (4) 设置组件属性组件属性设置见表 4-20 表 4-20 组件属性设置 组 件 属 性 属 性 值 属 性 属 性 值 Label1 Caption PC 机品牌 : Label2 Caption 移动电话品牌 : Label3 Caption 最近最想购买的大件商品 : Label4 Caption 选票内容 : ListBoxl Items ( 如图 4-11 所示 )PC 机品牌项 MultiSelect True CheckListBox1 Items ( 如图 4-11 所示 ) 移动电话品牌项

112 99 Delphi 程序设计基础 续表 组 件 属 性 属 性 值 属 性 属 性 值 ComboBox1 Items 住房 汽车 家电 电脑 其他 Style csdropdown Button1 Caption 提交 (&P) Button2 Caption 重选 (&R) Button3 Caption 取消 (&C) 设置完组件属性后, 窗体中组件及其布局如图 4-11 所示 (5) 添加组件事件 为各组件添加事件, 见表 4-21 表 4-21 添加事件 组 件 事 件 响应过程名 Button1 OnClick Button1Click Button2 OnClick Button2Click Button3 OnClick Button3Click (6) 编写事件代码响应过程 Button1Click 的作用是扫描列表框 复选列表框 组合框, 将从它们中选定的选项反映到复文本框中去 在扫描时注意, 列表框使用的是 Selected 属性, 复选列表框使用的却是 Checked 属性, 组合框则不需要扫描而直接使用 Text 属性, 其代码如下 : procedure TForm1.Button1Click(Sender: TObject); var Item:integer; RichEdit1.Lines[0]:=' 我最喜欢的 PC 机品牌有 :'; RichEdit1.Lines[1]:=''; //PC 机品牌 for Item:=0 to ListBox1.Items.Count 1 do if ListBox1.Selected[Item] then RichEdit1.Lines[1]:=RichEdit1.Lines[1] +ListBox1.Items.Strings[Item]+' '; 图 4-11 例 4-3 组件布局 RichEdit1.Lines[3]:=' 我最喜欢的手机品牌有 :'; RichEdit1.Lines[4]:=''; // 手机品牌 for Item:=0 to CheckListBox1.Items.Count 1 do if CheckListBox1.Checked[Item] then RichEdit1.Lines[4]:=RichEdit1.Lines[4] +CheckListBox1.Items.Strings[Item]+' ';

113 第 4 章 Delphi 的基本组件 100 RichEdit1.Lines[6]:=' 我最近想买 '+ComboBox1.Text; 响应过程 Button2Click 的作用是为列表框 复选列表框选项清空, 同时对 RichEdit1 文本也清空 代码如下 : procedure TForm1.Button2Click(Sender: TObject); var Item:integer; for Item:=0 to ListBox1.Items.Count 1 do ListBox1.Selected[Item]:=false; for Item:=0 to CheckListBox1.Items.Count 1 do CheckListBox1.Checked[Item]:=false; for Item:=0 to RichEdit1.Lines.Count 1 do RichEdit1.Lines[Item]:=''; 响应过程 Button3Click 的作用是关闭并退出, 代码如下 : procedure TForm1.Button3Click(Sender: TObject); Close; (7) 保存程序将单元文件保存为 Unit4_3.pas, 将项目文件保存为 Proiect4_3.dpr (8) 运行程序单击工具栏中 Run 按钮运行程序 运行后, 可以从列表框和复选列表框中选择多个选项, 从组合框中选择一个选项, 单击 提交 按钮可将所选项反映到复文本框中 ; 单击 重选 按钮, 可以清空列表框 复选列表框的选 项选择 图 4-12 显示了例子运行的效果 图 4-12 例 4-3 运行效果 4.5 滑块型组件 在某个范围内选择数值时, 通常使用滑块型组件 ScrollB ar( 滚动条 ) 组件和 TrackBar ( 刻度尺 ) 组件 一般情况下, 允许用户在较大范围内选择数值时, 选用滚动条组件 ; 而选

114 101 Delphi 程序设计基础择范围较小时, 则一般选用刻度尺组件 下面介绍这两种组件的用法 ScrollBar 组件我们已经在许多的组件上见到过滚动条, 如列表框 组合框等, 在当中设置 ScrollBar 属性就可以使之带有或不带滚动条 不过滚动条在其中是作为组件的一部分出现的 另外, 滚动条也可以单独使用, 例如用 ScrollBar( 滚动条 ) 组件来控制连续的数值输入 ScrollBar( 滚动条 ) 组件位于组件板的 Standard 选项卡上 1. 常用属性滚动条的常用属性有 Kind Max Min Position 等, 见表 4-22 表 4-22 滚动条属性 属 性 数据类型 说 明 Kind TScrollBarKind 确定滚动条是水平或垂直 LargeChange TScrollBarInc 滑块最大移动距离 Max Integer 滑块的最大值 Min Integer 滑块的最小值 Position Integer 滑块当前位置值 SmallChange TScrollBarInc 滑块最小移动距离 滚动条的左边 ( 或底边 ) 对应于最小值, 另一边对应于最大值, 它的当前值取决于滑块的位置 图 4-13 给出了滚动条组件各属性的含义 图 4-13 滚动条的属性 2. 基本操作在滚动条中, 单击其左边的三角形按钮, 可每次左移一个最小单位 ; 单击其右边的三角形按钮, 可每次右移一个最小单位 ; 单击滑块与左边界之间的空格, 可每次左移一个最大单位 ; 单击滑块与右边界之间的空格, 可每次右移一个最大单位 另外, 可用键盘来进行操作 按 键可左右移动最小单位, 而按 PageUp PageDown 键则可左右移动最大单位 还可用鼠标拖动滑块来直接调整滑块位置 最后通过读取滚动条的 Position 属性, 就能获取滚动条的当前位置 TrackBar 组件 TrackBar( 刻度尺 ) 组件与滚动条非常相似, 该组件位于组件板的 Win32 选项卡中,

115 主要用于小范围内数值选择 第 4 章 Delphi 的基本组件 102 刻度尺的常用属性有 Frequency Max Min TickMarks 等, 见表 4-23 表 4-23 刻度尺属性 属 性 数据类型 说 明 Frequency Integer 刻度尺的最小刻度单位 LineSize Integer 单击 键时, 滑块移动距离 Max Integer 刻度尺的最大刻度 Min Integer 刻度尺的最小刻度 Orientation TTrackBarOrientation 刻度尺的方向, 有 trhorizontal( 水平 ) trvertical( 垂直 ) 两种取值 PageSize Integer 单击 PgUp PgDn 键时, 滑块移动距离 Position Integer 滑块当前位置值 SelEnd Integer 最大可选刻度 SelStart Integer 最小可选刻度 TickMarks TickStyle TTickMark TTickStyle 刻度出现位置, 有 tmbottomright( 下端 ) tmtopleft( 上端 ) TmBothl( 上下端 )3 种取值 刻度标注方式, 有 tsnone( 不标注 ) tsauto( 自动标注 ) tsmanual( 手动标注 )3 种取值 刻度尺的左边 ( 或底边 ) 对应于最小值, 另一边对应于最大值, 它的当前值取决于滑块的位置 在程序运行时, 通过拖动鼠标或单击刻度尺可将刻度尺的滑块移动到所需位置 同时, 也可通过键盘来移动滑块, 按 键可左右移动最小单位, 而按 PageUp PageDown 键则可左右移动最大单位 滑块型组件实例例 4-4 设计一个用滑块控制的色板 (1) 新建应用程序单击 File 菜单的 New Application 命令开始一个新的应用程序 (2) 设置窗体属性窗体属性设置见表 4-24 表 4-24 窗体属性 属性属性值 Caption Font 色板 宋体 五号 (3) 添加组件往窗体中添加 4 个 Label 组件 Label1~Label4 3 个 ScrollBar 组件 ScrollBar1~ ScrollBar3 1 个 TrackBar 组件 TrackBar1, 以及 8 个 Panel 组件 Panel1~Panel8 (4) 设置组件属性组件属性设置见表 4-22

116 103 Delphi 程序设计基础 表 4-25 组件属性设置 组 件 属 性 属 性 值 Label1 Caption 红 :0 Label2 Caption 绿 :0 Label3 Caption 蓝 :0 Label4 Caption 步长 :0 ScrollBar1 ScrollBar2 ScrollBar3 Max 255 TrackBar1 Max 30 Min 1 Panel1 Panel2 Panel3 Color clblack Panel4 Panel5 Panel6 Panel7 Panel8 Color clblack BevelOuter BvNone 设置完组件属性后, 窗体中组件及其布局如图 4-14 所示 (5) 添加组件事件为 ScrollBar1~ScrollBar3 添加 OnScroll 事件, 共用一个响应过程, 过程名为 ScrollBarChange; 为 TrackBar1 添加 OnChange 事件, 响应过程为 TrackBar1Change (6) 编写事件代码 图 4-14 例 4-4 组件布局 响应过程 ScrollBarChange 的作用是检测各滚动条滑块的位置, 然后根据这些位置合成各种颜色, 用来设置各 Panel 颜色, 其代码如下 : procedure TForm1.ScrollBarChange(Sender: TObject); Panel1.Color:=RGB(ScrollBar1.Position,0,0); Panel2.Color:=RGB(0,ScrollBar2.Position,0); Panel3.Color:=RGB(0,0,ScrollBar3.Position); Panel4.Color:=RGB(ScrollBar1.Position,ScrollBar2.Position,0); Panel5.Color:=RGB(ScrollBar1.Position, ScrollBar2.Position,ScrollBar3.Position); Panel6.Color:=RGB(ScrollBar1.Position,0,ScrollBar3.Position); Panel7.Color:=RGB(ScrollBar1.Position,0,ScrollBar3.Position); Panel8.Color:=RGB(0,ScrollBar2.Position,ScrollBar3.Position); Label1.Caption:=' 红 :'+IntToStr(ScrollBar1.Position); Label2.Caption:=' 绿 :'+IntToStr(ScrollBar2.Position); Label3.Caption:=' 蓝 :'+IntToStr(ScrollBar3.Position); 响应过程 TrackBar1Change 的作用是根据刻度尺的滑块位置, 设置滚动条的最大滚动单位, 其代码如下 :

117 第 4 章 Delphi 的基本组件 104 procedure TForm1.TrackBar1Change(Sender: TObject); Label4.Caption:=' 步长 :'+IntToStr(TrackBar1.Position); ScrollBar1.LargeChange:=TrackBar1.Position; ScrollBar2.LargeChange:=TrackBar1.Position; ScrollBar3.LargeChange:=TrackBar1.Position; (7) 保存程序将单元文件保存为 Unit4_4.pas, 将项目文件保存为 Project4_4.dpr (8) 运行程序单击工具栏中 Run 按钮运行程序 该例子中, 每个滚动条的取值范围都是 0 到 255, 通过调整 3 个滚动条滑块的位置, 可以改变组件 Panel1~ Panel8 的颜色 另外, 通过调整刻度尺滑块的位置, 可以调整滚动条的最大滚动单位 图 4-15 显示了例 4-4 运行效果 图 4-15 例 4-4 运行效果 4.6 容器型组件 容器型组件, 顾名思义, 指的是能够容纳组件的组件, 常用于将组件按作用分组 当一个组件添加到容器型组件中后, 该组件的活动范围就限于容器型组件中, 诸如组件的移动 滚动和显示等操作都局限于容器型组件的范围内 比较常用的容器型组件有 Group( 成组框 ) 组件 Panel( 面板 ) 组件和 ScrollBox( 滚动框 ) 组件 GroupBox 组件 GroupBox( 成组框 ) 组件位于组件板的 Standard 选项卡上, 用于在窗体中组合相关组件 当另一个组件放置于 GroupBox 组件中时,GroupBox 组件成为父组件, 而放置于其中的组件则成为子组件 子组件的活动范围不能超出父组件 例如, 单选按钮组件和复选框组件经常用 GroupBox 组件来组合, 用来表示单选或复选范围, 以免与其他单选按钮组件和复选框组件混淆 GroupBox 组件是基于窗口类的组件, 也具有一般窗口的特性 例如,GroupBox 组件有窗口句柄, 用于被 Windows API 函数调用 GroupBox 组件的常用属性见表 4-26 表 4-26 GroupBox 组件常用属性 属 性 数据类型 含 义 Align TAlign 成组框组件在窗体中的放置位置 Caption String 成组框组件使用的标题 ControlCount Integer 成组框中的子组件数目

118 105 Delphi 程序设计基础 续表 属 性 数据类型 含 义 Controls TControl 成组框中的组件数组 Enabled Boolean 成组框中的所有子组件是允许还是禁用 Handle HWnd 代表成组框的窗口句柄 下面着重介绍 Controls 属性的用途 虽然成组框中的子组件可直接调用, 但也可通过成组框组件的 Controls 属性来调用 Controls 属性是一个 TControl 类数组, 数组下标对应于子组件在 GroupBox 组件中的创建顺序 例如, 在 GroupBoxl 组件中先后添加了 Label1 Button1 和 CheckBox1 组件, 则 Label1 组件可用 GroupBox1.Controls[0] 表示,Button1 组件可用 GroupBox1.Controls[1] 表示,CheckBox1 组件可用 GroupBox1.Controls[2] 表示 这给批量动态修改组件属性带来很大方便 Panel 组件 Panel( 面板 ) 组件位于组件板的 Standard 选项卡上, 作用和 GroupBox 组件类似, 也是为了分隔组合组件 Panel 组件和 GroupBox 组件的差别主要体现在两点 : 其一是 Panel 组件没有标题, 其二是 Panel 组件的显示样式比 GroupBox 组件丰富 Panel 组件还可用于将快捷按钮 (SpeedButton) 组件组合, 从而形成工具栏 面板组件常用属性见表 4-27 表 4-27 面板组件的常用属性 属 性 数据类型 含 义 Align TAlign 面板组件在窗体中的放置位置 BevelInner TBevelCut 面板的内斜面形式 BevelOuter TBevelCut 面板的外斜面形式 BevelWidth Integer 面板的斜面宽度 BorderStyle TborderStyle 面板的边框形式 BorderWidth Integer 面板组件的边框宽度 Caption String 面板组件使用的标题 ControlCount Integer 面板中的子组件数目 Controls TControl 面板中的组件数组 Enabled Boolean 面板中的所有子组件是允许还是禁用 Handle HWnd 代表面板的窗口句柄 下面解释一下斜面与边框的概念 面板组件常用四周饰以斜面来表示面板的三维立体感, 通过设置不同的斜面可以获得不同立体感的面板 图 4-16 清楚地表示了面板组件斜面和边框的效果 ScrollBox 组件 图 4-16 面板组件的边界形式 ScrollBox( 滚动框 ) 组件位于组件板的 Addional 选项卡上, 也是一种常用的容器型

119 第 4 章 Delphi 的基本组件 106 组件 滚动框的作用是将窗口分为滚动区和非滚动区, 当滚动区 ( 即滚动框 ) 内的组件滚动时, 非滚动区中的组件不受影响 例如, 在 Word 中, 滚动文档内容时 Word 的工具栏和状态栏并不滚动 如果要在 Delphi 中实现这种功能, 就得使用滚动框 滚动框的基本属性诸如 Align ControlCount Controls Enabled Handle, 其含义均与前面所介绍的一致 另外, 滚动框还有 HorzScrollBar 属性和 VertScrollBar 属性, 分别用于设置滚动框的水平滚动条和垂直滚动条 两个属性带有相同的子属性, 其中 Increment 子属性表示单击滚动条时滚动框可视部分移动的距离,Range 子属性表示滚动条可移动范围,Position 属性表示滚动块当前位置 容器型组件很少单独使用, 随着内容的展开, 容器型组件的应用将会非常频繁, 我们会在以后的实例中具体讲述它们的使用 习 题 1. 文本型组件常用在什么方面? 2.Label 组件的快捷键如何设置? 如何使用? 3. 按钮组件 单选组件 复选组件在使用方面的区别是什么? 4. 如何对 BitBtn 组件加用户位图? 5. 试比较 Edit 组件 MaskEdit 组件 SpinEdit 组件 Memo 组件 RichEdit 组件的各自特点是什么? 6. 如何将 RadioButton 组件分成 2 组单选项,RadioButton 组件通过哪个属性来返回选中情况? 7.RadioGroup 组件是通过哪个属性来调整按钮数量和提示内容的? 又是通过哪个属性返回选中按钮值的? 8.CheckBox 组件是通过哪个属性来返回选中情况的? 9.Edit 组件通过哪个属性来进行输入 输出? 当用作数值时应注意什么? 10.MaskEdit 组件设置掩码格式的属性是哪个? 如何设置类似 SH X 格式?( 其中 SH 为固定字母, 不用输入, 为任意六位数字,- 为固定分隔符,X 为任意一个字母 ) 11. 试比较 ListBox( 列表框 ) 组件 CheckListBox( 复选列表框 ) 组件和 ComboBox( 组合框 ) 组件的各自特点是什么? 12. 在使用 ScrollBar( 滚动条 ) 组件和 TrackBar( 刻度尺 ) 组件时, 我们主要想利用它们返回什么类型的数据? 通过哪个属性返回?

120 第 5 章 菜单设计 可以说, 任何 Windows 应用程序都有菜单, 因此, 菜单设计也是应用程序开发的核心 通常应用程序中最复杂的任务都通过菜单命令来完成 事实上, 应用程序可以带有多级级联菜单的主菜单和许多快捷菜单, 甚至还可以有控制菜单 Delphi 提供了主菜单 (MainMenu) 和弹出式菜单 (PopupMenu) 两种菜单组件, 它们都位于 Standard 选项卡上, 分别用于设计主菜单和快捷菜单 另外, 还可通过函数来定制窗口的控制菜单 本章将对 Delphi 所有形式的菜单作全面的介绍, 包括 : 主菜单设计 菜单命令响应 创建动态菜单 图形菜单 快捷菜单设计 控制菜单设计 * 5.1 菜单设计简介 菜单结构一般菜单分为两级结构 窗口标题栏下显示的是菜单栏, 菜单栏包含若干主菜单选项, 每一主菜单选项下有个下拉菜单, 排列着各菜单命令项 有些菜单命令项还有子菜单, 则以级联的方式显示在该菜单命令项的右边, 依次排列, 直至最后一级子菜单 带有级联菜单的菜单命令项通常在命令项最右边有一个右向的三角符号 当某菜单命令项被选中时, 则以深色显示或打开其级联菜单, 图 5-1 所示为 Windows 资源管理器的 查看 菜单 设计菜单时, 最好不要把菜单命令项直接放入菜单栏 这是因为, 用户喜欢用菜单栏中的元素来研究菜单结构, 而不希望直接执行命令 因此, 一般情况下应避免将菜单命令项放在菜单栏, 哪怕在下拉菜单中只放一条菜单命令项也行 最常见的就是只带一个 关于 命令项的 帮助 菜单 另外, 应控制级联菜单级联的级数, 最好不要超过 4 级 实际上, 如果不愿使用级联菜单, 可将菜单中一些菜单命令项归纳为一组, 并在菜单命令项组之间用分割条来分割 例如, 图 5-1 中的菜单就分为了 5 个菜单命令项组 菜单命令项的作用菜单命令项被选中后, 一般来说作用有如下 3 种

121 第 5 章菜单设计 108 执行命令 : 用于执行某操作的菜单命令, 它们没有特殊的指示符号 设置状态 : 用于设置或取消某设置的菜单命令项, 通常用来改变某特殊选项的状态, 这些命令项常用复选标记 或单选标记 来表明该选项是否处于有效状态 在有效状态情况下, 再次执行该命令项则产生相反的效果, 如图 5-1 中的 状态栏 菜单命令项 打开对话框 : 用于激活对话框, 具体操作在对话框中进行, 操作完毕后按 OK ( 确定 ) 按钮予以确认或按 Cancel ( 取消 ) 按钮予以取消 这些命令项通常在最右边有一个省略号作指示符号, 如图 5-1 中的 自定义文件夹... 菜单命令项 菜单设计器 Delphi 提供了两种菜单设计器, 分别用于设计主菜单和快捷菜单 : 1.MainMenu 设计器 主菜单设计器主菜单设计器用于设计下拉式主菜单, 这种类型的菜单最常见, 图 5-1 所示就是下拉式主菜单 利用 MainMenu 设计器, 能方便地完成设计主菜单栏 菜单命令项并创建级联菜单等一系列功能 2.PopupMenu 设计器 快捷菜单设计器快捷菜单设计器用于设计弹出式快捷菜单 通常情况下, 右击鼠标打开的就是快捷菜单 例如, 图 5-2 所示就是在 Windows 资源管理器文件窗口中右击鼠标时打开的快捷菜单 图 5-1 主菜单结构图 5-2 快捷菜单结构 5.2 主菜单设计 利用 MainMenu 组件可在窗体上生成菜单栏以及菜单栏下的菜单选项 设计时的菜单具有所见即所得的效果, 即设计时样式与运行时完全一样 下面介绍如何利用 MainMenu 组件 主菜单设计器来设计主菜单 当然, 其准备工作是先创建一个用来包含菜单栏的窗体 打开主菜单设计器设计主菜单的第一步是打开主菜单设计器, 其操作如下

122 109 Delphi 程序设计基础 (1) 在组件板的 Standard 选项卡中选择 MainMenu 组件, 把它添加到窗体上, 此时窗体上将出现一个 MainMenu 图标 (2) 执行如下操作之一, 打开 MainMenu Designer 主菜单设计器 双击窗体中的 MainMenu 组件图标 右击 MainMenu 组件, 打开一个快捷菜单, 再从中选择 Menu Designer 命令 选定 MainMenu 组件, 再在对象查看器中单击 Items 属性值编辑框右边的省略号按钮 主菜单设计器打开后如图 5-3 所示 在主菜单设计器中有一个深色加亮的方块, 即第一个空白菜单, 用户可以在上面输 入菜单名 菜单命令项的添加 图 5-3 主菜单设计器 下面为例 3-2 添加 选项 菜单的 颜色 字体 内容 对齐 等菜单命令项为例说明如何添加菜单命令项 首先添加菜单, 选中主菜单设计器中的空白菜单, 然后利用对象查看器设置菜单名 例如, 要添加 选项 菜单, 可在对象查看器中将空白菜单的 Caption 属性设置为 选项 (&O) 此时, 即添加了一个显示为 选项 (O) 的菜单 同时, 设置菜单的 Name 属性 例如, 将把 选项 菜单的 Name 属性设为 Option 同其他组件一样, & 用于设置菜单的快捷键, & 后的字符即为快捷键键名, 可用 Alt+ 快捷键键名 来打开菜单或执行菜单命令项的键盘命令组合 例如, 选项 (O) 菜单的快捷键为 Alt+O, 即表示用组合键 Alt+O 可打开 选项 菜单 添加菜单后, 将会发生两个变化 第一个变化是所添加的菜单的右边又出现空白菜单虚框, 表示可继续添加菜单 ; 第二个变化是所添加的菜单下面出现一个空白菜单命令项虚框, 用于添加菜单命令项, 如图 5-4 所示 接着是添加菜单命令项 单击新添加的菜单下的空白菜单命令项虚框, 此时该虚框将加亮, 表示获得输入焦点, 即可利用对象查看器设置菜单命令项名和快捷键 例如, 要为 选项 菜单添加一个快捷键为 Alt+C 的 颜色 命令, 可将菜单命令项的 Caption 属性设为 颜色 (&C) 同时, 将菜单命令项的 Name 属性设置为 OptionColor 按下 Enter 键后, 输入焦点又移动到下一个新的菜单命令项上, 这样可以添加一系列的菜单命令项, 如图 5-5 所示 注意 : 若不给菜单 菜单命令项的 Name 属性赋值,Delphi 会自动为其赋值, 规则为 : 空格或特殊字符删去 ; 如果名称左侧不是字母, 则添加字母 N ; 序数总在名称末尾, 对于使用给名称的第一个菜单项, 添加序数 1, 以后依次加 1 如果不给菜单命令项名称赋值, 将在添加菜单事件时给菜单命令项的识别造成一定困难 因此, 建议按功能给菜单 菜单命令项的 Name 属性赋值 当觉得菜单命令项够了以后, 可以选取主菜单项右边的空白菜单虚框, 开始添加第二个菜单, 以及其下的菜单命令项

123 第 5 章菜单设计 110 图 5-4 添加菜单图 5-5 添加菜单命令项 菜单命令项的分组如果一个菜单中的菜单命令项过多, 可以按功能将菜单命令项分为若干组, 组与组之间用分割线隔开 在 Delphi 中, 菜单分割条也是一项菜单命令项, 只不过该菜单命令项的 Caption 属性为 ( 减号 ) 注意 : 菜单分割条的 Caption 属性只能为一个 ( 减号 ), 多了反而不是分割条 菜单命令项的热键在许多应用程序中用户都使用过像 Ctrl+C( 复制 ) Ctrl+X( 剪切 ) 之类的热键 所谓热键, 就是指在不打开菜单的情况下, 直接使用预先设置的组合键, 就可以执行某个菜单命令 很明显, 热键和快捷键不同, 因为快捷键必须打开当前的菜单时才能打开 而且, 菜单栏中的主菜单项只能有快捷键, 而不能有热键 如果要给菜单命令项设置热键, 直接单击该菜单命令项的 Shortcut 属性, 打开一下拉列表框, 从中选择所需的热键名称即可 例如, 可将 选项 菜单下的 颜色 命令项的热键设置为 Ctrl+O 菜单命令项的调整创建完菜单后, 经常会发生要在已有菜单 菜单命令项之间插入新的菜单或菜单命令项, 剔除不需要的菜单 菜单命令项, 调整菜单 菜单命令项的排列等情况, 这就是现在要介绍的菜单命令项调整 如果要在现有菜单 菜单命令项之前插入新的菜单 菜单命令项, 可右击该菜单 菜单命令项, 打开一个快捷菜单从中选择 Insert 命令, 如图 5-6 所示 如果要删除现有菜单 菜单命令项, 可右击该菜单 菜单命令项, 打开一个快捷菜单, 从中选择 Delete 命令项 如果要调整现有菜单 菜单命令项的排列情况, 可选择要调整的菜单 菜单命令项, 按住并拖动鼠标, 到所需位置再释放鼠标 注意 : 删除一个菜单, 该菜单下的所有菜单命令项将同时被删除 ; 移动一个菜单, 该菜单下的所有菜单命令项随之移动

124 111 Delphi 程序设计基础 图 5-6 调整菜单命令图 5-7 级联菜单 创建级联菜单级联菜单指的是菜单命令项包括的子菜单 依此类推, 一个菜单可以有多级级联菜单 不过, 从条理性和操作方便而言, 级联菜单最好不要超过 4 级 如果要为某菜单命令项创建级联菜单可以右击该菜单命令项, 打开一个快捷菜单, 然后从中选择 Create Submenu 命令 ( 或直接按 Ctrl+ 键 ) 此时, 该菜单命令项就会出现一个右向三角形和一个空白的级联菜单 往级联菜单的各菜单命令项的 Caption 属性中输入标题, 并设置 Name 属性和快捷键, 就创建了一个级联菜单 例如, 图 5-7 中即为 对齐 命令创建了一个级联菜单, 包括 左对齐 居中 和 右对齐 三个命令 至此, 我们就完成了主菜单的初步设计, 使它有了一个基本的外观和框架 但要响应菜单命令项, 还需要给它添加响应的代码 5.3 菜单命令响应 主菜单对应于 TMainMenu 类, 而每一项菜单和菜单命令项都对应于 TMenuItem 类 这些 TMenuItem 都有自己的事件, 用以响应各菜单命令项 下面通过例子来说明如何对菜单命令项进行响应 例 5-1 给例 3-2 添加菜单 (1) 打开例 3-2 应用程序启动 Delphi, 从 File 菜单中选取 Reopen 命令, 从中选择例 3-2 的应用文件 Project3_2 或选取 Open Project 命令, 从对话框中选择例 3-2 的应用文件 Project3_2 如图 3-9(a) 所示 (2) 创建菜单创建菜单, 见表 5-1 表 5-1 菜单及菜单命令项 菜单菜单命令项级联命令项属性属性值属性属性值 选项 Caption 选项 (&O) Name Option

125 第 5 章 菜单设计 112 续表 菜 单 菜单命令项 级联命令项 属 性 属 性 值 属 性 属 性 值 颜色 Caption 颜色 (&C) Name OptionColor ShortCut Ctrl+O 字体 Caption 字体 (&F) Name OptionFont ShortCut Ctrl+F 对齐 Caption 对齐 (&A) Name OptionAlign 左对齐 Caption 左对齐 (&L) Name OptionAlignLeft ShortCut Ctrl+L 居中 Caption 居 中 (&C) Name OptionAlignCenter ShortCut Ctrl+C 右对齐 Caption 右对齐 (&R) Name OptionAlignRight ShortCut Ctrl+R 隐藏 Caption 隐藏 Name OptionHide 帮助 Caption 帮助 (&H) Name Help 关于 Caption 关于 (&A) Name HelpAbout (3) 添加事件为菜单命令项添加的事件见表 5-2 表 5-2 菜单命令项的事件 菜单命令项 组 件 事 件 事件响应函数 颜色 OptionColor OnClick Button1Click 字体 OptionFont OnClick Button2Click 左对齐 OptionAlignLeft OnClick OptionAlignLeftClick 居中 OptionAlignCenter OnClick OptionAlignCenterClick 右对齐 OptionAlignRight OnClick OptionAlignRightClick (4) 编写事件响应代码 颜色 命令项用于打开 颜色 对话框 ColorDialog1, 然后将从 颜色 对话框中选定的颜色作为文本 Memo1 的背景颜色, 其 OnClick 事件同 颜色 按钮相同, 所以可直接引用 Button1Click 的响应代码, 方法为 : 打开菜单设计器, 选择 颜色 菜单命令项, 在 Object Inspector 窗口中的 Events 页中, 在 OnClick 旁的下拉列表中选择 Button1Click 对于功能相同的事件, 我们建议采用事件引用, 这样做, 一方面可以减小程序代码的冗余, 另一方面, 一旦需要修改程序, 只要改被引用的地方一处就可以了 字体 命令项用于打开 字体 对话框 FontDialog1, 然后将从 字体 对话框中选定的字体设置给文本 Memo1, 其 OnClick 事件功能和 字体 按钮相同, 可直接引用 Button2Click 左对齐 命令项用于将文本 Memo1 的文本左对齐, 其 OnClick 事件的响应代码如下 : procedure TForm1.OptionAlignLeftClick(Sender: TObject); Memo1.Alignment:=taLeftJustify; OptionAlignLeft.Checked:=True; OptionAlignRight.Checked:=False;

126 113 Delphi 程序设计基础 OptionAlignCenter.Checked:=False; RadioGroup1.ItemIndex:=0; 居中 命令项用于将文本 Memo1 的文本居中对齐, 其 OnClick 事件的响应代码如下 : procedure TForm1.OptionAlignCenterClick(Sender: TObject); Memo1.Alignment:=taCenter; OptionAlignLeft.Checked:=False; OptionAlignRight.Checked:=False; OptionAlignCenter.Checked:=True; RadioGroup1.ItemIndex:=1; 右对齐 命令项用于将文本 Memo1 的文本右对齐, 其 OnClick 事件的响应代码如下 : procedure TForm1.OptionAlignRightClick(Sender: TObject); Memo1.Alignment:=taRightJustify; OptionAlignLeft.Checked:=False; OptionAlignRight.Checked:=True; OptionAlignCenter.Checked:=False; RadioGroup1.ItemIndex:=2; (5) 保存程序将单元文件另存为 Unit5_1.pas, 将项目文件另存为 Project5_1.dpr (6) 编译运行程序单击工具栏上 Run 按钮即可运行程序 运行后, 单击 选项 菜单的 颜色 命令, 可设置文本的颜色 ; 单击 字体 命令, 可设置文本的字体 ; 而单击 左对齐 居中 右对齐 命令, 则可调整文本的对齐方式 如图 5-8 所示 图 5-9 显示了将字体设置为楷体 加粗 三号, 颜色为红色, 对齐方式为居中时的效果 图 5-8 加入菜单后的窗口图 5-9 响应菜单命令

127 第 5 章菜单设计 运行时设置菜单 在应用程序运行时, 可以进行一系列的操作来调整菜单结构和外观 例如给菜单命令项添加单选或复选标记, 将菜单命令项灰显 隐藏等 通常, 有 5 种属性可用于应用程序运行时设置菜单 Checked 属性 : 可用于在运行时给菜单命令项添加复选标记 ; RadioItem 属性 : 可用于在运行时给菜单命令项添加单选标记 ; Enabled 属性 : 可用于在运行时将菜单命令项灰显 ; Caption 属性 : 可用于在运行时调整菜单命令项的文本 ; Visible 属性 : 可用于在运行时隐藏菜单命令项 下面介绍如何实现上述目的 并通过例 5-2 描述实现方法 菜单命令项灰显当我们在进行菜单操作时, 有时要求某项菜单或菜单命令项不能被用户操作, 就把该菜单或菜单命令项用灰色显示, 用户对它的操作不会有任何响应 菜单命令项灰显可以通过设置菜单命令项的 Enabled 属性来实现, 当该属性为 True 时, 菜单命令项有响应 ; 当该属性为 False 时, 菜单命令项灰显, 不响应鼠标和键盘操作 例 5-2 沿用上一节的例子, 要求单击 隐藏 命令后, 帮助 菜单灰显, 不能再使用, 再次单击 隐藏 命令, 帮助 菜单又恢复 首先为 隐藏 命令 ( Name 属性为 OptionHide) 添加 OnClick 事件, 事件响应过程为 OptionHideClick 然后为该过程添加如下代码 : procedure TForm1.OptionHideClick(Sender: TObject); Help.Enabled:=Not Help.Enabled; 这样, 就可实现上述目的, 其效果如图 5-10 所示 菜单命令项隐藏 图 5-10 菜单命令灰显 菜单或菜单命令项灰显是为了让用户不能对它操作, 但是由于它的可见性, 总会吸引用户的注意, 所以有时我们干脆让菜单或菜单命令项隐藏起来 这可利用菜单命令项的 Visible 属性来实现, 当该属性为 True 时菜单命令项可见 ; 属性为 False 时, 则该菜单命令项隐藏 将前面 OptionHideClick 过程的代码修改为如下形式 : procedure TForm1.OptionHideClick(Sender: TObject); Help.Visible:=Not Help.Visible; 这样, 就可以通过单击 隐藏 命令来控制 帮助 菜单的显示和隐藏了 图 5-11 显示

128 115 Delphi 程序设计基础了 帮助 菜单被隐藏的效果 改变菜单命令项文本在运行程序时, 可以让菜单命令项根据运行的情况来调整菜单命令项的文本内容, 这主要通过菜单命令项的 Caption 属性来实现 在前面的例子中, 我们希望隐藏 帮助 菜单后, 将 隐藏 命令改为 显示 命令, 这时可将 OptionHideClick 过程的代码修改为如下形式 : procedure TForm1.OptionHideClick(Sender: TObject); Help.Visible:=Not Help.Visible; if Help.Visible then OptionHide.Caption:=' 隐藏 ' else OptionHide.Caption:=' 显示 ' 图 5-12 显示了修改菜单命令文本的效果 图 5-11 隐藏菜单命令图 5-12 修改菜单命令文本 菜单命令项单选标记所谓单选菜单命令项就是一组相互排斥的菜单命令项, 用户只能在该组命令项中选择一个 设计单选菜单命令项, 必须保证两个条件 : 首先这一组菜单命令项位于同一下拉菜单或同一级联菜单中, 而且它们的 GroupIndex 属性必须相同 ; 其次 RadioItem 属性都是 True 这样, 惟一被选中的菜单命令项前面就出现一个圆点标记, 表示该菜单命令项被选中 菜单命令项的 Checked 属性为 True 时, 就添加单选标记 ; 为 False 时, 取消单选标记 沿用上一节的例子, 将 左对齐 居中 和 右对齐 菜单命令的 GroupIndex 属性值都设置为 2, 将 RadioItem 都设置为 True, 则运行时选中 3 个菜单命令中的任一个, 该命令

129 前都会出现 个单选标记, 如图 5-13 所示 第 5 章菜单设计 116 图 5-13 单选标记图 5-14 添加复选标记 菜单命令项复选标记复选标记是指当用户选中某个菜单命令项时, 系统会在该菜单命令项前加一个复选标记 复选标记常用于一些状态设置的菜单命令项, 如果取消选中, 则 标记消失 设置复选标记很简单, 只要把菜单命令项的 Checked 属性设置为 True, 该菜单项就有复选标记,Checked 属性为 False 时, 没有复选标记 在前面隐藏 帮助 菜单时, 我们希望 隐藏 命令前显示复选标记, 帮助 菜单恢复显示时, 则取消 隐藏 命令前的复选标记, 可将 OptionHideClick 过程的代码修改为如下形式 : procedure TForm1.OptionHideClick(Sender: TObject); Help.Visible:=Not Help.Visible; OptionHide.Checked:= Not OptionHide.Checked; 这样, 就可实现让 隐藏 命令根据 帮助 菜单的显隐来决定是否添加复选标记 图 5-14 显示了 隐藏 命令添加复选标记的效果 将单元文件另存为 Unit5_2.pas, 将项目文件另存为 Project5_2.dpr 5.5 创建动态菜单 用户可以在程序运行时动态地创建一个菜单, 就像在 Word 中, 每打开一个文档, 就会在 窗口 菜单下动态增加一个该文档的菜单项 在介绍如何创建动态菜单之前, 首先分析一下菜单类 主菜单对应于 Delphi 中的 TMainMenu 类, 主菜单项 ( 常简称为菜单 ) 对应于 Delphi 中的 TMenuItem 类 通常主菜单栏中的各菜单构成一个列表, 存储在主菜单 (TMainMenu) 的 Items 属性中 而每一菜单中的菜单命令数则存储在该菜单 (TMenuItem) 的 Count 属

130 117 Delphi 程序设计基础性中 这样, 往主菜单栏中添加一个菜单, 就可以利用 TMainMenu 类的 Items 属性, 通过 Insert 方法来实现 ; 而从主菜单栏中删除一个菜单, 同样是利用 Items 属性, 不过是利用 Remove 方法 在菜单中添加或删除一个菜单命令, 则需利用 TMenuItem 类的 count 属性, 同样也是利用 Insert 或 Remove 方法 动态添加菜单时, 必须为每一菜单命令指定 OnClick 事件的响应过程名称 在此过程中, 可以为多个菜单命令的 OnClick 事件指定同一个响应过程, 而通过 Sender 参数确定具体执行哪一项命令项 例 5-3 继续前面的例子, 在程序运行后, 动态地在 选项 菜单后添加一个 内容 菜单 首先我们先添加两个菜单项 增加菜单 (name 属性为 insmenu) 和 删除菜单 (name 属性为 delmenu), 用于动态地增加和删除菜单 在 增加菜单 的单击事件中创建 内容 菜单, 并指定菜单命令的 OnClick 事件的响应过程, 其代码如下 : procedure TForm1.InsmenuClick(Sender: TObject); var Content,Item:TMenuItem; Position,i:Integer; Content:=TMenuItem.Create(self); // 创建菜单 Content.Caption:=' 内容 (&C)'; Content.AutoHotkeys:=maManual; // 禁止系统自动产生菜单命令项快捷键 Content.OnClick:=ContentClick; // 决定菜单 OnClick 事件的响应过程 Position:=MainMenu1.Items.IndexOf(Option); // 确定菜单插入的位置 MainMenu1.Items.Insert(Position+1,Content); // 插入菜单 内容 (C) Item:=TMenuItem.Create(self); // 创建菜单命令项 Item.Caption:=' 文档 1'; Item.GroupIndex:=1; // 决定菜单命令项为单选 Item.RadioItem:=true; Item.OnClick:=ContentItemClick; Content.Insert(0,Item); // 插入菜单命令项 文档 1 Item:=TMenuItem.Create(self); // 创建菜单命令项 Item.Caption:=' 文档 2'; Item.GroupIndex:=1; // 决定菜单命令项为单选 Item.RadioItem:=true; Item.OnClick:=Button3Click; Content.Insert(1,Item); // 插入菜单命令项 文档 2

131 第 5 章菜单设计 118 Insmenu.Enabled:=false; Delmenu.Enabled:=true; 在 删除菜单 的单击事件中删除 内容 菜单, 并指定菜单命令的 OnClick 事件的响应过程, 其代码如下 : procedure TForm1.DelmenuClick(Sender: TObject); var Position:Integer; Position:=MainMenu1.Items.IndexOf(Option); // 确定删除菜单的位置 MainMenu1.Items.Delete(Position+1); Insmenu.Enabled:=true; Delmenu.Enabled:=false; 接下来, 我们应当手工编写 内容 菜单的 OnClick 事件的响应, 和 内容 菜单下各菜单命令的 OnClick 事件的响应 在上面的代码中, 我们已经给 内容 菜单的 OnClick 事件指定了 ContentClick 响应过程, 给 内容 菜单下各菜单命令的 OnClick 事件指定了 ContentItemClick 响应过程 因此, 先在 Form1 的类定义中添加这两个响应过程的说明 : type TForm1 = class(tform) procedure FormCreate(Sender: TObject); procedure ContentClick(Sender: TObject); // 手工添加 procedure ContentItemClick(Sender: TObject); // 手工添加 private { Private declarations } public { Public declarations } 然后编写 ContentClick 响应过程的代码, 该过程的作用是扫描 内容 菜单中选定了哪一项命令, 再让该命令显示单选标记 其代码如下 : procedure TForm1.ContentClick(Sender: TObject); if memo1.lines [ 0 ]=' 睡觉 ' then with Sender as TMenuItem do items [ 0 ].Checked:=true

132 119 Delphi 程序设计基础 else with Sender as TMenuItem do items [1].Checked:=true; 然后编写 ContentItemClick 响应过程的代码, 该过程的作用是扫描对 内容 菜单中选定命令作出执行反应 其代码如下 : procedure TForm1.ContentItemClick(Sender: TObject); Memo1.Lines.Text:=' 睡觉 '+chr(13)+chr(13)+ //chr(13) 为回车符 ' 大地公公睡觉,'+chr(13)+' 静悄悄 '+chr(13)+ ' 月亮婆婆睡觉,'+chr(13)+' 眯眯笑 '+chr(13)+ ' 老爷爷睡觉,'+chr(13)+' 胡子翘 '+chr(13)+ ' 小娃娃睡觉,'+chr(13)+' 呼噜呼噜,'+chr(13)+' 像只大花猫 '; 将单元文件另存为 Unit5_3.pas, 将项目文件另存为 Project5_3.dpr 这样, 就可以编译并运行程序了, 运行时, 单击 选项 菜单中的 增加菜单 命令项, 动态增加了 内容 菜单, 且可单击 内容 菜单中的 文档 1 和 文档 2, 执行相应命 令, 单击 选项 菜单中的 删除菜单 命令项, 则动态删除了 内容 菜单 图 5-15 是例子运行的效果图 图 5-15 创建动态菜单 5.6 图形菜单 菜单中应用图形主要有两种方式, 第一种方式是在菜单命令项前加上图标, 第二种方式是以图形代替菜单命令项的文本来表示菜单命令项 下面分别介绍这两种方式 菜单命令项图标在许多应用程序的菜单命令项前, 通常都有菜单命令项图标, 这些图标一般都和工具栏上快捷按钮的图标一致 同时, 菜单命令项前拥有图标也使菜单命令项的含义更加直观易懂 在 Delphi 中, 可以很容易地向菜单命令添加图标, 用户只需向窗体添加一个图像列表 (ImageList) 控件, 向该控件添加一系列位图, 再用菜单组件的 Images 属性将 ImageList 组件与菜单相连, 并为菜单命令项设置相应的 ImageIndex 属性 例 5-4 在例 5-3 的基础上介绍如何实现这些步骤 (1) 打开例子应用程序启动 Delphi, 从 File 菜单中选取 Reopen 命令, 从中选择例子的应用文件 Project5_3 或选取 Open Project 命令, 从对话框中选择例子应用文件 Project5_3 (2) 添加图像列表控件

133 第 5 章菜单设计 120 从组件板的 Win32 选项卡上选择 ImageList 控件, 将其添加到窗体中, 控件名为 ImageList1 (3) 向图像列表控件添加位图在窗体中双击 ImageList 控件, 打开该控件的图像列表编辑器窗口, 如图 5-16 所示 单击 Add 按钮, 可增加一幅位图 将菜单命令要用到的位图按顺序加载到 Images 列表中, 然后单击 OK 按钮返回 如果要使用自行绘制的位图, 可使用 Delphi 提供的 ImageEditor ( 图像编辑器 ) 图 5-16 图像列表编辑器窗口 如果要加载的位图不是 大小, 需要先设置 ImageList1 组件的 Height 属性和 Width 属性 (4) 将图像列表组件与菜单组件相连将 MainMenul 组件的 Images 属性设置为 ImageList1 组件的 Name 属性 ImageList1 (5) 为菜单命令项选择图标 ImageList 控件中添加的每个位图都有一个索引号, 从 0 开始顺序排列 要给菜单命令项添加图标, 则将该菜单命令项的 ImageIndex 属性设置为图标位图在 ImageList 组件中对应的图形的索引号 在不使用图标时, 菜单命令的 ImageIndex 属性值为 1 (6) 保存程序将单元文件另存为 Unit5_4.pas, 将项目文件另存为 Project5_4.dpr (7) 编译运行程序单击工具栏上 Run 按钮即可运行程序 图 5-17 显示了给菜单命令项添加图标后的效果 注意 : 给菜单命令添加图标后, 使用菜单命令的 Checked 属性时, 将不会开出现 标记, 而是菜单命令图标下凹 图 5-17 中的 左对齐 命令可看到这种 情况 图 5-17 菜单命令项图标

134 121 Delphi 程序设计基础 图形菜单命令项 * 所谓图形菜单, 指的是用位图代替菜单命令的文本来显示菜单命令 有些时候, 以图形 方式显示菜单, 将更加直观和有效 下面介绍如何创建图形菜单 例 5-5 创建图形菜单 创建图形菜单基本上可分为如下步骤 (1) 创建菜单 按 5-2 节介绍的知识创建菜单 例如, 创建表 5-3 所列的菜单 表 5-3 (2) 绘制位图 菜单及菜单命令 你可以使用已有位图, 也可以用自己绘制的位图, 作为图形菜单的位图 绘制位图可使用 Delphi 提供的 Image Editor( 图像编辑器 ) 这里, 我们绘制了如图 5-18 所示的位图, 并将其 命名为 Color.bmp 和 Font.bmp (3) 装载位图 给菜单命令装载位图使用的是 ModifyMenu 函数, 这是一个 API 函数, 该函数的语法如下 : function ModifyMenu(hMenu:HMENU; uposition, uflags,uidnewitem:uint; lpnewitem :PChar) :BOOL stdcall; 函数中各参数的含义如下 hmenu 参数 : 菜单命令所属的菜单的句柄, 通常利用菜单名 (Name 属性 ) 的 Handle 方法来获取 例如, 字体 命令所属的菜单是 选项, 该菜单的 Name 属性为 Option, 因 此可通过 Option.Handle 来获取句柄 uposition 参数 : 要用图形显示的菜单命令的位置, 即该菜单命令的索引号 例如, 字 体 命令是 选项 菜单的第一项命令, 可用 Option.Items [0] MenuIndex 来获取索引号 uflags 参数 : 说明其他参数的一些菜单标志, 应当使用 mf_byposition or mf_bitmap uidnewitem 参数 : 菜单命令的标志符, 存储在 Command 属性中 例如, 字体 命 令的标志符可通过 Option.Items [0].Command 来获取标志符 菜单或菜单命令属性属性值备注 选项 Caption 选项 (&O) Name Option 颜色 Caption 颜色 (&C) 属于 选项 菜单 Name OptionColor 字体 Caption 字体 (&F) 属于 选项 菜单 Name OptionFont IpNewItem 参数 : 传递位图的句柄, 例如, 位图对象 Bmp 的句柄可用 Pointer(Bmp.Handle) 来获取 图 5-18 绘制位图 装载位图通常在窗体的 OnCreate 事件的响应过程中进行 下面给出了为 颜色 和 字

135 第 5 章菜单设计 122 体 命令装载位图时的窗体的 OnCreate 事件的响应过程 : procedure TForm1.FormCreate(Sender: TObject); Var Bmp:Tbitmap; Begin Bmp:=Tbitmap.Create; // 给 颜色 菜单命令装载位图 Bmp.LoadFromFile('Color.bmp'); ModifyMenu(Option.Handle,Option.Items [0].MenuIndex, Mf_ByPosition or mf_bitmap,option.items [0].Command, Pointer(Bmp.Handle)); Option.Items [0].Tag:=Integer(Bmp); Bmp:=Tbitmap.Create; // 给 字体 菜单命令装载位图 Bmp.LoadFromFile('Font.bmp'); ModifyMenu(Option.Handle,Option.Items [1].MenuIndex, Mf_ByPosition or mf_bitmap,option.items [1].Command, Pointer(Bmp.Handle)); Option.Items [1].Tag:=Integer(Bmp); (4) 清除位图图形菜单的最后一步是在关闭窗口时清除位图对象, 释放位图对象所占的内存空间 清除位图通常在窗体的 OnDestroy 事件的响应过程中进行 下面给出了为 字体 命令清除位图时的窗体的 OnDestroy 事件的响应过程 : procedure TForm1.FormDestroy(Sender: TObject); Tbitmap(Option.Items [0].Tag).Free; Tbitmap(Option.Items [1].Tag).Free; 这样, 就完成了图形菜单的创建工作 至于图形菜单的事件响应, 则完全和文本菜单一样, 这里不再赘述 (5) 保存程序将单元文件另存为 Unit5_5.pas, 将项目文件另存为 Project5_5.dpr (6) 编译运行程序单击工具栏上 Run 按钮即可运行程序 图 5-19 显 示了图形菜单的效果 图 5-19 图形菜单 5.7 菜单模板 我们在菜单设计中, 经常要设计同种样式和作用的菜单项, 有些菜单格式都成了约定俗 成的标准, 所以, 我们会想, 是否可以让 Delphi 自动创建某些格式的菜单项, 而且能够非常

136 123 Delphi 程序设计基础全面地完成大部分标准格式的设计, 这就是使用菜单模板 使用菜单模板可以给用户节省大量的时间, 不必再重复一些简单的格式设计, 而且由于菜单模板使用的是标准 Windows 技术, 如菜单命令的命名 热键的设置都非常的规范 当然, 在某些场合菜单模板创建的菜单不能满足用户的要求, 还需要自己修改 下面介绍菜单模板的操作 插入菜单模板 Delphi 的菜单模板存储在文件 delphi7\bin\delphi32.dmt 中 要使用菜单模板, 执行如下操作 (1) 在窗体中插入 MainMenu 组件 (2) 双击 MainMenu 组件, 进入主菜单设计器窗口 (3) 右击要插入菜单模板的空白主菜单项或空白菜单命令, 或按组合键 Alt+Fl0, 打开一快捷菜单, 如图 5-20 所示 (4) 选择 Insert From Template 命令, 打开 Insert Template ( 插入模板 ) 对话框, 如图 5-21 所示 图 5-20 菜单设计器中的快捷菜单图 5-21 插入模板 对话框 (5) 选择所需的菜单 Delphi 缺省情况下提供了 Edit ( 编辑 ) 菜单 File ( 文件 ) 菜单 File ( 文件, 用于文本编辑器 ) 菜单 Help ( 帮助 ) 菜单 Help ( 帮助, 扩展 ) 菜单 MDI 框架菜单 Window ( 窗口 ) 菜单共 7 个菜单模板 (6) 单击 OK 按钮, 完成插入菜单模板 插入所需菜单模板后, 就可以用上几节中所学的主菜单设计方法来对菜单进行定制或修改, 并为其中的各个菜单命令加入 OnClick 事件响应程序 创建菜单模板除了 Delphi 预定义的几种菜单模板外, 还允许用户将自己设计的菜单保存为菜单模板 如果要创建菜单模板, 执行如下操作 (1) 在窗体中插入 MainMenu 组件 (2) 双击 MainMenu 组件, 进入主菜单设计器

137 第 5 章 菜单设计 124 (3) 在主菜单设计器中设计所需菜单 (4) 鼠标右键单击已经创建好的主菜单, 或按组合键 Alt+F10, 打开一快捷菜单 (5) 选择 Save As Template ( 保存为模板 ) 命令, 打开 Save Template ( 保存模板 ) 对话框, 如图 5-22 所示 图 5-22 保存模板 对话框图 5-23 删除模板 对话框 (6) 在 Template Description ( 模板描述 ) 编辑框中输入要保存的模板名称 (7) 单击 OK 按钮 这样, 就将用户创建的菜单保存为了菜单模板, 下次打开对话框时, 就会发现对话框中有用户自己创建的菜单模板 删除菜单模板 Delphi 也允许用户删除不需要的菜单模板 如果要删除菜单模板, 执行如下操作 (1) 打开主菜单设计器 (2) 鼠标右键单击主菜单设计器, 打开一快捷菜单 (3) 选择 Delete Templates ( 删除模板 ) 命令, 打开 Delete Templates ( 删除模板 ) 对话框, 如图 5-23 所示 (4) 选择要删除的菜单模板 (5) 单击 OK 按钮 这样就可以将选定的菜单模板删除 5.8 快捷菜单设计 我们在前面经常使用快捷菜单 所谓快捷菜单就是右击鼠标时, 在鼠标当前位置弹出的菜单 快捷菜单可以更方便于操作和某些命令项的选取 这一节我们介绍如何创建和使用快捷菜单 创建快捷菜单和创建主菜单的过程基本相同, 也是使用菜单设计器来完成, 快捷菜单组件 PopupMenu 位于组件板的 Standard 选项卡上

138 125 Delphi 程序设计基础 快捷菜单的设计设计快捷菜单时, 先在组件板 Standard 选项卡中选取 PopupMenu 组件, 添加到窗体中, 然后双击 PopupMenu 组件, 或右击组件从打开的快捷菜单中选择 Menu Designer 命令, 就可以打开菜单设计器 设计的过程与主菜单设计完全相同, 这里不再重复 注意 : 要在窗体上弹出快捷菜单, 窗体的 PopupMenu 属性必须为要打开的快捷菜单名称 (PopupMenu 组件的 Name 属性 ) 如果空白, 不能打开快捷菜单 如果有多个快捷菜单, 而且在不同的组件中打开, 应该在要打开快捷菜单的组件的 PopupMenu 属性中指定要打开的快捷菜单名称 例如, 要在组件 1( 如 RichEdit) 中使用快捷菜单 1, 应在组件 1 的 PopupMenu 属性中选择要打开的快捷菜单 1 的名称 在组件 2( 如 Button) 中使用快捷菜单 2, 应在组件 2 的 PopupMenu 属性中选择要打开的快捷菜单 2 的名称 例 5-6 设计快捷菜单, 见表 5-4 表 5-4 设计快捷菜单 菜单命令项属性属性值备注 颜色 Caption 颜色 (&C) Name Color 字体 Caption 字体 (&F) Name Font 对齐 Caption 对齐 (&A) Name Align 左对齐 Caption 左对齐 (&L) 级联于 对齐 命令 Name AlignLeft 居中 Caption 居中 (&C) 级联于 对齐 命令 Name AlignCenter 右对齐 Caption 右对齐 (&R) 级联于 对齐 命令 Name AlignRight 隐藏 Caption 隐藏 Name Hide 设计完快捷菜单后, 别忘了在打开快捷菜单的窗体 ( 假定为 Form1) 的 PopupMenu 属性中添加快捷菜单的名称 ( 假定为 PopupMenu1) 这样, 运行时, 在窗体中用鼠标右击才能打开快捷菜单 运行后右击鼠标效果如图 5-24 所示 快捷菜单的响应快捷菜单的弹出位置有两种方式 一种是自动在鼠标的指针位置弹出, 称为自动方式 ; 另一种是弹出位置由用户自定义, 称为手动方式 如果采用自动方式, 必须将 PopupMenu 组件的 AutoPopup 属性设置为 True, 这也是缺省方式

139 第 5 章菜单设计 126 如果采用手动方式, 先将 AutoPopup 属性设为 False, 通过函数 Popup(X,Y) 来自定义快捷菜单的弹出位置 (X,Y) 然后给窗体添加 OnMouseDown 事件, 编写相应的代码, 下面给出了样本代码 : procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); if Button=mbRight then PopupMenu1.Popup(Form1.Left,Form1.Top+Form1.Height 100); 上面的 Button=mbRight 表示右击鼠标 程序运行后, 在窗体上的任意一个位置单击鼠标右键, 就会在窗体的左下角弹出快捷菜单, 如图 5-25 所示 图 5-24 右击鼠标后显示快捷菜单图 5-25 手动方式打开快捷菜单 至于快捷菜单中菜单命令的响应, 仍是通过给菜单命令添加 OnClick 事件, 通过事件响 应过程来实现菜单命令的功能 这一点与主菜单完全相同, 这里不再重复 将单元文件另存为 Unit5_6.pas, 将项目文件另存为 Project5_6.dpr 5.9 控制菜单设计 * 在应用程序窗口中的标题栏左侧有一个图标, 单击时会出现一 个下拉菜单, 里面有 还原 最小化 最大化 关闭 等一 些对窗口进行控制的菜单命令项, 我们把这个菜单称作控制菜单, 也称系统菜单 图 5-26 所示就是上一节例子中的控制菜单 Delphi 允许对控制 菜单进行操作, 下面介绍如何进行控制菜单设计 控制菜单设计 Delphi 允许往控制菜单中添加整个菜单, 但要借助于 MainMenu 组件或 PopupMenu 组件和名为 AppendMenu 的 API 函数 图 5-26 控制菜单

140 127 Delphi 程序设计基础如果往控制菜单中添加单项菜单命令, 则直接借助于 AppendMenu 函数即可 例 5-7 控制菜单设计 (1) 创建菜单往控制菜单中添加菜单命令的第一步是创建由要添加的菜单命令构成的菜单 首先往窗体中添加一个 MainMenu 组件 MainMenu1 然后双击该组件, 打开主菜单设计器, 设计所需菜单 例如, 设计表 5-5 所列的菜单 表 5-5 设计菜单 菜单命令项 属 性 属 性 值 备 注 对齐 Caption 对齐 (&A) Name Align 左对齐 Caption 左对齐 (&L) 属于 对齐 命令 Name AlignLeft 居中 Caption 居中 (&C) 属于 对齐 命令 Name AlignCenter 右对齐 Caption 右对齐 (&R) 属于 对齐 命令 Name AlignRight (2) 添加菜单创建完菜单之后, 就可以往控制菜单中添加菜单命令了 往控制菜单中添加菜单需要利用 API 函数 AppendMenu, 这通常在窗体 ( 假定为 Form1) 的 OnCreate 事件的响应过程中进行编程 下面给出了一个样本代码 : procedure TForm1.FormCreate(Sender: TObject); Const idsyscolor=100; var i:integer; AppendMenu(GetSystemMenu(Handle,False),MF_SEPARATOR,0,''); AppendMenu(GetSystemMenu(Handle,False),MF_STRING,idSysColor,' 颜色 (&C)'); with MainMenu1 do for i:=0 to Items.Count 1 do AppendMenu(GetSystemMenu(Self.Handle,False), MF_POPUP,Items [ i ].Handle,PChar(Items [ i ].Caption)); 上面的代码中,GetSystemMenu 是应用程序的接口 (API) 函数, 用来打开控制菜单 ; 而用 AppendMenu 函数分别给控制菜单添加 3 项不同的菜单命令项 1 语句 : AppendMenu(GetSystemMenu(Handle,False),MF_SEPARATOR,0,''); 给控制菜单添加 个分割条, 用 MF_SEPARATOR 作标识 2 语句 :

141 第 5 章菜单设计 128 AppendMenu(GetSystemMenu(Handle,False),MF_STRING,idSysColor,' 颜色 (&C)'); 给控制菜单添加一菜单命令, 该菜单命令的标题用 颜色 (&C) 指定, 同时必须指定一常量 ( 此处为 idsyscolor) 作为菜单命令的文本表示, 并用 MF_STRING 作标识 同时, 别忘了声明文本表示为一常量 循环语句中的语句 : AppendMenu(GetSystemMenu(Self.Handle,False),MF_POPUP,Ite ms [ i ].Handle,PChar(Items [ i ].Caption)); 用以将主菜单 MainMenu1 添加进控制菜单中, 用 MF_POPUP 作标识 如果要将快捷菜单加进控制菜单中, 只需在 With 语句中将主菜单 MainMenu1 换成相应的快捷菜单 ( 如 PopupMenu1) 即可 上述代码经过编译运行后, 可以得到应用程序的控制 菜单如图 5-27 所示 控制菜单响应 图 5-27 控制菜单设计 控制菜单命令的响应使用的是 WM_Command 命令 用户选中一项菜单命令时,Delphi 就会根据所产生的 WM_SysCommand 消息产生响应, 但这些响应只是对于预定义的菜单命令的 用户自行加入到控制菜单中的菜单命令的响应, 需要用户来编写响应函数 要对 WM_Command 消息作出响应, 首先必须在单元文件中窗体 ( 假定为 TForm1) 类定义中 Public 部分插入 WM_SysCommand 消息的响应过程 WMSysCommand 以及消息 WM_ SysCommand 的说明 : private { Private declarations } public { Public declarations } procedure WMSysCommand(var Msg:TMassage); message WM_SysCommand; 接着是手动编写响应过程 WMSysCommand 的代码 根据控制菜单中菜单命令的添加方式, 代码的编写也分为以下两种情况 第一种情况是菜单命令通过指定菜单命令标题和文本表示, 用 MF_STRING 作标识添加的, 此时可进行如下编程 : procedure TForm1.WMSysCommand(var Msg:TMessage); if Msg.WParam=idSysColor then with ColorDialog1 do Color:=Memo1.Color;

142 129 Delphi 程序设计基础 if Execute then Memo1.Color:=Color; Inherited; 在上述代码中, 应用程序窗体中有一 Memo 组件 Memo1, 通过执行控制菜单中的 颜色 命令, 设置 Memo1 的背景颜色 首先, 通过 TMessage 类型变量 Msg 检测是否单击了 颜色 命令, 然后再执行相应的操作 第二种情况是菜单命令通过 MainMenu 组件或 PopupMenu 组件创建, 用 MF_POPUP 作标识添加的 MainMenu 组件或 PopupMenu 组件创建的菜单命令可对 OnClick 事件进行响应, 因此, 此时可直接调用菜单命令的 OnClick 事件的响应过程, 样本代码如下 ( 假定菜单命令通过 MainMenu1 组件创建 ): procedure TForm1.WMSysCommand(var Msg:TMessage); var item:tmenuitem; Inherited; item:=mainmenu1.finditem(msg.wparam,fkcommand); // 检索 MainMenu1 中的对应菜单命令 if not(item=nil) then item.click; // 执行相应菜单命令的 Click 事件响应 上述代码中, 首先通过主菜单组件 MainMenu1 组件检索所单击的菜单命令在主菜单中对应的菜单命令, 然后调用给命令的 OnClick 事件响应过程 如果菜单命令通过快捷菜单组件 PopupMenu1 创建, 只需将 MainMenu1 换成相应的 PopupMenu1 即可 这里, 再次强调一下, 必须预先编有主菜单或快捷菜单中命令的 OnClick 事件的响应过程, 只有这样控制菜单中的命令才能正确响应 例如, 对于通过 MainMenu1 添加到控制菜单中的 左对齐 命令, 必须预先编有该命令的 OnClick 事件的响应过程 AlignLeftClick, 然后再编写上述代码, 此时控制中的 左对齐 命令才能响应 如果控制菜单中菜单命令的添加两种情况都有, 则编程时也应考虑两种情况, 下面给出了这种情况下的一个样本代码 : procedure TForm1.WMSysCommand(var Msg:TMessage); var item:tmenuitem; if Msg.WParam=100 then with ColorDialog1 do Color:=Memo1.Color;

143 第 5 章菜单设计 130 if Execute then Memo1.Color:=Color; Inherited; item:=mainmenu1.finditem(msg.wparam,fkcommand); // 检索 MainMenu1 中的对应菜单命令 if not(item=nil) then item.click; // 执行相应菜单命令的 Click 事件响应 将单元文件另存为 Unit5_7.pas, 将项目文件另存为 Project5_7.dpr 习 题 1. 菜单命令项的作用是什么? 2. 如何在菜单中设计快捷键? 如何在菜单中加 分割条? 3. 快捷键和热键的区别是什么? 4. 菜单的单选 复选 灰显 隐藏等是如何设计的? 5. 菜单模板的作用是什么? 6. 如何手工指定快捷菜单的位置? 7. 思考一下, 如何用最简单的方法, 使菜单平时只显示最近刚用过的菜单项, 如图 5-28 所示, 并在该菜单列最底下显示, 当选择菜单项时, 才打开整个菜单显示所有菜单 项 图 5-28 只显示最近刚用过的菜单项

144 第 6 章 对话框设计 几乎所有的 Windows 应用程序都借助于对话框和用户进行交流 对话框本质上是一种窗口, 不但可以接受消息, 还能移动和关闭 本章主要介绍 Delphi 应用程序使用的对话框组件, 包括 : 公共对话框组件 标准对话框组件 Delphi 应用程序可使用 3 种对话框 : (1) 由 Delphi 提供的公共对话框组件, 如打开文件对话框 文件保存对话框 字体对话框 颜色对话框 查找对话框和替换对话框等 (2)Delphi 预定义的标准对话框组件, 包括消息框和输入框 可用函数和过程调用的形式来显示这些对话框 (3) 用户自己设计的对话框 本章主要介绍前两种对话框, 用户自定义对话框的设计方法类似于窗口设计, 请读者参阅第 3 章 6.1 公共对话框 Delphi 的公共对话框组件都是从抽象的 TCommonDialog 继承下来的, 而 TCommonDialog 又是从 TComponent 继承下来的 因此, 这些对话框组件都是非可视的 在设计期, 把这些公共对话框组件加到 Form 上后, 看到的是这些对话框组件的图标, 只有调用这些对话框的 Execute( ) 方法, 才能在运行期看到真正的对话框 Delphi 所提供的对话框组件共有 11 种, 它们包括 :Open Save OpenPicture SavePicture Font Color Print PrintSetup Find Replace 和 PageSetup 图 6-1 所示为对话框组件板 这些对话框的使用方法都比较相似, 而且使用方法也比较简单 图 6-1 对话框组件板 所有的对话框组件都是不可见组件 当程序运行时也不会自动显示, 而需要用户编写一 些代码来显示 ( 例如使用某菜单或按钮的 OnClick 事件处理过程 ) 每一个对话框的显示方式

145 第 6 章对话框设计 132 均相同, 即都使用 Execute 方法 例如, 可用 OpenDialog1.Execute 来显示一个 打开文件 对话框 Execute 方法的返回值为布尔类型 当用户单击对话框中的 OK 按钮时, 返回 True, 而单击 Cancel 按钮或用系统菜单命令关闭对话框时返回 False 用户可以根据返回值的不同执行不同的事件处理过程 对话框组件所提供的对话框大多是模态对话框, 即 : 在对话框被关闭之前, 无法在同一应用程序的其他地方进行工作 打开 对话框组件 打开 对话框如图 6-2 所示, 是用来打开文件的对话框, 是用 TOpenDialog 组件实现的 图 6-2 打开 对话框 在介绍使用 TOpenDialog 组件之前, 我们先介绍该组件的常用属性 DefaultExt 属性 : 用于指定一个默认的扩展名 主要用在 SaveDialog 组件中 (SaveDialog 组件和 OpenDialog 组件采用相同属性 ), 当用户存盘不输入扩展名时, 就以该指定扩展名作为默认的扩展名 FileName 属性 : 指定一个文件名 在打开对话框时, 这个文件名出现在对话框的 文件名 框中 Filter 属性 : 设置文件过滤器, 让对话框只列出特定类型的文件 单击 Filter 属性右侧的省略号按钮, 可打开 Filter Editor 对话框, 从中定义 Filter 属性, 如图 6-3 所示 也可在程序中使用命令来定义它, 如 : OpenDialog1.Filter:= 'Rich text files (*.rtf) *.rtf Plain text files (*.txt) *.txt All files *.*'; FilterIndex 属性 : 如果有多个过滤器, 这个属 图 6-3 Filter Editor 对话框

146 133 Delphi 程序设计基础性用于指定一个作为默认过滤器 InitialDir 属性 : 默认情况下, 对话框打开时, 文件列表中显示的是当前目录的文件 可以设置这个属性指定另外一个目录 Title 属性 : 用于设置对话框的标题 另外 TOpenDialog 组件有一组 Options 属性, 缺省时它们的取值均为 False, 表 6-1 为它们取值为 True 时的含义 表 6-1 打开对话框的 Options 属性取值为真值的含义 值含义 ofallowmultiselect ofcreateprompt ofextensiondifferent offilemustexist ofhidereadonly ofnochangedir ofnodereferencelinks ofnolongnames ofnoreadonlyreturn ofnotestfilecreate ofnovalidate ofoldstyledialog ofoverwriteprompt ofpathmustexit ofreadonly ofshareaware ofshowhelp 允许在文件名列表中选择多个文件 当用户在文件编辑框中输入一不存在的文件名, 并选择 OK 按钮, 则会出现消息框, 提示用户此文件不存在并询问是否以此文件名创建一新文件 从对话框中返回的文件扩展名将不同于缺省扩展名 其值存入 DefaultExt 属性中 当用户在文件编辑框中输入一个不存在的文件名时, 并选择 OK 按钮, 则会出现一消息框提示用户此文件不存在, 并询问是否输入了正确的路径和文件名 对话框中不显示 以只读方式打开 复选框 当前目录将设置成对话框第一次出现的目录, 并忽略任何目录改变 如果用户选择的是快捷方式文件 (.LNK),FileName 特性是快捷方式文件本身, 而不是快捷文件指向的文件 不允许长文件名 不允许用户选择只读的文件, 否则将显示一个警告框 保存文件时不进行写保护 磁盘满 驱动器门打开等检查 不对文件名中的字符进行合法性检查 使用旧版本对话框 当用户试图保存一个已存在的文件时, 将出现一消息框, 提示用户此文件已存在, 并询问是否覆盖 用户在文件名编辑框只能输入有效路径名, 否则出现消息框, 提示用户路径无效 选中 以只读方式打开 复选框 对话框不理会所有的共享错误 对话框中将显示 帮助 按钮 下面, 我们以例 6-1 来说明使用 TOpenDialog 组件的方法 例 6-1 通过 OpenDialog 组件的应用, 说明如何使用 打开 对话框组件 (1) 新建应用程序启动 Delphi, 选取 File 菜单的 New Application 命令, 开始一个新的应用文件 (2) 设置窗体属性窗体属性见表 6-2 表 6-2 窗体属性 属性属性值 Caption Font 文本阅读 宋体 五号 Height 378

147 第 6 章对话框设计 134 Width 680 (3) 向窗体中添加组件往窗体中添加 9 个 Button 组件 Button1~Button9 1 个 Memo 组件 Memo1 1 个 OpenDialog 组件 OpenDialog1 其中有些按钮是为了后面介绍其他对话框组件而提前添上的 (4) 设置组件属性窗体中的组件属性见表 6-3 表 6-3 组件属性 组 件 属 性 属 性 值 组 件 属 性 属 性 值 Buttonl Caption 打开 Button6 Caption 设置 Button2 Caption 存盘 Button7 Caption 查找 Button3 Caption 字体 Button8 Caption 替换 Button4 Caption 颜色 Button9 Caption 页面 Button5 Caption 打印 Memo1 Lines 空串 设置完属性后组件在窗体上的布局如图 6-4 所示 图 6-4 例 6-1 窗体设计 (5) 添加事件为 Button1 组件添加 OnClick 事件, 事件响应过程名为 Button1Click (6) 编写事件响应代码 Button1 的 OnClick 事件的响应代码如下 : procedure TForm1.Button1Click(Sender: TObject); with OpenDialog1 do Filter:=' 文本文件 (*.txt) *.txt'; DefaultExt:='txt';

148 135 Delphi 程序设计基础 FileName:=''; Options:= ''ofhidereadonly,offilemustexist,ofpathmustexist''; if Execute then if ofextensiondifferent in Options then MessageDlg(' 这不是文本文件!',mtError, ''mbok'',0) Else Memo1.Lines.LoadFromFile(FileName); (7) 保存程序将单元文件保存为 Unit6_1.pas, 将项目文件保存为 Project6_1.dpr (8) 编译运行程序单击工具栏上 Run 按钮运行程序 运行后单击窗口中的 打开 按钮, 将出现 打开 对话框 选定一个以.txt 为扩展名的文本文件后, 单击 打开 按钮, 该文本文件就会显示在窗口中的 Memo1 中 (9) 程序说明代码中首先设置 OpenDialog 的 Filter( 文件过滤器 ) DefaultExt( 缺省扩展名 ) FileName ( 缺省文件名 ) Options( 选项 ) 属性 当然, 这些属性可预先直接在 对象查看器窗口 中设置, 而且那样会更容易 然后执行该对话框, 如果从对话框中返回值的扩展名不是以.txt 为扩展名的文本文件 (ofextensiondifferent), 则显示消息框 ; 如果文件类型正确, 则将文件内容显示在 Memo1 中 另外, 还有一种能预览图像的 打开 对话框, 是用 TOpenPictureDialog 组件实现的, 在选择图像文件时, 可以在对话框中预览图像 TOpenPictureDialog 的直接上级是 TOpenDialog, 它的特性 方法和事件与 TopenDialog 完全相同 它的外观与一般的 打开 对话框很相似, 只是增加了一个预览区域 当用户选择图像文件时, 预览区域就显示用户所选择的图像, 并且显示该图像的大小 单击对话框上的 放大镜 按钮, 可以放大显示图像 可以预览的图像格式有 BMP ICO WMF 和 EMF, 如果是其他格式的图像, 预览区域将显示 (None) 保存 对话框组件 保存 对话框组件的属性以及界面和 打开 对话框几乎一样, 所以这里不再详细介绍 我们直接用例 6-2 来介绍它的使用 例 6-2 保存 对话框组件的使用 (1) 启动 Delphi, 从 File 菜单中选取 Reopen 命令或 Open Project 命令, 打开应用文件 Project6_1 此时,Delphi 将打开例 6-1 窗体, 我们在例 6-1 的基础上继续做下去 (2) 向窗体中添加组件向窗体中添加 SaveDialog 组件 SaveDialog1 (3) 设置 SaveDialog1 组件属性

149 第 6 章对话框设计 136 窗体中的组件属性见表 6-4 表 6-4 DefaultExt Filter FileName 组件属性属性属性值 txt 文本文件 (*.txt) *.txt 空 像例 6-1 中的一样, 这些属性也可以由程序命令设置 (4) 添加事件为 Button2 组件添加 OnClick 事件, 事件响应过程名为 Button2Click (5) 编写事件响应代码 Button2 的 OnClick 事件的响应代码如下 : procedure TForm1.Button2Click(Sender: TObject); with SaveDialog1 do if Execute then Memo1.Lines.SaveToFile(FileName); Memo1.Modified:=False; (6) 保存程序将单元文件保存为 Unit6_2.pas, 将项目文件保存为 Project6_2.dpr (7) 编译运行程序单击工具栏上的 Run 按钮运行程序 运行后单击窗口中的 打开 按钮打开一个文 本文件, 修改后再单击 保存 按钮, 将出现 另存为 对话框 选择路径, 输入一个文件 名, 单击 保存 按钮, 该文本文件就会保存在指定路径的目录中 图 6-5 所示的是例 6-2 运行的 保存 对话框

150 137 Delphi 程序设计基础 图 6-5 例 6-2 中的 另存为 对话框 与 打开 对话框一样, 保存 对话框也有一个带图像预览的 保存 对话框, 是用 TSavePictureDialog 元件实现的, 在保存图像文件时, 可以在对话框中预览图像 TSavsPictureDialog 的直接上级是 TOpenPictureDialog, 它的特性 方法和事件与 TOpenPictureDialog 组件完全相同, 它的外观与一般的 另存为 对话框很相似, 只是增加了一个预览区域 图像的用法和格式与 TopenPictureDialog 相同 字体 对话框组件大多数文本编辑软件都提供用户使用 字体 对话框, 用于设置选定文本的字体 字号 字形 字色等 为了方便用户, Delphi 预定义了 FontDialog 组件 字体 对话框如图 6-6 所示 在介绍使用 TFontDialog 组件之前, 我们先介绍该组件的常用属性和事件 Device 属性 : 用于设置从哪儿检索可用的字体 ( 可选项有 fdscreen/ 屏幕 fdprinter/ 打印机 fdboth/ 屏幕和打印机 ) OnApply 事件 : 当 OnApply 事件被定义后, 字体 对话框会出现 应用 按钮, 当用户按下 应用 按钮时将触发这个事件 图 6-6 字体 对话框 另外 TFontDialog 组件有一组 Options 属性, 缺省时它们的取值均为 False, 表 6-5 为它们取值为 True 时的含义 表 6-5 TFontDialog 组件的 Options 取值为真值的含义 取值含义 fdansionly fdapplybutton 对话框只列出使用 Ansi 字符集的字体 对话框中将显示 应用 按钮

151 第 6 章对话框设计 138 fdeffects fdfixedpitchonly fdforcefontexise fdlimitsize fdnofacesel fdnooemfont fdscalableonly fdnosimulations fdnosizesel fdnostylesel fdnovectorfonts fdshowhelp fdtruetypeonly 对话框中显示 颜色 列表和 效果 复选框 ; 用户可使用效果复选框定义 Strikout 下划线文本 ; 使用颜色列表定义字体颜色 对话框中只列出等宽字体 用户必须输入一个合法的字体名, 否则将显示一个警告框 使 MinFontSize 特性和 MaxFontSize 特性设置有效 对话框打开时, 字体 组合框中不预先选定一种字体 字体组合框中将不显示向量字体 对话框中只列出可以缩放的字体 对话框中不列出 GDI 仿真字体 对话框的 大小 组合框不预先选定一种尺寸 对话框的 字体样式 组合框不预先选定一种风格 与 fdnooemfont 相同 对话框显示 帮助 按钮 对话框中只列出 TrueType 字体 fdwysiwyg 对话框中只列出所见即所得的字体 例 6-3 在例 6-2 的基础上, 加入字体设置功能 (1) 打开应用文件 Project6_2 (2) 向窗体中添加组件向窗体中添加 FontDialog 组件 FontDialog1 (3) 添加事件为 FontDialog1 组件添加 OnApply 事件 FontDialog1Apply, 为 Button3 组件添加 OnClick 事件, 事件响应过程名为 Button3Click procedure TForm1.FontDialog1Apply(Sender: TObject; Wnd: HWND); Memo1.Font:=FontDialog1.Font; procedure TForm1.Button3Click(Sender: TObject); with FontDialog1 do Font:=Memo1.Font; if Execute then Memo1.Font:=Font; (4) 保存程序将单元文件保存为 Unit6_3.pas, 将项目文件保存为 Project6_3.dpr (5) 编译运行程序单击工具栏上 Run 按钮运行程序 运行后单击窗口中的 打开 按钮打开一个文本

152 139 Delphi 程序设计基础文件, 修改后再单击 字体 按钮, 将出现 字体 对话框 设置字体 字号 字形 字色等, 单击 确定 按钮, 该文本就会被设置成所选定的字体 颜色 对话框组件 颜色 对话框用于设置选定对象的前景色和背景色, 是用 TColorDialog 组件实现的 颜色 对话框如图 6-7 所示 TColorDialog 组件的 Options 属性取值为 True 时的含义见表 6-6 表 6-6 TColorDialog 组件的 Options 取值为真值的含义 取 值 含 义 cdfullopen 对话框打开时同时打开自定义颜色部分 cdpreventfullopen 对话框中不允许自定义颜色 cdshowhelp 对话框中将显示 帮助 按钮 cdsolidcolor 让 Windows 使用与所选颜色最接近的基本颜色 cdanycolor 允许用户选择非基本颜色 例 6-4 利用 颜色 对话框设置文本背景色 (1) 打开应用文件 Project6_3 (2) 向窗体中添加组件向窗体中添加 ColorDialog 组件 ColorDialog1 (3) 添加事件为 Button4 组件添加 OnClick 事件, 事件响应过程名为 Button4Click procedure TForm1.Button4Click(Sender: TObject); with ColorDialog1 do Color:=Memo1.Color; if Execute then Memo1.Color:=Color; (4) 保存程序 图 6-7 颜色 对话框 将单元文件保存为 Unit6_4.pas, 将项目文件保存为 Project6_4.dpr (5) 编译运行程序单击工具栏上 Run 按钮运行程序 运行后单击窗口中的 打开 按钮打开一个文本文件, 单击 颜色 按钮, 将出现 颜色 对话框 选择颜色, 单击 确定 按钮, 该文本的背景色就会被设置成所选定的颜色 打印 对话框组件 打印 对话框是用 TPrintDialog 组件实现的 它能让用户选择使用哪台打印机 设置

153 第 6 章对话框设计 140 打印机的属性 选择页的范围 设置打印份数等 打印 对话框如图 6-8 所示 图 6-8 打印 对话框 打印 组件的常用属性有以下几项 Collate: 若该属性为 True, 对话框中的 分页 复选框就被选中 Copies: 设置打印的份数 FromPage ToPage: 设置打印范围的起始页码和结束页码 PrintToFile: 打印作业被输出到一个文件而不是到打印机上 TPrintDialog 组件的 Options 属性取值为 True 时的含义见表 6-7 表 6-7 TPrintDialog 组件的 Options 取值为真值的含义 取值含义 popagenums poprinttofile poselection powarning pohelp podisableprinttofile 用户可以选择页的范围对话框中将出现 打印到文件 复选框用户可以只打印文档中选择的部分如果没有安装打印机, 将显示一个警告框对话框将显示一个 帮助 按钮对话框上的 打印到文件 复选框将变灰 打印设置 和 页面设置 对话框 打印设置 对话框是用 TPrinterSetupDialog 组件实现的 打印设置 对话框如图 6-9 所示 页面设置 对话框是用 TPageSetupDialog 组件实现的 页面设置 对话框如图 6-10 所示

154 141 Delphi 程序设计基础 图 6-9 打印设置 对话框图 6-10 页面设置 对话框 例 6-5 让我们继续前面的编程 往窗体中添加一个 PrintDialog 组件 PrintDialog1 PrinterSetupDialog 组件 PrinterSetupDialog1 及 PageSetupDialog 组件 PageSetupDialog1 为 Button5( 打印 按钮 ) 添加 OnClick 事件, 事件响应过程为 Button5C1ick procedure TForm1.Button5Click(Sender: TObject); with PrintDialog1 do Options:= [ poprinttofile ] ; PrintToFile:=True; if Execute then if PrintToFile then SaveDialog1.Title:=' 打印到文件 :'; if SaveDialog1.Execute then Memo1.Lines.SaveToFile(SaveDialog1.FileName); end else Memo1.PaintTo(Handle, 10, 10); 为 Button6( 设置 按钮 ) 添加 OnClick 事件, 事件响应过程为 Button6C1ick procedure TForm1.Button6Click(Sender: TObject);

155 第 6 章对话框设计 142 with PrinterSetupDialog1 do Execute; 为 Button9( 页面 按钮 ) 添加 OnClick 事件, 事件响应过程为 Button9C1ick procedure TForm1.Button9Click(Sender: TObject); with PageSetupDialog1 do Execute; 这样就可以有正常的打印和打印机设置 打印页面设置的功能了 保存单元文件为 Unit6_5.pas 及项目文件为 Project6_5.dpr 查找 对话框组件 查找 对话框用于查找指定字符串, 是一种非模态对话框 在 查找 对话框中有一个 找下一个 按钮, 单击该按钮就可以开始对指定字符串的查找 这是通过调用 FindDialog 组件的 OnFind 事件的响应过程来实现的 FindDialog 组件的 Options 属性的取值为 True 时的含义见表 6-8 表 6-8 FindDialog 组件的 Options 属性的取值为真值的含义 frdown frdisablematchcase frdisableupdown frdisablewholeword frfindnext frhidematchcase frhidewholeword frhideupdown frmatchcase frwholeword frreplace frreplaceall 取值含义 对话框中出现 Down 按钮, 查找方向向下 如果是假值,Up 按钮将被选中, 查找方向向上, frdown 值可在设计或运行时设置 区分大小写 复选框变灰 Up 和 Down 按钮将变灰, 用户不能进行选取 ; 如果是假值, 用户可以选择其中之一 全字匹配 复选框变灰 应用程序查找在 FindNext 属性中的字符串 对话框中不显示 区分大小写 复选框 对话框中不显示 全字匹配 复选框 对话框中不显示 方向 分组框 区分大小写 复选框被选中, 设计 运行时均可设置 全字匹配 复选框被选中, 设计 运行时均可设置 如果是真值, 应用程序将 ReplaceText 属性中的字符串替换 FindText 属性中的字符串 如果是真值, 应用程序将 ReplaceText 属性中的字符串替换查找到的所有 FindText 属性中的字符串 例 6-6 让我们继续前面的编程 往窗体中添加一个 FindDialog 组件 FindDialog1 并为 FindDialog1 添加 OnFind 事件, 事件响应过程为 FindDialog1Find; 为 Button7( 查找 按钮 ) 添加 OnClick 事件, 事件响应过程为 Button7C1ick

156 143 Delphi 程序设计基础 procedure TForm1.FindDialog1Find(Sender: TObject); var FoundPos,InitPos:integer; InitPos:=Memo1.SelStart+Memo1.SelLength; FoundPos:=Pos(FindDialog1.FindText,Copy(Memo1.Text,InitPos+1,Length(Memo1.Text) InitPos)); if FoundPos>0 then Memo1.SetFocus; Memo1.SelStart:=InitPos+FoundPos 1; Memo1.SelLength:=Length(FindDialog1.FindText); end else Messagedlg(' 没有找到要查找的文本!',mtInformation, [ mbok ],0); procedure TForm1.Button7Click(Sender: TObject); with FindDialog1 do OnFind:=FindDialog1Find; Execute; 保存单元文件为 Unit6_6.pas 及项目文件为 Project6_6.dpr 然后单击工具栏上的 Run 按钮运行程序 运行后, 首先单击窗口中的 打开 按钮, 打开一文本文件 然后单击 查找 按钮, 可打开 查找 对话框, 输入要查找的字符串后, 单击 找下一个 按钮, 窗口光标立即定位到第一 图 6-11 查找 对话框 个符合要求的字符处, 而对话框仍保持打开 其效果如图 6-11 所示 替换 对话框组件例 6-7 我们将给前面的例子添加 替换 对话框, 使之形成一个完整的应用程序 往窗体中添加一 ReplaceDialog 组件 ReplaceDialog1 并为 ReplaceDialog1 添加 OnFind 事件, 事件响应过程为 ReplaceDialog1Find procedure TForm1.ReplaceDialog1Find(Sender: TObject);

157 第 6 章对话框设计 144 var FoundPos,InitPos:integer; InitPos:=Memo1.SelStart+Memo1.SelLength; FoundPos:=Pos(ReplaceDialog1.FindText, Copy(Memo1.Text,InitPos+1,Length(Memo1.Text) InitPos)); if FoundPos>0 then Memo1.SetFocus; Memo1.SelStart:=InitPos+FoundPos 1; Memo1.SelLength:=Length(ReplaceDialog1.FindText); end else Messagedlg(' 没有找到要查找的文本!',mtInformation, [ mbok ],0); 再为 ReplaceDialog1 添加 OnReplace 事件, 事件响应过程为 ReplaceDialog1Replace procedure TForm1.ReplaceDialog1Replace(Sender: TObject); Memo1.SelText:=ReplaceDialog1.ReplaceText; 最后为 Button8( 替换 按钮 ) 添加 OnClick 事件, 事件响应过程为 Button8Click procedure TForm1.Button8Click(Sender: TObject); with ReplaceDialog1 do OnFind:=ReplaceDialog1Find; Execute; 保存单元文件为 Unit6_7.pas 及项目文件为 Project6_7.dpr 然后单击工具栏上的 Run 按钮运行程序 运行后, 首先单击窗口中的 打开 按钮, 打开一文本文件 然后单击 替换 按钮, 可打开 替换 对话框, 输入要查找的字符串后, 单击 找下一个 按钮, 窗口光标立即定位到第一个匹配字符串处, 再单击 替换 按钮即将找到的字符串用指定字符串替换, 此时对话框保持打开 其效果如图 6-12 所示

158 145 Delphi 程序设计基础 图 6-12 替换 对话框 6.2 标准对话框 消息框和输入框是 Delphi 预定义的又一系列对话框, 用于显示各种信息, 以及接收简单 的用户输入, 称为标准对话框 这些对话框无须使用对话框组件, 简单地调用函数或过程就 能实现 消息框 所谓消息框, 指的是显示提示信息的一些简单对话框 这些对话框无须用户任何的输入, 只需简单地确认或取消即可 消息框的显示无须使用对话框组件,Delphi 用两个函数 两个 过程用来显示消息框 1.MessageDlg 函数 function MessageDlg(Const Msg:String; Atype:TmsgDlgType; AButtons:TMsg DlgButtons; HelpCtx:Longint):Word; 用于在屏幕中央显示提示信息 各参数含义如下 Msg 参数 : 显示内容 AType 参数 : 决定消息框的类型, 有 mtinformation mterror mtwarning mtconfirmation 几种类型 AButtons 参数 : 决定消息框中显示的位图按钮, 可由一系列子参数组成, 每一参数 代表一位图按钮, 如 mbyes mbno mbok mbcancel 等 注意 : 位图按钮组件使用的前缀为 mr, 而不是 mb, 如 mryes mrno 等 HelpCrt 参数 : 决定消息框使用哪个帮助屏幕 2.MessageDlgPos 函数 function MessageDlgPos(Const Msg:String ; AType : TmsgDlgType; AButtons:Tmsg DlgButton; HelpCtx:longint;X,Y:Integer):Word;

159 第 6 章 对话框设计 146 与 MessageDlg 函数作用相同, 区别在于 MessageDlgPos 函数可用 X Y 表明消息框左上 角的坐标 3.ShowMessage 过程 procedure ShowMessage(Const Msg:String); 用于显示一个带有 OK 按钮的消息框, 其中 Msg 为显示内容 4.ShowMessagePos 过程 procedure ShowMessagePos(Const Msg:String;X,Y: Integer); 与 ShowMessage 过程作用相同, 区别在于 ShowMessagePos 过程可用 X Y 表明消息框 左上角的坐标 输入框 所谓输入框, 指的是带有一个编辑框, 用于输入简单字符串信息的一些简单对话框 输 入框的显示同样无须使用对话框组件,Delphi 提供了两个函数用于显示输入框 1.InputBox 函数 function InputBox(Const ACaption:String, Aprompt,Adefault:String):String; 用于显示带有一个编辑框的对话框, 当用户按 OK 按钮返回时, 返回值为编辑框中的 输入内容 ; 当用户按 Cancel 按钮返回时, 返回值为缺省字符串 函数各参数含义如下 ACaption 参数 : 对话框的标题 APrompt 参数 : 编辑框的输入提示 ADefault 参数 : 编辑框中的缺省字符串 2.InputQuery 函数 function InputQuery(Const ACaption:String,APrompt:String;Var Value:String)Boolean; 用于显示带有一个编辑框的对话框, 当用户按 OK 按钮返回时, 返回值为 True, 编 辑框中的输入内容被赋给 Value 字符串 ; 当用户按 Cancel 按钮返回时, 返回值为 False, 缺省字符串被赋给 Value 字符串 ACaption 参数和 APrompt 参数的含义与 InputBox 函数相同 例 6-8 消息框和输入框的使用 (1) 新建应用程序 启动 Delphi, 选取 File 菜单中的 New Application 命令, 开始一个新应用程序 (2) 设置窗体属性 窗体属性见表 6-9 表 6-9 窗体属性 属性属性值 Caption BorderStyle 了解对话框 BsSingle (3) 向窗体中添加组件往窗体中添加一个 Button 组件 Button1 (4) 设置组件属性设置 Button1 的 Caption 属性为 进入

160 147 Delphi 程序设计基础 (5) 添加事件为 Button1 组件添加 OnClick 事件, 事件响应过程名为 Button1Click (6) 编写事件响应代码 Button1 的 OnClick 事件的响应代码如下 : procedure TForm1.Button1Click(Sender: TObject); var cho:string; cho:=(inputbox(' 选择 ',' 请输入 : '+chr(13)+' 1. 信息 '+chr(13)+' 2. 错误 '+chr(13)+' 3. 警告 '+chr(13)+' 4. 确认 '+chr(13),'1')); if cho='1' then MessageDlg(' 信息 ',mtinformation, [ mbyes,mbno ],0) else if cho='2' then MessageDlg(' 错误 ',mterror, [ mbyes,mbno ],0) else if cho='3' then MessageDlg(' 警告 ',mtwarning, [ mbyes,mbno ],0) else if cho='4' then MessageDlg(' 确认 ',mtconfirmation, [ mbyes,mbno ],0); (7) 保存程序将单元文件保存为 Unit6_8.pas, 将项目文件保存为 Project6_8.dpr (8) 编译运行程序单击工具栏上 Run 按钮运行程序 运行后单击窗口中的 进入 按钮, 将出现 选择 对话框 如果在编辑框中输入 1, 单击 OK 按钮, 将打开 Information 消息框 ; 如果输入 2, 单击 OK 按钮, 将打开 Error 消息框 ; 如果输入 3 或 4, 单击 OK 按钮, 将打开 Warning 或 Confirm 消息框 图 6-13 所示为程序运行效果

161 第 6 章对话框设计 148 图 6-13 使用消息框与输入框 习 题 1.Delphi 有哪几类对话框? 2. 在什么情况下对话框的 Execute 函数返回 True? 3. OpenDialog 对话框组件的 DefaultExt 属性 FileName 属性 Filter 属性的作用是什么?SaveDialog 的该 3 个属性的作用又是什么? 4.FontDialog 对话框组件的 OnApply 事件被定义后, 字体 对话框会出现什么现象? 你认为在 FontDialog 对话框组件的 OnApply 事件中应编写些什么功能的代码? 5. 在 PrintDialog 对话框组件中,Collate 属性 Copies 属性 FromPage 属性 ToPage 属性 PrintToFile 属性起什么作用? 6. 在 FindDialog 对话框组件和 ReplaceDialog 对话框组件中,OnFind 事件是什么时候起作用的? 一般应编写什么功能的代码? 7. 消息框和输入框的功能是什么? 它们能否输入 输出复杂的数据?

162 第 7 章 工具栏和状态栏设计 目前大部分 Windows 应用程序中都含有工具栏和状态栏 工具栏一般位于窗口的上部, 可由面板 (Panel) 组件和若干个快捷按钮组成, 也可直接用工具栏 (ToolBar) 组件创建 一般每个快捷按钮都是代表一个常用的菜单命令 当然, 工具栏还可包括其他组件, 如组合框 (ComboBox) 等 状态栏一般位于窗口的底部, 用于显示当前的状态及一些提示信息 比如按钮或命令的功能, 当前打开的文件路径等 本章将对各种工具栏及状态栏的设计进行介绍, 主要包括 : 用面板构成工具栏 使用工具栏组件设计工具栏 使用 CoolBar 组件设计工具栏 使用控件栏组件设计工具栏 状态栏设计 7.1 快捷按钮 快捷按钮 (SpeedButton) 在组件板的 Additional 选项卡上, 默认形状为正方形, 当然也可以改变它的形状和大小 快捷按钮和位图按钮有相似之处, 在按钮的表面可以同时放置位图和文本, 也可以给按钮设置功能提示 ( 当鼠标指向它时所弹出的功能提示 ) 但快捷按钮和位图按钮也有差别, 二者间最大差别在于功能上, 快捷按钮兼具位图按钮 复选框和单选按钮的功能, 可根据不同状态显示不同的位图 下面重点介绍一下快捷按钮的常用属性 Caption 属性 : 用于设置快捷按钮表面所显示的文本 Glyph 属性 : 用于设置快捷按钮表面的位图 Hint 属性 : 用于设置快捷按钮的提示功能及在状态栏所显示的文本 当鼠标指向按钮时, 自动弹出所设置的功能提示 当然首先要将窗体的 ShowHint 属性设为 True Layout 属性 : 用于设置快捷按钮表面的文本和位图的显示风格 该属性有 4 种可取值,blGlyphBottom 位图位于文本的下面 ;blglyphleft 位图位于文本的左面 ;blglyphright 位图位于文本的右面 ;blglyphtop 位图位于文本的上面 GroupIndex 属性 : 通过设置 GroupIndex 属性, 可以像使用复选框或单选按钮那样来使用快捷按钮 如果你想使一组快捷按钮像一组单选按钮那样, 当按下某个按钮时, 只有被选择的按钮处于按下状态, 而其他的快捷按钮均处于弹起状态, 就应将这一组快捷按钮的 GroupIndex 属性赋予相同的值, 当然该值不能和其他组的 GroupIndex 值相冲突 GroupIndex

163 150 Delphi 程序设计基础属性不同的快捷按钮之间相互不影响, 就如同复选框一样 要使某按钮被选中时保持按下状态应给该按钮的 GroupIndex 属性赋予一个大于 0 的整数值 否则在松开按钮后, 它也会自动弹起 Down 属性 : 用于判断快捷按钮是否处于被按下状态 当属性值为 True 时, 按钮处于按下状态, 属性值为 False 时, 按钮处于弹起状态 你可以在设计时使某个快捷按钮的 Down 属性设为 True, 这样在运行程序时, 这个按钮在一开始就处于按下状态, 这就像我们将单选按钮或复选框的 Check 属性设为 True, 使它们在程序运行一开始就自动被选中一样 AllowAllUp 属性 : 将某个快捷按钮的 AllowAllUp 属性设为 True 时, 则当单击处于按下状态的该快捷按钮时, 它可恢复弹起状态 当在设置某个快捷按钮的 AllowAllUp 属性时, 其他与该按钮的 GroupIndex 属性值相同的快捷按钮的 AllowAllUp 属性也会发生相同的变化 7.2 工具栏设计 对快捷按钮有了一定了解后, 下面介绍工具栏的设计 工具栏设计有两种方法, 第一种方法是用面板 (Panel) 组件和快捷按钮 (SpeedButton) 组件以及组合框等组件构成工具栏, 第二种方法是直接使用工具栏组件构成工具栏 用面板构成工具栏面板是一个容器型的组件, 在面板上可以放置其他组件 ( 包括面板组件 ) 所有放置在面板上的组件都以面板为父组件 当移动或删除面板时, 面板上的其他组件也一起被移动或删除 类似的容器型组件还有窗体 (Form) 单选按钮组 (RadioGroup) 成组框 (GroupBox) 等 在工具栏设计中一般将面板的 Align 属性设为 altop, 使面板与窗体的顶部对齐 如果将之设为 alnone, 则可将面板放置在窗体上的任何地方 我们已经在第 4 章中, 简单地介绍过面板 (Panel), 面板的一般用法可参见第 4 章 下面通过实例来说明如何用面板构成工具栏 例 7-1 为例 5-4 用面板和快捷按钮建立工具栏 (1) 打开应用程序启动 Delphi, 从 File 菜单中选取 Reopen 命令或 Open Project 命令, 打开应用文件 Project5_4 此时, 应用程序将打开例 5-4 窗体, 参见第 5 章图 5-17 (2) 设置窗体属性窗体的属性见表 7-1 表 7-1 修改窗体的属性 属 性 属 性 值 属 性 属 性 值 Caption 工具栏设计 ShowHint True Height 328 Width 268 (3) 创建菜单因为通常情况下, 工具栏中的快捷按钮都会和菜单中某个命令相对应, 因此在设计工具栏之前, 一般应先创建菜单栏 这里就使用例 5-4 原窗体的菜单 MainMenu1

164 第 7 章工具栏和状态栏设计 151 (4) 设计工具栏下面开始设计工具栏 1 为窗体添加一个面板组件 Panel1, 并将其 Align 属性设为 altop, 为面板设置适当的高度值 22 为了使工具栏更好看, 可以通过 Color 属性改变面板的颜色 2 在面板中放置 3 个小面板 Panel2 Panel3 和 Panel4, 用于对快捷按钮按菜单划分 Panel2 上容纳 样式 菜单的对应快捷按钮, 其 Height 属性值为 22,Width 属性值为 97; Panel3 容纳 对齐 菜单的对应快捷按钮, 其 Height 属性值为 22,Width 属性值为 73; Panel4 用于容纳一个 字号 组合框, 用于设置示例文本的字体大小, 其 Height 属性值为 22,Width 属性值为 80; Panel2 Panel3 和 Panel4 在 Panel1 中水平并排排列 3 在两个小面板上放置快捷按钮和组合框等组件 共添加了 7 个快捷按钮和一个组合框组件 各快捷按钮 Height 属性值为 22,Width 属性值为 22, 快捷按钮其余属性及组合框属性见表 7-2 注意 :Panel2 上第 2 个到第 4 个按钮为一组, 作为复选框使用, 因此其 GroupIndex 属性值分别为 2 3 4, 作为复选框, 它们的 AllowAllUp 属性必须为 True Panel3 上 3 个快捷按钮作为单选按钮使用, 因此其 GroupIndex 属性值必须相同, 这里都设为 5 每个快捷按钮的位图通过 Glyph 属性来选择,Hint 属性用于设置功能提示文本 表 7-2 组件属性 组件属性属性值说明 SpeedButton1 AllowAllUp False 对应 样式 菜单的 颜色 命令, 位于面板 Pane12 上 Glyph Color.bmp 自定义的 位图 GroupIndex 0 Hint 颜色 SpeedButton2 AllowAllUp True 加粗 命令, 位于面板 Panel2 上 Glyph FontBold.bmp 自定义的 位图 GroupIndex 2 Hint 加粗 SpeedButton3 AllowAllUp True 倾斜 命令, 位于面板 Panel2 上 Glyph FontItalic.bmp 自定义的 位图 GroupIndex 3 Hint 倾斜 SpeedButton4 AllowAllUp True 下划线 命令, 位于面板 Panel2 上 Glyph FontUnline.bmp 自定义的 位图 GroupIndex 4 Hint 下划线 SpeedButton5 AllowAllUp False 对应 对齐 菜单的 左对齐 命令, 位于面板 Panel3 上 Glyph AlignLeft.bmp 自定义的 位图

165 152 Delphi 程序设计基础 续表 组件属性属性值说明 GroupIndex 5 Hint 左对齐 SpeedButton6 AllowAllUp False 对应 对齐 菜单的 居中 命令, 位于面板 Panel3 上 Glyph AlignCenter.bmp 自定义的 位图 GroupIndex 5 Hint 居中 SpeedButton7 AllowAllUp False 对应 对齐 菜单的 右对齐 命令, 位于面板 Panel3 上 Glyph AlignRight.bmp 自定义的 位图 GroupIndex 5 Hint 右对齐 ComboBox1 Hint 字号 位于面板 Panel4 上 Items 12,15,18,21,24 Style CsDropDown Text 10 Width 100 缺省情况下快捷按钮的 NumGlyphs 属性值为 2, 标识每个快捷按钮有两幅位图, 一幅为正常状态, 一幅为凹陷状态, 由系统自动处理 快捷按钮的位图为 大小 绘制位图可通过 Delphi 提供的 Image Editor 这样, 工具栏就设计完毕, 如图 7-1 所示 (5) 添加其他组件在实际设计过程中, 我们还要根据需要在窗体上添加一些组件, 以达到功能所需的界面 这里我们就沿用例 5-2 的组件 (6) 链接工具栏与菜单的 OnClick 事件工具栏中有一些快捷按钮的功能与已有的菜单功能相同, 就不必再重新编写事件, 如 颜色 左对齐 居中 右对齐 与之对应的菜单及各自的事件见表 7-3 图 7-1 工具栏设计 表 7-3 与快捷按钮对应的菜单命令项及其事件 菜单命令项 组 件 事 件 事件响应函数 颜色 OptionColor OnClick Button1Click 左对齐 OptionAlignLeft OnClick OptionAlignLeftClick 居中 OptionAlignCenter OnClick OptionAlignCenterClick 右对齐 OptionAlignRight OnClick OptionAlignRightClick 现在将工具栏上快捷按钮的 OnClick 事件与相应的菜单命令的 OnClick 事件链接起来, 以使快捷按钮与相应菜单命令具有相同的功能 其方法是 : 选定快捷按钮后, 在对象查看器的 Events 选项卡上, 单击 OnClick 事件右侧的下拉按钮, 从中选择相对应的菜单命令的

166 第 7 章工具栏和状态栏设计 153 OnClick 事件的响应过程 各快捷按钮的 OnClick 事件选定的响应过程为 : 颜色 快捷按钮 SpeedButton1 Button1Click 左对齐 快捷按钮 SpeedButton5 OptionAlignLeftClick 居中 快捷按钮 SpeedButton6 OptionAlignCenterClick 右对齐 快捷按钮 SpeedButton7 OptionAlignRightClick (7) 编写事件响应代码通常情况下, 将快捷按钮的 OnClick 事件与相应菜单命令的 OnClick 事件链接起来, 以使二者具有相同的操作 但是, 这并不是说快捷按钮的 OnClick 事件都与菜单事件链接, 有些快捷按钮的功能菜单并未提供, 这时用户也可以为其添加与菜单命令不同的 OnClick 事件, 进行单独编程 例如, 这里我们所添加的 加粗 倾斜 下划线 快捷按钮和 字号 组合框, 没有原菜单命令项, 所以必须独立编写事件 为快捷按钮添加的事件见表 7-4 表 7-4 快捷按钮和组合框的事件 组 件 Name 事 件 事件响应函数 加粗 SpeedButton2 OnClick SpeedButton2Click 倾斜 SpeedButton3 OnClick SpeedButton3Click 下划线 SpeedButton4 OnClick SpeedButton4Click 字号 ComboBox1 OnChange ComboBox1Change 加粗 命令为一复选快捷按钮, 用于将 Memo1 的文本加粗或取消加粗, 其 OnClick 事件的响应代码如下 : procedure TForm1.SpeedButton2Click(Sender: TObject); if SpeedButton2.Down then Memo1.Font.Style:=Memo1.Font.Style+ [ fsbold ] else Memo1.Font.Style:=Memo1.Font.Style [ fsbold ] ; 倾斜 命令为一复选快捷按钮, 用于将 Memo1 的文本倾斜或取消倾斜, 其 OnClick 事件的响应代码如下 : procedure TForm1.SpeedButton3Click(Sender: TObject); if SpeedButton3.Down then Memo1.Font.Style:=Memo1.Font.Style+ [ fsitalic ] else Memo1.Font.Style:=Memo1.Font.Style [ fsitalic ]; 下划线 命令为一复选快捷按钮, 用于将 Memo1 的文本添加下划线或取消下划线,

167 154 Delphi 程序设计基础其 OnClick 事件的响应代码如下 : procedure TForm1.SpeedButton4Click(Sender: TObject); if SpeedButton4.Down then Memo1.Font.Style:=Memo1.Font.Style+ [ fsunderline ] else Memo1.Font.Style:=Memo1.Font.Style [ fsunderline ]; 字号 组合框 (ComboBoxl) 用于设置示例文本的字体大小, 其 OnChange 事件的响应代码如下 : procedure TForm1.ComboBox1Change(Sender: TObject); Memo1.Font.Size:=StrToInt(ComboBox1.Text); (8) 保存程序将单元文件另存为 Unit7_1.pas, 将项目文件另存为 Project7_1.dpr (9) 编译运行程序单击工具栏上 Run 按钮即可运行程序 运行后, 单击工具栏上 颜色 按钮, 可设置文本的背景颜色 ; 单击 加粗 倾斜 下划线 按钮, 可将文本相应地加粗 倾斜和加下划线, 由于这一组按钮为复选按钮, 因此可综合使用 ; 而单击 左对齐 右对齐 居中 按钮, 则可调整文本的对齐方式, 这一组按钮为单选按钮, 一次只有一个按钮有效 另外, 将鼠标指向工具栏上的快捷按钮, 稍停, 将会出现该 按钮的功能提示 图 7-2 显示了程序的运行效果 (10) 程序说明 图 7-2 例子运行效果 和菜单命令一样, 快捷按钮也可以灰显和隐藏, 方法完全相同, 也是在运行时调整快捷按钮的 Enabled 属性和 Visible 属性 其中,Enabled 属性为 False 时, 快捷按钮灰显 ;Visible 属性为 False 时, 快捷按钮隐藏 使用工具栏组件 Delphi 提供了新的工具栏 (ToolBar) 组件, 位于组件板的 Win32 选项卡上, 可用来直接创建工具栏 用工具栏组件设计工具栏非常容易, 下面我们仍利用上面的例子来进行说明, 用工具栏组件进行设计 例 7-2 为例 5-4 用工具栏组件建立工具栏 (1) 打开应用程序启动 Delphi, 从 File 菜单中选取 Reopen 命令或 Open Project 命令, 打开应用文件 Project5_4 此时, 应用程序将打开例 5-4 的窗体, 修改 Form1 的 Caption 属性为 工具

168 第 7 章工具栏和状态栏设计 155 栏设计 (2) 往窗体中添加一个 ToolBar 组件 ToolBar1 如果要求工具栏上按钮是平的, 只有当鼠标停驻在按钮上才凸显, 可将 ToolBar1 的 Flat 属性设置为 True 如果要求工具栏显示边界, 可根据需要将 EdgeBorders 属性的 4 个子属性 ebleft( 左边界 ) ebtop( 上边界 ) ebright( 右边界 ) ebbottom( 底边界 ) 设置为 True (3) 工具栏上添加快捷按钮 ( 不是快捷按钮组件 ) 鼠标右键单击工具栏组件, 打开一快捷菜单, 如图 7-3 所示 如果要添加按钮, 选择 New Button 命令 ; 如果要添加分隔条, 选择 New Separator 命令 这里, 我们往工具栏上添加了 7 个按钮和 3 条分隔条, 见表 7-5 图 7-3 工具栏组件快捷菜单 表 7-5 工具栏上 ToolButton 的属性 按钮 Name 作 用 Hint 属性 Style 属性 Grouped 属性 ToolButton1 颜色 颜色 tbsbutton False ToolButton2 分隔条 ToolButton3 加粗 加粗 tbscheck False ToolButton4 倾斜 倾斜 tbscheck False ToolButton5 下划线 下划线 tbscheck False ToolButton6 分隔条 ToolButton7 左对齐 左对齐 tbscheck True ToolButton8 居中 居中 tbscheck True ToolButton9 右对齐 右对齐 tbscheck True ToolButton10 分隔条 (4) 设置工具栏上按钮的属性工具栏上添加的按钮属于 TtoolButton 类型, 每个按钮都可用对象查看器设置属性 1 Style 属性 TtoolButton 对象有一个基本属性 Style 属性, 该属性提供了以下属性值 : tbsbutton: 表示标准按钮 ( 缺省 ) tbscheck: 表示具有复选功能或单选功能的按钮 如果该按钮不与其他按钮编组, 则具有复选功能 ; 如果与其他按钮一起编组, 则具有单选功能 tbsdevider: 表示一条竖线型分隔条 tbsdropdown: 表示凹陷式按钮, 但需要使用其他组件进行支持 tbsseparator: 表示空格型分隔条 2 Grouped 属性要使一组按钮具有单选功能, 通常要给工具栏上相邻按钮分组, 将组中每个 TtoolButton 按钮的 Grouped 属性设置为 True, 这些按钮必须是相邻的 按钮分组时, 如果遇到一个按钮的 Grouped 属性不是 True, 或其 Style 属性不是 tbscheck, 或添加了一个分隔条, 则分组自动结束

169 156 Delphi 程序设计基础 3 MenuItem 属性要使工具栏上按钮与相应的菜单命令对应, 请在 MenuItem 属性中选择相应的菜单命令名称 (Name 属性 ) 但是设置 MenuItem 属性后, 按钮将不再保留位图或需要重新设置位图 4 Hint 属性要在程序运行时能显示按钮的功能提示, 还得将窗体 Form1 的 ShowHint 属性和工具栏 ToolBar1 的 ShowHint 属性设置为 True 这里, 我们将 ToolButton2~ToolButton7 的 Style 属性设置为 tbscheck 将 ToolButton5~ ToolButton7 的 Grouped 属性设置为 True 同时, 添加相应的功能提示文本 (5) 为按钮提供位图鼠标右键单击窗体中的 ImageList1 组件, 将打开一个快捷菜单, 从中选择 ImageList Editor 命令, 打开图像列表编辑器窗口, 如图 7-4 所示 单击 Add 按钮, 可增加一幅位图 将工具栏上按钮用到的位图按顺序加载到 Images 列表中, 然后单击 OK 按钮返回 图 7-4 图像列表编辑器 注意 : 如果要加载的位图不是 大小, 请先设置 ImageList1 组件的 Height 属性和 Width 属性 再将 ToolBar1 组件的 Images 属性设置为 ImageList1 组件的 Name 属性 ImageList1 提示 : 如果 ImageList 加载位图的顺序与工具栏上的按钮顺序不一致, 请将每一个 TtoolButton 对象的 ImageIndex 属性设置位图加载的序号 如果工具栏上按钮在灰显时要用另外的位图图像表示, 请再增加一个 ImageList 组件, 加载按钮要用到的位图后, 再将 ToolBar1 组件的 DisabledImages 属性设置该 ImageList 组件 如果工具栏上按钮在鼠标停驻时要用另外的位图图像表示, 请再增加一个 ImageList 组件, 加载按钮要用到的位图后, 再将 ToolBarl 组件的 HotImages 属性设置该 ImageList 组件 (6) 往工具栏中添加其他组件工具栏组件是一个容器型组件, 也可以添加其他组件 这里往工具栏中添加一个组合框 ComboBox1, 用于设置字号 其 Items 设置为 共 6 项,Text 属性为 10,Width 属性为 50 (7) 链接工具栏按钮和菜单命令的 OnClick 事件同上一节一样, 可以将工具栏上各按钮的 OnClick 事件与相应的菜单命令的 OnClick 事件链接起来, 以便按钮与相应菜单命令具有相同的功能

170 第 7 章工具栏和状态栏设计 157 工具栏各按钮的 OnClick 事件选定的响应过程为 : 颜色 按钮 ToolButton1 Button1Click 左对齐 按钮 ToolButton7 OptionAlignLeftClick 居中 按钮 ToolButton8 OptionAlignCenterClick 右对齐 按钮 ToolButton9 OptionAlign RightClick (8) 编写事件响应代码同上一节一样, 我们所添加的 加粗 倾斜 下划线 按钮和 字号 组合框, 没有原菜单命令项, 所以必须独立编写事件 加粗 按钮事件代码 : procedure Tform1.ToolButton3Click(Sender: Tobject); if ToolButton3.Down then Memo1.Font.Style:=Memo1.Font.Style+ [ fsbold ] else Memo1.Font.Style:=Memo1.Font.Style [ fsbold ] ; 倾斜 按钮事件代码 : procedure Tform1. ToolButton4Click(Sender: Tobject); if ToolButton4.Down then Memo1.Font.Style:=Memo1.Font.Style+ [ fsitalic ] else Memo1.Font.Style:=Memo1.Font.Style [ fsitalic ] ; 下划线 按钮事件代码 : procedure Tform1.ToolButton5Click(Sender: Tobject); if ToolButton5.Down then Memo1.Font.Style:=Memo1.Font.Style+ [ fsunderline ] else Memo1.Font.Style:=Memo1.Font.Style [ fsunderline ] ; ComboBoxl 组件的 OnChange 事件响应过程为 ComboBox1Change, 其代码与上一节相同 (9) 保存程序将单元文件另存为 Unit7_2.pas, 将项目文件另存为 Project7_2.dpr (10) 编译运行程序单击工具栏上 Run 按钮即可运行程序 运行后, 单击工具栏上 颜色 按钮, 可设置文本的背景颜色 ; 单击 加粗 倾斜 下划线 按钮, 可将文本相应地加粗 倾斜和加下划线, 由于这一组按钮为复选按钮, 因此可组合使用 ; 而单击 左对齐 右对齐 居中 按钮, 则可调整文本的对齐方式, 这一组按钮为单选按钮, 一次只有一个按钮有效 另外, 将鼠标指向工具栏上的快捷按钮, 稍停, 将会出现该按钮的功能提示

171 158 Delphi 程序设计基础这样, 例程中的工具栏就改造完毕, 编译程序后, 将与前面例程的运行效果完全相同 不过, 显然工具栏的外观效果要美观得多 图 7-5 所示的是例 7-2 的设计效果 如果要将工具栏设置为浮动式, 可将其 DockSite 属性设置为 False,DragKind 属性设置为 dkdock,dragmode 属性设置为 dmautomatic, 窗体 Form1 的 DockSite 属性设置为 True 再给工具栏的 OnEnd 事件添加响应过程 ToolBar1EndDock, 其代码如下 : procedure Tform1.ToolBar1EndDock(Sender, Target: Tobject; X, Y: Integer); ToolBar1.Left:=0; ToolBar1.Top:=0; 编译程序后, 可用鼠标拖动工具栏形成浮动式效果, 如图 7-6 所示 其中浮动窗口名 工具栏 是 ToolBarl 组件的 Caption 属性值 图 7-5 用工具栏组件设计工具栏图 7-6 浮动式工具栏 使用 CoolBar 组件除了 ToolBar 组件,Delphi 还提供了 CoolBar 组件, 可以用来设置工具栏 CoolBar 组件位于组件板的 Win32 选项卡上 和 ToolBar 组件不同,CoolBar 组件是一个容器型组件, 利用其他组件来设计工具栏, 这些组件在 CoolBar 组件中以 TCoolBand 类型对象的形式出现, 每一个 TCoolBand 对象还可单独设置属性 下面仍利用前面的例 5-4 来介绍如何利用 CoolBar 组件设计工具栏 例 7-3 用 CoolBar 组件为例 5-4 建立工具栏 (1) 打开应用程序启动 Delphi, 从 File 菜单中选取 Reopen 命令或 Open Project 命令, 打开应用文件 Project5_4 此时, 应用程序将打开例程 5-4 窗体, 修改 Form1 的 Caption 属性为 工具栏设计 (2) 添加 CoolBar 容器中将包括的组件 CoolBar 将包括两个组件, 一个是添加并像例 7-2 一样设置好的 ToolBar 组件, 另一个是

172 第 7 章工具栏和状态栏设计 159 ComboBox 组件 ComboBox1, 并利用 Items 属性为其添加 10,12,15,18,2l,24 六个选项条目 再用 Text 属性将其缺省选项改成 10 我们将用这两个组件组合成一个 CoolBar 工具栏 (3) 添加 CoolBar 组件下面往窗体中添加一个 CoolBar 组件 CoolBar1, 并将其 AutoSize 属性设置为 True (4) 添加 TCoolBand 对象, 将组件添加到 TCoolBand 对象中在 CoolBar 工具栏中, 通常包括很多子工具栏, 每个子工具栏只能容纳一个组件, 各个子工具栏可以在 CoolBar 工具栏的范围内调整位置和顺序, 这些子工具栏就是 TCoolBand 对象 如果要添加 TCoolBand 对象, 执行如下操作 1 单击 CoolBar 组件的 Bands 属性右侧的 按钮, 打开 Editing CoolBar1.Bands 窗口, 如图 7-7 所示 2 单击 Add New 按钮, 可添加一个 TCoolBand 对象 3 单击 TCoolBand 对象的 Control 属性右侧的下拉按钮, 可从中选择一个组件, 例如选择 ToolBar1 然后利用 Text 属性添加一个标题, 例如添加 工具栏 图 7-7 Editing CoolBar1.Bands 窗口 4 继续单击 Add New 按钮, 可继续添加 TCoolBand 对象 这里, 我们只添加两个 TCoolBand 对象 5 继续给 TCoolBand 对象添加组件 TCoolBand 对象使用的典型组件是 ToolBand, 但也可以使用编辑框 组合框等组件 例如, 我们添加第二个 TCoolBand 对象, 将其 Control 属性选择为 ComboBox1, 将其 Text 属性设置为 字号 6 添加 TCoolBand 对象完毕后, Editing CoolBar1.Bands 窗口关闭 用户可以每行放置一个 TCoolBand 对象, 也可以将几个 TCoolBand 对象放置在同一行上, 每个对象使用一部分 例如, 我们在 CoolBand 中使用了两个 TCoolBand 对象, 共占两行, 每行放置一个对象 至于 TCoolBand 对象所对应的组件, 仍可单独进行编程, 对此我们不再进行重复讲述 图 7-8 显示了上述操作的运行效果 在程序运行时, 将鼠标指向 TCoolBand 对象左侧的竖形条, 按住并拖动鼠标可调整对象位置 另外, 单击 TCoolBand 对象的标题可自动扩大它 图 7-9 显示了经过调整后的 TCoolBand 如果要使 ToolBar 组件在 CoolBar 组件中仍保持浮动特性, 则应给 CoolBar 组件添加 OnDockOver 事件, 并编写如下代码 : procedure TForm1.CoolBar1DockOver(Sender: TObject; Source: TDragDockObject; X, Y: Integer; State: TDragState; var Accept: Boolean); var ARect:TRect; Accept:=(Source.Control is TToolBar); if Accept then

173 160 Delphi 程序设计基础 ARect.TopLeft:=CoolBar1.ClientToScreen(CoolBar1.ClientRect.TopLeft); ARect.BottomRight:=CoolBar1.ClientToScreen (CoolBar1.ClientRect.BottomRight); Source.DockRect:=ARect; 图 7-8 使用 CoolBar 工具栏图 7-9 调整 TCoolBand 对象位置和大小 (5) 保存程序将单元文件另存为 Unit7_3.pas, 将项目文件另存为 Project7_3.dpr (6) 编译运行程序单击工具栏上 Run 按钮即可运行程序 运行后, 操作方法基本上与用 ToolBar 组件制成的工具栏相同 图 7-9 给出了例子的运行效果 使用控件栏组件用 CoolBar 组件设计的工具栏可以做到非常完美, 但是,Windows 的 CoolBar 控件有许多不同的互不兼容的版本, 其中有一些版本与 Delphi 中的 CoolBar 控件不兼容 为了适应这种情况,Delphi 专门开发出一种设计工具栏的容器型控件 控件栏 (ControlBar) 控件栏与 CoolBar 一样, 是一个容器型控件, 可以管理多个控件, 允许用户在运行时拖动并重新布置工具栏 同时, 控件栏组件的使用更加简单, 只需将其他控件放置到其中即可, 就像面板一样 Delphi 自己的工具栏就是利用控件栏设计的, Microsoft 的 Office 应用软件也是使用控件栏技术实现的 例 7-4 这里沿用例 7-3, 只不过将 CoolBar1 中的组件剪切到控件栏 ControlBar1 中, 并删除掉 CoolBar1 组件, 其效果如图 7-10 所示 我们可以看到, 每个放置到控件栏中的控件前图 7-10 使用控件栏构成工具栏

174 第 7 章工具栏和状态栏设计 161 都有两个竖条 运行程序时, 将鼠标停放在竖条上, 按住并拖动鼠标, 即可将控件在控件栏范围内自由移动 注意 : 使用控件栏时, 通常先将控件放到工具栏或其他容器型组件中, 而不直接放到控件栏中 图 7-11 显示了运行时拖动控件栏中的控件形成的两个不同的效果比较图 图 7-11 用控件栏制作的工具栏的运行效果 将单元文件另存为 Unit7_4.pas, 将项目文件另存为 Project7_4.dpr 7.3 状态栏设计 在应用程序的窗口底部, 经常会有状态栏 状态栏通常用于显示当前的状态及一些提示信息 比如按钮或命令的功能 利用 Delphi 提供的状态栏 (StatusBar) 组件可以很容易地设计状态栏 下面介绍如何进行状态栏设计 状态栏的基本属性状态栏 (StatusBar) 组件位于组件板的 Win32 选项卡上, 它比较类似于面板组件 一般将状态栏的 Align 属性设为 albottom, 使它靠窗体的底部对齐 在许多 Windows 应用程序中, 用户也许会发现状态栏实际上可以看成由多个子面板组成, 它们将状态栏分成几部分, 而每一个子面板都有自己的显示区域 要在状态栏上定义多个子面板, 在往窗体中添加状态栏组件 ( 假定为 StatusBar1) 后, 执行如下操作 (1) 将状态栏的 SimplePanel 属性设为 False 因为当 SimplePanel 属性为 True 时, 状态栏将只有一个显示区域, 显示在 SimpleText 中设定的文本 (2) 双击状态栏的 Panels 属性, 打开 Editing StatusBar1.Panels 窗口, 如图 7-12 所示 (3) 单击窗口中的 Add New 按钮, 就会增加一个子面板 图 7-12 Editing StatusBar1.Panels 窗口

175 162 Delphi 程序设计基础 (4) 在对象查找器中设置子面板的属性 (5) 连续单击 Add New 按钮, 可添加多个子面板 (6) 关闭 Editing StatusBar1.Panels 窗口 下面介绍一下子面板的常用属性, 状态栏子面板的常用属性见表 7-6 表 7-6 状态栏子面板的常用属性 属性数据类型说明 Alignment Bevel Style TAlignment TStatusPanelBevel TStatusPanelStyle 用于决定在子面板中所显示的文字的对齐格式 有 3 种取值 :taleftjustify ( 左对齐 ) tacenter( 居中对齐 ) 和 tarightjustify( 右对齐 ) 用于决定子面板的风格 有 3 种取值 :pblowered( 表示子面板为下陷状 ) PbNone( 表示子面板为一平板, 无立体感 ) pbraised( 表示子面板为突起状态 ) 用于决定在子面板内显示的内容是文字 (pstext) 还是用户自己绘制的图形 (psownerdraw) Text String 用于保存在子面板内要显示的文字 Width Integer 决定子面板的长度 显示状态及提示信息了解子面板及其属性后, 我们通过实例来介绍如何设置状态栏 例 7-5 为例 7-4 建立状态栏 (1) 打开应用程序启动 Delphi, 从 File 菜单中选取 Reopen 命令或 Open Project 命令, 打开应用文件 Project7_4 此时, 应用程序将打开例程 7-4 窗体, 修改 Form1 的 Caption 属性为 状态栏设计 (2) 往窗体中添加一个 StatusBar 组件 StatusBar1 双击 StatusBar1 组件, 用上述方法为状态栏定义 3 个子面板, 如图 7-13 所示 状态栏有 3 个子面板, 其中第 1 个子面板的 Width 设为 60, 第 2 个子面板的 Width 设为 38 (3) 往状态栏子面板中添加显示内容我们可以直接将要显示内容文本赋值给 StatusBar1.Panels [0].Text 至 StatusBar1.Panels [ n-1 ].Text, 直接在状态栏的 n 个子面板中显示所需内容 例如, 在第 1 个子面板中显示时钟 : 先在窗口中加入 Timer 组件 Timer1, 将其 Interval 属性 改为 500, 并加入事件 Timer1Timer: procedure TForm1.Timer1Timer(Sender: TObject); StatusBar1.Panels [ 0 ].Text:= TimeToStr(Time); (4) 往状态栏子面板中添加动态信息 图 7-13 增加状态栏后的窗体 我们经常要在状态栏中动态地显示提示信息 在介绍使用状态栏显示提示信息前, 先介

176 第 7 章工具栏和状态栏设计 163 绍一下组件的 Hint 属性, 以及 Delphi 为每个应用程序自动声明的 Application 对象的 Hint 和 OnHint 属性 以前在讨论输入组件的 Hint 属性时, 均只用了一个提示, 实际上组件的 Hint 属性可由两部分组成, 中间用 字符隔开 例如, 对于一个用于打开 颜色 对话框的工具栏按钮, 其 Hint 属性可设为 字体颜色 打开 颜色 对话框设置文本背景色 前一部分用于当鼠标指向组件时所弹出的快捷功能提示, 而后一部分则用于在状态栏上显示 在状态栏上显示组件的提示信息, 具体执行过程为 : 当用户将鼠标指向某个组件时, 定期触发的 Application 对象的 OnHint 事件响应过程 ( 由 OnHint 属性指定 ) 就会将组件的 Hint 属性的第 2 部分提示文本转存到 Application 对象的 Hint 属性中, 再由用户编写的代码将它显示到状态栏上 显示组件的快捷功能提示时, 同时会调用该事件响应过程, 在状态栏上显示相应的提示文本 首先要给应用程序指定一个 OnHint 事件响应过程, 这可在窗体 OnCreate 事件响应过程中进行编程, 给 Application 对象的 OnHint 属性赋予一个过程名, 其代码如下 ( 假定窗体为 Form1): procedure TForm1.FormCreate(Sender: TObject); Application.OnHint:=ShowHint; 上述代码中,ShowHint 是用于处理 Application 对象的 OnHint 事件的过程,Delphi 系统不会自动生成它, 用户必须自己在单元文件的 Type 部分的函数声明的末尾写入以下的声明语句 : type TForm1 = class(tform) procedure ShowHint(Sender:TObject); 然后在单元文件的 Implementation 部分手动编写该过程的源代码 procedure TForm1.ShowHint(Sender:TObject); StatusBar1.Panels [ 1 ].Text:=' 文本 '; StatusBar1.Panels [ 2 ].Text:=Application.Hint; (5) 保存程序将单元文件另存为 Unit7_5.pas, 将项目文件另存为 Project7_5.dpr (6) 编译运行程序

177 164 Delphi 程序设计基础现在编译运行程序, 当鼠标停驻在工具栏的按钮上时, 除了浮现工具栏功能的快捷提示外, 在状态栏上也会显示工具栏按钮的状态提示文本, 如图 7-14 所示 习 题 1.Delphi 可以用哪些组件建立工具栏? 2. 快捷按钮和位图按钮的相同之处和不同之处有哪些? 3. 工具栏按钮能否实现单选和复选功能? 如何实现? 4. 一般情况下, 工具栏和菜单有什么关系? 5. 工具栏的主要功能是什么? 6. 状态栏的主要功能是什么? 图 7-14 运行时状态栏内容

178 第 8 章 数据库编程 Delphi 具有强大的数据库应用程序开发功能, 它能适应各种大型数据库, 如 Oracle DB2 SyBase 和 SQL Server 等,Delphi 数据库应用程序基于 Borland 强大的数据库引擎 (BDE) 和流行的数据库接口, 以及丰富的数据库组件 利用 Delphi 开发数据库应用程序, 会使用户得到意想不到的收获 本章对 Delphi 常用的数据库编程方法进行了详细介绍, 主要包括 : 数据库系统概述 数据库设计 BDE 组件 ADO 组件 数据控制组件 数据库编程 8.1 数据库系统概述 数据库系统为我们提供了一种把与我们的工作和生活紧密相关的信息集合在一起的方法, 它还提供了在某个集中的地方存储和维护这些信息的方法 数据库系统主要由三大部分组成 : 数据库管理系统 (DBMS, 它是专门负责组织和管理数据信息的程序 ) 数据库应用程序 ( 它使我们能够获取 显示和更新由 DBMS 存储的数据 ) 数据库( 按一定结构组织在一起的相关数据的集合 ) 以前, 大多数 DBMS 和数据库应用程序都驻留在同一台计算机上并在同一台计算机上运行, 很多情况下两者甚至结合在同一个程序中 但是随着 DBMS 技术的发展, 目前的数据库系统正向客户 / 服务器模式发展 客户 / 服务器数据库将 DBMS 和数据库应用程序分开, 从而提高了数据库系统的处理能力 数据库应用程序运行在一个或多个用户工作站 ( 客户机 ) 上, 并且通过网络与运行在其他计算机上 ( 服务器 ) 的一个或多个 DBMS 进行通信 数据库管理系统 (DBMS) 数据库管理系统 (DBMS) 是用于描述 管理和维护数据库的程序系统, 是数据库系统的核心组成部分 它建立在操作系统的基础上, 对数据库进行统一的管理和控制 其主要功能如下 (1) 描述数据库 : 描述数据库的逻辑结构 存储结构 语义信息和保密要求等 (2) 管理数据库 : 控制整个数据库系统的运行, 控制用户的并发性访问, 检验数据的安全 保密与完整性, 执行数据检索 插入 删除 修改等操作

179 166 Delphi 程序设计基础 (3) 维护数据库 : 控制数据库初始数据的装入, 记录工作日志, 监视数据库性能, 修改更新数据库, 重新组织数据库, 恢复出现故障的数据库 (4) 数据通信 : 组织数据的传输 DBMS 主要有 4 种类型 : 文件管理系统 层次数据库系统 网状数据库系统和关系数据库系统 因为目前关系数据库系统应用最为广泛, 所以我们重点对关系数据库系统中的几个概念进行介绍 关系数据库 (Relational Database) 一个关系数据库是由若干表组成的 表 (Table): 一个表就是一组相关的数据按行排列, 像一张表格一样 比如一个班所有学生的期末考试成绩, 存在一个表中, 每一行对应一名学生, 在这一行中, 包括学生的学号 姓名以及各门课程的成绩 字段 (Field): 在表中, 每一列称为一个字段 每一个字段都有相应的描述信息, 如数据类型 数据宽度等 记录 (Record): 在表中, 每一行称为一条记录 索引 (Index): 为了加快访问数据库的速度, 许多数据库都使用索引 数据库应用程序 DBMS 中存储了大量的数据信息, 其目的是为用户提供数据信息服务, 而数据库应用程序正是与 DBMS 进行通信, 并访问 DBMS 中的数据, 它是 DBMS 实现其对外提供数据信息服务这一目的的惟一途径 简单地说, 数据库应用程序是一个允许用户插入 修改 删除并报告数据库中的数据的计算机程序 数据库应用程序在传统上是由程序员用一种或多种通用或专用的程序设计语言编写的, 但是近年来出现了多种面向用户的数据库应用程序开发工具, 这些工具可以简化使用 DBMS 的过程, 并且不需要专门编程 Delphi 就是一种强有力的数据库应用程序开发工具 Delphi 数据库的体系结构 Delphi 的数据库应用程序不能直接访问数据, 而是使用附带的 BDE(Borland Database Engine,Borland 数据库引擎 ) ADO 接口或 ODBC 接口等来对数据资源直接进行访问 通常情况下, 使用数据库 (Database) 来表示数据表 (Table) 的集合 一个数据表有很多记录, 因此数据表又称为记录集 (Record Set) 一个表有很多列, 对应于记录的每个字段 对用户而言, 开发 Delphi 数据库应用程序主要应掌握数据库组件的使用方法 Delphi 为开发数据库应用程序提供了许多组件, 这些组件可以分为两类 : 一类是数据库的数据访问组件 (Data Access 类组件 ); 另一类是数据库的数据控制组件 (Data Control 类组件 ) 这两类组件分别在组件板的 Data Access 和 Data Controls 选项卡上 Data Access 类组件负责和 BDE( 或 ADO 等 ) 进行数据交换, 它首先通过 BDE( 或 ADO 等 ) 将数据库文件的数据提供给应用程序, 最后将被修改过的数据经 BDE( 或 ADO 等 ) 传送到数据库文件中 其中和 BDE( 或 ADO 等 ) 直接打交道的是 DataSet 组件 DataSet 组件包括 Table 组件 Query 组件等, 每个 DataSet 组件都和一个数据库文件链接, 并且为 DataSource 组件提供数据 每

180 第 8 章数据库编程 167 个 DataSource 组件都应指定一个 DataSet 组件 DataSource 组件负责将 DataSet 组件和数据控制组件链接起来 它首先从 DataSet 组件中接收数据, 然后再传递给 DataControl 组件, 待用户查询或修改完数据后, 再把被修改的数据经 DataSet 组件传给 BDE( 或 ADO 等 ), 由 BDE( 或 ADO 等 ) 将数据返回到数据库文件 图 8-1 显示了这些数据库组件之间的关系 数据库 数据库 BDE 接口 ADO 接口 dbexpress InterBase DataSet 组件 BDE 组件 Table Query StoredProc ADO 组件 ADOTable ADOQuery ADOStoredProc dbexpress 组件 SQLTable SQLQuery SQLStoredProc InterBase 组件 IBTable IBQuery IBStoredProc DataAccess 组件 DataSource DataControl 类组件 DBGrid DBNavigator DBText DBEdit DBMemo DBImage DBLookupListBox DBComboBox DBCheckBox DBRadioGroup DBListBox DBLookupComboBox DBRichEdit DBCtrlGrid DBChart 用户界面 图 8-1 数据库组件之间的关系 下面通过例子帮助读者理解数据库组件之间的关系 例 8-1 编辑一个简单的数据库应用程序, 使用户对数据库应用程序有一个基本概念 (1) 新建应用程序启动 Delphi, 从 File 菜单中选取 New Application 命令, 开始一个新的应用文件 此时, 应用程序将有一缺省的窗体 Form1 (2) 设置窗体属性设置窗体的 Caption 属性为 数据库应用,Font 属性为 宋体 五号 (3) 向窗体中添加组件从组件板的 DataAccess 选项卡上往窗体中添加一个 DataSource 组件 DataSource1, 从 BDE 选项卡选择一个 Table 组件 Table1, 再从 Data Control 选项卡上往窗体中 添加一个 DBImage 组件 DBImage1 一个 DBMemo 组件 DBMemo1 一个 DBGrid 组件 DBGrid1 一个 DBNavigator 组件 DBNavigator1

181 168 Delphi 程序设计基础这里,DBImage 组件是一个图片,DBMemo 组件是一段文字,DBGrid 组件是一个表格, DBNavigator 组件是一组可对数据库进行操作的按钮 DataSource 组件和 Table 组件在运行时不可见 (4) 设置组件属性窗体中的组件属性见表 8-1 表 8-1 组件属性 组 件 属 性 属 性 值 组 件 属 性 属 性 值 DataSource1 DataSet Table1 DBImage1 DataSource DataSource1 Table1 Active True DataField Graphic DatabaseName DBDEMOS DBMemo1 DataSource DataSource1 TableName biolife.db DataField Notes DBNavigator DataSource DataSource1 DBGrid1 DataSource DataSource1 上面,Table1 的属性中,DBDEMOS 是 Delphi 自带的一个样本数据库, 包含有许多数据表,biolife.db 是其中的一个数据表 注意 : 只有先设置了 DatabaseName 和 TableName 属性, 才能设置 Active 属性 设置完组件属性后, 窗体组件及布局如图 8-2 所示 图 8-2 例 8-1 窗体 (5) 保存程序将单元文件保存为 Unit8_1.pas, 将项目文件保存为 Project8_1.dpr (6) 编译运行程序单击工具栏上 Run 按钮即可运行程序 运行后, 即可对数据库 DBDEMOS 中的数据表 biolife.db 进行查询 可用 和 键或用 DBNavigator 组件中的按钮来查询各个记录, 并且图片和注解内容会随之变化, 还可以修改记录的内容 在 DBNavigator 组件上, 单击带有 + 的按钮, 表示在当前记录前增加一个空白记录,

182 第 8 章数据库编程 169 单击带有 的按钮表示删除当前记录 除此之外, 还可以利用鼠标直接在表格上选择某个记录, 修改该记录的某个字段 上面的例子是一个基本的数据库应用程序, 它具有数据库应用程序的基本功能 例子并没有编写一句代码, 就实现了对数据库的操作, 这就是 Delphi 的奇妙之处 但是数据库应用程序的功能远不止这些, 且这些功能也不能满足要求 以下各节我们将逐步介绍如何构造一个功能齐全的数据库应用程序 例子中的数据都保存在数据表中, 数据表的各数据项的字段在实际应用中是预先定义的, 各个字段如同内存变量一样, 有不同的数据类型及数据宽度, 用于储存不同内容的数据 虽然定义数据库 ( 表 ) 结构通常是在 DBMS 中做的, 但它对整个数据库编程来说是必不可少的一部分, 所以下面我们通过例子来说明如何定义一个数据表的结构, 读者必须作为要点来掌握, 并通过实训 8-1 掌握其他平台的数据库定义方式 例 8-2 使用 Database Desktop 创建一个简易的人员档案数据表的结构 启动 Delphi, 从 Tools 菜单中选取 Database Desktop 命令, 打开 Database Desktop 对话框, 然后进行如下操作 (1) 定义表的类型建立一个新表首先要定义表的类型, 选择 File 菜单中的 New 菜单项下 Table 子菜单项 在出现的 Create Table 对话框中选择 Paradox 7, 如图 8-3 所示 (2) 定义表的结构 图 8-3 选择表类型 定义完表的类型, 可以创建表的结构 在表中建立 9 个字段, 分别是 :GH( 工号 ) XM ( 姓名 ) XB( 性别 ) CSRQ( 出生日期 ) HF( 婚否 ) ZC( 职称 ) GZ( 工资 ) JL( 简历 ) ZP( 照片 ), 每个字段都有自己的数据类型和数据长度, 如 :A( 字符型 ) D( 日期型 ) L( 逻辑型 ) N( 数值型 ) M( 备注型 ) G( 图形型 ) 创建好的表如图 8-4 所示 图 8-4 创建好的表的结构 (3) 定义关键字 双击 Key 空白处, 出现 *, 这里我们选择 GH 字段作为关键字 若关键字是多字

183 170 Delphi 程序设计基础段的可以在多个字段中都选中 Key 创建好表的结构, 单击 Save As 按钮, 将表命名为 ZG.DB, 存放在指定的路径下 (4) 为数据表添加数据打开 ZG.DB, 并按下 Edit Data 按钮, 使它处于编辑状态, 这时可以逐条输入数据, 如图 8-5 所示 图 8-5 添加数据后的 ZG 表 (5) 为数据表设定别名为了数据库的移植, 通常使用别名 (Alias) 这样, 在数据库的位置改动后, 不必修改应用程序, 只需重新设定别名就可以了 这里我们为创建好的数据表设立一个别名 EX8 在 DataBase DeskTop 窗口中, 选择菜单 Tools 中的 Alias Manager 菜单项, 这时会出现 Alias Manager 对话框, 如图 8-6 所示 图 8-6 Alias Manager 对话框 单击 New 按钮, 然后在 Database alias 文本框中输入别名 EX8, 并在 Path 文本框中 输入路径 ( 或通过单击 Browse 设置路径 ), 最后按下 OK 按钮 这样就完成了数据库 别名的设置

184 第 8 章数据库编程 BDE 组件 数据库引擎 B D E(Borland Database Engine) 是 Delphi C++ Builder IntraBuilder Paradox for Windows 和 Visual dbase 中特有的用于访问数据库的一种机制, 它可以让多个应用程序共享 BDE 提供了强大的 API 调用函数库, 可以对本地及远程数据库进行操作并且提供了几乎所有数据库的驱动程序, 比如, 可以访问本地数据库 Paradox dbase FoxPro 和 Access, 通过 SQL Links 驱动程序又可以访问远程数据库, 比如 InterBase Oracle Sybase Informix Microsoft SQL server 和 DB2, 并且还可以通过 ODBC 适配器来访问数据库 Delphi 中的 BDE 数据访问组件页如图 8-7 所示 图 8-7 BDE 组件页 Delphi 中使用 BDE 建立数据库应用程序, 可以通过 BDE 组件面板的各个组件实现 下面首先说明该面板各个组件的作用及主要属性 TTable 组件介绍 TTable 组件是 Delphi 开发数据库应用程序中最常用的组件, 也是最重要的组件之一 它在应用程序访问数据库时起着极其重要的作用 TTable TQuery 和 TStoreProc 同属于数据集 (DataSet) 组件, 它们从数据集继承而来, 有着许多共同的属性 方法和事件, 所以, 我们先从整体上了解一下有关数据集的基本概念 1. 数据集组件的基本知识在 Delphi 中, 访问数据的基本单元是数据集对象 应用程序正是提供数据集组件来访问数据库的 一个数据集对象就代表了数据库的一张表格, 或者是访问数据库的一个查询或存储的过程 所有在应用程序中使用的数据集对象都是由实际的数据集组件 TDataSet 派生而来的 数据集组件 DataSet 作为 TTable TQuery 和 TStoreProc 的基类, 具有它们的属性 方法和事件以及它们的派生关系 所以它们的相同部分, 都在 TTable 中介绍 2.TTable 组件的主要属性 TTable 组件的属性见表 8-2 表 8-2 TTable 组件的主要属性 属性含义 Active AutoCalcFields Bof CachedUpdates CanModify DatabaseName 指明一个数据集是否处于打开状态决定何时触发 OnCalcFields 事件标志着记录指针是否停留在数据集的第一个记录上表明一个数据集缓存的更新特性是否可用表明应用程序是否可以在表格里插入 编辑或删除数据表明数据集联系的数据库名 续表

185 172 Delphi 程序设计基础 属性含义 DBHandle DefaultIndex Eof Exclusive Fields Filter Filtered FilterOptions Handle IndexFieldNames IndexFields IndexName MasterFields MasterSource Name Modified ObjectView RecordCount ReadOnly SessionName StoreDefs TableName TableStyle UpdateMode UpdateObject 表明数据集所在数据库 BDE 的句柄表明一个打开的表格中的数据是否按默认的索引排序标志着记录指针是否停留在数据集的最后一个记录上允许用户以专有的方式打开一个 Paradox 或 dbase 表格指向数据集的字段列表表明当前数据集过滤的文本内容表明一个数据集的过滤是否被激活设置过滤选项允许程序直接调用 API 函数显示数据库表格所采用的索引排序的字段名指出数据库中的字段名列表用来为数据库表格指定当前排列索引在主表中指定一个或多个字段以建立主附表之间的联系指定作为数据集主表的 datasource 组件的名字该组件在被其他组件引用时的名字标志当前记录是否已被修改指明字段在 Fieldsproperty 中是层次排列还是平铺显示与数据集相连的记录的总数表明一个数据库表格在此应用程序中是否只读指定与数据集相连的 Session 的名字指出数据库表格的字段和索引与数据模块一致, 还是与窗体一致指明该组件指向的数据库表格的名字指出当前操作的数据表格的类型决定 BDE 如何在 SQL 数据库中查询更新的记录指出在允许缓存更新时, 用来更新只读记录的 updateobject 组件 下面详细叙述主要的属性 (1)DatabaseName DatabaseName 属性用来说明当前数据集的来源, 即应用程序所利用的数据库的名字 它可以是 BDE 定义的数据库别名, 如 DBDEMOS 或 EX8; 也可以是数据库文件, 像 Paradox 和 dbase 等文件所在的路径 ; 还可以是由 TDataBase 组件定义的数据库名 应用最多的还是用 BDE 定义的数据库别名 因为这样可以避免在应用程序所操作的数据库发生变化时修改整个应用程序, 而只需重新设置一下 BDE 定义的数据库别名即可 这一属性的设置通常是在设计阶段 在设计阶段, 只要双击 TDatabase 组件就可以激活数据库编辑器 (DatabaseEditor) 来设定 DatabaseName 举例说明 : { 更改数据集前, 表格必须先被关闭 } Table1.Active:=False; TRY { 首先, 试用数据库别名 }

186 第 8 章数据库编程 173 Table1.DatabaseName:='EX8'; Table1.Active:=True; EXCEPT on EDatabaseError do { 如果试用失败, 改用数据库文件的路径名 } Table1.DatabaseName:='c:\delphi\demos\database'; Table1.Active:=True; (2)TableStyle TableStyle 属性是用来说明当前应用程序所操作的数据库表格的类型, 在对象观察器中该属性框有一个下拉列表, 可以用来确定数据库文件的类型 (3)TableName TableName 是 TTable 最重要的属性之一 它是用来说明这个 TTable 组件所对应的是数据库中的哪一张数据库表格 它和 DataBaseName 一样, 是在设计阶段给定的, 它在 DataBaseName 设定后给出 一般在 DataBaseName 设定后, 如果有符合将要打开的表格的文件格式 (TableStyle) 的, 会自动在 TableName 的属性框中生成一个下拉列表, 包含所有符合该文件格式的数据库文件 注意 : 设定 TableName 属性值时,Active 属性值一定要设为 False (4)Active Active 属性用来说明数据库文件的打开状态 应用 Active 属性来决定及设定一个数据集组件与数据库数据之间的联系 它的属性值是用一个布尔数 (Ture/False) 来表示的 当 Active 属性值为 Ture 时, 表明数据集是打开的, 数据集组件可以对数据库进行读写操作 ; 反之, 表示数据集是关闭的, 数据集组件不能从数据库读取数据, 也不能向数据库中写数据 如果在文件打开过程中发生错误, 数据集的状态会被设置成 dsinactive, 同时记录指针会被关闭 应用程序在改变其他影响数据库状态或在应用程序中显示数据的控件状态的属性之前, 必须将 Active 属性设置为 False 注意 : 用 Open 和 Close 方法对数据库文件操作的效果与改变 Active 属性的效果是一样的 调用 Open 方法会将 Active 属性值设为 True; 调用 Close 方法会将 Active 属性值设为 False 需要说明的是, 在属性值 DataBaseName 和 TableName 发生改变时,Active 属性值会自动变为 False, 所以使用时必须重新将它改成 Ture (5)Bof 和 Eof Bof(ning of file) 属性值为一个布尔值, 表明当前记录指针所处的位置是否为数据集的第一个记录 如果 Bof 值为 True, 表明当前记录指针所处的位置确实是数据集的第一个记录 Eof(end of file) 属性值为一个布尔值, 表明当前记录指针所处的位置是否为数据集的最后一个记录 如果 Eof 值为 True, 表明当前记录指针所处的位置确实是数据集的最后一个记录 如果 Bof 和 Eof 的值都为 True, 则数据集为空 (6)Fields

187 174 Delphi 程序设计基础 Fields 属性用来指出数据集的字段列表 应用 Fields 属性可以访问数据库表格中的字段组合 如果字段是在运行时动态产生的, 那么,Fields 属性中字段组合的顺序直接与数据集表格中的列的顺序相一致 如果数据集应用的是持续性字段, 那么, 字段组合的顺序与设计阶段在字段编辑器中设定的字段顺序相一致 如果用户知道独立字段的数据类型, 那么他就可以通过 Fields 属性对字段进行读或写的操作 如用 Edit1 的值修改字段值 : Table1.Edit; // 设置编辑状态 Table1.Fields.Fields [ 6 ].AsString:=Edit1.Text; Table1.Post; // 提交修改记录注意 : 读取和设置字段值的最佳方案是应用持续性字段或 FieldByName 方法 (7)Filter 与 Filtered Filter 属性允许用户定义一个数据集过滤器 当过滤被数据集应用时, 只有那些满足过滤器条件的记录才会被显示 例如, 以下过滤条件将只显示 XB 字段为 ' 男 ' 的记录 : XB=' 男 '; 在定义过滤条件时, 允许使用 * 作为通配符, 而且可以在运行时定义 Filtered 属性用来表明数据集的过滤是否被激活 通过检测 Filtered 属性值来确定一个数据集的过滤是否有效 如果 Filtered 属性为 True, 那么过滤是激活的 否则,Filtered 属性值为 False 为了应用在 Filter 属性栏或在 OnFilterRecord 事件处理程序当中定义的过滤条件, 将 Filtered 的属性值设为 True 注意 : 当允许过滤时, 用户对任何记录进行编辑就意味着这条记录再也不满足过滤条件了 当数据集过滤有效时, 这条记录将不被显示, 而数据集的下一条记录将作为当前的记录被显示 (8)IndexFieldNames IndexFieldNames 属性显示了表格索引的字段名 IndexFieldNames 用来作为指明表格索引的一种方法, 其中字段的排序非常重要 对于 Paradox 和 dbase 表格, 所有在 IndexFieldNames 属性中说明的字段必须有索引 对于 SQL 数据库中的表格, 则没有这种限制 (9)IndexFields IndexFields 属性是数据库中的字段名列表, 其格式如下 : property IndexFields [ Index:Integer ] :TField; 每一个字段对象都对应着一个当前索引中的字段 Index 标识字段在索引中的位置 索引中的第一个字段是 IndexFields [ 0 ], 第二个是 IndexFields [ 1 ] 等等 需要注意的是, 不要直接设置 IndexField 属性, 而应用 IndexFieldNames 属性在运行过程中对数据集排序 (10)IndexName IndexName 属性用来指明一个数据库表格的附属索引, 如果 IndexName 为空, 一个表格就会根据它的主索引排序, 对于 dbase 表格, 则根据它的物理记录排序 如果 IndexName 包含了一个有效的索引名, 这个索引将决定记录的顺序 对于 dbase 表格,IndexName 采用的索引名必须是在表格主索引文件中, 或者是在 IndexFiles 属性早已指明的索引文件中

188 第 8 章数据库编程 175 注意 :IndexFieldNames 属性与 IndexName 属性是相互排斥的, 设置一个就会清除另一个 3.TTable 组件的重要方法 TTable 组件的重要方法见表 8-3 表 8-3 TTable 组件的重要方法 方法功能 AddIndex Append ApplyRange BatchMove BookmarkValid Cancel CancelRange CancelUpdates CheckOpen ClassParent ClearFields Close ControlsDisabled Create CreateTable Delete DeleteIndex DeleteTable DisableControls Edit Editkey EditRangeEnd EditRangeStart EnableControls FetchAll FieldByName FindField FindFirst FindKey FindLast FindNearest FindNext FindPrior First GetBookmark 为数据库表格建立一个新的索引向数据集中添加一条新的空记录设定数据集的检索范围将数据集中的记录转移到当前表格中来检验一个特定的书签是否可用在对当前的记录的更改尚未提交时撤销它们撤销当前表格中所有有效的检索范围撤销缓存的更新, 保存数据集前一状态检测调用 BDE 的结果返回当前类的直接父类清除当前记录的所有字段内容关闭一个数据集标志数据集是否允许在数据控制组件中显示更新的数据产生一个数据库表格组件建立一个使用新的结构信息的表格删除当前的记录, 将记录指针指向下一条记录删除数据库表格的辅助索引删除一个已存在的数据库表格使通过数据源与数据库相连的数据控制组件不能显示数据允许用户编辑数据集中的数据将 Table 组件置于查询状态允许用户改变一个已存在检索范围的结束值允许用户改变一个已存在检索范围的起始值允许通过 datasource 与数据库相连的数据控制组件显示数据读取记录指针当前位置至文件结束的所有记录根据特定的字段名查找字段在数据集中查询一个特定的字段实现在过滤的数据集中, 将记录指针置于第一记录处查找包含特定字段值的记录实现在过滤的数据集中, 将记录指针置于最后一条记录处将记录指针移至最匹配查询值的记录实现在过滤的数据集中, 将记录指针置于下一条记录处实现在过滤的数据集中, 将记录指针置于上一条记录处用一般的方法实现将记录指针置于数据集第一记录处在数据集当前记录指针的位置处设置书签 续表

189 176 Delphi 程序设计基础 方法功能 GetCurrentRecord GetFieldData GetFieldNames GetIndexNames GotoBookmark GotoCurrent GotoKey GotoNearest Insert InsertRecord IsEmpty Last Locate MoveBy Next Open Post Prior Refresh RenameTable Resync SetFields SetKey SetRange SetRangeEnd SetRangeStart UnlockTable UpdateRecord 读取当前记录到缓存中读取字段中的数据到缓存中读取一个数据集中所有字段名的列表读取数据库表格中有效的索引列表将记录指针置于书签处使此表格中的当前记录与一个特定表格中的当前记录同步将记录指针移至一条与当前查询值匹配的记录将记录指针移至一条与当前查询值最匹配的记录向数据集中插入一条新的空记录在数据集中插入一条新记录标志一个数据集是否不包含任何记录用一般的方法实现将记录指针置于数据集最后一条记录处查找一条特定的记录并使之成为当前记录将记录指针置于数据集中与当前记录相关的一条记录处将记录指针移至下一条记录处打开一个数据集向数据库提交修改的记录将记录指针移至上一条记录处从数据库取得数据来更新数据集对与此表格组件相关的 Paradox 或 dbase 表进行更名操作取得当前记录以及其前后的两条记录设置一个记录中所有的字段值在查询前设定查询值和检索范围设置并应用一个检索范围的起始值和结束值指定检索范围的结束记录指定检索范围的起始记录解除对 Paradox 或 dbase 表格的锁定对一个记录更新触发一个数据事件 下面就主要的方法进行详细的阐述 (1) 表格组件的 CreateTable 方法 CreateTable 方法是用来应用新的结构信息建立一个新表格的方法 在应用程序运行时调用 CreateTable 方法会产生一个利用数据集当前定义建立的表格 使用 CreateTable 方法会覆盖已存在表格的结构和数据 所以, 为避免覆盖一个已经存在的表格, 在使用 CreateTable 方法前检查 Exists 属性 如果 FieldDefs 属性包含数值, 那么这些数值将被用来建立字段定义 否则, 就将应用 Fields 属性的值 这二者至少有一个必须有值以保证数据集的重建 如果 IndexDefs 属性包含数值, 它们将被用来创建数据集的索引定义 下面结合一个实际的例子来说明 CreateTable 方法的使用 if not Table1.Exists then { 避免覆盖已存表格 }

190 第 8 章数据库编程 177 with Table1 do Active:=False; { 设置前表格组件必须被关闭 } { 首先, 确定表格的类型和名字 } DatabaseName:='EX8'; TableType:=ttParadox; TableName:='ZGInfo'; { 其次, 确定表格中的字段 } with FieldDefs do Clear; Add('gh',ftString,4,True); Add('xm',ftString,10,False); Add('gz',ftFloat,0,False); { 然后, 再确定索引 } with IndexDefs do Clear; Add('','gh', [ ixprimary,ixunique ]); Add('Fld2Indx','gh', [ ixcaseinsensitive ]); CreateTable; { 在给出我们的条件后, 就可以建立表格了 } (2) 数据集打开和关闭的方法 :Open/Close 在前面介绍数据集属性时, 我们通过设置 Active 属性值来打开和关闭一个数据集, 我们也曾经提到用 Open 和 Close 方法可以达到同样的效果 调用 Open 方法将 Active 属性设置为 True 只有当 Active 属性为 True 时, 可以从数据库中读取数据或向数据库中写数据 调用 Close 方法设置 Active 属性值为 False 当 Active 属性值为 False 时, 数据集将被关闭, 无法对数据库进行读 / 写操作 例如, 在实际程序代码中, 语句 Table1.Open; 就等价于语句 Table1.Active:=True; 而语句 Table.Close; 等价于语句 Table1.Active:=False; 需要注意的是, 应用程序在改变任何影响数据库状态的属性时, 必须先将数据集关闭 例如, 在改变数据集 DataSource 属性的时候, 数据集必须先被关闭 (3) 浏览数据库中数据的方法 1 First 在 TDataSet 的派生类中, 调用 First 方法将记录指针移至数据集的第一条记录处, 并使

191 178 Delphi 程序设计基础之成为当前记录 将 Bof 属性值置为 True, 触发数据集的 change 事件 2 Last Last 方法与 First 方法极其相似, 只不过 Last 方法是将记录指针移至数据集的最后一条记录处, 并使之成为当前记录 它是将 Eof 属性值置为 True, 触发数据集的 change 事件 3 MoveBy MoveBy 函数的基本格式如下 : function MoveBy(Distance:Integer):Integer; 调用 MoveBy 方法将记录指针指向数据集中与当前记录相关的一条记录处, 距离 (Distance) 是指需要移动的记录数目 距离是正值表明在数据集中朝前移动, 负值表明是往回移动 例如, 在数据集中往回移动 8 条记录表示如下 : MoveBy( 8); MoveBy 提交所有更改到当前记录 4 Next 调用 Next 方法将记录指针置于数据集中的下一条记录, 并使之成为当前记录 Next 方法提交所有更改到当前记录, 如果记录指针早已处于数据集的最后一条记录, 就将 Eof 属性值置为 True 5 Prior Prior 方法与 Next 方法极其相似, 所不同的只是调用 Prior 方法会将记录指针指向数据集中的前一条记录, 并使之成为当前记录 当记录指针早已处于数据集的起始记录时, 将 Bof 属性值置为 True (4) 在数据库中查询记录的方法 1 EditKey 调用 EditKey 方法将数据集置于 dssetkey 状态, 也就是将 TTable 组件置于查询状态 同时, 存储当前查询值缓冲区的当前内容 想要明确当前查询值, 可以通过 IndexFields 属性来了解当前索引所使用的字段 在执行多项查询, 而各查询的许多字段值中仅有一两项发生了改变的情况下,EditKey 方法显得尤为重要 2 SetKey 调用 SetKey 方法是为了将数据集置于 dssetkey 状态并清除查询值缓冲区的当前内容, 也就是将 TTable 组件置于查询状态 在执行查询前可以调用 FieldByName 方法来提供新的查询值 如果要更改一个查询值或检索范围, 可以调用 EditKey 方法 3 FieldByName FieldByName 函数的基本格式如下 : function FieldByName(const FieldName:string):TField; FieldByName 方法是根据一个特定的字段名查询一个字段 FieldName 是一个已存在的字段名 当只知道字段名时, 可以调用 FieldByName 来获取关于该字段的信息 通过 FieldByName 属性, 应用程序可以直接获得关于该字段的特殊的属性和方法, 而不用通过字段名数组的索引 4 FindKey

192 第 8 章数据库编程 179 FindKey 函数的基本格式如下 : function FindKey(constKeyValues:arrayofconst):Boolean; FindKey 方法相当于将设置表格组件的查找状态 设置查询值以及在数据集中查询这三个步骤的功能集中在一个方法调用中实现 调用 FindKey 方法在数据集中查找一条特定的记录,KeyValues 中包含了字段值的一个序列, 称之为查询值 查询值中的数值可以是一个常量, 也可以是变量 零或是空指针 如果 KeyValues 中数值的数目小于用来查找的索引的列数, 缺少的值将被置为零 对于 Paradox 和 dbase 表格, 查询值必须是一个索引 索引可以在 IndexName 属性中指定, 如果 IndexName 属性值为空, 表格会采用主索引 对于 SQL 表格, 查询值会与 IndexName 中的特定索引对应, 或者与 IndexFieldNames 属性中的字段名列表相对应 如果查询成功,FindKey 将记录指针置于匹配的记录处, 返回 True 值 否则, 记录指针不发生移动, 返回 False 值 5 FindNearest FindNearest 方法与 FindKey 方法很相似, 不同之处在于 FindNearest 方法不要求精确查询 调用 FindNearest 方法将移动记录指针到数据集中与查询值精确符合的一个特定的记录或数据集中与查询值最相近的记录 KeyExclusive 属性限定了检索范围, 同样, 它也决定了调用 FindNearest 方法查询记录的范围 6 GotoKey 调用 GotoKey 方法可以用来查询一条特定记录, 查询值是已经用 SetKey 或 EditKey 方法与 Fields 属性值确定了的 如果调用 GotoKey 方法找到了匹配记录, 它会将记录指针移动到这条记录处并返回 True 值 否则, 记录指针的位置会发生改变,GotoKey 返回 False 值 下面举例说明 GotoKey 方法的使用 : with Table1 do EditKey;{ 将 TTable 组件置于查询状态 } FieldByName('XB').AsString:=' 男 '; { 设置查询值 } FieldByName('ZC').AsString:=' 工程师 ';{ 设置查询值 } GotoKey;{ 执行查询过程 } 7 GotoNearest GotoNearest 方法与 GotoKey 方法之间的区别和 FindNearest 方法与 FindKey 方法之间的区别一样 调用 GotoNearest 方法也是移动记录指针到当前查询值缓冲区精确定义的查询值, 如果没有找到与查询值精确匹配的记录, 它会将记录指针移动到与查询值最相近的记录上 与 GotoKey 方法一样,GotoNearest 方法查询记录的范围也由 KeyExclusive 属性决定, 在调用 GotoNearest 方法前, 应用程序必须调用 SetKey 或 EditKey 方法将数据集置于查询状态 (dssetkey), 明确查询值 下面举例说明 GotoNearest 方法的使用 : with Table1 do

193 180 Delphi 程序设计基础 SetKey;{ 将 TTable 组件置于查询状态 } FieldByName('XB').AsString:=' 男 '; { 设置查询值 } FieldByName('ZC').AsString:=' 工程师 '; { 设置查询值 } GotoNearest;{ 执行查询过程 } 8 Locate Locate 函数的基本格式如下 : Function Locate(const KeyFields:string; const KeyValues:Variant; Options:TlocateOptions):Boolean; 通过调用 Locate 方法, 可以在数据集中查询一个特定的记录并将记录指针指向它 KeyFields 是一个包含想要检索字段名列表的字符串 KeyValues 是一个用来匹配需查询字段名的变量 如果 KeyFields 是一个单独的字段,KeyValues 指明的是想要记录的字段值 想要指明多项查询值,KeyValues 就得是一个变量数组, 或者建立一个应用 VarArrayOf 格式的变量数组 例如 : if Table1.Locate('XB;ZC',VarArrayOf( [ ' 男 ',' 工程师 ' ]), [ lopartialkey ] ) then Options 是在搜索字符串字段时限定搜索范围的附加条件, 如果 Options 的设置包含 locaseinsensitive, 那么 Locate 函数在匹配字段时将忽略 case 如果 Options 的设置包含 lopartialkey, 那么 Locate 函数将允许对 KeyValues 中字符串的部分匹配 如果 Options 设置为空或 KeyFields 不包含任何字符串字段,Options 的设置将被忽略 如果找到匹配的记录,Locate 将返回 True 值, 并使该匹配的记录成为当前记录 否则返回 False 值 Locate 使用最快的方法寻找匹配的记录, 如果 KeyFields 中的查询字段是有索引的, 而索引与说明的查询选项相符合,Locate 函数会使用这个索引, 否则,Locate 函数将为查询建立一个过滤器 (5) 编辑修改数据库数据的方法 1 Append 调用 Append 方法可以 : 在数据集的末尾建立一个新的空记录 ; 将新的记录置为当前记录 在调用 Append 方法后, 应用程序允许用户向记录的字段中输入数据, 并且能够通过调用 Post 方法 ( 如果允许缓存更新还可以调用 ApplyUpdates 方法 ) 将这些更改提交给数据库 2 Cancel 调用 Cancel 方法用来取消对当前记录中一个或多个字段的修改 在这些更改还未提交给数据库时,Cancel 方法使记录恢复到修改前的状态, 并将数据集置于 dsbrowse 状态 典型的 Cancel 方法是针对用户的需要取消修改, 或者在使字段生效的格式中取消非法的字段值 在数据控制组件 TDBNavigator 中包含了一个调用 Cancel 方法的取消按钮

194 第 8 章数据库编程 Delete 调用 Delete 方法用来将当前记录从数据库中删除 如果该数据集处于激活状态,Delete 方法将产生一个异常事件 4 Edit 调用 Edit 方法用来编辑数据集中的当前记录,Edit 方法决定了数据集的当前状态 如果数据集是空的, 那么,Edit 方法将调用 Insert 方法 5 Insert 调用 Insert 方法可以 : 在数据集中打开一个新的空记录 ; 将新记录作为当前记录 在调用 Insert 方法以后, 应用程序允许用户向记录的字段中输入数据, 能够通过调用 Post 方法 ( 如果允许缓存更新还可以调用 ApplyUpdates 方法 ) 将这些更改提交给数据库 提交的方法与 Append 方法一样 6 InsertRecord InsertRecord 过程的基本格式如下 : Procedure InsertRecord(const Values:arrayofconst); Values 参数说明的是新记录的字段值数组 调用 InsertRecord 方法用来在数据集中建立一个新的记录, 它与 Insert 方法类似, 只不过 InsertRecord 方法直接将新记录的字段值以参数形式传给数据库, 而不用再调用 Post 方法 如 : Table1.InsertRecord( [ GHEdit.Text,XMEdit.Text,XBEdit.Text,ZCEdit.Text ] ); 如果插入记录中字段的数目小于 Table1 中的字段数目,InsertRecord 方法会将缺少的字段值处理成 Null 7 Post 调用 Post 方法用来向数据库提交一个修改的记录 数据集中编辑修改数据库数据的方法 ( 例如 Edit Insert 或 Append), 以及浏览数据库中数据的方法 ( 例如 First Last Next 和 Prior) 会自动地调用 Post 方法 下面举例说明 Post 方法的使用 : procedure TForm1.Button1Click(Sender:TObject); Table1.App Table1.FieldValues [ 'GH' ] :=Edit1.text; Table1.FieldValues [ 'GZ' ] :=StrToInt(Edit2.text); Table1.Post; 8 SetFields 调用 SetFields 过程的基本格式如下 : procedure SetFields(const Values:array of const); 调用 SetFields 方法是用来在当前记录中一次修改多个字段值 Values 中包含的是将要插入每个字段的值, 插入的顺序是根据表中字段的先后顺序决定

195 182 Delphi 程序设计基础的 这些值可以是常量 变量或零, 还可以为空指针 如果 Values 中所含的字段值数目比记录中的字段数目少, 缺少的字段会作为 NULL 处理 在调用 SetFields 方法前, 必须先调用 Edit 方法将数据集置于 dsedit 状态, 在调用 SetFields 方法后, 需要调用 Post 方法将更改提交给数据库 注意 : 如果只想更改记录中的部分字段而保持其他值不变, 给那些不需更改的字段赋空指针 9 Refresh 调用 Refresh 方法用来从数据库中取出数据来更新数据集的内容 它保证了应用程序拥有数据库的最新数据 例如, 当应用程序关闭了一个对数据集的过滤时, 它必须立即调用 Refresh 方法来显示数据集中的所有记录, 而不只是符合原先过滤条件的记录 4.TTable 组件的重要事件 TTable 组件具有很多事件, 我们可以通过这些事件对数据集进行相应操作 TTable 组件的重要事件见表 8-4 表 8-4 TTable 组件的重要事件 事件含义 AfterCancel AfterClose AfterDelete AfterEdit AfterInsert AfterOpen AfterPost AfterScroll BeforeCancel BeforeClose BeforeDelete BeforeEdit BeforeInsert BeforeOpen BeforePost BeforeScroll OnCalcFields OnDeleteError OnEditError OnFilterRecord OnNewRecord OnPostError OnUpdateError OnUpdateRecord 发生在应用程序完成了取消对当前记录的修改之后发生在应用程序关闭一个数据集之后发生在应用程序删除一条记录之后发生在应用程序开始编辑一条记录之后发生在应用程序插入一条记录之后发生在应用程序完成打开一个数据集并在任何数据访问之前发生在应用程序向数据库或缓存提交当前记录之后并在数据集返回浏览状态之前发生在应用程序从一个记录转到另一个记录之后发生在应用程序执行取消对当前记录的修改之前发生在应用程序执行关闭数据集之前发生在应用程序删除当前记录之前发生在应用程序进入编辑当前记录的状态之前发生在应用程序进入插入记录的状态之前发生在应用程序执行打开数据集之前发生在应用程序向数据库或缓存提交当前记录之前发生在应用程序从一个记录转到另一个记录之前发生在应用程序重新计算要计算的字段之时发生在应用程序删除一条记录并产生一个异常事件时发生在应用程序修改或插入一条记录并产生一个异常事件时发生在数据集中的一条记录变成当前记录并且过滤生效时发生在应用程序插入一条记录时发生在应用程序修改或插入一条记录并产生一个异常事件时当缓存的更新特性应用到数据库产生异常事件时当缓存的更新特性应用到记录时

196 第 8 章数据库编程 TQuery 组件介绍 TQuery 是一个建立在 SQL 基础上, 专门用于对数据库中的数据进行查询的组件 TQuery 组件使用 SQL 语言, 可以一次访问数据库中的一个或多个表格 TQuery 组件访问的表格可以是在远程服务器的数据库中的 ( 例如 Sybase SQL Server Oracle Informix DB2 和 InterBase), 也可以是当地的表格 ( 例如 Paradox dbase Access 和 FoxPro), 还可以是 ODBC 从属数据库 另外,TQuery 在开发范围可变的数据库应用程序中显得尤为重要 SQL 语言作为关系数据库管理系统中的一种通用的结构查询语言, 已经被众多的数据库管理系统所采用, 如 Oracle Sybase Informix 等数据库管理系统, 它们都支持 SQL 语言 Delphi 与使用 SQL 语言的数据库管理系统兼容, 在使用 Delphi 开发数据库应用程序时, 我们可以使用 SQL 语言编程, 支持 SQL 编程是 Delphi 的一个重要特征, 也是体现 Delphi 作为一个强大的数据库应用开发工具的一个重要标志 由于 TQuery 组件主要应用 SQL 语言, 所以我们必须先熟悉 SQL 语言 1. 结构化查询语言 (SQL) SQL(Standard Query Language) 是最重要的数据库操作语言 SQL 是过程性语言, 允许用户提交一组命令查询或定义数据 SQL 查询语句格式为 : Select 选择选项 [Into 表 ] From 表 [Where 表达式 ] [Group By 分组字段 ] [Having 分组表达式 ] [Order By 排序字段 [DESC,ASC]] (1) 查询单个表 1 投影 : 从一个表中显示部分列 ( 字段 ) 下面是用 SQL 进行投影的例子,ZG 指的是例 8-2 的数据表 : Select GH,XM From ZG 2 过滤 : 从一个表中显示部分行 ( 记录 ) 下面的查询将找出 XB 为 男 的所有员工 : Select * From ZG Where XB= ' 男 ' Where 子句可以使用通配符 %, 以模糊查询, 如查询所有姓 张 的职员 : Select * From ZG Where XM Like ' 张 %' 3 排序

197 184 Delphi 程序设计基础可以对查询的结果按照一个或者多个字段排序, 例如 : Select * From ZG Where XB=' 男 ' Order By XM ASC 排序列必须出现在投影列中, 上面按 XM 的升序对结果数据集排序 降序用 DESC 4 内制函数 SQL 提供了 5 个内制函数 :Count Sum Avg Max 和 Min Count 计算结果数据集的行数 ;SUM 对结果数据集的某一列求和 ;Avg 计算平均值 ;Max 和 Min 计算最大值和最小值 例如 : Select Count(*) From ZG 上面查询了 ZG 的行数 5 分组分组是根据数据集列的值进行分类 例如 : Select zc,sum(gz) From ZG Group By ZC 上面按照 ZC( 职称 ) 进行分组, 即 工程师 的记录一起分组, 助理工程师 的记录一起分组 (2) 查询多个表我们要用到下面的关系数据表 : ZG(GH,BMDM,XM,XB,CSRQ,ZC,GZ) BM(BMDM,BMMC,FZR,BMDH) // 意思为 : 部门 ( 部门代码, 部门名称, 负责人, 部门电话 ) 1 子查询如果打算查询 人事处 的职员姓名, 假如知道部门代码是 0020, 可以使用下面的 SQL 语句查询职员姓名 : Select XM From ZG Where BMDM In ['0020'] 通常, 我们不知道部门代码, 因此常常用下面的方法查找部门代码 : Select BMDM From BM Where BMMC=" 人事处 " 把两个语句结合起来, 可以查找出 人事处 的职员姓名 : Select XM From ZG Where BMDM In ( Select BMDM

198 第 8 章数据库编程 185 From BM WHERE BMMC=" 人事处 ") 圆括号里的查询就称为子查询 2 连接假如想得到职员的姓名和他们的负责人, 即 GH( 工号 ) XM( 姓名 ) 和 FZR( 负责人 ), 这时, 子查询就无法胜任了, 因为字段来自两个不同的数据库表 可以使用连接完成这个功能 例如 : Select ZG.GH,ZG.XM,BM.FZR From ZG,BM Where ZG.BMDM=BM.BMDM 上面的 Where 语句完成了连接运算 (3) 添加数据可以向数据库插入记录 : Insert Into ZG (GH,XM,ZC,GZ) Values ('0027',' 罗德祥 ', ' 技术员 ',1300) (4) 删除记录下面是从数据库中删除工号为 0027 的记录 : Delete ZG Where GH='0027' 上面的 WHERE 子句指明了删除记录需要满足的条件 (5) 修改记录如果将 ZG 数据库表中 GH='0005' 的记录的姓名字段由 郑幼秋 修改为 郑美棠, 可以使用如下的 SQL 语句 : UPDATE ZG SET XM=" 郑美棠 " WHERE XM=" 郑幼秋 " 上面的 SET 子句完成赋值功能, 而 WHERE 子句的功能与前面的相同, 即过滤功能 SQL 语句还有其他许多功能, 这里只介绍较常用的 2.TQuery 组件和 TTable 组件的比较 TQuery 组件的重要性体现在 : 可同时访问多张表格 ; 自动访问基本表格的子集, 而不是访问所有的数据 TQuery 组件和 TTable 组件同属于数据集组件, 它们有着许多相似的地方, 但有各自特殊的地方 本节首先将 TQuery 组件和 TTable 组件作一个比较, 然后再对 TQuery 组件特殊的属性 方法和事件做详细介绍 由 TQuery 组件和 TTable 组件的继承关系可知,TQuery 组件和 TTable 组件同属于数据集组件, 所以 TTable 组件继承来的属性 方法和事件,TQuery 组件都具有 TQuery 组件和 TTable 组件在很多地方是相似的, 但二者又有区别 主要表现在以下几个方向 :

199 186 Delphi 程序设计基础 (1)TQuery 组件主要功能是用来支持 SQL 语言访问本地或远程数据库, 所以,TQuery 组件提供了一系列与 TTable 组件不同的属性 方法和事件 (2)TQuery 组件允许用户同时访问多个表, 而 TTable 组件一次只能访问一个表 (3)TQuery 组件和 TTable 组件以不同的方式与 SQL 服务器进行交互, 在执行数据定义语句 (DDL) 时, 应当使用 TQuery 组件, 而在以非集中方式访问数据库时应当使用 TTable 组件 (4)TQuery 组件访问的是表格中的特定数据内容 ; 而 TTable 组件只有提供过滤或限定检索范围才能访问表格中的特定数据内容, 否则,TTable 组件访问的将是表格中的全部数据 3.TQuery 组件的重要属性如前所述,TQuery 组件和 TTable 组件同属于数据集组件, 所以数据集组件具有的属性 方法和事件,TQuery 组件都具有 下面只介绍 TQuery 组件的特有属性, 其他的重要属性可参见 TTable 组件的重要属性 表 8-5 列出了 TQuery 组件的特有属性 表 8-5 TQuery 组件的特有属性 属性含义 Constrained DataSource Local ParamCheck ParamCount Params Prepared RequestLive RowsAffected SQL SQLBinary StmtHandle Text UniDirectionl 表明 Paradox 和 dbase 表格是否必须在用 SELECT 语句设定的范围内执行更新和插入操作指明引入当前字段值的 datasource 组件表明当前访问的是当地的 Paradox 或 dbase 表格还是远程服务器上的 SQL 表格表明当 SQL 属性在运行时发生改变后, 查询的参数列表表示当前查询参数的总数包含了用 SQL 语句查询的参数性质决定是否准备好执行一个查询表明执行查询时, 是否允许 BDE 即时返回应用程序对数据结果的修改返回上一次执行查询更新或删除的记录数设置执行查询所需的 SQL 语句用于 TQuery 与 BDE 的直接联系用于调用一些 BDE 的 API 函数用于指明传递给 BDE 的 SQL 查询的实际内容决定在查询数据结果时, 是否允许 BDE 的记录指针双向移动 下面详细介绍 TQuery 组件的几个重要属性 (1)SQL SQL 属性是 TQuery 组件最重要的属性之一, 它用来设置在 TQuery 组件调用 ExecSQL 或 Open 方法执行查询时所需的选择条件 在设计阶段, 可以通过单击对象观察器中的 SQL 属性栏激活 String List Editor 窗口, 然后在该窗口中编辑 SQL 语句, 如图 8-8 所示 除了在 String List Editor 窗口中编辑 SQL 语句可以设置 SQL 属性以外,SQL 属性也可以在运 图 8-8 在 String List Editor 窗口中编辑 SQL 语句

200 第 8 章数据库编程 187 行时动态地设置, 看下面的一个例子 : Query1.Close; Query1.SQL.Clear; Query1.SQL.Add('Select * From ZG Where XM='' 周强 '''); Query1.Open; 从例子中不难看出,SQL 属性是一个 TStrings 对象 如果要在代码中实现对 SQL 属性的设置, 必须按以下步骤进行 : 1 调用 TQuery 的 Close 方法关闭 TQuery 对象 2 调用 TStrings 的 Clear 方法清除 TQuery 中的 SQL 属性值 3 调用 TStrings 的 Add 方法向 TQuery 的 SQL 属性中添加 SQL 语句 4 调用 TQuery 的 Open 方法或者 ExecSQL 方法恢复 TQuery 对象的打开状态 注意 : 当 SQL 语句中使用 Select 语句时,Query 组件使用 Open 方法, 使用 Insert Delete Update 等语句时,Query 组件使用 ExecSQL 方法 另外,Client/Server 应用程序开发者还可以通过激活 Visual Query Builder 窗口来设置 SQL 属性值 Query 组件中的 SQL 语句是一个字符串, 在运行时除了本身需要字符串的分隔符 ' 外, 还需要描述嵌套字符串的分隔符 ', 在 Delphi 字符串中可以用 " 表示 ', 因为单个 ' 会与原字符串的分隔符号相混 如 :Query1.SQL.Add('Select * From ZG Where XM=" 周强 "'); 中的 SQL 语句实际执行效果是 Select * From ZG Where XM=' 周强 ' (2)DataSource 设置 DataSource 属性可以自动地将另一个数据集的字段值赋给当前查询的参数, 但这些参数必须具有与该数据集相同的字段名 如果不同名, 就不能自动地赋值, 而必须为其编制程序 例如, 在 TQuery 组件的 SQL 属性中设置了以下语句, 并且通过 DataSource 指向的数据集含有一个 Country 字段, 其他数据集就可以利用 Country 参数来得到该值 Select * From OrdersO Where (O.Country=:Country) DataSource 属性必须是指向一个链接另一个数据集的 TDataSource 组件 DataSource 属性可以在运行时设定, 也可以在设计阶段通过对象观察器在该属性栏的下拉列表中选择适当的 TDataSource 组件名 (3)Params 和 ParamCount Params 属性的基本格式如下 : Property Params [ Index:Word ] :TParams; 在运行时可以访问 Params 来动态地观察和设置参数名 参数值和数据类型, 在设计阶段可以通过编辑 Params 属性来设置参数的形式 从 Params 属性的格式易知,Params 参数值是 TParams 参数记录的数组 在 Select 语句中使用 Parameters 属性不能为 Null, 但在 Update 和 Insert 语句中可以 注意 : 另一种在知道每个参数名时设置和获得参数值的简便方法是调用 ParamByName

201 188 Delphi 程序设计基础方法 但 ParamByName 方法不能用来更改参数的数据类型和参数名 检查 ParamCount 的值可以知道 Params 属性中有多少参数 如果 ParamCheck 属性值为 True, 则 ParamCount 与 SQL 查询语句中的实际参数数目对应 应用程序对 Params 属性的操作, 例如增添或删除参数, 会自动地反映在 ParamCount 中 (4)Prepared 通过检查 Prepared 的属性值来确定是否准备好查询 如果 Prepared 属性值为 True, 说明已经准备好查询 ; 反之, 说明没有准备好 设置 Prepared 属性值为 True 与调用 Prepare 方法的效果是一样的, 设置 Prepared 属性值为 False 与调用 UnPrepare 方法的效果是一样的, 在程序运行时调用 Prepare 方法和 UnPrepare 方法会自动地更新 Prepared 的属性值 (5)RequestLive 设置 RequestLive 属性来说明执行查询时, 是否允许 BDE 即时向应用程序返回对数据结果的修改 如果 RequestLive 属性是默认值 False, 表示查询将返回只读的数据结果 ; 反之, 如果 RequestLive 属性值是 True, 则返回修改的数据结果 但需要注意的是,RequestLive 属性是 True 并不能保证 BDE 一定返回修改的数据结果, 它还有其他条件的限制 在激活一个 TQuery 组件后, 可以通过查看 CanModify 属性值来决定 BDE 是否能返回修改的数据结果 以上介绍了 TQuery 组件的重要属性, 下面将介绍如何通过设置 TQuery 组件的重要属性在应用程序中使用 TQuery 组件 在应用程序中使用 TQuery 组件, 其创建步骤如下 : 1 从 DataAccess 组件板中选取 TQuery 组件放置在窗体或数据模块中, 并指定它在应用程序中的名字 2 设置 DatabaseName 属性为需查询的数据库名,DatabaseName 属性值可以是一个 BDE 数据库别名, 一个当地数据库的直接路径, 还可以是应用程序中 Tdatabase 组件的 DatabaseName 属性值 3 设置 SQL 属性中的 SQL 语句, 并设置 Params 属性中的参数 4 如果查询的数据是通过数据控制组件来显示的, 还要在窗体或数据模块中放置一个数据源组件 TDataSource, 并将其 DataSet 属性设置为该查询组件 它是用来返回查询结果并显示在数据浏览组件中的 通过设置数据浏览组件中 DataSource 和 DataField 属性来联系数据浏览组件和数据源组件 5 激活查询组件 通过设置 Active 属性, 或者调用 Open 方法或 ExecSQL 方法来使 TQuery 组件处于活动状态 4.TQuery 组件的重要方法除了数据集组件共有的方法外,TQuery 组件有自己特有的方法, 本节先列表介绍 TQuery 组件的方法 ( 见表 8-6), 然后再详细介绍其中最重要的几个 关于数据集组件共有的重要方法, 在介绍 TTable 组件时已详细介绍, 在此不再作过多说明, 读者需要了解, 可以参阅前面 TTable 组件的重要方法 表 8-6 TQuery 组件的重要方法 方法含义 Create 在运行时产生一个查询组件

202 第 8 章数据库编程 189 方法含义 续表 Destroy 撤销查询, 断开与数据库的联系 ExecSQL 执行 SQL 查询语句 (Select 语句除外 ) GetDetailLinkFields GetProviderAttributes ParamByName Prepare UnPrepare 取得数据表格之间的主从关系取得 BDE 的有关参数 数据表格的名称以及数据集的只读信息等根据参数名访问参数信息将查询信息送至 BDE 和服务器为执行查询作优化工作释放为先前查询所分配的资源 下面详细介绍 TQuery 组件的几个重要方法 (1)Create 调用 Create 方法在运行时开始一个查询,TQuery 组件会自动地放置在窗体或数据模块中 Create 方法会自动调用它派生的 CreateConstructor, 产生一个新的 SQL 语句空列表和一个空的参数列表, 为 SQL 语句列表触发 OnChange 事件, 建立数据联系, 设置 RequestLive 属性值为 False, 设置 ParamCheck 属性值为 True, 并设置 RowsAffected 属性值为 1 (2)Destroy 与 Create 方法正好相反, 调用 Destroy 方法来取消与服务器之间的联系, 撤销 SQL 语句列表 参数列表 数据联系以及 SQL 的存储区域, 然后再调用它派生的 destructor (3)ExecSQL 调用 ExecSQL 方法来执行当前 SQL 属性中的 SQL 查询语句 ExecSQL 用于不需要返回记录指针的数据访问, 例如执行 Insert Update Delete 和 CreateTable 语句 而对于 Select 语句, 则应调用 Open 方法 如果 ExecSQL 执行的查询没有完成准备工作, 它会先完成准备工作 所以如果想要提高执行速度, 应在第一次调用 ExecSQL 前调用 Prepare 方法 (4)ParamByName ParamByName 函数的基本格式如下 : Function ParamByName(const Value:string):TParam; 调用 ParamByName 方法根据参数名来设置和使用参数信息 其中,Value 是希望获取信息的参数的参数名 ParamByName 方法主要用来在运行时设置参数值 在 Select 语句中的参数值不能为 Null, 但在 Update 和 Insert 语句中可以 (5)Prepare 调用 Prepare 方法让 BDE 和远程的数据库服务器为查询分配资源并执行一些优化操作, 称为执行查询前的准备工作 在执行查询前调用 Prepare 方法会提高应用程序的执行效率 在第一次执行查询前,Delphi 会自动地完成准备工作 注意 : 当我们在应用程序运行过程中更改查询的文本时, 查询的 Prepared 属性会自动变成 False (6)UnPrepare 执行查询的准备工作会消耗一定的资源, 所以在完成查询以后应该调用 UnPrepare 方法来释放分配给查询的资源

203 190 Delphi 程序设计基础以上介绍了 TQuery 组件的重要事件, 下面将介绍如何在应用程序运行时使用 TQuery 组件进行查询 要在运行时执行查询, 需遵循以下步骤 : 1 关闭 TQuery 组件 2 如果在设计阶段没有设置 SQL 属性, 或者希望更改原来 SQL 属性中的 SQL 语句, 就需要设置新的 SQL 语句 否则就忽略这一步 3 直接设置或调用 ParamByName 方法设置 Params 属性中的参数和参数值 4 调用 Prepare 方法初始化 BDE, 联系查询中的参数值 这一步并不是必不可少的, 但使用它可以提高应用程序运行的效率 5 调用 Open 或 ExecSQL 方法激活 TQuery 组件, 执行查询过程 在第一次执行查询后, 直到改变 SQL 查询语句, 应用程序可以反复地关闭和打开 TQuery 组件, 重新执行查询而无需再调用 Prepare 方法完成准备工作 8.3 ADO 组件 自 Delphi 5.0 版本后, 新增加的 ADO 数据集访问组件可以算是对数据库应用程序开发的最大改进 通过 ADO 数据集访问组件, 可以不借助 BDE 而是通过微软的 O L E(Object Linking and Embedding, 对象链接与嵌入 ) 来访问更为广泛的数据库中的数据 ADO 数据集访问组件与常用的数据访问组件是并列的关系, 在这里介绍是因为 ADO 数据集访问组件是从常用数据访问组件发展而来, 它的许多用法和常用数据访问组件都是相同的 Delphi 中的 ADO 数据访问组件页如图 8-9 所示 ADO 组件包含了 ADO 结构的各项功能 ADO 是 Microsoft ActiveX Data Objects 的缩写, 它是一系列使应用程序具有访问数据库能力的数据对象 Delphi 的 ADO 组件应用 Delphi 组件的内容和使用方式来实现 ADO 数据对象的功能 最为突出的 ADO 对象包括 Connection Command Recordset 对象 这些对象分别体现在 Delphi ADO 组件中的 TADOConnection TADOCommand 以及 ADO 数据集组件中 图 8-9 ADO 数据访问组件页 使用 ADO 和 ADO 组件允许程序员使用 ADO 代替原来的 Borland 数据库引擎 (BDE) 来访问数据 不同于基于 Borland 数据库引擎 (BDE) 的连接和数据集组件,Delphi 提供了一套采用 ADO 的组件 利用这些组件, 用户可以与 ADO 数据库相联系, 读取数据库中的数据并执行相应的操作 利用 ADO 数据访问组件, 可以只使用 ADO 结构与数据库取得联系并对其中的数据进行操作, 而在此过程中完全不需要使用 BDE 用户可以在能使用 ADO 而不希望使用 BDE 时采用此类组件, 但前提是在主机上必须启动 ADO2.1( 或更高版本 ) 大多数的 ADO 连接和数据集组件都是与基于 BDE 的连接和数据集组件相类似的

204 第 8 章数据库编程 191 TADOConnection 组件与基于 BDE 的应用程序中的 TDatabase 组件类似 TADOTable 与 TTable,TADOQuery 与 TQuery, 以及 TADOStoredProc 与 TStoredProc 之间都具有这种类似的对应关系 使用这些 ADO 组件的方式与我们使用常用的数据访问组件 ( 基于 BDE) 都有许多相同之处 TTADODataSet 没有直接的 BDE 对应组件, 但它提供了许多与 TTable 和 TQuery 相同的功能 同样,TADOCommand 也没有相对应的 BDE 组件, 它是在 Delphi/ADO 环境中完成特定功能的组件 下面简单介绍 ADO 组件的功能 1.TADOConnection TADOConnection 是用来建立与 ADO 数据库之间联系的组件, 各种 ADO 的数据集及操作组件可以共用这种联系来执行命令, 读取数据, 并执行相应的操作 2.TADOCommand TADOCommand 主要用来执行命令操作 (SQL 语句中不返回数据结果的命令 ) 它与一个相支持的数据集组件一起使用, 同样可以用来从数据表格中读取数据 同 TADODataSet 一样, 它可以直接与数据库相联, 也可以通过 TADOConnection 来实现连接 3.TADODataSet TADODataSet 主要用来读取数据, 并对读取的数据执行相应的操作 它能从单个数据表格或多个数据表格中读取数据 TADODataSet 可以直接与数据库相联, 也可以通过 TADOConnection 来实现连接 4.TADOTable TADOTable 组件主要用来从单个数据表格中读取数据, 完成相应操作 同 TADODataSet 一样, 它可以直接与数据库相联, 也可以通过 TADOConnection 来实现连接 5.TADOQuery TADOQuery 组件通过使用常用的 SQL 语句来读取数据, 完成相应操作 它还可以使用 DDLSQL 语句, 例如 CreateTable 同 TADODataSet 一样, 它可以直接与数据库相联, 也可以通过 TADOConnection 来实现连接 6.TADOStoredProc TADOStoredProc 用来完成数据存储过程 完成的数据存储过程包括读取数据以及执行 DDL 语句 同 TADODataSet 一样, 它可以直接与数据库相联, 也可以通过 TADOConnection 来实现连接 下面各节将分别介绍各组件的使用方法 TADOConnection 组件 Delphi 中的这个组件对应着 ADO 数据对象中的 Connection 对象 它用来建立与 ADO 数据库之间的联系, 由一个 TADOConnection 建立的联系可以被多个 ADO 数据集组件和操作组件通过设置它们的 Connection 实现共享 TADOConnection 允许通过改变其属性值来控制与数据库之间联系的属性和情况 通过 TADOConnection 组件的方法, 可以在使用联合数据集组件时完成数据的交互任务, 可以取

205 192 Delphi 程序设计基础得所连接数据库中的数据表名, 还可以取得数据库中的存储过程名 1.TADOConnection 的重要属性 (1)ConnectionString ConnectionString 属性用来指明数据库的连接信息 通过设置 ConnectionString 来指明将 ADO 联系组件与数据集相连的必要信息 ConnectionString 的属性值包含了一个或多个 ADO 用来建立联系的变元 如果是包含多个变元, 那么它们相互之间要用冒号分开 例如 : ADOConnection1.ConnectionString:='Provider=ProviderRef:RemoteServer=ServerRef'; 在程序设计阶段, 它可以通过激活对象观察器中该属性栏, 从允许的 ADO 数据库连接中选取 该属性值可以保存为文件以后使用, 在以后使用时只需要在该属性栏中指明此文件名就可以再次使用该值 该属性值也可以包含用户的身份和密码等信息 当采用 Open 方法或通过 ConnectionString 显式地注册登录信息时, 最好将 LoginPrompt 属性值设置为 False, 这样可以避免不必要的注册对话框 ADO 的 ConnectionString 的属性值支持 Provider,Filename,RemoteProvider,RemoteServer 四种变元 其他的变元 ( 例如用户的身份和密码 ) 将不被 ADO 处理而只简单地被传输 (2)Connected Connected 属性用来说明一个与数据库的联系是否被激活 设置 Connected 属性值为 True 以建立一个与 ADO 数据库之间的联系而不打开一个数据集 将 Connected 设置为 False 用来使一个联系失效 Connected 属性的默认值为 False 在应用程序中, 可以通过检查 Connected 属性值来判断一个联系的当前状态 如果 Connected 属性值为 True, 表明该联系是处于激活状态的 反之, 如果该属性值为 False, 而另一个属性 KeepConnection 的值也为 False 的话, 表明该联系处于中断状态 Connected 同样可以在程序中用来判断调用 Open 方法和 Close 方法的成功与否 Connected 属性的使用如下例所示 : With ADOConnection1 do Open; if Connected then {connection successful} else {connection unsuccessful}; (3)ConnectionObject ConnectionObject 属性提供对 ADO 联系对象的直接访问 通过设置 ConnectionObject 属性可以取得与其参照的 ADO 联系对象的直接联系 通过这种访问, 应用程序可以使用与其对应的 ADO 联系对象的方法和属性 在没有与之对应的 ADO 联系对象, 而使用 TADOConnection 组件与数据库相连的组件中, 这个属性显得尤为重要 注意 : 利用 ConnectionObject 属性对 ADO 联系对象进行直接访问是建立在对 ADO 对象尤其是 ADO 组件充分熟悉的基础之上的

206 第 8 章数据库编程 193 (4)ConnectionTimeout ConnectionTimeout 属性用来声明连接可能需要的最长时间 该属性的值是一个整数, 它的单位是秒, 默认值为 15 如果在 ConnectionTimeout 表示的时间之前联系成功或者调用了 Cancel 方法的话,ConnectionTimeout 属性没有任何效用, 但是如果一个联系超过了它规定的时间, 它会终止联系的请求, 并产生一个异常 2.TADOConnection 的重要方法 (1)Cancel Cancel 方法用来取消一个准备与 ADO 数据库建立的联系 调用 Cancel 方法要求联系的方式必须是非同步的 ( 即 ConnectOptions 属性必须设置为 coasyncconnect) Cancel 方法的调用必须在连接的尝试开始以后 ( 调用 Open 方法或将 Connected 属性设置为 True) 并在联系成功或超时之前 (2)Open Open 过程的基本格式如下 : procedure Open(const UserID:WideString;const Password:WideString); 调用 Open 方法来开始建立与 ConnectionString 属性中指明的数据库之间的联系 其中 UserID 和 Password 参数是可选项, 它们可以在发出联系要求的同时登录用户的身份和密码信息 例如 : ADOConnection1.Open('JoeSixpack','SecretWord'); 另外, 用户的登录信息也可以在 ConnectionString 属性中说明 3.TADOConnection 的使用方法如果使用 TADOConnection 组件可与 ADO 数据库联系, 这种联系被 ADO 的操作和数据集组件绑定, 即通过 TADOConnection 组件建立与数据库之间的联系 首先使用 TADOConnection 的 ConnectionString 属性,ConnectionString 属性可以包含一系列参数值, 相互之间用冒号分开 ConnectionString 属性的值可以是包含一系列参数值的文件名 这种文件的内容与格式都与 ConnectionString 属性值一样 ConnectionString 属性和它的各种参数可以在程序中作为字符串型数设置, 但更常用的方式是在程序设计阶段通过激活对象观察器中该属性栏的对话框设定 ( 双击 ConnectionString 属性栏或者单击属性栏中的省略号按钮 ) 在给 ConnectionString 属性提供了必要的参数值后, 将 Connected 属性设置为 True 如果与 TADOConnection 组件绑定的 TADOCommand 或 ADO 数据集组件被激活时,Connected 属性值将被自动地设置为 True TADOCommand 组件 TADOCommand 对应的是 ADO 中的 command 对象 TADOCommand 组件用来处理对数据库的操作命令, 例如专门的 SQL 命令 TADOCommand 更通常的是用来执行 DDLSQL 命令, 或者执行一个不需要返回结果的存储过程 对于那些不返回结果的 SQL 语句, 使用 TADODataSet 组件 TADOQuery 组件或者 TADOStoredProc 组件会更好 TADOCommand 组件执行的命令是在 CommandText 属性中说明的 如果有参数值的话,

207 194 Delphi 程序设计基础它们是在 Parameters 属性中说明的 通过调用 Execute 方法执行命令 TADOCommand 组件可以通过 TADOConnection 组件与数据库相连, 也可以通过在自己的 ConnectionString 属性中说明连接信息与数据库取得联系 1.TADOCommand 的重要属性 (1)CommandText CommandText 属性用来说明要使用 ADO 操作组件执行的命令内容 CommandText 属性值是文本形式的命令, 例如 SQL 语句 一个数据表格名或者一个存储过程名 在程序中设置 CommandText 属性的形式如下 : ADOCommand1.CommandText:='DROPTABLE Employee 2000'; 如果操作中包含了一些参数 ( 像在执行 SQL 语句或者一个存储过程时的情况 ), 我们可以通过 Parameters 属性值来设定 (2)CommandType CommandType 属性用来说明在 CommandText 中所说明操作的类型 CommandType 的属性值应该与 CommandText 中所说明操作相一致, 例如 : 当 CommandText 属性的内容为数据表格名时,CommandType 的属性值就应当为 cmdtable 或者是 cmdtabledirect (3)CommandObject 通过设置 ConnectionObject 属性可以取得与其对应的 ADO 操作对象直接联系 通过这种访问, 应用程序可以使用与其对应的 ADO 操作对象的方法和属性 在没有与之对应的 ADO 操作对象, 而使用 TADOCommand 组件与数据库相连的组件中, 这个属性显得尤为重要 2.TADOCommand 的重要方法 (1)Execute Execute 函数用来立即执行 CommandText 中定义的操作 当执行的操作是用来新增一个记录时,Execute 函数将返回这个记录 而这个记录必须通过 ADO 数据集组件来访问, 为了达到这个目的, 需要将此 ADO 数据集组件的 RecordSet 属性直接设置为 Execute 函数的返回值 例如 : TADODataSet1.RecordSet:=ADOCommand1.Execute; (2)Cancel Cancel 方法用来取消一个操作组件准备执行的操作 调用 Cancel 方法要求执行操作的方式必须是非同步的 ( 即 ExecuteOptions 属性必须设置为 eoasyncexecute) 注意 : 为了成功地取消一个操作,Cancel 方法的调用必须在达到 CommandTimeout 属性里说明的时间之前 3.TADOCommand 的使用 TADOCommand 组件用来执行对数据库的操作 首先, 在 CommandText 属性中说明使用 ADO 操作组件执行操作的内容 在程序设计阶段, 在对象观察器中通过在 CommandText 属性栏中输入命令 ( 一条 SQL 语句 一个数据表格名或一个过程名 ) 在运行阶段, 可以将 CommandText 属性值作为字符串类型的数据设定 如果需要的话, 我们可以在 CommandType 属性中显式地定义执行操作的类型 CommandType 属性包含的选项有 :cmdtext( 当执行操作为一个 SQL 语句时 ) cmdtable( 当执行操作为一

208 第 8 章数据库编程 195 个数据表格名时 ), 以及 cmdstoredproc( 当执行操作为一个存储过程时 ) 它同样可以在设计阶段从对象观察器中设定, 也可以在程序运行时做为 TCommandType 类型数值设定 在 ADO 操作组件执行操作之前,TADOCommand 组件必须与数据库有效连接 如果调用 TADOCommand 的 Execute 方法执行一个需要返回结果的操作,Execute 方法会返回一个 ADO 记录对象 为了访问此结果, 需要将一个像 TADODataSet 这样的 ADO 数据集组件的 RecordSet 属性值指定为该返回结果 在下面的例子里, 我们可以清楚地看到 TADOCommand 的使用方法 : with ADOCommand1 do CommandText:='SELECT Company,State From customer Where State=:StateParam'; CommandType:=cmdText; Parameters.ParamByName('StateParam').Value:='HI'; TADODataSet1.Recordset:=Execute; ADO 数据集组件的 Recordset 属性一旦设置以后, 该数据集组件就会自动被激活, 在程序中利用该数据集组件的方法和属性就可以访问这些数据 如果想要通过数据控制组件使返回的结果可视化, 其采用的方法和通用的数据集组件一样, 可以使用 TDataSource 组件作为 ADO 数据集组件和数据控制组件之间的联系 TADODataSet 组件 TADODataSet 是最常用的 ADO 数据集组件 TADODataSet 可以从 ADO 数据库内读取一张或多张数据表 这种读取可以是直接读取数据表格, 也可以通过 SQL 语句访问 在使用 TADODataSet 访问数据之前需要建立它与数据库之间的联系 可以通过设置 TADODataSet 的 ConnectionString 属性或者通过设置 Connection 属性为一个 TADOConnection 组件建立这种联系 使用 TADODataSet 组件的 CommandText 属性获取数据集中的数据 它可以指定为一个数据表格或者 SQL 语句 ( 只限于 Select 语句 ) TADODataSet 不能使用不输出数据结果的 DMLSQL 语句 ( 数据操作语言 ), 例如 Delete 语句 Insert 语句和 Update 语句 如果要使用这些语句, 可以通过 TADOCommand 组件或 TADOQuery 组件 1.TADODataSet 组件的属性通过设置组件的属性, 可以完成用户对数据访问的需要, 下面介绍该组件的一些属性 (1)ConnectionString ConnectionString 是用来指明数据库的连接信息的属性 通过设置 ConnectionString 来指明将 ADO 数据集组件与数据集相连的必要信息 ConnectionString 的属性值包含了一个或多个 ADO 用来建立联系 如果是包含多个参数, 那么它们相互之间要用冒号分开 例如 : ADODataSet1.ConnectionString:='Provider=ProviderRef:RemoteServer=ServerRef'; 在程序设计阶段, 它可以通过激活对象观察器中该属性栏, 从允许的 ADO 数据库连接中选取 该属性值可以保存为文件以后使用, 在以后使用时只需要在该属性栏中指明此文件名就可以再次使用该值 该属性值也可以包含用户的身份和密码等信息, 以实现自动登录的目的

209 196 Delphi 程序设计基础 ADO 的 ConnectionString 的属性值支持下列 4 种参数 :Provider Filename RemoteProvider 和 RemoteServer 其他的变元( 例如用户的身份和密码 ) 将不被 ADO 处理而只简单地被传输 (2)CommandText CommandText 是一个可以用来表达语句 数据表格名或者执行的存储过程, 要为该属性赋一个文本值, 如下面的例子 : CommandText:='Select * From CustomerTable'; 在 TADODataSet 组件的属性对话框中单击 CommandText 属性, 就会弹出如图 8-14 的对话框, 可以在其中设置该属性 (3)CommandType CommandType 用于指明 CommandText 属性的类型, 该属性的值应该和 CommandText 属性的值相一致, 例如 CommandText 属性是数据表格的名称, 那么 CommandType 属性的值就应该是 cmdtable 或 cmdtabledirect, 如果 CommandText 属性的值是一个 SQL 语句, CommandType 属性的值就应该是 cmdtext CommandType 属性的默认值是 cmdunknown, 对于各种类型的命令都可以使用该默认值, 但是由于 ADO 必须确定命令的类型, 就会降低运行的速度 下面的例子演示了如何为属性赋值 : CommandType:=cmdText; CommandText:='Select * From CustomerTable'; (4)Connection 使用 Connection 属性来指明 ADO 组件与 ADO 数据库联系的方式 在程序设计阶段, 从对象观察器中的 Connection 属性栏的下拉列表中选择可能的 TADOConnection 对象 当然, Connection 属性也可以在程序运行阶段设置 例如 : ADODataSet1.Connection:=ADOConnection1; 2.TADODataSet 组件的方法 TADODataSet 组件的方法大多从 TDataSet 处继承而来 例如用来移动数据指针的 First Next Last 和 Prior 的方法, 用来编辑数据记录的 Insert 和 Edit 方法 在此不再赘述 3.TADODataSet 组件的使用 TADODataSet 组件使 Delphi 的应用程序具有通过 ADO 访问一个或多个数据表格的能力 在 ADO 数据集组件的 CommandText 属性中说明需要访问的数据表格名 TADODataSet 同样也提供给应用程序执行操作的能力 与数据库的联系可以通过指定 ADO 数据集组件的 ConnectionString 的属性值或者通过另外一个 TADOConnection 组件完成 应用程序中访问和操作 TADODataSet 组件中的数据的方法与标准的基于 BDE 的数据集组件的方法一样 将 ADO 数据集组件的 DataSet 属性设置为一个标准的 TDataSource 组件 TDataSource 这时就联系着 ADO 数据集组件和数据控制组件 TADODataSet 组件的方法基本与 TDataSet 组件一样, 可以使用 First Next Last 和 Prior 来移动数据记录指针, 使用 Insert 和 Edit 方法来编辑数据记录 TADOTable 组件 TADOTable 组件的属性和方法在 TTable 组件和 TADODataSet 组件中都有体现, 在这里

210 第 8 章数据库编程 197 不再赘述 我们只介绍 TADOTable 组件的使用方法, 读者应将重点放在将它和 TTable 组件异同点的比较上, 因为 TADOTable 组件与 TTable 组件的区别与 TADOQuery 组件与 TQuery 组件 TADOStoredProc 组件与 TStoredProc 组件的区别一样 为了节约篇幅, 我们不再分别介绍 TADOQuery 组件和 TADOStoredProc 组件 TADOTable 组件与 TTable 组件的区别就在于前者通过 ADO 与数据库相连, 而后者则是依靠 BDE 所以与 TADOTable 组件除了具有与 TTable 组件一样的访问数据库数据的属性和方法以外, 还具有一些用以建立组件与 ADO 数据库之间联系的属性和方法, 例如 : CommandText CommandTimeout CommandType Connection ConnectionString 等等 这些属性在 TTADODataSet 中我们已经作过介绍, 它们的使用方法完全一样 当一个 TADOTable 组件已经与数据库建立了有效的连接后, 它可以访问数据库中的数据表格 在 TableName 属性中指明要访问的数据表格名 这样在激活该组件后, 就可以通过它访问表格中的数据 在程序设计阶段, 如果 TADOTable 组件与数据库正确连接, 那么在 TableName 属性栏里会出现允许访问表格的下拉列表 而在程序运行阶段, 我们可以通过将 TableName 的属性值设置为一个字符串类型的数据即可 例如 : ADOTable1.TableName:='Orders'; 如果采用了 TADOConnection 组件来实现与数据库之间的联系, 可以使用 GetTableNames 方法来获得允许的数据表格名列表 8.4 数据控制组件简介 我们开发数据库应用程序时, 利用数据访问组件建立了应用程序与数据库之间的联系, 这时, 我们只完成了一半 我们开发数据库应用程序是为了与数据库信息进行交互, 也就是浏览和编辑数据库中的数据, 因而设计用户接口也成为数据库应用程序开发中一个非常重要的方面 数据控制组件为开发者设计用户接口提供了极大的方便, 这些控制组件通过使用数据库引擎 BDE 实现与数据库数据信息之间的联系 利用 Delphi 提供的数据控制组件可以使应用程序开发者轻松地设计出功能强大的用户接口, 并与数据库信息之间进行交互 因为数据控制组件的功能是浏览和编辑数据库中的数据, 所以数据控制组件又被称为数据浏览组件 数据控制组件集中在数据控制组件页上, 数据控制组件页如图 8-10 所示 图 8-10 Delphi 中的数据控制组件页 数据控制组件包括 TDBGrid TDBNavigator TDBText 和 TDBImage 等 应用程序通过这些组件可以浏览数据集中的数据信息, 还可以编辑修改数据信息并将它们提交给数据库 它们有时候也被称为数据感知组件 (DataAware), 因为这些组件如果与一个处于打开状态的数据集相连, 它们会马上显示该数据集中的数据 例如在一个最简单的数据库应用程序的设

211 198 Delphi 程序设计基础计阶段, 当我们将与数据控制组件相连的数据集激活时, 就会看到在数据控制组件中显示了此数据集中的数据信息 数据控制组件与数据集组件之间的联系是通过数据源组件 TDataSource 来实现的, 这种联系的实现在前面一章已经详细阐述, 这里不再介绍 在应用程序中创建数据控制组件的基本步骤如下 : (1) 在窗体中添加数据控制组件 数据集组件和数据源组件 (2) 将此数据控制组件的 DataSource 属性设置为窗体上数据源组件的名称, 这样就建立了数据控制组件与数据源组件之间的联系 (3) 设置数据控制组件的 Datafield 属性 TDBGrid 组件和 TDBNavigator 组件是访问数据集中所有的字段, 所以没有这一属性 而其他的数据控制组件都需要设定 DataSource 属性来说明访问的是数据表格中的哪一部分 下面列表说明各数据控制组件的基本功能, 见表 8-7 表 8-7 数据控制组件简介 图标组件名功能 TDBGrid TDBNavigator TDBText TDBEdit TDBMemo TDBImage TDBListBox TDBComboBox TDBCheckBox TDBRadioGroup TDBLookupListBox TDBLookupComboBox TDBRichEdit TDBCtrlGrid TDBChart 将数据集的数据信息显示在网格中将在一个数据表格中移动记录指针及编辑修改数据将显示当前记录的字段值将显示及编辑当前记录的字段值将显示数据库表格中的备注型字段将显示 剪切及粘贴当前记录的 BLOB 图像将显示数据表格中选定字段中字段值的列表框将显示及编辑数据表格中选定字段中字段值的组合框将显示及编辑当前选定字段内容的复选框将显示及设置字段值的单选按钮将通过列表框提供相关表格中的多个选项用来编辑当前记录的指定字段将通过组合框提供相关表格中的多个选项用来编辑当前记录的指定字段将可以显示和编辑数据集中一个多行文本的字段将以自由的形式显示和编辑数据表格将显示数据库的图表 TDBGrid 组件 TDBGrid 组件的作用是将一个数据集记录显示在网格中, 并且可以对其中的数据进行编辑修改 在窗体中放置一个 TDBGrid 对象来显示和编辑一个数据集 (table 或 query) 中的记录, 应用程序可以通过数据网格组件来插入 删除或编辑数据集中的数据, 或者只是简单地利用它来显示数据集中的数据记录 网格中的各字段值可以使用字段编辑器来设定, 也可以在运行时动态地设置 在运行时, 用户可以使用 TDBNavigator 在数据网格中移动, 也可以插入 删除和编辑数据 编辑的结果在移动记录指针到另一条记录或者结束应用程序时提交给数据库

212 第 8 章数据库编程 TDBGrid 组件的重要属性 (1)Columns Columns 属性用来读取和设置网格中列的特性 它可以在设计阶段由 Columnseditor 对话框设置, 也可以在应用程序运行时动态地设置 在设计阶段, 如果已经建立了 TDBGrid 组件与数据集的联系, 并且此数据集处于打开状态, 则单击对象观察器的 Columns 属性框会激活 Columnseditor 对话框 单击工具条中的 AddAll 按钮或在快捷菜单中选取 AddAll 命令, 对话框中就会出现此数据集的所有字段, 可以通过对话框中的工具条或单击鼠标右键弹出的快捷菜单对这些字段进行增添或删除的操作 在选择了对话框中的某一字段后, 在对象观察器会出现网格中该字段对象的一些属性 通过这些属性的设置, 我们可以改变每一列字段内容的布局和按钮的显示形式 例如, 可以改变字段名, 设定显示字段值的字体风格, 控制网格线的显示等等 (2)DataSource DataSource 属性可以说是 TDBGrid 组件最重要的一个属性, 它指明了 TDBGrid 组件中显示数据的来源 正是通过这一属性,TDBGrid 组件与 TDataSource 组件发生联系, 从而引入与此 TDataSource 组件相连的数据集, 显示其中的数据信息 所以, 通常 TDBGrid 组件都是和 TDataSource 组件以及数据集组件 (TTable 或 TQuery) 一起使用 通过这一属性, 允许 TDBGrid 组件从数据集中取得数据 写入数据和显示数据 (3)DefaultDrawing 将 DefaultDrawing 属性设置为 True, 允许 TDBGrid 组件自动地在每一单元格中显示数据 ; 而将 DefaultDrawing 属性设置为 False 会取消自动显示, 只有当用户触发 OnDrawColumnCell 事件或 OnDrawDataCell 事件时才会显示相应单元格的数据内容 (4)DragMode 使用 DragMode 属性来控制是否允许用户对数据单元进行拖放操作 DragMode 属性值可以为 dmautomatic 或 dmmanual, 选择 dmautomatic 属性值允许用户对数据单元进行拖放操作 ; 而如果将属性值设置为 dmmanual, 用户就不能对数据单元进行拖放操作, 直到在应用程序中调用了 BeginDrag 方法 在运行时将 DragMode 属性值置为 dmmanual 可以使用户无法进行拖放操作 (5)EditorMode EditorMode 属性用来控制是否允许编辑当前单元内容 在运行时将 EditorMode 属性设置为 True 会将网格置于编辑状态 在这种情况下, 用户可以对单元格的内容进行编辑操作 当用户按下 F2 键时,EditorMode 将被设置为 True, 网格进入编辑状态 注意 : 当 Options 属性中不包含 dgediting 属性或者 Options 属性中包含 dgalwaysshow Editor 时,EditorMode 是不起作用的 (6)Fields 和 FieldCount 通过 Fields 属性可以直接地访问作为网格中一列的数据集中的字段对象 列的序号从 0 开始, 第二列的字段使用序号 1, 依此类推 FieldCount 属性用来记录网格中列的总数, 即字段的总数 所以序号的范围是 0~FieldCount 1 Fields 中独立的字段对象可以用来获取当前记录中的字段值, 使用它可以不通过编辑单

213 200 Delphi 程序设计基础元格而直接向数据集中写入数据 (7)Options Options 中包含了一系列规定 TDBGrid 显示和编辑操作属性的选项 (8)ReadOnly ReadOnly 属性用来标志网格是只用来显示记录, 还是允许用户通过它来编辑数据 设置 ReadOnly 属性值为 True 来防止用户更改数据集中的数据, 设置 ReadOnly 属性值为 False 允许用户使用网格编辑数据集中的数据 当 ReadOnly 属性为 True 时, 用户无法使用 Insert 键来插入一条记录或者使用 DownArrow 键在网格末尾添加一条记录 (9)SelectedField SelectedField 属性说明了当前选择单元格的字段 设置 SelectedField 属性来将焦点移至网格中一个特定的字段 读取 SelectedField 属性来访问当前选中的字段对象 如果当前没有选中任何单元格,SelectedField 属性值为空 例如, 当整行被选中后,SelectedField 属性值就为空 2.TDBGrid 组件的重要事件下面列表说明 TDBGrid 组件的重要事件, 见表 8-8 表 8-8 TDBGrid 组件的重要事件 事 件 含 义 OnCellClick 在单击网格中的单元格时触发 OnColEnter 当焦点移动到网格中的另一个单元格时触发 OnColExit 当一个单元格即将失去焦点时触发 OnColumnMoved 当网格中的一列发生移动时触发 OnEditButtonClick 在单击网格中一个字段的编辑按钮时触发 OnTitleClick 在单击网格中一个字段的标题时触发 TDBNavigator 组件 TDBNavigator 组件 ( 又称为数据库导航器 ) 用来在数据集中浏览数据和编辑数据, 例如插入一条空记录或者提交记录等 TDBNavigator 组件由一组控制按钮组成, 通过这些控制按钮, 用户可以完成在数据集中移动记录指针 增添或删除一项记录 编辑修改数据记录以及向数据库提交对数据集记录的修改等工作 TDBNavigator 组件一般与其他数据控制组件 (TDBGrid 或 TDBEdit) 一起使用, 如图 8-1 所示 TDBNavigator 组件提供给用户在编辑或浏览数据时对数据集的控制 当用户使用 TDBNavigator 组件中的按钮时, 与此 TDBNavigator 组件相连的数据集会发生相应的变化 例如, 当用户选择了其中的 Insert 按钮, 数据集中将被插入一条空的新记录 而当用户选择了移动记录的按钮 (First Prior Next 和 Last) 后, 数据集中的记录指针也会随着发生移动 1.TDBNavigator 组件实现的主要功能在窗体中加入 TDBNavigator 组件后, 用户可以看见在窗体中出现一组控制按钮 我们

214 通过单击这些按钮完成对数据集的一系列操作 第 8 章数据库编程 201 TDBNavigator 组件共有 10 个按钮, 各按钮完成自己的功能 每个按钮的功能见表 8-9 表 8-9 TDBNavigator 组件各按钮功能 名称功能 First Prior Next Last Insert Delete Edit Post Cancel Refresh 记录指针指向第一条记录记录指针指向上一条记录记录指针指向下一条记录记录指针指向最后一条记录在当前记录前插入一条新记录删除当前记录编辑当前记录提交对当前记录的修改取消对当前记录的修改用数据集中的新记录刷新显示缓冲区 2.TDBNavigator 组件的重要属性 (1)ConfirmDelete ConfirmDelete 属性用来决定用户在删除记录时是否显示要求用户确认的消息框 使用这个属性可以防止用户无意中从数据集里删除了记录 如果 ConfirmDelete 属性值设置为 True, 在用户按下删除按钮后会弹出一个消息框要求确认 直到用户按下 OK 按钮, 记录才会被删除 如果 ConfirmDelete 属性值是 False, 删除记录前就不会有要求确认删除的消息框出现 (2)DataSource 通过设置 TDBNavigator 组件的 DataSource 属性将它与其控制的数据集联系起来 这个属性是所有数据控制组件都具有的基本属性 通过这个属性建立数据控制组件与数据集之间的联系, 从而实现对数据集中数据的操作 如果没有设置这个属性, 说明此 TDBNavigator 组件没有与数据集取得联系, 在应用程序运行时,TDBNavigator 组件上所有的按钮都会显示灰色, 说明它失效 (3)ShowHint 与 Hints ShowHint 属性决定是否显示 TDBNavigator 组件中各按钮的提示信息, 如果 ShowHint 属性值设为 True, 当鼠标的光标在 TDBNavigator 组件中的某一按钮上停留一段时间后, 就会自动地出现提示信息 Hints 属性是用来设置提示信息的 单击对象观察器的 Hints 属性框会激活 StringListeditor 对话框, 在对话框中输入提示信息的顺序与 TDBNavigator 组件中各按钮的先后顺序一样 另外,Hints 属性也可以在运行程序时通过 Add 方法实现, 例如 : DBNavigator1.Hints.Items.Add( 第一条记录 ); (4)VisibleButtons VisibleButtons 属性用来确定 TDBNavigator 组件中需要显示哪些按钮, 它包括 10 个选项 : nbfirst nbprior nbnext nblast nbinsert nbdelete nbedit nbpost nbcancel 和 nbrefresh, 它们分别对应着 10 个按钮 当某一项的属性值设置为 True 时, 这一项对应的按钮就会显示

215 202 Delphi 程序设计基础反之设置为 False 就不会显示 例如 : 只允许用户浏览的数据集只需要用到前四个按钮, 将 nbfirst nbprior nbnext nblast 属性值设置为 True, 而将其他属性设置为 False 3.TDBNavigator 组件的重要事件 TDBNavigator 组件的重要事件是 OnClick 事件, 它在 TDBNavigator 组件的某个按钮被单击并执行完相应的操作之后触发 它的基本格式如下 : procedure TForm1.DBNavigator1Click(Sender:TObject;Button:TNavigateBtn); 其中 Button 参数的值可以为以下的值 :nbfirst nbprior nbnext nblast nbinsert nbdelete nbedit nbpost nbcancel 和 nbrefresh 分别对应着 TDBNavigator 组件中的各按钮 TDBText 组件 TDBText 组件是用来显示数据集里当前记录中一个特定字段的值的数据控制组件 用 TDBText 组件显示的字段值是只读属性的, 即用户不能通过这个组件来修改数据 如果用户要修改数据, 就需要使用 TDBEdit 组件或者 TDBMemo 组件 TDBText 组件显示的是当前记录中特定字段的值, 所以随着记录指针的移动, 其显示的内容也不断变化 这也就是它与 TLabel 组件不同的地方 TDBText 组件的重要属性如下 1.DataSource DataSource 属性与其他的数据控制组件一样, 设置为一个数据源组件的名称, 通过此数据源组件与数据集取得联系, 从而读取数据集中的数据 2.DataField DataField 属性用来确定 TDBText 组件显示的是当前记录中哪个特定字段的值 在完成 TDBText 组件与特定数据集的联系后, 对象观察器中的 DataField 属性框会自动产生一个下拉列表, 包含了当前打开数据集中的所有字段 TDBEdit 组件 TDBEdit 组件是用来显示和编辑数据集里当前记录中一个特定字段的值的数据控制组件 用 TDBText 组件显示的字段值的属性是只读的, 而使用 TDBEdit 组件允许用户编辑修改数据 这也是它们之间惟一的区别 TDBText 组件显示和编辑修改的是当前记录中特定字段的值, 所以随着记录指针的移动, 其显示的内容也不断变化 但与 TDBGrid 组件不同, 它一次只能显示及编辑修改当前记录中特定的一个字段值 TDBEdit 组件的重要属性如下 1.DataSource TDBEdit 组件的 DataSource 属性与其他数据控制组件一样, 设置为窗体中的一个数据源组件的名称, 通过此数据源组件与数据集取得联系, 从而对数据集中的数据进行操作 2.DataField DataField 属性用来确定 TDBEdit 组件显示与编辑的是当前记录中哪个特定字段的值 在完成 TDBEdit 组件与特定数据集的联系后, 对象观察器中的 DataField 属性框会自动产生一

216 第 8 章数据库编程 203 个下拉列表, 其中包含了当前打开数据集中的所有字段 TDBMemo 组件 TDBMemo 组件用来显示和编辑数据集中的多行文本 TDBMemo 组件允许用户显示和编辑一个包含多行文本内容的字段 TDBMemo 的 Text 属性代表了该字段的内容 TDBMemo 的显示与编辑数据集字段内容的功能与 TDBEdit 类似, 只不过 TDBMemo 允许多行文本, 而 TDBEdit 组件显示较少内容的文本字段 TDBMemo 组件的重要属性除了和其他数据控制组件一样的 DataSource 和 DataField 属性以外还具有以下不同的属性 1.AutoDisplay AutoDisplay 用来决定是否自动显示一个数据集中备注类型的字段值 当 AutoDisplay 属性值为 True 时,TDBMemo 组件将随着当前记录的改变自动显示该字段的新的内容 如果 AutoDisplay 属性值为 False,TDBMemo 组件在当前记录改变时只显示字段名 如果用户想要查看其中的数据, 只要双击这个字段名或者选择字段名后按下 Enter 键 使用 AutoDisplay 属性的目的是为了提高应用程序的运行速度, 因为 TDBMemo 组件是使用 Text 属性来显示大量的文本信息的, 当 AutoDisplay 属性值为 True 时, 应用程序必须耗费很多时间来更新显示信息 这样会影响程序运行的速度 2.Alignment Alignment 属性用来说明在 TDBMemo 组件中显示文本时的对齐方式 可以有左对齐 右对齐和居中 3 种方式 3.MaxLength MaxLength 属性用来限定可以输入 TDBMemo 组件中的最大字符数 此属性值为 0 时, 表明不限制最大字符数 4.WordWrap WordWrap 属性是一个布尔值, 用来指明向 TDBMemo 组件中输入的文本到了右边界处是否自动换行 5.ReadOnly ReadOnly 属性限定了 TDBMemo 组件中显示的文本是只读类型的, 不能编辑修改 TDBImage 组件 TDBImage 组件用来显示和编辑当前记录中的 Graphic BLOB 类型的图形字段 TDBImage 组件除了可以在窗体中显示数据集里的图形数据, 还允许用户通过粘贴板对图形数据进行编辑操作 在应用程序运行时, 用户可以通过标准的 Windows 快捷键 Ctrl+X Ctrl+C 和 Ctrl+V 对图形数据进行剪切 复制和粘贴操作 在转向其他记录前按 Esc 键可以返回该数据库图形的初始状态 TDBImage 组件的重要属性与 TDBMemo 组件类似, 它也主要有 DataSource 属性 DataField 属性和 AutoDisplay 属性 TDBListBox 组件在用户更改当前记录中特定字段值的时候, 可以使用 TDBListBox 组件来提供给用户一

217 204 Delphi 程序设计基础个可选工程的列表 用户可以从中选取适当的值来修改当前记录中的特定字段 列表框中的选项可以在设计阶段通过单击对象观察器的 Items 属性框激活 StringListeditor 进行编辑 也可以在程序运行时, 使用 Items 的 Add 方法动态地改变 TDBList 组件的重要属性有 DataSource DataField 和 Items, 这些属性的设置与其他组件类似 TDBComboBox 组件 TDBComboBox 组件与 TDBList 组件的功能类似, 也是在用户更改当前记录中特定字段值时, 用来提供给用户一个可选工程的下拉列表 不同之处在于用户可以从下拉列表中选取适当的值来修改当前记录中的特定字段, 也可以直接输入新的字段值 TDBComboBox 组件的重要属性有 DataSource DataField 和 Items 属性, 其中 DataSource 属性和 DataField 属性是大部分数据控制组件共有的属性, 用来指向数据集中当前记录的特定字段 因为这些属性的设置与其他组件类似, 此处不再赘述 Items 属性用来决定下拉列表的工程内容, 和 TDBList 一样, 组合框中的选项可以在设计阶段通过单击对象观察器的 Items 属性框激活 String List Editor 进行编辑, 也可以在应用程序运行时, 使用 Items 的 Add 方法动态地改变 建立一个使用 TDBComboBox 组件的应用程序的主要步骤如下 : (1) 向窗体中添加 TDBComboBox 组件 (2) 设置 TDBComboBox 组件的 DataSource 属性, 使它与数据集产生联系 (3) 设置 TDBComboBox 组件的 DataField 属性, 使它指向数据集中的特定字段 (4) 设置 TDBComboBox 组件的 Items 属性, 为列表框设计选项 TDBCheckBox 组件 TDBCheckBox 是允许用户选择或不选择一个值的数据控制组件,TDBCheckBox 组件与 CheckBox 组件非常相似, 只不过 TDBCheckBox 组件指向数据集中一个特定的字段, 因为复选框只能提供两个值, 所以 TDBCheckBox 组件最适合于表达布尔类型数据的字段 总而言之,TDBCheckBox 组件可以表达一组只包含两个可能值的数据 TDBCheckBox 组件的基本属性和普通复选框 CheckBox 组件的区别在于 TDBCheckBox 组件的 DataSource 属性和 DataField 属性将它与数据集的一个特定字段联系在了一起 CheckBox 组件的应用一般是用于接收用户对一个选项值选择或不选择的选项, 反馈给应用程序再根据不同值作出不同的处理 而 TDBCheckBox 组件除了完成 CheckBox 组件的功能外, 主要用来显示和修改一个布尔类型数据字段的字段值 在对此没有特殊要求的情况下, 尽量选择 CheckBox 组件, 因为这样可以节约资源 建立一个使用 TDBCheckBox 组件的应用程序的主要步骤如下 : (1) 向窗体中添加 TDBCheckBox 组件 (2) 设置 TDBComboBox 组件的 DataSource 属性, 使它与数据集产生联系 (3) 设置 TDBComboBox 组件的 DataField 属性, 使它指向数据集中的特定字段 这个字段最好是布尔类型数据的字段, 即使不是, 也必须只有两种设置形式

218 第 8 章数据库编程 TDBRadioGroup 组件 TDBRadioGroup 组件是允许用户在一组选项中选取惟一一项的数据控制组件, TDBRadioGroup 组件与 RadioGroup 组件的区别与 TDBCheckBox 组件与 CheckBox 组件相同, TDBRadioGroup 组件必须指向数据集中一个特定的字段 TDBRadioGroup 组件与 TDBCheckBox 组件的区别与 RadioGroup 组件与 CheckBox 组件的区别相同 TDBCheckBox 组件用来提供给用户一个选项, 用户可以选择或者不选择 ; 而 TDBRadioGroup 组件用来提供一组两两互斥的选项, 也就是说用户只能选择其中的一个选项 前面提到的 TDBRadioGroup 组件与普通单选框 RadioGroup 组件的区别正是由于 TDBRadioGroup 组件的 DataSource 属性和 DataField 属性将它与数据集的一个特定字段联系起来 普通单选框 RadioGroup 组件的应用一般是用于接收用户在一组互斥选项值惟一选择的选项, 反馈给应用程序再根据不同情况作出不同的处理 而 TDBRadioGroup 组件除了完成 RadioGroup 组件的功能外, 主要用来显示一个字段的字段值, 以及通过在一组选项中选择其中的一项来编辑修改一个字段的字段值 如果在对此没有特殊要求的情况下, 尽量选择 RadioGroup 组件来节约资源 建立一个使用 TDBRadioGroup 组件的应用程序的主要步骤如下 : (1) 向窗体中添加 TDBRadioGroup 组件 (2) 设置 TDBRadioGroup 组件的 DataSource 属性, 使它与数据集产生联系 (3) 设置 TDBRadioGroup 组件的 DataField 属性, 使它指向数据集中的特定字段 (4) 设置 TDBRadioGroup 组件的 Items 属性, 为 TDBRadioGroup 设计选项 通过单击对象观察器中的 Items 属性激活 StringListeditor 对话框进行单选框中选项的编辑 TDBLookupListBox 组件 TDBLookupListBox 组件是用来提供给用户一个数据集中的特定字段的字段值列表, 它与 TDBList 组件的不同之处在于它的列表项目不是用户自己添加的, 而是自动显示数据集中指定字段的值 TDBLookupListBox 组件中显示的为数据集中特定字段的字段值列表, 该字段值列表中的选项与数据集的当前记录相对应 TDBLookupListBox 组件提供给用户的特定字段的字段值列表经常是来源于另一个相关的数据集 因为 TDBLookupListBox 组件显示相关数据集的这种特性, 它的重要属性除了和其他数据控制组件一样的 DataSource 属性和 DataField 属性以外, 还有 KeyField ListField ListFieldIndex 和 ListSource 这样的属性, 它们是用来规定显示字段的一些属性的, TDBLookupListBox 组件主要通过这些属性来调用显示内容 TDBLookupComboBox 组件 TDBLookupComboBox 组件与 TDBLookupListBox 组件一样用来提供给用户一个数据集中的特定字段的字段值列表, 它与 TDBComboBox 组件之间的区别与 TDBLookupListBox 组件与 TDBList 组件之间的区别一样 TDBLookupComboBox 组件下拉列表的内容是另一个相

219 206 Delphi 程序设计基础关数据集中特定字段的字段值, 它在设置好属性后自动添加到 TDBLookupComboBox 中, 而不用像使用 TDBComboBox 组件时一样需用户自己输入列表内容 TDBLookupComboBox 组件与 TDBLookupListBox 组件一样, 提供给用户的特定字段的字段值列表也主要是来源于另一个相关的数据集 所以它的重要属性除了和其他数据控制组件一样的 DataSource 属性和 DataField 属性以外, 还有 KeyField ListField ListFieldIndex 和 ListSource 这样的属性, 它们是用来规定显示字段的一些属性的,TDBLookupComboBox 组件主要通过这些属性来调用显示内容 TDBLookupComboBox 组件与 TDBLookupListBox 组件的不同之处与 TDBComboBox 组件与 TDBListBox 组件一样,TDBLookupComboBox 组件除了在下拉列表中显示相关数据集中的特定字段的字段值列表外, 还允许用户自行输入新的字段值用来编辑当前记录 TDBCtrlGrid 组件 TDBCtrlGrid 组件其实和 TDBGrid 组件实现的功能差不多 只不过 TDBCtrlGrid 组件是用一种用户自己定义的方式来显示各条记录的 在窗体中添加 TDBCtrlGrid 组件用来显示和编辑一个数据集中的记录 和 TDBGrid 组件不一样的是,TDBCtrlGrid 组件不是将一条记录显示在单独的一行中, 它允许用户使用自己定义的方式来显示各条记录 每条记录都显示在自己独立的 Panel 上, 在设计阶段设置记录的显示方式, 它会自动应用到每一条记录的显示上 TDBCtrlGrid 组件的属性与 TDBGrid 的属性类似, 它也是显示数据集中记录的所有字段对象, 所以没有 DataField 属性 不同之处在于 TDBCtrlGrid 的属性中有一些可以让用户定义用于记录显示的 Panel 的属性 在运行时, 用户可以使用 TDBNavigator 组件在 TDBCtrlGrid 中移动记录 添加或删除一条记录, 还可以编辑修改当前记录, 就像在 TDBGrid 中一样 TDBRichEdit 组件 TDBRichEdit 组件的使用方法和它所实现的功能与 TDBEdit 组件非常相似, 只不过 TDBEdit 组件显示和编辑普通文本类型的字段, 而 TDBRichEdit 组件主要用于 RichEdit 文本类型字段的显示和编辑 TDBRichEdit 组件可以是多行显示 TDBChart 组件 TDBChart 组件由 TChart 组件派生而来,TDBChart 组件与 TChart 组件的使用方法和实现功能类似,TDBChart 组件有 DataSource 属性, 用于数据集中数据汇总得到的图形 下面通过例子来理解 BDE 组件和 DataControls 组件的使用 例 8-3 设计一窗体, 对例 8-2 设计的数据表进行数据编辑 (1) 新建应用程序进入 Delphi 后, 单击 File 菜单的 New Application 命令开始一个新的应用程序 (2) 设置窗体属性窗体属性设置见表 8-10

220 第 8 章数据库编程 207 表 8-10 窗体属性 属性属性值属性属性值 Caption 数据库编程 Font 宋体 五号 (3) 添加组件首先往窗体中添加 1 个 GroupBox 组件 GroupBox1 1 个 Table 组件 Table1 1 个 DataSource DataSource1; 然后在 GroupBox1 组件上添加 6 个 Label 组件 Label1~Label6 4 个 DBEdit 组件 DBEdit1~DBEdit4 1 个 DBRadioGroup 组件 DBRadioGroup1 1 个 DBComboBox 组件 DBComboBox1 1 个 DBCheckBox 组件 DBCheckBox1 1 个 DBMemo 组件 DBMemo1 1 个 DBImage 组件 DBImage1 1 个 DBGrid 组件 DBGrid1; 最后再在 GroupBox1 组件外添加 1 个 DBNavigator 组件 DBNavigator1 8 个 Button 组件 Button1~Button8 (4) 设置组件属性先将所有 Data Controls 组件的 DataSource 属性设置为 DataSource1,DataSource1 的 DataSet 属性设置为 Table1 然后再按表 8-11 设置窗体中的组件属性 表 8-11 组件属性 组件属性属性值组件属性属性值 Table1 DataBaseName EX8 DBComboBox1 DataField ZC TableName Zg.DB Items Active True Label1 Caption 工号 Label2 Caption 姓名 Label3 Caption 出生日期 高级工程师工程师助理工程师技术员工人 Label4 Caption 职称 DBMemo1 DataField JL Label5 Caption 工资 DBImage1 DataField ZP Label6 Caption 简历 Buttonl Caption 新增 (&A) DBEdit1 DataField GH Button2 Caption 删除 (&D) DBEdit2 DataField XM Button3 Caption 修改 (&U) DBEdit3 DataField CSRQ Button4 Caption 定位 (&L) DBEdit4 DataField GZ Button5 Caption 查询 (&Q) DBRadioGroup1 Caption 性别 Button6 Caption 保存 (&S) DataField XB Button7 Caption 取消 (&C) DBCheckBox1 DataField HF Button8 Caption 退出 (&E) DBNavigator1 组件 :VisibleButtons 属性 = [ nbfirst, nbprior, nbnext, nblast ] 设置完组件属性后, 窗体中组件及其布局如图 8-11 所示 (5) 添加和编写组件事件代码为组件 DataSource1 添加 OnStateChange 事件, 响应过程为 DataSource1StateChange, 当数据源状态发生变化时, 在状态栏上显示相应提示 :

221 208 Delphi 程序设计基础 图 8-11 例 8-3 界面 procedure TForm1.DataSource1StateChange(Sender: TObject); if Table1.State=dsInsert then StatusBar1.Panels [ 0 ].Text:=' 数据表处于插入状态 '; if Table1.State=dsEdit then StatusBar1.Panels [ 0 ].Text:=' 数据表处于编辑状态 '; if Table1.State=dsBrowse then StatusBar1.Panels [ 0 ].Text:=' 数据表处于浏览状态 '; if Table1.State=dsSetKey then StatusBar1.Panels [ 0 ].Text:=' 数据表处于查询状态 '; 为按钮 Button1 添加 OnClick 事件, 响应过程为 Button1Click, 单击 新增 按钮时, 使数据表添加一条空记录, 同时设置相应按钮灰显 : procedure TForm1.Button1Click(Sender: TObject); if Table1.CanModify then Table1.App GroupBox1.Enabled:=true; DBNavigator1.Enabled:=false; Button1.Enabled:=false; Button2.Enabled:=false; Button3.Enabled:=false; Button4.Enabled:=false; Button5.Enabled:=false; Button8.Enabled:=false;

222 第 8 章数据库编程 209 end else showmessage(' 当前数据表不能新增记录 '); 为按钮 Button2 添加 OnClick 事件, 响应过程为 Button2Click, 单击 删除 按钮时, 确认后删除当前记录 : procedure TForm1.Button2Click(Sender: TObject); if MessageDlg(' 确实要删除当前记录吗?',mtInformation, [ mbok,mbcancel ],0) =mrok then Table1.Delete; 为按钮 Button3 添加 OnClick 事件, 响应过程为 Button3Click, 单击 修改 按钮时, 使数据表进入编辑状态, 同时设置相应按钮灰显 : procedure TForm1.Button3Click(Sender: TObject); if Table1.CanModify then Table1.Edit; GroupBox1.Enabled:=true; DBNavigator1.Enabled:=false; Button1.Enabled:=false; Button2.Enabled:=false; Button3.Enabled:=false; Button4.Enabled:=false; Button5.Enabled:=false; Button8.Enabled:=false; end else showmessage(' 当前数据表不能被修改 '); 为按钮 Button4 添加 OnClick 事件, 响应过程为 Button4Click, 单击 定位 按钮时, 打开一输入框, 输入定位步长 ( 允许负数 ), 指针移到相应记录 : procedure TForm1.Button4Click(Sender: TObject); var i,code:integer; scope:string; repeat scope:=inputbox(' 移动指针位置 ',' 请输入移动距离 :','0'); Val(scope,i,code); if code<>0 then // 当 code<>0 时,scope 为非数值字符 ShowMessage(' 你输入了一个错误的移动范围, 请重试!');

223 210 Delphi 程序设计基础 until code=0; Table1.MoveBy(i); 为按钮 Button5 添加 OnClick 事件, 响应过程为 Button5Click, 单击 查询 按钮时, 打开一对话框 Form2( 在同一工程下另外制作的窗体, 保存在 Unit8_3b 单元文件中, 界面如图 8-12 所示 ), 然后根据输入的工号进行查询 首先必须在 implementation 下写入单元引用 : uses Unit8_3b; 图 8-12 查询对话框 procedure TForm1.Button5Click(Sender: TObject); if Form2.ShowModal=mrOK then =mrok then Table1.IndexFieldNames:='GH'; Table1.SetKey; Table1.FieldByName('GH').Value:=Form2.Edit1.Text; if not Table1.GotoKey then if MessageDlg(' 无匹配记录, 是否转到最近记录?',mtInformation, [ mbok,mbcancel ],0) Table1.GotoNearest; 为按钮 Button6 添加 OnClick 事件, 响应过程为 Button6Click, 单击 保存 按钮时, 使 控制组件的数据保存到数据表中, 同时设置相应按钮正常显示 : procedure TForm1.Button6Click(Sender: TObject); if table1.modified then Table1.Post; GroupBox1.Enabled:=false; DBNavigator1.Enabled:=true; Button1.Enabled:=true; Button2.Enabled:=true; Button3.Enabled:=true; Button4.Enabled:=true; Button5.Enabled:=true; Button8.Enabled:=true; 为按钮 Button7 添加 OnClick 事件, 响应过程为 Button7Click, 单击 取消 按钮时, 取 消刚编辑或新增等操作, 同时设置相应按钮正常显示 :

224 procedure TForm1.Button7Click(Sender: TObject); 出窗体 : Table1.Cancel; GroupBox1.Enabled:=false; DBNavigator1.Enabled:=true; Button1.Enabled:=true; Button2.Enabled:=true; Button3.Enabled:=true; Button4.Enabled:=true; Button5.Enabled:=true; Button8.Enabled:=true; 第 8 章数据库编程 211 为按钮 Button8 添加 OnClick 事件, 响应过程为 Button8Click, 单击 退出 按钮时, 退 procedure TForm1.Button8Click(Sender: TObject); Close; (6) 保存程序 将单元文件保存为 Unit8_3.pas, 将项 目文件保存为 Project8_3.dpr (7) 运行程序 单击工具栏中 Run 按钮运行程序 运 行后, 通过选择相应按钮, 可进入不同状态, 可对数据表进行浏览和编辑, 其中, 照片通过 复制 (Ctrl+C) 粘贴 (Ctrl+V) 输入 运行 效果如图 8-13 所示 例 8-4 设计一窗体, 对例 8-2 设计的数 据表进行数据查询 (1) 新建应用程序 进入 Delphi 后, 单击 File 菜单的 New Application 命令开始一个新的应用程序 (2) 设置窗体属性 窗体属性设置见表 8-12 图 8-13 例 8-3 运行效果 表 8-12 窗体属性 属性属性值属性属性值 Caption 数据库查询 Font 宋体 五号 (3) 添加组件首先往窗体中添加 1 个 GroupBox 组件 GroupBox1 1 个 Query 组件 Query1 1 个 DataSource DataSource1

225 212 Delphi 程序设计基础然后在 GroupBox1 组件上添加 8 个 CheckBox 组件 CheckBox1~CheckBox8 4 个 Edit 组件 Edit1~Edit4 1 个 RadioGroup 组件 RadioGroup1 1 个 ComboBox 组件 ComboBox1 2 个 DateTimePicker 组件 DateTimePicker1 和 DateTimePicker2 最后再在 GroupBox1 组件外添加 1 个 DBMemo 组件 DBMemo1 1 个 DBImage 组件 DBImage1 1 个 DBGrid 组件 DBGrid1 1 个 DBNavigator 组件 DBNavigator1 2 个 Button 组件 Button1 和 Button2 (4) 设置组件属性先将所有 Data Controls 组件的 DataSource 属性设置为 DataSource1,DataSource1 的 DataSet 属性设置为 Query1, 在 Query 组件的 SQL 属性中输入 Select * From zg.db 然后再按表 8-13 设置窗体中的组件属性 表 8-13 组件属性 组 件 属 性 属 性 值 组 件 属 性 属 性 值 Query1 DataBaseName EX8 ComboBox1 Items 高级工程师 Active True 工程师 CheckBox1 Caption 工号 助理工程师 CheckBox2 Caption 姓名 技术员 CheckBox3 Caption 性别 工人 CheckBox4 Caption 生日 DBMemo1 DataField JL CheckBox5 Caption 婚否 DBImage1 DataField ZP CheckBox6 Caption 职称 Buttonl Caption 查询 (&Q) CheckBox7 Caption 工资 Button2 Caption 退出 (&E) CheckBox8 Caption 已婚 Edit1 Text [ 空 ] RadioGroup1 Items 男 Edit2 Text [ 空 ] 女 Edit3 Text [ 空 ] Columns 2 Edit4 Text [ 空 ] DBNavigator1 组件 :VisibleButtons 属性 = [ nbfirst, nbprior, nbnext, nblast ] 设置完组件属性后, 窗体中组件及其布局如图 8-14 所示 (5) 添加和编写组件事件代码为按钮 Button1 添加 OnClick 事件, 响应过程为 Button1Click, 单击 查询 按钮时, 对数据表进行查询, 查询结果通过 DBGrid1 显示 : procedure TForm1.Button1Click(Sender: TObject); var tj,tj1,tj2,tj3,tj4,tj5,tj6,tj7:string; tj1:=' 1=1 '; if checkbox1.checked then // 按工号查询 图 8-14 例 8-4 界面

226 第 8 章数据库编程 213 tj1:=' GH like '''+'%'+Edit1.Text+'%'+''''; tj2:=' 1=1 '; if checkbox2.checked then // 按姓名查询 tj2:=' XM like '''+'%'+Edit2.Text+'%'+''''; tj3:=' 1=1 '; if checkbox3.checked then // 按性别查询 if RadioGroup1.ItemIndex=0 then tj3:=' XB like '''+'% 男 %'+''''; if RadioGroup1.ItemIndex=1 then tj3:=' XB like '''+'% 女 %'+''''; tj4:=' 1=1 '; if checkbox4.checked then // 按生日查询 tj4:=' CSRQ>=#'+DateToStr(DateTimePicker1.Date)+'# and CSRQ<=#'+DateToStr(DateTimePicker2.Date)+'#'; tj5:=' 1=1 '; if checkbox5.checked then if checkbox8.checked then tj5:=' HF=true ' else tj5:=' HF=false '; // 按婚否查询 tj6:=' 1=1 '; if checkbox6.checked then // 按职称查询 tj6:=' ZC like '''+ComboBox1.Text+''''; tj7:=' 1=1 '; if checkbox7.checked then // 按工资查询 tj7:=' GZ>='+Edit3.Text+' and GZ<='+Edit4.Text; tj:='select * from zg.db where ' +tj1+' and '+tj2+' and '+tj3+' and '+tj4+' and ' +tj5+' and '+tj6+' and '+tj7 ;

227 214 Delphi 程序设计基础 Query1.Close; Query1.SQL.Clear; Query1.SQL.Add(tj); Query1.Open; (6) 保存程序将单元文件保存为 Unit8_4.pas, 将项目文件保存为 Project8_4.dpr (7) 运行程序单击工具栏中 Run 按钮运行程序 运行后, 通过选择相应复选框, 选择查询项, 设置查询项, 单击 查询 按钮将符合条件的数据显示在 DBGrid 中, 单击 DBNavigator 按钮可在查询到的数据中浏览, 运行效果如图 8-15 所示 图 8-15 例 8-4 运行效果 习 题 1. 数据库系统主要由哪些部分组成? 各自功能是什么? 2. 简述数据库管理系统 (DBMS) 的主要功能和分类 3. 什么是数据表 (Table) 字段 记录和索引? 4.TTable 组件中 DataBaseName TableName 和 Active 等属性的作用是什么? 5.TTable 组件中, 希望记录指针指向第一 上一 下一 最后记录, 分别用什么方法? 指向当前记录的上 N 条记录又用什么方法呢? 6.TTable 组件中的查询记录的几个 方法 各自有什么不同? 7.TQuery 组件和 TTable 组件的区别是什么? 8. 如何在 Delphi 中表示 I don t know! 字符串? 9.ADO 组件与 BDE 组件有什么区别? 10.Data Controls 组件的作用是什么?

228 第 9 章 报表与图表 QuickReport 是 Delphi 环境下进行数据库应用程序的报表输出时的重要设计工具, 虽然它是由第三方公司制作的, 被 Borland 公司收入 Delphi 中, 但经过 Borland 公司的组合, 几乎和 Delphi 合得天衣无缝, 它可以设计出包括分析图表在内的复杂图表 注意 :Borland 公司自 Delphi 7.0 后不再缺省安装 QuickReport 组件页, 使用前须安装该组件页 本章主要介绍 : QuickReport 组件 各种常用报表设计 Chart 图表设计 9.1 QuickReport 组件 QuickReport 概述 1. 关于报表 Reports 当你需要使用各种数据及数据库完成工作时, 经常是这样的情况, 你面对的是分类 组织在多个表格或文件中的数据, 这些数据以多种不同的方式相互关联, 并且往往这些内部联系不是你要查阅或使用的 ; 或者你的公司的不同部门需要查阅不同的数据或各不相同的内部联系, 这使你处理这些数据很困难 所有需要的这些信息确实是存在于数据库中的, 但因为数据并非专门为各个部门组织或提取, 所以信息寻找起来难度很大 报表提供了一种过滤 呈报数据的手段 例如, 销售部门可以选择查阅其中他们需要的数据, 如按推销员或按季度或同时按两个方面组织的数据 ; 人事部门可能有完全不同的数据需求 但他们可以用同一个数据库去创建报表, 并准确呈报他们所需的数据, 以便适应他们的工作需要 QuickReport 提供了功能强大 灵活方便的报表工具, 可用它创建动态的 含丰富信息的报表, 充分 完全地满足各种需求 2.QuickReport 概述 QuickReport 是一种功能强大的可视化数据库报表 查询工具, 它集成在 Delphi 环境下, 提供用数据库文件 表格创建报表的方法 有了 QuickReport, 我们可以 : 用 SQL 和数据库创建报表, 而不必通晓复杂的数据库指令 ; 编辑 格式化报表, 将各项目的数据 文本 图表 图片及声音等元素进行组合 ; 用动态数据立即查看你改动后的结果

229 216 Delphi 程序设计基础 图 9-1 Delphi 中的 QReport 组件页 3.QReport 组件页 Delphi 中的报表输出功能主要是通过 QReport 组件面板中的组件实现的 通过这些组件可以设计出功能齐全 具有专业水平的报表 下面将详细讲解 QReport 组件的重要属性 方法 事件以及在报表编程中的使用方法 Delphi 中的 QReport 组件组中的组件共有 23 种, 组件组如图 9-1 所示 下面将依次介绍它们 TQuickRep 组件 TQuickRep 组件是制作报表的基础, 每一个报表窗口必须包含一个 TQuickRep 组件 通过该组件可以设计报表的大小 页边距等属性 使用 TQuickRep 组件的方法是 : (1) 通过 Delphi 中的 New Form 创建一个新的窗体, 比如窗体取名为 RoportForm (2) 选择 QReport 组件页, 将 TQuickRep 组件拖到新窗口中, 如图 9-2 所示 (3) 设置 TQuickRep 组件的 Bands 属性, 确认是否打印标题 页眉 页脚等 (4) 在 TQuickRep 组件中放入其他种类的 QReport 组件, 并进行属性设置 (5) 为程序加入代码 注意 : 如果不对 TQuickRep 组件的 Bands 属性进行设置, 则图 9-2 窗口不会出现 PageHeaders 等明细栏 1.TQuickRep 组件的主要属性 (1)Bands 属性 Bands 属性是 TQuickRep 组件最重要的属性 它是一个属性集, 该属性集由 6 个子属性组成, 它们的作用是 : 每设置这些属性集中一个属性为 True 时, 在 TQuickRep 组件中就自动增加一个相应的 TQRBand 组件 图 9-3 是对属性集的设置 Bands 属性集见表 9-1 图 9-2 加入一个 TQuickRep 组件图 9-3 Bands 属性集的设置

230 第 9 章报表与图表 217 表 9-1 Bands 属性集 (2)DataSet DataSet 属性用于指定报表的数据源 这个数据源可以是 TTable 或 TQuery 组件 对于简 单的列表类型报表, 通常只使用一个数据集 但对于一个主 / 明细类型的报表来讲,TQuickRep 组件的 DataSet 属性应设置成主数据集 (3)Options 属性集 Options 属性集用于设置报表的 3 种不同属性, 包括 FirstPageHeader LastPageFooter 和 Compression 属性含义如下 FirstPageHeader: 如果该属性设置为 True, 则在报表的第一页生成页首标题, 否则, 不打印 但需要注意的是该属性要和 Band 属性协调使用 LastPageFooter: 如果该属性设置为 True, 则在报表的最后一页生成页脚, 否则, 不 打印 该属性也要和 Band 属性协调使用 Compression: 如果为 True, 则以压缩格式存储报表, 为 False 则不以压缩格式存 储 使用压缩格式存储报表时, 虽然可以节省大量的磁盘空间, 但是大大减慢了程序的运 行速度 (4)Page 属性 Page 属性用来设置报表中页的大小 页边距 页的方向等页属性进行设置以及系统打印 机的设置等 属性说明 HasColumnHeader 如果为 True, 在多列的报表中, 每列的列首上将打印出列的标题条 ; (5)PrinterSettings 属性 PrinterSettings 属性允许选择想要打印的副本数 起始页 终止页以及是否需要重复打印 和打印输出的输出途径 (6)ShowProgress 属性 ShowProgress 属性允许在准备和打印报表期间显示一个过程对话框 过程对话框中包含 一个 Cancel 按钮, 允许用户停止生成报表 除了通过对这些属性的设置来改变报表的样式, 还可以使用 Delphi 提供的 Report Settings 工具 在 TQuickRep 组件上双击鼠标, 或单击在该组件上单击鼠标的右键, 在弹出式菜单中 选择 Report Settings 如果该属性设置为 False, 则不打印列的标题条 HasDetail 如果该属性设置为 True, 在报表中, 打印出详细的明细记录 ; 如果该属性设置为 False, 则不打印详细记录 HasPageFooter 如果为 True, 则打印报表时, 每页报表的底部打印出页脚 ; 如果为 False, 则打印报表时, 每页报表的底部不打印页脚 HasPageHeader 如果为 True, 则打印报表时, 每页报表的顶部打印出页眉 ; HasSummary HasTitle 如果为 False, 则打印报表时, 每页报表的顶部不打印页眉 如果为 True, 在打印报表的最后一页, 打印一个总结数据, 否则不打印 无论该报表一次打印多少页, 该子 Band 在打印时只打印一次 如果为 True, 则在每个报表的开始打印报表标题 ; 否则不打印 这时, 会出现如图 9-4 所示的对话框

231 218 Delphi 程序设计基础 Report Settings 属性设置共分 5 部分, 它们是 :Papers size Margins Other Pageframe 和 Bands Papers Size 属性集用于设置报表版面的大小 ( 缺省为 A4 纸面 ) 和版面方向等,Portrait 表示纵向版面,LandScape 表示横向版面 Margins 属性集用于设置报表的页边距 可以对报表的上 下 左 右边距进行设置 Other 属性集可以改变报表中字体大小 字体种类和尺寸单位 Page frame 属性集用于设置报表是否有边框及边框线的颜色 线宽 Bands 属性集的作用和 Object Inspector 中的 Bands 属性一样 Preview 按钮用于即时预览报表 图 9-4 Report Settings 报表修改工具 Apply 按钮将修改的参数存盘, 但不退出 Report Settings 窗口 Ok 按钮实现参数存盘并退出该窗口 2.TQuickRep 组件的方法和事件 (1)OnNeedData 事件用来从一个非 DBE 数据集中生成一个报表 当报表需要下一个记 录的数据时, 触发该事件 如果没有连接到一个 DBE 数据集, 则需要自己填写报表中 TQuickLabel 组件的文本值 OnNeedData 有一个名为 MoreData 的布尔类型的参数, 在报表 完成时需要将其设置成 False (2)Preview 方法用于报表预览 例如 :Form1.QuickRep1.preview, 其中,Form1 是 QuickRep1 报表所在的窗体 (3)Print 方法用于报表打印 例如 :Form1.QuickRep1.print TQRSubDetail 组件 TQRSubDetail 组件用来在主表 / 明细表类型的报表中显示明细表的数据 1.TQRSubDetail 组件的主要属性 (1)Bands 属性集 可以对 HasFooter 和 HasHeader 属性进行设置 使用这两个属性可以创建 Group Footer ( 组脚 ) 和 Group Header( 组眉 ), 这两个 Band 是用来显示明细表中记录字段的说明文字的 设置这个属性后, 在 TQRSubDetail 组件的相应位置将自动加入一个 TQRGroup 组件 在生 成的 TQRGroup 组件中可以加入显示记录中字段说明文字的组件, 如 TQRLable 组件等 (2)DataSet 属性 DataSet 属性用于指明这个明细 Band 上的组件从哪个数据集中获得数据 在生成主表 / 明细表类型的报表时, 应该将其设置成 主表 / 明细表 关系中明细表的数据库 (3)Master 属性 Master 属性需要设置成指向主表数据集连接的 Band 这通常是一个 TQuickRep 组件,

232 第 9 章报表与图表 219 如果创建了一个主表 / 明细表类型的报表, 这个属性需要指向第一个 TQuickRep 组件 2.TQRSubDetail 组件的方法和事件 TQRSubDetail 组件主要的事件有 AfterPrint BeforePrint 和 OnNeedData BeforePrint 事件一般用于在报表生成前对报表中的数据进行合法性的检查, 以免报表中显示不必要的记录, 还可以显示提示框以便在必需时取消打印 AfterPrint 事件可以为用户在打印结束后进行后续工作 3.TQRSubDetail 组件的用法 (1) 在生成主表的 TQuickRep 组件中加入 TQRSubDetail 组件 (2) 根据需要决定是否设定 Bands 属性集中的 HasHeader HasFooter 属性, 如果需要在报表中增加明细表字段的说明文字, 就设置 HasHeader 属性为 Ture (3) 设置 DataSet 属性为明细表的数据源 (4) 在 TQRSubDetail 组件中添加 TQRDBText 组件, 用于显示明细表记录的各个字段 TQRBand 组件 TQRBand 组件可以说是 QReport 组件组中又一个重要的组件 每个报表中都包含了一种或者两种类型的 TQRBand 组件 当通过 TQuickRep 组件的 Bands 属性向一个报表添加 Band 时,Delphi 实际上创建了一个 TQRBand 组件 有些 Band 自动打印 有些 Band 在每页中打印, 还有些 Band 在整个报表之中只打印一次 这些都取决于 TQRBand 组件的属性设置 方法的使用和事件的触发等 1.TQRBand 组件的主要属性 (1)BandType 属性 BandType 属性用来指明一个 TQRBand 组件是何种类型的 Band,Band 属性决定了在最后的报表中该 Band 出现的位置 BandType 属性共有 11 种取值, 分别是 : rbchild rbcolumnheader rbdetail rbgroupfooter rbgroupheader rboverlay rbpagefooter rbpageheader rbsubdetail rbsummary rbtitle (2)ForceNewColmun 属性 ForceNewColmun 属性使报表在打印这个 Band 前创建一个新的列 (3)ForceNewPage 属性 ForceNewPage 属性使报表在打印这个 Band 以前生成新的一页 对于一个简单的列表类型的报表, 在其 Detail Band 中将这个属性设置为 True, 会使报表的每一页仅显示一个记录 在一个主表 / 明细表类型的报表中, 将 Detail Band 的这个属性为设为 True, 会强制为该报表的每个记录生成新的一页, 同时该记录的所有明细记录出现在同一页中 (4)LinkBand 属性当报表打印一个 Band 时,Delphi 将检查当前的页, 看上面是否有足够的空间打印这个 Band LinkBand 属性使 TQuickRep 报表上的 Band 连接到一起, 被连接的 Band 作为当前的 Band 显示在同一页中 当前页没有足够的地方打印当前页和连接页时, 报表会自动生成新的一页 (5)HasChild 属性这个属性为当前 Band 产生下一级 Band, 比如在主表 / 明细表类型的报表中, 如果想为某

233 220 Delphi 程序设计基础个字段增加更详细的信息, 可以设置当前 Band 的 HasChild 属性,Delphi 将自动生成一个 Band 作为下级 Band 2.TQRBand 组件的方法和事件这里介绍 TQRBand 组件的 BeforePrint 事件 在报表打印一个 Band 时将触发 BeforePrint 事件 一个名为 PrintBand 的布尔型参数将传递给该事件, 它用来决定是否打印这个 Band PrintBand 参数的缺省值为 True, 如果要制止打印这个 Band, 应该将这个参数设为 False 在主 明细表类型的报表中经常使用这个事件, 当一个给定的主记录没有明细记录时, 可以通过这个事件来限制对明细和子明细 Band 的打印 3.TQRBand 组件的一般用法在实际的报表制作中,TQRBand 组件一般由报表的核心组件生成, 如 TQuickRep 组件 TQRDetail 组件等 当然, 也可以根据自己的需要在报表窗体中增加 TQRBand 组件, 步骤就和在窗体中增加其他组件一样 TQRChildBand 组件 TQRChildBand 组件用来创建与另一个 Band 联系的 Band, 非常类似一个明细 Band 和一个子明细 Band 的关系, 但没有主表 明细表关系间的形式 通过拖放一个 TQRChildBand 组件到一个报表上, 或者设置一个 Band 的 HasChild 属性为 True, 就可以创建一个子 Band 通常需要使用子 Band 的情况是要有一个明细 Band 内显示备注信息, 而这个备注信息后又跟随着其他的记录信息 如果使用 TQRDBText 组件显示备注信息, 可能因为信息太多而无法正常显示 这时就可以用 TQRChildBand 组件解决这个问题 : 在明细 Band 中显示备注信息, 而将其他信息放在与该明细 Band 相连的子 Band 中 这样就可以按照需要扩展备注信息, 而不需要重写其他相关的信息 ParentBand 属性是 TQRChildBand 组件的一个重要属性 这个属性用来将子 Band 连接到它的父 Band 上 这个 Band 可以连接到任何类型的报表 Band 上, 甚至是其他的子 Band 上 TQRGroup 组件 TQRGroup 组件用来在一个报表内创建组, 组主要用在主表 / 明细表类型的报表中, 也可以在简单的列表类型的报表中使用 TQRGroup 组件的 Expression 属性用来创建一个指明何时需要取消组的限制的表达式 比如, 对于一个简单的列表类型的报表, 通过在 Expression 属性中输入如下所示的代码就可以使得当一个特定字段的第一个字母改变时取消组的限制 : Copy(fieldname,1,1) 该组件的 Master 属性用来指明 TQRGroup 组件从哪里得到它的数据 该属性通常连接到相关的 TQuickRep 组件上 TQRLabel 组件 TQRLabel 组件用来在报表中显示静态文本, 就和使用 TLabel 组件在一个窗体中显示静态文本一样 这个文本值在显示时不能被改变 TQRLabel 组件的属性 方法和事件以及用法和 TLabel 组件基本一致

234 第 9 章报表与图表 TQRDBText 组件 TQRDBText 组件是一个指明数据来源的组件, 用来显示数据库中记录的字段, 可以是字符串字段 数值字段 日期字段和备注字段的值 它和 TDBText 组件一样, 可以通过设置 DataSet 和 DataField 属性来确定数据源 AutoStretch 属性是 TQRDBText 组件的一个重要属性 AutoStretch 是一个布尔型属性, 用于指定 TQRDBText 组件是否需要进行垂直扩展, 以适应一个备注字段的完整内容 如果 TQRDBText 组件为备注字段, 并且 AutoStretch 属性为 False, 则备注字段的内容将被分隔成 TQRDBText 组件的大小 如果 AutoStretch 属性为 True, 组件将显示完整的内容, 需要的话会打破页的限制 TQRDBText 组件用于实现在报表中显示数据表字段内容, 使用方法如下 : (1) 建立一个窗体, 并放置一个 QuickRep 组件在窗体上 在窗体上加入一 TTable 组件, 并设置其属性, 如 :Name:qryOrders;Database:DBDEMOS (2) 在报表上加入 TQRBand 组件, 其类型设为 Detail Band 类型 (3) 在 Detail Band 上加入 TQRDBText 组件, 如设置其 DataSet:qryOrders;DataField: OrderNo TQRExpr 组件 TQRExpr 组件用来为报表创建从简单到复杂的计算 这个组件的功能非常强大 灵活 1.Expression 属性 Expression 属性是使用 TQRExpr 组件的关键 当单击 Expression 属性值时, 可以看到一个省略按钮, 在其上单击, 可以激活 Expression 属性的编辑对话框 Expression Wizard, 如图 9-5 所示 通过 Expression Wizard 对话框设置 TQRExpr 组件的 Expression 属性 这里详细介绍 Expression Wizard 对话框的用法, 通常可以按照以下的步骤进行 : (1) 为 TQuickRep 组件设置 DataSet 属性, 将其连接到数据源 (2) 在 TQuickRep 组件中添加 TQRExp 组件 (3) 单击 Object Inspector 对话框中的 Expression 选项 (4) 按下 Functions 按钮为字段选择相应的计算方式, 这时将激活选择计算方式的对话框, 如图 9-6 所示 图 9-5 Expression Wizard 对话框图 9-6 选择计算方式

235 222 Delphi 程序设计基础 (5) 在 Select function 框中选择计算方式 (6) 单击 Expression Wizard 对话框中的 Database field 按钮, 激活相应的对话框, 出现选择需要计算字段的对话框 (7) 在对话框中选择需要计算的字段, 并返回 Expression Wizard 对话框 (8) 这时在 Expression Wizard 对话框中将自动产生运算的表达式, 同时在报表窗体中也显示计算的表达式 2.ResetAfterPrint 属性 ResetAfterPrint 是一个布尔型的属性, 用于确定是否应该在每次打印完 TQRExpr 组件值后, 再将它的值重置回默认值, 通常在创建主 明细表类型的报表时希望将其设为默认值 TQRsysData 组件 TQRsysData 组件用于在打印报表时, 显示有关报表以及报表内操作系统的信息 Data 属性是 TQRsysData 组件最重要的属性, 用来指定 TQRsysData 组件显示信息的种类 这个属性可以取 7 个值, 它们分别是 : qrsdata qrsdatatime qrsdetailcount qrsdetailno qrspagenumber qrsreporttitle qrstime 这些属性值代表的含义如下 qrsdata: 当前日期 ; qrsdatatime: 当前日期和时间 ; qrsdetailcount: 报表内的记录数 ; qrsdetailno: 当前的记录号 ; qrspagenumber: 当前的页号 ; qrsreporttitle: 显示 TQuickRep 组件的 ReportTitle 属性值 ; qrstime: 当前时间 TQRMemo 组件 TQRMemo 组件用来在报表中显示备注信息, 这个备注信息不是数据库记录中的信息, 而是通过设置 TQRMemo 组件的 Line 属性来添加备注信息 TQRRichText 组件 TQRRichText 组件用来在报表中显示 RTF 类型的文件 TQRRichText 组件有一个 ParentRichEdit 属性, 这个属性允许将 TQRRichText 组件连接到 TRichText 组件上 这样, TQRRichText 组件就可以反映另一个组件 RTF 类型的备注信息 TQRDBRichText 组件 TQRDBRichText 组件用来在报表中显示数据库中记录的备注信息, 用法和 TQRRichText 组件一样 TQRShape 组件 TQRShape 组件允许在报表内绘制一些简单的图形 绘制的图形依赖 Shape 属性 其属性值如下

236 第 9 章 报表与图表 223 qrscircle: 绘制一个圆 ; qrshorline: 绘制一条水平直线 ; qrsrectangle: 绘制一个矩形 ; qrsrightandleft: 在左边和右边各绘制一条直线 ; qrstopandbottom: 在顶部和底部各绘制一条直线 ; qrsverline: 绘制一条垂直的直线 该组件在报表设计时非常重要, 因为, 报表常有表格线 该组件相当于一个图形工具, 通过它可以在报表中绘制出水平线, 垂直线等表格线 TQRImage 组件 TQRImage 组件允许在报表内显示图像, 可以使用这个组件向报表添加图形 TQRDBImage 组件 TQRDBImage 组件允许从数据库向报表添加图像 它的作用和 TQRImage 组件一样, 只 是随着记录的不同, 相应的图像也不一样 这个组件的使用方式和 TDBImage 组件一样 TQRComposite 组件 TQRComposite 组件可以帮助将多个报表合并成一个报表 使用这个组件可以创建一个 包含许多不同条件的大报表, 而不需要通过编程来实现打印 可以简单地将条件报表当成一 个分离的报表进行创建, 然后只把需要打印到总报表内的部分添加进去 通过 OnAddReport 事件将报表添加到 TQRComposite 组件内 TQRPreview 组件 TQRPreview 组件允许创建自定义的预览屏幕以取代 Delphi 中默认的预览屏幕, 在 Delphi 中通过使用 TQRPreview 组件可能很方便地创建自定义预览屏幕 创建一个自定义预览屏幕 可以按照如下的步骤进行 : (1) 创建一个预览窗体, 并将 TQRPreview 组件添加到窗体中 (2) 在窗体中添加按钮和菜单项, 允许对报表的各种操作, 如打印预览等 (3) 为所有需要使用自定义预览的 OnPreview 事件的句柄中增加代码 QuickReport 报表实例 其实, 建立数据库报表并不难, 只需将组件板 QuickReport 选项卡上的 QuickRep 组 件放置到窗体中, 添加一个或多个信息行区 ( 即 QRBand 组件 ), 在信息行区上放置数据提示 报表组件 (QRLabel 组件 QRDBLabel 组件 QRRichText 组件 QRDBRichText 组件等 ), 将数据提示报表组件与数据源组件相连 数据可以来自一个或多个数据表, 就像在标准的数 据访问组件中一样 下面通过简单的实例说明如何创建数据库报表 例 9-1 用 QuickReport 打印数据库中各种数据类型的数据 该例子用到了许多 QReport 组件, 如 :QuickRep QRLable QRDBText RQDBImage QRDBRichText 和 QRShape 组件, 我们可以从中体会这些组件的使用

237 224 Delphi 程序设计基础 (1) 新建应用程序启动 Delphi, 从 File 菜单中选取 New Application 命令, 开始一个新的应用文件 (2) 设置窗体属性窗体的 Caption 属性为 QuickReport 例程 (3) 向窗体中添加组件往窗体中添加 3 个 Button 组件 Button1~Button3;1 个 Memo 组件 Description;1 个 GroupBox 组件 GroupBox1;1 个 Image 组件 Image1;2 个 Lable 组件 Lable1 和 Lable2;4 个 RadioButton 组件 RadioButton1~RadioButton4 (4) 设置组件属性窗体中组件属性见表 9-2 表 9-2 窗体中组件属性 组 件 属 性 属 性 值 Button1 Caption 预览 Button2 Caption 打印 Button3 Caption 取消 Lable1 Caption QuickReport 例程 Lable2 Caption Demo version /June 16, 2005 delphiline@sohu.com RadioButton1 Caption 例 9-1 打印数据库中的各种数据类型的报表 RadioButton2 Caption 例 9-2 打印 ExprMemo 报表 RadioButton3 Caption 例 9-3 打印主明细报表 RadioButton4 Caption 例 9-4 打印分组与统计报表 组件属性设置后, 窗体中组件布局如图 9-7 所示 图 9-7 报表例程界面 (5) 添加事件为按钮 Button1 添加 OnClick 事件, 事件响应过程为 Button1Click, 为按钮 Button2 添加 OnClick 事件, 事件响应过程为 Button2Click, 为按钮 Button3 添加 OnClick 事件, 事件响应过程为 Button3Click (6) 编写事件代码先在程序的 interface 块中的 var 说明中加入 Report:TCustomQuickRep; 说明 procedure TfrmEx9.Button1Click(Sender: TObject);

238 第 9 章报表与图表 225 if report <> nil then report.preview; // 预览 procedure TfrmEx9.Button2Click(Sender: TObject); if report <> nil then report.print; // 打印 procedure TfrmEx9.Button3Click(Sender: TObject); close; // 关闭 这样, 报表例程的调用界面就做好了, 接下来我们开始制作例 9-1 的报表 (7) 建立例 9-1 报表从 File 菜单中选取 New Form 命令, 新建一个 Form 组件 将其 Name 属性设为 Form9_1 在 Form9_1 中加入 QuickRep 组件 QuickRep1, 并将其 Bands.HasColumnHeader 属性和 Bands.HasDetail 属性设为 True, 这时会在 QuickRep1 中出现 ColumnHeaderBand1 和 DetailBand1 两个区域 接着再加入 Table 组件 tbzg 在 ColumnHeaderBand1 区域中加入 3 个 QRLable 组件 QRLable1~QRLable3; 在 DetailBand1 区域中加入 6 个 QRLable 组件 QRLable4~QRLable9 6 个 RQDBText 组件 RQDBText1~RQDBText6 1 个 QRDBImage 组件 QRDBImage1 1 个 QRDBRichText 组件 QRDBRichText1 和一个 QRShape 组件 QRShape1 各组件属性设置见表 9-3 表 9-3 例 9-1 报表中组件属性 组 件 属 性 属 性 值 属 性 属 性 值 QuickRep1 ReportTitle 职工信息 tbzg DataBaseName EX8 TableName ZG.db QRLable1 Caption 基本信息 QRLable2 Caption 照片 QRLable3 Caption 简历 QRDBText1 DataSet tbzg DataField GH QRDBText2 DataSet tbzg DataField XM QRDBText3 DataSet tbzg DataField XB QRDBText4 DataSet tbzg DataField CSRQ QRDBText5 DataSet tbzg DataField ZC QRExpr1 Expression IF (tbzg.hf,' 已婚 ',' 未婚 ') QRDBImage1 DataSet tbzg DataField ZP QRDBRichText1 DataSet tbzg DataField JL QRShape1 Shape qrshorline 组件属性设置后, 窗体中组件布局如图 9-8 所示 回到图 9-8 调用界面, 给 RadioButton1 组件添加 OnClick 事件如下 :

239 226 Delphi 程序设计基础 procedure TfrmEx9.RadioButton1Click(Sender: TObject); Report := Form9_1.QuickRep1; // 将例 9-1 的报表传递给 Report, 以便 浏览 或 打印 按钮调用 图 9-8 例 9-1 窗体组件布局 (8) 保存程序将窗体 frmex9 的单元文件保存为 Unit9.pas, 将窗体 Form9_1 的单元文件保存为 Unit9_1.pas, 将项目文件保存为 Project9.dpr (9) 编译运行程序单击工具栏上 Run 按钮即可运行程序 运行后, 单击 例 9-1 RadioButton1 组件, 再单击 预览 按钮, 将直接显示数据库报表的打印预览效果, 而且在窗口顶端还有一排按钮用于进行打印预览操作, 如图 9-9 所示 单击窗口顶端的 Print 按钮也可直接打印数据库报表 图 9-9 例 9-1 运行效果

240 第 9 章报表与图表 227 例 9-2 使用 ExprMemo 组件打印标签 该例子除了使用例 9-1 的部分组件以外, 还使用了 QRBand QRExprMemo QRImage QRSysData 组件 (1) 打开例 9-1 应用程序从 File 菜单中选取 Reopen 命令, 从中选择例 9-1 的应用文件 Project9 或选取 ReOpen 命令, 从对话框中选择例 9-1 的应用文件 Project9 (2) 建立例 9-2 报表从 File 菜单中选取 New Form 命令, 新建一个 Form 组件 将其 Name 属性设为 Form9_2 在 Form9_2 中加入 QuickRep 组件 QuickRep1 Table 组件 Table1 QRBand 组件 QRBand1; 在 QRBand1 区域中加入 QRExprMemo 组件 QRExprMemo1 QRImage 组件 QRImage1 1 个 QRSysData 组件 QRSysData1 1 个 QRDBImage 组件 QRDBImage1 设置各组件属性见表 9-4 表 9-4 例 9-2 报表中组件属性 组 件 属 性 属 性 值 属 性 属 性 值 Table1 DataBaseName EX8 TableName zg.db Active true QRBand1 BandType rbdetail QRDBImage1 DataSet EX8 DataField zp QRImage1 Picture 任找一个 BMP 文件 QRSysData1 Data qrsdetailno 上海蓝科信息技术有限公司工作证 ==================================== QRExprMemo1 Lines 工号 :{gh} 姓名 :{xm} 性别 :{xb} 职称 :{zc} 部门 : 组件属性设置后, 窗体中组件布局如图 9-10 所示 图 9-10 例 9-2 窗体布局 TQRExprmemo 组件类似 TQRMemo 组件, 但它能处理任何包含在 {} 中的文本作为 TQRExpr 表达式 你能使用数据库字段或函数, 这对于打印信封或统一格式的标签非常有用

241 228 Delphi 程序设计基础本例用 ZG.db table 中的字段制作信封标签 回到图 9-8 调用界面, 给 RadioButton2 组件添加 OnClick 事件如下 : procedure TfrmEx9.RadioButton2Click(Sender: TObject); Report := Form9_2.QuickRep1; // 将例 9-2 的报表传递给 Report, 以便 浏览 或 打印 按钮调用 (3) 保存程序将窗体 Form9_2 的单元文件保存为 Unit9_2.pas, 项目文件仍保存为 Project9.dpr (4) 编译运行程序单击工具栏上 Run 按钮即可运行程序 运行后, 单击 例 9-2 RadioButton2 组件, 再单击 预览 按钮, 将显示标签的打印预览效果, 如图 9-11 所示 例 9-3 制作一个主 / 明细类型的报表 该例程除 图 9-11 例 9-2 预览效果 了使用例 9-1 例 9-2 的部分组件以外, 还使用了 QRSubDetail 组件 在做例 9-3 前我们先建立一个数据库例子, 以便例 9-3 使用, 假设除了 ZG.db 库外, 还有一个 ZGXS.db, 记录了职工销售情况, 内容见表 9-5 各字段意义为 : Gh: 工号 Xh: 产品型号 SL: 销售数量 JE: 销售金额 XSRQ: 销售日期 表 9-5 例 9-3 数据库用例 记 录 号 Gh Xh SL Je Xsrq A A A A A A032 1, , A , A A A A A A A

242 第 9 章 报表与图表 229 续表 记 录 号 Gh Xh SL Je Xsrq A A A A A A A A A A (1) 打开例 9-2 应用程序 从 File 菜单中选取 Reopen 命令, 从中选择例 9-2 的应用文件 Project9 或选取 ReOpen 命令, 从对话框中选择例 9-2 的应用文件 Project9 (2) 建立例 9-3 报表 从 File 菜单中选取 New Form 命令, 新建一个 Form 组件 将其 Name 属性设为 Form9_3 在 Form9_3 中加入 QuickRep 组件 QuickRep1 1 个 DataSource 组件 DataSource1 2 个 Table 组件 Table1 和 Table2( 它们的 DataBaseName 属性都设置成 EX8) 1 个 QRSubDetail 组件 QRSubDetail1, 和一些 QRDBText 组件 QRLable 组件 各组件属性设 置见表 9-6 表 9-6 例 9-3 报表中组件属性 组 件 属 性 属 性 值 属 性 属 性 值 位 置 Table1 TableName Zg.db Active True Table2 TableName Zgxs.db Active True QuickRep1 Bands.HasDetail True Bands.HasTitle True QRSubDetail1 Bands.HasHeader True QRDBText1 DataSet Table1 DataField Gh DetailBand1 QRDBText2 DataSet Table1 DataField Xm DetailBand1 QRDBText3 DataSet Table2 DataField Xsrq QRSubDetail1 QRDBText4 DataSet Table2 DataField Xh QRSubDetail1 QRDBText5 DataSet Table2 DataField SL QRSubDetail1 QRDBText6 DataSet Table2 DataField Je QRSubDetail1 其他一些 QRLable 组件按图 9-12 所示设置 主 / 明细表最关键的部分是给 Table2 建立一个 MasterSource, 具体方法是 : 在 Table2 组件的 MasterSource 属性中选择 DataSource1, 在 MasterField 属性中选择, 出现 Field Link Designer 对话框, 如图 9-13 所示, 在 Detail Fields 的列表框中选择 Gh 字段, 在 Master Fields 的列表框中选择 Gh, 单击 Add 按钮, 使 Joined Field 列表框中出现 Gh->Gh

243 230 Delphi 程序设计基础 图 9-12 例 9-3 窗体组件布局图 9-13 Field Link Designer 对话框 回到图 9-8 调用界面, 给 RadioButton3 组件添加 OnClick 事件如下 : procedure TfrmEx9.RadioButton3Click(Sender: TObject); Report := Form9_3.QuickRep1; // 将例 9-3 的报表传递给 Report, 以便 浏览 或 打印 按钮调用 (3) 保存程序将窗体 Form9_3 的单元文件保存为 Unit9_3.pas, 项目文件仍保存为 Project9.dpr (4) 编译运行程序单击工具栏上 Run 按钮即可运行程序 运行后, 单击 例 9-3 RadioButton3 组件, 再单击 预览 按钮, 将显示标签的打印预览效果, 如图 9-14 所示 例 9-4 制作一个主 / 明细及分组统计的报表 该例除了使用例 9-1 例 9-2 例 9-3 的部分组件以外, 还使用了 QRGroup QRExpr 组件 (1) 打开例 9-3 应用程序从 File 菜单中选取 Reopen 命令, 从中选择例 9-3 的应用文件 Project9 或选取 ReOpen 命令, 从对话框中选择例 9-3 的应用文件 Project9 (2) 建立例 9-4 报表从 File 菜单中选取 New Form 命令, 新建一个 Form 组件 将其 Name 属性设为 Form9_4 在 Form9_4 中加入例 9-3 的所有组件并按例 9-3 设置所有属性, 在此基础上设置 QRSubDetail1 组件的 Bands.HasFooter 属性为 True, 会自动出现 GroupFooterBand1 组件 在此组件上添加 4 个 QRExpr 组件 QRExpr1 ~QRExpr4 各组件属性设置见表 9-7 表 9-7 例 9-4 报表中组件属性 图 9-14 例 9-3 预览效果

244 第 9 章 报表与图表 231 组 件 属 性 属 性 值 属 性 属 性 值 位 置 QRExpr1 Expression SUM(Table2.Sl) ResetAfterPrint True 按每组计算 QRExpr2 Expression SUM(Table2.Sl) ResetAfterPrint False 累计计算 QRExpr3 Expression SUM(Table2.Je) ResetAfterPrint True 按每组计算 QRExpr4 Expression SUM(Table2.Je) ResetAfterPrint False 累计计算 其他一些 QRLable 组件按图 9-15 所示设置 图 9-15 例 9-4 窗体组件布局 回到图 9-8 所示调用界面, 给 RadioButton4 组件添加 OnClick 事件如下 : procedure TfrmEx9.RadioButton4Click(Sender: TObject); Report := Form9_4.QuickRep1; // 将例 9-4 的报表传递给 Report, 以便 浏览 或 打印 按钮调用 (3) 保存程序将窗体 Form9_4 的单元文件保存为 Unit9_4.pas, 项目文件仍保存为 Project9.dpr (4) 编译运行程序单击工具栏上 Run 按钮即可运行程序 运行后, 单击 例 9-4 RadioButton4 组件, 再单击 预览 按钮, 将显示标签的打印预览效果, 如图 9-16 所示 9.2 图表 所谓图表, 指的是用图形方式表示表格数据 例如, 棒图 饼图等 Delphi 中有一图表组件 TeeChart, 由 David Berneda 开发, 授权 Borland 使用 实际上 TeeChart 有 3 个版本 : 单机版的 Chart 组件, 位于组件板的 Additional 选项卡上 ; 数据库版的 DBChart 组件, 位于组件板的 Data Controls 选项卡 图 9-16 例 9-4 预览效果 上 ; 报表版的 QRChart, 位于组件板的 QReport 选项卡上 本节我们主要介绍数据库版的

245 232 Delphi 程序设计基础 DBChart 组件, 其他两个 Chart 组件使用与之相近, 我们也应掌握 提示 :DBChart 的帮助不在 Delphi 集成环境中, 单击 开始 程序 Borland Delphi 7 Help DBChart Help 命令, 可获取有关 DBChart 的相关帮助 DBChart 组件 DBChart( 图表 ) 组件提供了图表的基本结构, 并提供了图表的可视化容器 然而, 图表实际上是 TChartSeries 类型的对象 一旦往窗体上添加 Chart 组件, 就可以建立一个或多个 Series( 序列 ) 1. 图表序列将表格数据用图表表示, 每一列数据可称为一个序列, 整个图表则由多个序列组成 如果要建立图表的序列, 执行如下操作 (1) 从组件板的 Data Controls 选项卡上选择 DBChart 组件, 往窗体中添加一个 DBChart 组件, 假定为 DBChart1 (2) 选定组件后, 在对象查看器单击 SeriesList 属性右侧属性值中的 按钮, 或直接在窗体中双击 DBChart 组件, 打开 Editing DBChart1 对话框, 如图 9-17 所示 图 9-17 Editing Chartl 对话框图 9-18 TeeChart Gallery 对话框 (3) 单击 Add 按钮, 打开 DBChart Gallery 对话框, 如图 9-18 所示 (4) 选择所需的一种图表类型 DBChart 共提供了 11 种图表类型, 包括折线图 棒图 面积图 散点图 饼图 冒泡图等 例如, 选择垂直棒图 (Bar) 类型 (5) 单击 OK 按钮, 返回 Editing DBChart1 对话框 (6) 单击 Close 按钮, 关闭 Editing DBChart1 对话框 添加序列后, 可以在 Editing DBChart1 对话框中设置序列的一系列属性 另外, 由于 Delphi 也把所添加的 Series 视为一种组件, 可直接在对象查看器中设置 Series 的属性, 不过选定 Series 要在对象查看器顶端的下拉列表中进行, 如图 9-19 所示 不同的 TChartSeries 子类, 也就是说不同种类的图表序列, 可以集成在一幅图表中 例如, 棒图和折线图序列就可以集成在一起 2. 图表数轴

246 第 9 章报表与图表 233 图表总共有左数轴 右数轴 顶数轴 底数轴和深度数轴 5 个数轴 最常用的数轴是左数轴和底数轴, 左数轴用以标识数值, 底数轴用以标识序号 每个数轴都有范围 标题 数标 位置等属性 设置数轴通常在 Editing DBChart1 对话框中 Chart 选项卡上的 Axis 上进行, 如图 9-20 所示 图 9-19 设置 Series 属性图 9-20 Axis 标签 3. 图表标题图表可以有上标题和下标题两个标题, 在 Editing DBChart1 对话框中 Chart 选项卡上的 Title 上进行设置 两个标题可分别设置字体 大小 颜色和对齐方式 4. 图表图例图表有一个图例, 最初图例显示在图表右上角 用户可自行设置图例的位置 ( 上 下 左 右 ) 内容 ( 序列名称 序列数值 最近数值 ) 字体等, 这些设置在 Editing DBChart1 对话框中 Chart 选项卡上的 Legend 上进行 5. 图表修饰整个图表显示在一个面板上, 该面板的属性在 Editing DBChart1 对话框中 Chart 选项卡上的 Panel 上进行设置 在图表左侧 底部 背部均有一个背景墙, 这三个背景墙在 Editing DBChart1 对话框中 Chart 选项卡上的 Walls 上进行设置 另外, 图表还可具有三维效果, 三维效果在 Editing DBChart1 对话框中 Chart 选项卡上的 3D 上进行设置 图表应用实例下面通过例子来说明如何应用图表 例 9-5 按 zg.db 数据生成 职员工资 图表 (1) 新建应用程序启动 Delphi, 从 File 菜单中选取 New Application 命令, 开始新的应用程序 (2) 设置窗体属性将窗体 Form1 的 Caption 属性设置为 图表应用, 其 Font 属性设置为宋体 五号

247 234 Delphi 程序设计基础 (3) 向窗体中添加组件往窗体中添加 1 个 DBChart 组件 Chart1 1 个 Table 组件 Table1 (4) 设置组件属性首先将 Table1 的 DataBaseName 设置为 EX8,TableName 设置为 zg.db,active 属性设置为 True 将 DBChart1 的上标题设置为 职员工资, 其字体为宋体 加粗 小五 切换至 Series 标签, 设置 Data Source 子标签, 单击下拉列表选择 DataSet, 对 DataSet 下拉列表选择 Table1,Labels 选 Xm,Bar 选 Gz,Series 设置后如图 9-21 所示 经过设置, 窗体如图 9-22 所示 图 9-21 Series 设置图 9-22 图表应用 (5) 保存程序将单元文件保存为 Unit9_5.pas, 将项目文件保存为 Project9_5.dpr (6) 运行程序编译 运行程序 运行后, 将显示各职员的工资图表 习 题 1. 用 QuickReport 制作报表, 哪个组件是必不可少的? 它的主要功能是什么? 2.TQRSubDetail 组件的主要作用是什么? 3.TQRLabel 组件和 TQRDBText 组件的主要作用是什么? 4.TQRExpr 组件和 TQRsysData 组件的作用是什么? 5.TQRMemo 组件与 TQRRichText 组件的区别是什么? 6.TQRShape 组件和 TQRImage 组件的作用是什么? 它们的区别是什么? 7. 报表预览和打印的方法名是什么? 8.Chart( 图表 ) 组件的功能是什么?

248 第 10 章 实 训 10.1 实训 1 Delphi 集成开发环境操作 Delphi 集成开发环境操作 1. 实训目的熟悉 Delphi 集成开发环境, 掌握编辑 编译 运行程序的操作 2. 实训要求创建控制台应用程序, 输入程序源程序, 编译 运行程序, 发现并改正错误 3. 实训示例将下列程序编辑 保存 编译和运行 程序功能是读入一个整数 n, 求 0~n 间的所有偶数 源程序如下 : program Project1_ex1; {$APPTYPE CONSOLE} // 进入控制台方式, 即非窗体方式 var n,s:integer; write ('n=?'); // 在屏幕上提示 n=? readln(n); // 在屏幕上等待键盘输入到 n 中 S:=1; while s<n do if s mod 2=0 then writeln(s); //s 除 2 取余, 等于 0 时 s 为偶数 s:=s+1; readln; // 等待按任意键 end. (1) 进入 Delphi 开发环境展开 Windows 的 开始 菜单, 选择 程序 Borland Delphi 7 Delphi 7, 进入 Delphi 开发环境 (2) 创建项目缺省时 Delphi 创建了一个项目和一个窗体单元文件, 我们这里直接在项目文件中编写代码, 所以不需要窗体单元文件, 在代码编辑窗口中右击 Unit1 标签, 选择快捷菜单中 Close

249 236 Delphi 程序设计基础 Page 选项关闭窗体单元文件 (3) 编写代码 在工具栏中选择 View Unit 按钮, 在打开的对话框中选择 Project1, 在代码编辑窗 口中打开 Project1, 输入上述源程序 (4) 保存程序 单击 File 菜单中 Save All 选项, 在保存对话框中选择文件夹并输入文件名, 单击 保存 按钮, 保存程序 (5) 编译程序 单击 Project 菜单, 选择 Compile< 项目名 > 命令项, 进行编译, 如果程序编写有语法错误, 系统会将光标停在错误 处, 一一修改后, 重新进行编译, 直到编译通过 (6) 运行程序通过 Run 菜单的 Run 命令运行程序 程序运行结果如图 10-1 所示 4. 实训练习实训练习按题号顺序难度逐级加大 (1) 编写程序, 程序功能是读入一个整数 n, 求 0~n 间的所有奇数 将程序编辑 保 存 编译和运行 (2) 编写程序, 功能是读入一个整数 n, 求 0~n 间的所有素数 实训报告 记录实训任务的内容 步骤, 以及完成情况的小结 写出实训成功或失败的原因, 实训后的心得体会 建议等 图 10-1 实训 1 程序运行界面 10.2 实训 2 Delphi 编程语言训练 编写对象 Pascal 应用程序 1. 实训目的 Object Pascal 语言程序设计基础训练 理解对象 Pascal 程序格式, 掌握基本数据类型, 熟练运用分支 循环等语句控制程序流程, 并进一步熟悉 Delphi 集成开发环境 2. 实训要求编写应用程序, 实现指定功能 3. 实训示例输入 3 个整数, 求该 3 个数的最大公约数 (1) 进入 Delphi 开发环境展开 Windows 的 开始 菜单, 选择 程序 Borland Delphi 7 Delphi 7, 进入 Delphi 开发环境 (2) 创建项目缺省时 Delphi 创建了一个项目和一个窗体单元文件, 我们这里直接在项目文件中编写代

250 第 10 章实训 237 码, 所以不需要窗体单元文件, 在代码编辑窗口中右击 Unit1 标签, 选择快捷菜单中 Close Page 选项关闭窗体单元文件 (3) 编写代码在工具栏中选择 View Unit 按钮, 在打开的对话框中选择 Project1, 在代码编辑窗口中打开 Project1, 输入下述源程序 program Project2_ex1; {$APPTYPE CONSOLE} var n1,n2,n3,n:integer; readln(n1,n2,n3); n:=n1; repeat if (n1 mod n=0) and (n2 mod n=0) and (n3 mod n=0) then break; n:=n 1; until n=1; writeln(n); readln; end. (4) 保存程序单击 File 菜单中 Save All 选项, 在保存对话框中选择文件夹并输入文件名, 单击 保存 按钮, 保存程序 (5) 编译程序单击 Project 菜单, 选择 Compile 项目名 命令项, 进行编译, 如果程序编写有语法错误, 系统会将光标停在错误处, 一一修改后, 重新进行编译, 直到编译通过 (6) 运行程序通过 Run 菜单的 Run 命令运行程序 程序运行结果如图 10-2 所示 4. 实训练习 实训练习按题号顺序难度逐级加大 (1) 输入 3 个整数, 求该 3 个数的最小公倍数 图 10-2 最大公约数程序运行结果 (2) 输入 3 个整数, 判断该 3 个整数是否构成等差数列或等比数列, 若是, 则输出 等差 或 等比 字样, 否则输出 否 字样 函数和过程的编写和调用 1. 实训目的函数和过程的编写和调用

251 238 Delphi 程序设计基础 2. 实训要求编写和调用函数和过程, 实现指定功能 3. 实训示例编写函数, 输入 2 个整数 n 和 m, 求排列 P(n,m)=n (n 1) (n 2) (n-m+1) (1) 进入 Delphi 开发环境展开 Windows 的 开始 菜单, 选择 程序 Borland Delphi 7 Delphi 7, 进入 Delphi 开发环境 (2) 创建项目缺省时 Delphi 创建了一个项目和一个窗体单元文件, 我们这里直接在项目文件中编写代码, 所以不需要窗体单元文件, 在代码编辑窗口中右击 Unit1 标签, 选择快捷菜单中 Close Page 选项关闭窗体单元文件 (3) 编写代码在工具栏中选择 View Unit 按钮, 在打开的对话框中选择 Project1, 在代码编辑窗口中打开 Project1, 输入下述源程序 program Project2_ex2; {$APPTYPE CONSOLE} var n1,n2:integer; Function Pl(n,m:integer):integer; var nm,i:integer; nm:=1; for i:=n m+1 to n do nm:=nm*i; Pl:=nm; readln(n1,n2); writeln( pl(n1,n2)); readln; end. (4) 保存程序单击 File 菜单中 Save All 选项, 在保存对话框中选择文件夹并输入文件名, 单击 保存 按钮, 保存程序 (5) 编译程序单击 Project 菜单, 选择 Compile 项目名 命令项, 进行编译, 如果程序编写有语法错误, 系统会将光标停在错误处, 一一修改后, 重新进行编译, 直到编译通过

252 第 10 章实训 239 (6) 运行程序通过 Run 菜单的 Run 命令运行程序 程序运行结果如图 10-3 所示 4. 实训练习实训练习按题号顺序难度逐级加大 (1) 编写函数, 输入 2 个整数 n 和 m, 求组合 C(n,m) (2) 下面函数 的功能是 : 根据以下公式, 返回满足精度 ( 如 : ) 要求的 的值 /2=1+1/3+(1/3)*(2/5)+(1/3)*(2/5)*(3/7)+(1/3)*(2/5)*(3/7)*(4/9)+ 如图 10-4 所示, 输入不同的精度, 得到不同的 值 图 10-3 排列程序运行结果 图 10-4 不同精度的 值 (3) 编写小写金额转大写金额的函数 ( 最大金额为 10 亿元, 最小金额为分 ), 如图 10-5 所示输入小写金额, 显示大写金额, 当输入 999 时退出 提示 : 如果在程序中用到 StrToInt IntToStr 等函数, 必须在程序的开头引用单元 : uses SysUtils; 函数和过程的编写和调用, 尝试窗体编程方法 图 10-5 小写金额转大写金额 1. 实训目的函数和过程的编写和调用, 了解 Delphi 窗体编程方法 2. 实训要求编写和调用函数和过程, 在窗体中实现指定功能 3. 实训示例编写 10 进制转换成 进制的函数, 输入一个 10 进制数转换成其他进制值 (1) 进入 Delphi 开发环境展开 Windows 的 开始 菜单, 选择 程序 Borland Delphi 7 Delphi 7, 进入 Delphi 开发环境 (2) 设置窗体属性窗体 Caption 属性设置为 进制转换,Font 设置为 宋体 五号

253 240 Delphi 程序设计基础 (3) 添加组件往窗体中添加 1 个 Edit 组件 Edit1 4 个 RadioButton 组件 RaidoButton1~ RaidoButton4 (4) 设置组件属性组件属性设置见表 10-1 表 10-1 组件属性设置 组 件 属 性 属 性 值 属 性 属 性 值 RaidoButton1 Caption 2 RaidoButton2 Caption 8 RaidoButton3 Caption 10 Checked True RaidoButton4 Caption 16 设置完组件属性后, 窗体中组件及其布局如图 10-6 所示 (5) 添加组件事件并编写事件代码在代码窗口 Unit1 中编写函数 ( 把函数编写在原有的 {$R *.dfm} 下面 ): var // 原来就有 Form1:TForm1; // 原来就有 x1:longint; // 添加 implementation // 原来就有 {$R *.dfm} // 原来就有 { 下面是自己编写的 10 进制转换成任意进制的函数 } function DecToBase(Decimal:longint;base:integer):String; //10 进制转换成任意进制 const Symbols:String [ 16 ] =' ABCDEF'; var outstr:string; n:integer; outstr:=''; repeat n:=decimal mod base; outstr:=symbols [ n+1 ] +outstr; Decimal:=Decimal div Base; until Decimal=0; Result:=outstr; 图 10-6 进制转换界面

254 第 10 章实训 241 为按钮 RaidoButton1 添加 OnClick 事件, 从窗体上选择 RaidoButton1 组件, 双击对象查看器的事件选项卡中的 OnClick 事件名称右侧, 进入代码编辑窗口, 直接在 RadioButton1Click 中编写该按钮的单击事件 procedure TForm1.RadioButton1Click(Sender: TObject); Edit1.Text:=Dectobase(x1,2); 用同样方法, 为 RaidoButton2 RaidoButton3 RaidoButton4 添加 OnClick 事件 : procedure TForm1.RadioButton2Click(Sender: TObject); Edit1.Text:=Dectobase(x1,8); procedure TForm1.RadioButton3Click(Sender: TObject); Edit1.Text:=Dectobase(x1,10); procedure TForm1.RadioButton4Click(Sender: TObject); Edit1.Text:=Dectobase(x1,16); 为按钮 Edit1 添加 OnExit 事件, 从窗体上选择 Edit1 组件, 双击对象查看器的事件选项卡中的 OnExit 事件名称右侧, 进入代码编辑窗口, 直接在 Edit1Exit 中编写该编辑框的 离开 事件 procedure TForm1.Edit1Exit(Sender: TObject); if (length(edit1.text)=0) then // 如果用户没有输入数字, 提示输入 MessageDlg(' 请输入一个整数 ',mterror, [ mbyes ],0); form07.activecontrol:=edit1; x1:=0; end else x1:=strtoint(edit1.text); // 将编辑框中的文本数字转换成整数型 (6) 保存程序将单元文件保存为 Unit2_3ex.pas, 将项目文件保存为 Project2_3ex.dpr (7) 运行程序单击工具栏中 Run 按钮运行程序 运行后, 在编辑框中输入一个数字, 单击不同的

255 242 Delphi 程序设计基础 单选按钮, 就转换成不同进制的值 用户可以通过图 10-7 所做的对比看出应用程序的运行效果 图 10-7 进制转换运行效果 (8) 程序说明程序中, 编辑框用来输入数字, 通过调用不同的单选按钮事件来调用进制转换函数 4. 实训练习实训练习按题号顺序难度逐级加大 (1) 完成 2 进制数转换成 8 进制 10 进制 16 进制数的函数, 输入一个 2 进制数, 转换成其他进制值 (2) 在窗体中完成排列 组合函数的调用, 如图 10-8 所示 实训报告记录各实例任务的内容 步骤, 以及完成情况的小结 写出实训成功或失败的原因, 实训后的心得体会 建议等 图 10-8 排列 组合计算 10.3 实训 3 Delphi 窗体设计 建立窗体, 在窗体中添加和设置组件 1. 实训目的熟练掌握常用的窗体属性, 能设计美观实用的窗体, 较熟练地在窗体中添加组件, 设置组件属性 设置 Tab 次序 对齐组件, 及动态创建组件和设置属性 2. 实训要求设计窗体程序, 使窗体完成指定的功能 3. 实训示例设计窗体, 能在窗体中输入参数, 并根据参数设置窗体的标题栏 位置 大小, 每单击窗体一次窗体向左边移动 5, 双击窗体后退出, 单击 添加 按钮, 可生成新按钮 (1) 进入 Delphi 开发环境展开 Windows 的 开始 菜单, 选择 程序 Borland Delphi 7 Delphi 7 (2) 设置窗体属性缺省时 Delphi 创建了一个项目和一个窗体单元文件, 我们在对象查看器中设置窗体的属性, 设置窗体 Height 属性为 310,Width 属性为 368,Font 属性为 宋体 五号

256 第 10 章实训 243 (3) 添加组件往窗体中添加 7 个 Label 组件 Label1~Label7 5 个 Edit 组件 Edit1~Edit5 2 个 Button 组件 Button1~Button2 (4) 设置组件属性组件属性设置见表 10-2 表 10-2 组件属性设置 组 件 属 性 属 性 值 组 件 属 性 属 性 值 Label1 Caption 标题栏 : Edit1 Text [ 空串 ] Label2 Caption 窗体位置 : Edit2 Text [ 空串 ] Label3 Caption X: Edit3 Text [ 空串 ] Label4 Caption Y: Edit4 Text [ 空串 ] Label5 Caption 窗体大小 : Edit5 Text [ 空串 ] Label6 Caption 长 : Button1 Caption 确定 Label7 Caption 宽 : Button2 Caption 添加 设置完组件属性后, 窗体中组件及其布局如图 10-9 所示 (5) 添加组件事件为按钮 Button1 添加 OnClick 事件, 响应过程为 Button1Click; 为按钮 Button2 添加 OnClick 事件, 响应过程为 Button2Click; 为 Form1 添加 OnClick 事件和 OnDblClick 事件, 响应过程分别为 FormClick 和 FormDblClick 图 10-9 窗体组件及布局图 窗体设计程序运行效果 (6) 编写事件代码 Button1Click 过程的作用是按 Edit1~Edit5 的值设置窗体, 从而让 Form1 组件作出相应的反应, 其代码如下 : procedure TForm1.Button1Click(Sender: TObject); self.caption:=edit1.text; self.left:=strtoint(edit2.text); self.top:=strtoint(edit3.text);

257 244 Delphi 程序设计基础 self.width:=strtoint(edit4.text); self.height:=strtoint(edit5.text); 上述过程中使用 StrToInt 函数将文本类型转换成整型数据 Button2Click 过程用来动态添加一个按钮组件, 其代码如下 : procedure TForm1.Button2Click(Sender: TObject); var NewButton:TButton; // 创建组件 NewButton:=TButton.Create(Form1); NewButton.Left:=240; NewButton.Top:=216; NewButton.Caption:=' 加 '; Form1.InsertControl(NewButton); FormClick 过程实现每次单击窗体, 窗体左移 5 个像素, 其代码如下 : procedure TForm1.FormClick(Sender: TObject); self.left:=self.left 5; FormDblClick 过程是当双击窗体时退出窗体, 其代码如下 : procedure TForm1.FormDblClick(Sender: TObject); close; (7) 保存程序将单元文件保存为 Unit3_ex1.pas, 将项目文件保存为 Project3_ex1.dpr (8) 运行程序单击工具栏中 Run 按钮运行程序 运行后, 分别在 Edit1~Edit5 中输入数据, 单击 确定 按钮, 窗体将按 Edit 组件的内容设置 注意 : 由于目前仅考虑简单编程, 所以在 Edit2~Edit5 中必须输入数字, 不输入及输入字母都将造成运行错误 单击 添加 按钮将会动态增加一个 加 按钮 单击窗体, 窗体会左移 5 个像素, 双击窗体后退出 用户可以通过图 与图 10-9 所做的对比看出应用程序的运行效果 4. 实训练习实训练习按题号顺序难度逐级加大 (1) 设计窗体, 将窗体中的标题栏 位置 大小 窗体名 (Name 属性 ) 等显示在相应组件中, 每次单击窗体, 窗体上移 5 个像素, 双击窗体后关闭

258 第 10 章实训 245 (2) 单击 显示 按钮, 动态地将窗体中所有组件的组件名 位置 大小显示在 Memo 组件中 ( 所有信息必须通过程序获得 ), 如图 所示, 单击 打开 按钮, 打开一个其他窗体 提示 : 在 Form1 中的组件可以通过 Form1.Controls[i] 获取, 组件的数量可以通过 Form1.ControlCount 得到 图 实训练习 (2) 界面 (3) 请参阅有关参考书, 制作一非矩形窗体 提示 : 请参阅有关 SetWindowRgn()API 函数的使用 function SetWindowRgn(hWnd: HWND; hrgn: HRGN; bredraw: BOOL): Integer; stdcall; 上面的声明表明了 SetWindowRgn 是个函数, 它返回 Integer 类型的值, 有 3 个参数, 分别如下 hwnd:hwnd 型, 窗口区域的句柄 ; hrgn:hrgn 型, 待设置区域的句柄, 一旦设置了该区域, 就不能使用或修改该区域句柄, 也不能删除它 ; bredraw:bool 型, 若为 True, 则立即重画窗口 由于 Delphi 已经声明了该过程, 如果你要使用, 只需将 Windows 单元加入到 Uses 子句中并调用该过程 例如下面设计了一个椭圆窗体 var Form1: TForm1; h1:hwnd; rgn1:hrgn; xy:array [ 0..4 ] of TPoint; procedure TForm1.Button1Click(Sender: TObject); h1:=handle; rgn1:=createellipticrgn(0,0,300,250);

259 246 Delphi 程序设计基础 SetWindowRgn(h1,rgn1,true); 建立 MDI 窗体, 并对子窗体进行管理 1. 实训目的熟练掌握常用的 MDI 窗体的编程和使用, 能设计美观实用的主窗体和子窗体, 较熟练地动态增加和关闭子窗体 2. 实训要求设计 MDI 窗体程序, 使窗体完成 MDI 方面的应用 3. 实训示例设计 MDI 主窗体和子窗体, 能在主窗体中调用和增加子窗体, 实现子窗体菜单合并 主窗体 Window 菜单等, 并将 MDI 窗体运用于应用程序模块调用方法 (1) 进入 Delphi 开发环境展开 Windows 的 开始 菜单, 选择 程序 Borland Delphi 7 Delphi 7, 进入 Delphi 开发环境 (2) 设置主窗体属性缺省时 Delphi 创建了一个项目和一个窗体单元文件, 我们在对象查看器中设置窗体的属性, 窗体属性设置见表 10-3 表 10-3 窗体属性 属 性 属 性 值 属 性 属 性 值 Name FormMain Font 宋体 五号 Height 330 FormStyle fsmdiform Width 400 (3) 添加组件添加 MainMenu1 ToolBar1 StatusBar1 等组件, 为相应组件添加菜单项或按钮等, 并为组件设置相应属性值, 如图 所示 (4) 建立子窗体执行 File 菜单下 New Form 菜单项新建一个窗体,Name 属性值设置为 FormChild1, 用同样的方法再新建一个窗体,Name 属性值设置为 FormChild2, 将它们的 FormStyle 属性值设置为 fsmdichild, 则它们成为 FormMain 的子窗体 为两个子窗体随便添加一些不同的组件, 以实现不同的功能, 如图 所示 图 主窗体界面 将 Project 文件中创建子窗体的语句删除, 或执行 Project 菜单中 Options 菜单项, 选中 FormChild1 和 FormChild2, 执行 > 按钮, 将它们移到右边的 Available Forms 框中 则在程序启动时, 不会自动创建 FormChild1 和 FormChild2 子窗体, 而必须由程序在运行时动态创建

260 第 10 章实训 247 图 子窗体界面 保存主窗体 子窗体的单元文件分别为 Unit3_ex2.pas Unit3_ex2_2.pas 和 Unit3_ex2_3.pas (5) 动态建立与释放子窗口在主窗体 FormMain 的单元文件中说明使用子窗体的单元 在主窗体的 游戏 菜单中 开始 和 设置 菜单项上分别写如下程序, 当执行该菜单项时, 系统将动态创建子窗口 implementation uses Unit3_ex2_2, Unit3_ex2_3; // 说明使用子窗体的单元 {$R *.dfm} procedure TFormMain.N1Click(Sender: TObject); // 创建子窗口 Application.CreateForm(TFormChild1, FormChild1); // 开始 菜单项 procedure TFormMain.O1Click(Sender: TObject); // 设置 菜单项 Application.CreateForm(TFormChild2, FormChild2); 关闭子窗口时, 必须释放子窗口所占的内存, 而不是让其最小化, 则需在子窗体的 OnClose 事件上写如下程序 : procedure TFormChild1.FormClose(Sender: TObject; var Action: TCloseAction); Action:=caFree; FormChild2 同上 (6) 菜单合并主窗体的主菜单中有 游戏 查看 窗口 帮助 等菜单项, 将它们的 GroupIndex 属性值分别设为

261 248 Delphi 程序设计基础子窗体 1 的主菜单中有 选项 菜单项, 将它的 GroupIndex 属性值设置为 2 子窗体 2 的主菜单中有 设置 菜单项, 将它的 GroupIndex 属性值设置为 3 运行时, 最初只显示主窗口的菜单项, 当新建子窗口后, 就显示合并起来的 5 个菜单项, 顺序依次是 游戏 选项 查看 窗口 帮助 (7) 在菜单中列出打开的文档将 窗口 菜单项的 Name 属性值设为 Window1, 将主窗体 FormMain 的 WindowMenu 属性值选择为 Window1, 意为将运行时创建的子窗口名挂在 窗口 菜单项之下 (8) 主窗体的 窗口 菜单项设计用例 3-3 中的方法建立 窗口 菜单项 (9) 运行程序单击工具栏中 Run 按钮运行程序 运行后, 单击 游戏 菜单中的 开始 和 设置 菜单项可调用两个子窗体模块 如图 所示 4. 实训练习实训练习按题号顺序难度逐级加大 (1) 设计 MDI 窗体, 其中文档子窗体采用同一模板, 另外建立两个不同的模块子窗体, 并通过主窗体调用它们 (2) 设计 MDI 窗体, 尝试不用文件和数据库的图 运行界面及 窗口 菜单方法, 来对两个子窗体中的数据进行相互传递或比较 实训报告记录各实例任务的内容 步骤, 以及完成情况的小结 写出实训成功或失败的原因, 实训后的心得体会 建议等 10.4 实训 4 Delphi 组件应用 设计由按钮类组件实现的功能窗体 1. 实训目的熟悉 Delphi 中按钮型组件的使用, 锻炼代码编写 2. 实训要求按要求设计一窗体, 并实现其功能 3. 实训示例设计一点菜窗口, 用户只能在 龙虾 青蟹 鲍鱼 中选择一项, 对佐料 酱油 芥末 醋 项中任意选择, 提交后生成选择内容的文本 (1) 进入 Delphi 开发环境展开 Windows 的 开始 菜单, 选择 程序 Borland Delphi 7 Delphi 7, 进入 Delphi 开发环境

262 第 10 章实训 249 (2) 创建项目缺省时 Delphi 创建了一个项目和一个窗体单元文件, 我们直接对窗体设置大小和字体等属性 (3) 添加组件往窗体中添加 1 个 Edit 组件 Edit1 1 个 RadioGroup 组件 RadioGroup1 1 个 GroupBox 组件 GroupBox1 2 个 Button 组件 Button1 和 Button2, 再在 GroupBox1 中添加 3 个 CheckBox 组件 CheckBox1~CheckBox3 (4) 设置组件属性组件属性设置见表 10-4 表 10-4 组件属性设置 组件属性属性值组件属性属性值 Edit1 Text [ 空串 ] Form1 Caption 按钮组件练习 Caption 海鲜 GroupBox1 Caption 佐料 RadioGroup1 Items 龙虾 (&L) 青蟹 (&C) CheckBox1 Caption 酱油 (&S) CheckBox2 Caption 芥末 (&M) 鲍鱼 (&A) CheckBox3 Caption 醋 (&V) Button1 Caption 提交 (&R) Button2 Caption 关闭 (&C) 设置完组件属性后, 窗体中组件及其布局如图 所示 (5) 添加并编写组件事件代码为按钮 Button1 添加 OnClick 事件, 响应过程为 Button1Click;Button1Click 过程的作用是按用户设置的 RadioGroup1 和 CheckBox1~CheckBox2 的值提交内容, 从而让 Edit1 组件作出相应的显示, 其代码如下 : procedure TForm1.Button1Click(Sender: TObject); var choice:string; if RadioGroup1.ItemIndex<> 1 then case RadioGroup1.itemindex of 0:choice:=' 龙虾 '; 1:choice:=' 青蟹 '; 2:choice:=' 鲍鱼 '; Edit1.Text:=' 你选择了 '+choice; if CheckBox1.Checked then Edit1.Text:=Edit1.Text+' 酱油'; if CheckBox2.Checked then Edit1.Text:=Edit1.Text+' 芥末'; if CheckBox3.Checked then Edit1.Text:=Edit1.Text+' 醋'; end

263 250 Delphi 程序设计基础 else Edit1.Text:=' 你没有点任何海鲜!'; 为按钮 Button2 添加 OnClick 事件, 响应过程为 Button2Click,Button2Click 过程用来关闭窗体, 其代码如下 : procedure TForm1.Button2Click(Sender: TObject); Close; (6) 保存程序将单元文件保存为 Unit4_ex1.pas, 将项目文件保存为 Project4_ex1.dpr (7) 运行程序单击工具栏中 Run 按钮运行程序 运行后, 分别在单选按钮和复选框中输入数据, 单击 提交 按钮, 窗体将按选择的内容显示在文本框中, 如图 所示 4. 实训练习实训练习按题号顺序难度逐级加大 (1) 按图 所示设计窗体, 当用户选择某一选项后, 按 确定 按钮, 将选择内容显示在 Edit 组件中, 注意各组件上的快捷键 按 取消 按钮, 将 Edit 组件内容清空 图 组件布局图 运行效果图 实训练习 (1) 界面 (2) 设计一表决器, 表决器中有 6 个候选项 ( 如 : 北京 上海 深圳 广州 武汉 南京 ), 单选按钮有 , 当选择 3 时, 只能选择 3 个候选城市, 通过程序自动限制复选框的选择数量, 提交 后将选择的城市显示在编辑框中, 如图 所示 (3) 用窗体方式设计一摇号器, 输入一个整数 n, 代表摇号范围, 输入一个整数 m(m<n), 代表摇出 m 个不重复的随机数, 要求 : 每次摇号得出不同的结果, 随机数出现概率均衡, 窗 体随摇出数量多少而自动改变大小, 如图 所示 提示 :Random() 为随机数函数 图 实训练习 (2) 界面和运行效果

264 第 10 章实训 251 图 实训练习 (3) 运行效果 设计由列表类组件实现的功能窗体 1. 实训目的熟悉 Delphi 中列表型组件的使用, 锻炼代码编写 2. 实训要求按要求设计一窗体, 并实现其功能 3. 实训示例用列表框设计一表决窗口, 从候选城市中选出若干城市, 并可以对选出的城市进行排序 (1) 进入 Delphi 开发环境展开 Windows 的 开始 菜单, 选择 程序 Borland Delphi 7 Delphi 7, 进入 Delphi 开发环境 (2) 创建项目缺省时 Delphi 创建了一个项目和一个窗体单元文件, 我们直接对窗体设置大小和字体等属性 (3) 添加组件往窗体中添加 2 个 ListBox 组件 ListBox1 和 ListBox2,7 个 Button 组件 Button1~ Button7 (4) 设置组件属性组件属性设置见表 10-5 表 10-5 组件属性设置 组件属性属性值组件属性属性值 ListBox1 Items 北京上海天津重庆 Button1 Caption >> Button2 Caption > Button3 Caption < Button4 Caption << 广州杭州南京 Button5 Caption Button6 Caption Button7 Caption 退出 设置完组件属性后, 窗体中组件及其布局如图 所示 (5) 添加并编写组件事件代码为按钮 Button1 添加 OnClick 事件, 响应过程为 Button1Click Button1Click 过程的作用是将所有候选项都提交到已选项列表中, 其代码如下 :

265 252 Delphi 程序设计基础 图 组件布局图 运行效果 procedure TForm1.Button1Click(Sender: TObject); for i:=0 to ListBox1.Items.Count 1 do // 将 ListBox1 中所有选项加到 ListBox2 中 ListBox2.Items.Add(ListBox1.Items.Strings [i ] ); // 将 ListBox1 中所有选项删除 for i:=listbox1.items.count 1 downto 0 do ListBox1.Items.Delete(i); showbtnen; 为按钮 Button2 添加 OnClick 事件, 响应过程为 Button2Click,Button2Click 过程用来将当前选中的候选项提交到已选项列表中, 其代码如下 : procedure TForm1.Button2Click(Sender: TObject); for Item:=0 to ListBox1.Items.Count 1 do if ListBox1.Selected [ Item ] then ListBox2.Items.Add(ListBox1.Items.Strings [ Item ] ); ListBox1.Items.Delete(item); break; showbtnen; 我们可以发现, 几个按钮的事件中, 都调用了 showbtnen 过程, 它是用来设置按钮灰显的, 使得按钮的使用符合环境状况, 其代码如下 :

266 第 10 章实训 253 procedure TForm1.ShowBtnEn; if ListBox1.Count>0 then else button2.enabled:=true button2.enabled:=false; if ListBox2.Count>0 then else button5.enabled:=true button5.enabled:=false; if ListBox1.SelCount>0 then else button3.enabled:=true button3.enabled:=false; if ListBox2.SelCount>0 then else button4.enabled:=true button4.enabled:=false; button6.enabled:=false; for i:=1 to ListBox2.Count 1 do if ListBox2.Selected [ i ] then button6.enabled:=true; break; button7.enabled:=false; for i:=0 to ListBox2.Count 2 do if ListBox2.Selected [ i ] then button7.enabled:=true; break; (6) 保存程序将单元文件保存为 Unit4_ex2.pas, 将项目文件保存为 Project4_ex2.dpr (7) 运行程序单击工具栏中 Run 按钮运行程序 运行后, 分别在候选项中选中选项, 单击 > 按钮, 即可提交至已选列表中, 或直接单击 >> 按钮, 将所有候选项提交至已选列表中, 如图 所示 4. 实训练习实训练习按题号顺序难度逐级加大 (1) 刚才, 我们仅仅完成了 > 和 >> 事件, 只能从候选列表中提交至已选列表中, 而无法将错选的选项返回候选列表, 请同学们完成 < 和 << 功能 (2) 上题中, 当选中已选列表的选项时, 可通过单击 或 调整次序, 请完

267 254 Delphi 程序设计基础成该 2 个按钮事件 (3) 上题中, 还可以通过直接用鼠标拖拽候选项至已选列表, 或拖拽已选项至候选列表, 请完成相应事件 按需求将各种组件灵活组合, 实现功能窗体 1. 实训目的熟悉 Delphi 中各种组件的灵活使用, 锻炼代码编写 2. 实训要求按要求设计一窗体, 并实现其功能 3. 实训练习实训练习按题号顺序难度逐级加大 (1) 界面如图 所示 1 包括组件 Image Label ComboBox Edit Button Panel 2 要求 图 实训练习 (1) 运行效果 在 ComboBox 中选择某一用户, 输入相应密码, 点击 确定 按钮, 若密码是 123, 在 Panel 中显示 欢迎你进入, 否则显示 敲错门了吧? (2) 界面如图 所示 根据 3 个 ScrollBar 的值设置 Panel 的颜色, 色板 二字始终与 Panel 反色 点击 OK 按钮, 将 永 字颜色按 Panel 的颜色设置, 点击 Cancel 按钮退出 图 实训练习 (2) 运行效果图 简易计算器运行效果 (3) 制作一个简易计算器, 如图 所示 要求 : 能用键盘和鼠标输入数据, 选择运算符按钮和 = 按钮, 可以进行四则运算 (4) 模仿 Delphi 设计界面 要求 : 如图 所示 1 Edit1 被选中后显示 8 个点 2 鼠标置于边上或斜角时光标变化 3 可变化 Edit1 的大小, 搬动它的位置, 显示 Hint( 其中有它的位置值等 ) 图 实训练习 (4) 运行效果

268 第 10 章实训 实训报告 记录各实训任务的内容 步骤, 以及完成情况的小结 写出实训成功或失败的原因, 实训后的心得体会 建议等 10.5 实训 5 Delphi 菜单设计 设计窗体菜单 (1) 1. 实训目的熟悉 Delphi 中主菜单的使用, 锻炼界面设计 代码编写 2. 实训要求按要求设计一窗体菜单系统, 并实现其功能 3. 实训示例设计一菜单, 菜单及菜单选项见表 10-6 表 10-6 菜单及菜单选项 文件 (F) 格式 (O) 工具 (T) 打开 (O) 对齐 隐藏 (H) 保存 (S) 加粗 Ctrl+A 选项 (O) 退出 (E) 保存 和 格式 开始时灰显, 单击 打开 后正常显示 加粗 的热键为 Ctrl+A (1) 进入 Delphi 开发环境展开 Windows 的 开始 菜单, 选择 程序 Borland Delphi 7 Delphi 7, 进入 Delphi 开发环境 (2) 创建项目缺省时 Delphi 创建了一个项目和一个窗体单元文件, 我们直接对窗体设置大小和字体等属性 (3) 添加组件 MainMenu 组件 MainMenu1, 双击 MainMenu1 组件, 进入主菜单设计器, 开始进行主菜单设计 (4) 分别创建菜单及菜单项, 添加菜单项并按表 10-7 设置属性 表 10-7 组件属性设置 Caption Name Enabled ShortCut 打开 (&O) mopen 保存 (&S) msave False 退出 (&E) mexit 格式 (&O) mstyle False 对齐 malign 续表

269 256 Delphi 程序设计基础 Caption Name Enabled ShortCut 加粗 mover Ctrl+A 工具 (&T) 隐藏 (&H) mhide 选项 (&O) moption (5) 添加并编写组件事件代码为 打开 菜单项添加 OnClick 事件, 响应过程为 mopenclick, 作用是将 保存 菜单项和 格式 菜单设置成正常显示, 其代码如下 : procedure TForm1.mOpenClick(Sender: TObject); mopen.enabled:=true; mstyle.enabled:=true; (6) 保存程序将单元文件保存为 Unit5_ex1.pas, 将项目文件保存为 Project5_ex1.dpr (7) 运行程序单击工具栏中 Run 按钮运行程序 运行后, 分别在单选按钮和复选框中输入数据, 单击 提交 按钮, 窗体 将按选择的内容显示在文本框中, 如图 所示 4. 实训练习实训练习按题号顺序难度逐级加大 图 菜单设计界面 (1) 在上例的基础上, 给 对齐 菜单项增加级联菜单, 见表 5-8, 并设置 左对齐 居中 右对齐 为单选方式, 加粗 为复选方式 表 10-8 实训练习 (1) 的菜单 文件 (F) 格式 (O) 工具 (T) 打开 (O) 对齐 > 左对齐 (L) 隐藏 (H) 保存 (S) 加粗 Ctrl+A 居中 (C) 右对齐 (R) 选项 (O) 退出 (E) 复选 3 个单选 给 隐藏 菜单项编写事件, 当单击 隐藏 项时, 则隐藏 选项 菜单项, 同时 隐藏 菜单项变成 显示 单击 显示 菜单项, 则显示 选项 菜单项, 同时 显示 变成 隐藏 如图 所示, 添加 Edit1 和 Button1 组件, 然后给窗体加快捷菜单 PopupMenu1, 给 Edit1 组件加快捷菜单 PopupMenu2, 给 Button1 组件加快捷菜单 PopupMenu3, 快捷菜单内容分别见表 10-9

270 第 10 章实训 257 PopupMenu1 PopupMenu3 PopupMenu2 图 增加快捷菜单 表 10-9 实训练习 (1) 的快捷菜单 PopupMenu1 PopupMenu2 PopupMenu3 背景色 (C) 增加按钮 (A) 复制 (C) 隐藏所有 (H) 隐藏按钮 (H) 剪切 (T) 粘贴 (P) (2) 对菜单加上图标, 给 选项 菜单项编写事件, 当单击 选项 时, 在 选项 下动态增加 虚拟 菜单项, 且单击 虚拟 后, 动态删除 加粗 菜单项 (3) 在控制菜单中增加 格式 菜单及其下所有菜单项, 格式 和 工具 菜单之间增加 Edit 菜单模板 设计窗体菜单 (2) 1. 实训目的熟悉 Delphi 中主菜单的使用, 锻炼界面设计 代码编写 2. 实训要求按要求设计一窗体菜单, 并实现其功能 3. 实例示例设计表 所列的菜单 表 菜单选项及属性设置 菜 单 栏 菜 单 级联菜单 属 性 单击事件 游戏 新游戏 (N) [ 分隔线 ] 撤销 (U) 重玩 (R) [ 分隔线 ] 初始灰显, 单击 新游戏 后正常显示 初始隐藏, 单击 新游戏 后正常显示 * 撤销 3 次后隐藏 * 重玩 3 次后灰显 难度 退出 (X) Close; 初级 (E) 单选组

271 258 Delphi 程序设计基础 续表 菜 单 栏 菜 单 级联菜单 属 性 单击事件 高手 (M) 大师 (G) 选项 计时 (T) 背景 (B) [ 分隔线 ] 高山 (M) 海洋 (S) 复选 级联 单选组 帮助 状态栏 (S) 帮助 (H) 关于 (A) 复选 按要求编写事件, 给菜单加合适的图标 热键 实训报告记录各实训任务的内容 步骤, 以及完成情况的小结 写出实训成功或失败的原因, 实训后的心得体会 建议等 10.6 实训 6 对话框设计 对话框的设计和使用 1. 实训目的熟悉 Delphi 中对话框和标准框的使用, 锻炼界面设计和代码编写 2. 实训要求按要求设计一窗体, 并根据需要调用各类对话框 3. 实训示例设计一文字编辑窗口, 可打开文本文件, 经编辑后保存文件 (1) 进入 Delphi 开发环境展开 Windows 的 开始 菜单, 选择 程序 Borland Delphi 7 Delphi 7, 进入 Delphi 开发环境 (2) 创建项目缺省时 Delphi 创建了一个项目和一个窗体单元文件, 我们直接对窗体设置大小和字体等属性 (3) 添加组件往窗体中添加 1 个 MainMenu 组件 MainMenu1 1 个 Memo 组件 Memo1 1 个 OpenDialog 组件 OpenDialog1 1 个 SaveDialog 组件 SaveDialog1 (4) 设置组件属性

272 第 10 章实训 259 将 Form1 的 Caption 属性设置为 草稿纸,Memo1 的 Align 属性设置为 alclient, 使 Memo1 随窗体的大小变化而变化,Memo1 的 Lines 属性设置为 空,OpenDialog1 组件的 Filter 属性设置为 文本文件 *.txt (5) 建立菜单 ( 见表 10-11) 表 菜单及菜单选项 文 件 (&F) 编 辑 (&E) 格 式 (&O) 帮 助 (&H) 新纸 (&N) 撤销 (&U) 换行 (&H) 主题 (&T) 打开 (&O) [ 分隔线 ] 字体 (&F) 关于 (&A) 保存 (&S) 剪切 (&T) 颜色 (&C) [ 分隔线 ] 复制 (&C) 页面 (&G) 粘贴 (&P) 打印 (&P) 删除 (&L) [ 分隔线 ] [ 分隔线 ] 退出 (&E) 查找 (&F) 替换 (&R) 全选 (&A) 转到 (&G) [ 分隔线 ] 日期 (&D) 时间 (&I) 设置完组件属性后, 窗体中组件及其布局如图 所示 图 窗体中组件及布局 (6) 添加并编写组件事件代码为菜单 打开 添加 OnClick 事件, 作用是打开 Open 对话框, 从中选择一个文本文件, 并在 Memo1 组件中打开, 其代码如下 : procedure TForm1.O1Click(Sender: TObject); if OpenDialog1.Execute then Memo1.Lines.LoadFromFile(OpenDialog1.FileName);

273 260 Delphi 程序设计基础 为菜单 保存 添加 OnClick 事件, 作用是打开 Save 对话框, 从中选择一个文件名, 并将 Memo1 组件中文本按该文件名保存, 其代码如下 : procedure TForm1.S1Click(Sender: TObject); if SaveDialog1.Execute then Memo1.Lines.SaveToFile(SaveDialog1.FileName); 为菜单 退出 添加 OnClick 事件, 作用是关闭窗体, 其代码如下 : procedure TForm1.E1Click(Sender: TObject); Close; (7) 保存程序将单元文件保存为 Unit7_ex1.pas, 将项目文件保存为 Project7_ex1.dpr (8) 运行程序单击工具栏中 Run 按钮运行程序 运行后, 单击 打开 菜单, 打开 Open 对话框, 选择一个文本文件打开, 如图 所示, 编辑后单击 保存 菜单, 打开 Save 对话框, 选择文件夹, 输入文件名保存 图 运行效果 4. 实训练习实训练习按题号顺序难度逐级加大 (1) 添加 FontDialog 组件和 ColorDialog 组件, 通过 格式 菜单下的 字体 和 颜色 菜单项设置 Memo1 组件中文字的字体和背景色 (2) 添加 FindDialog 组件和 ReplaceDialog 组件, 通过 编辑 菜单下的 查找 和 替换 菜单项在 Memo1 组件中查找指定文本, 替换指定文本 (3) 添加 PageDialog 组件和 PrintDialog 组件, 通过 文件 菜单下的 页面 和 打印 菜单项将该两个对话框中的主要属性以文本方式保存在 PrintINF.txt 文件中 (4) 完成各个菜单功能 :

274 第 10 章实训 261 单击 新纸 时, 若 Memo1 已编辑新的内容, 并且未保存过, 则弹出 是否保存? 警告消息框, 点击 Yes, 打开 SaveDialog 对话框保存, 否则不予提示 然后将 Memo1 清空 单击 全选 时,Memo1 组件中文本全部被选中 单击 日期 时间 时, 在当前光标处添加系统日期和系统时间 单击 转到 时, 打开一输入框, 从中输入一整数 n, 点击 OK 后, 光标停留至第 n 行 (5) 完成 剪切 复制 粘贴 撤销 等菜单项功能 实训报告记录实训任务的内容 步骤, 以及完成情况的小结 写出实训成功或失败的原因, 实训后的心得体会 建议等 10.7 实训 7 工具栏 状态栏设计 建立窗体工具栏 状态栏 1. 实训目的熟练掌握用各种组件建立工具栏 状态栏的方法 2. 实训要求从已有的窗体中, 选择常用的菜单命令, 制作工具栏, 并制作状态栏 3. 实训示例在实训 对话框的设计和使用 的基础上, 用 ToolBar 组件制作工具栏, 完成 文件 菜单中的 打开 和 保存 菜单项功能 (1) 打开应用程序启动 Delphi, 从 File 菜单中选取 Reopen 命令或 Open Project 命令, 打开应用文件 Project6_ex1 此时, 应用程序将打开实训 对话框的设计和使用 窗体, 参见第 6 章图 6-13 (2) 添加组件往窗体中添加 1 个 ToolBar 组件 ToolBar1 1 个 ImageList 组件 ImageList1 可根据需要将 EdgeBorders 属性的 4 个子属性 ebleft( 左边界 ) ebto p( 上边界 ) ebright ( 右边界 ) ebbottom( 底边界 ) 设置为 True (3) 工具栏上添加快捷按钮鼠标右键单击工具栏组件, 打开一快捷菜单, 如图 7-3( 第 7 章 ) 所示 如果要添加按钮, 选择 New Button 命令 ; 如果要添加分隔线, 选择 New Separator 命令 这里, 我们往工具栏上添加了 12 个按钮和 4 条分隔线, 见表 表 工具栏上 ToolButton 的属性 按钮 Name 作 用 按钮 Name 作 用 ToolButton1 [ 新纸 ] ToolButton9 [ 复制 ] ToolButton2 [ 打开 ] ToolButton10 [ 粘贴 ] ToolButton3 [ 保存 ] ToolButton11 分隔线

275 262 Delphi 程序设计基础 续表 按钮 Name 作 用 按钮 Name 作 用 ToolButton4 分隔线 ToolButton12 [ 左对齐 ] ToolButton5 [ 页面 ] ToolButton13 [ 居中 ] ToolButton6 [ 打印 ] ToolButton14 [ 右对齐 ] ToolButton7 分隔线 ToolButton15 分隔线 ToolButton8 [ 剪切 ] ToolButton16 [ 加粗 ] (4) 为按钮提供位图 将工具栏上按钮用到的位图按顺序加载到 ImageList1 组件的 Images 列表中, 然后单 击 OK 按钮返回 再将 ToolBar1 组件的 Images 属性设置为 ImageList1 组件的 Name 属性 ImageList1 将每一个 TToolButton 对象的 ImageIndex 属性设置位图加载的序号 (5) 链接工具栏按钮和菜单命令的 OnClick 事件 工具栏各按钮的 OnClick 事件选定的响应过程为 : 打开 按钮 ToolButton2 O1Click 保存 按钮 ToolButton3 S1Click (6) 保存程序 将单元文件另存为 Unit7_ex1.pas, 将项目文件另存为 Project7_ex1.dpr (7) 编译运行程序 单击工具栏上 Run 按钮即可运行程序 运行后, 单击工具栏上 打开 按钮, 打开 Open 对话框, 选择一个文本文件打开, 如图 所示, 编辑后单击 保存 按钮, 打 开 Save 对话框, 选择文件夹, 输入文件名保存 图 实训 7 运行效果 4. 实训练习实训练习按题号顺序难度逐级加大 (1) 完成 新纸 页面 打印 剪切 复制 粘贴 等按钮的功能, 并根据实际需求进行灰显设置 (2) 完成 左对齐 居中 右对齐 按钮功能 ( 单选 ) 和 加粗 按钮功能 ( 复选 )

276 第 10 章实训 263 (3) 增加状态栏, 从中显示即时时间 鼠标所点组件的 Hint 光标在 Memo 中的行和列值 (4) 在状态栏中动态显示小图标 (5) 在状态栏中动态显示 Memo 中的汉字数 字母数 空格数 行数 实训报告记录实训任务的内容 步骤, 以及完成情况的小结 写出实训成功或失败的原因, 实训后的心得体会 建议等 10.8 实训 8 数据库编程 设计数据表结构 1. 实训目的掌握数据表结构设计方法, 了解不同数据库管理系统 (DBMS) 的设计技术 2. 实训要求给出一信息对象, 根据该对象的基本信息设计一数据库 3. 实训示例设计一学生基本信息的 MS Access 数据表, 包括学号 班号 姓名 性别 生日 政治现状 入学总分 简历 照片等信息 (1) 运行 MS Access, 从 文件 菜单中选择 新建 菜单项, 在打开的 文件新建数据库 对话框中, 键入 SC 文件名, 单击 创建 按钮, 进入 Access 数据表管理器, 如图 所示 (2) 单击 设计 按钮, 出现一表结构设计器, 在设计器中定义各字段的字段名 类型 长度 说明, 如图 所示 图 MS Access 数据表管理器图 MS Access 数据表设计器 (3) 单击右上角 按钮, 输入表名 XS, 返回数据表管理器

277 264 Delphi 程序设计基础 4. 实训练习实训练习按题号顺序难度逐级加大 (1) 在同一数据库中, 同时设计一班级信息数据表 BJ, 包括班号 班级名称 专业 教室 班主任 人数和奖惩记录 (2) 在 VFP 中重新定义 学生信息 和 班级信息 数据表 (3) 分别用 TTable 组件的 CreatTable 方法和 TQuery 组件的 SQL 语句来创建 学生信息 和 班级信息 数据表 设计数据表编辑窗体 1. 实训目的掌握数据表维护窗体的设计, 了解不同数据库格式的数据库应用程序的设计技术, 灵活应用数据库控制组件 2. 实训要求给出一数据表, 根据该数据表, 用 ADO 组件设计该数据表维护窗体 3. 实训示例针对实训 设计数据表结构 中完成的 XS 数据表, 设计该数据表的维护窗体 (1) 新建应用程序进入 Delphi 后, 单击 File 菜单的 New Application 命令开始一个新的应用程序 (2) 设置窗体属性窗体 Caption 属性设置为 数据库练习,Font 属性设置为 宋体 五号 (3) 添加 ADOConnection 组件, 并设置 ConnectionString 属性从 ADO 组件板中选择 ADOConnection 组件, 添加到窗体中, 双击该组件出现 ADOConnection ConnectionString 对话框, 如图 所示, 单击 Build 按钮, 出现 数据链接属性 对话框, 如图 10-34(a) 所示, 在列表中选择 Microsoft Jet 4.0 OLE DB Provider, 单击 下一步, 进入 连接 标签, 如图 10-34(b) 所示, 单击 选择或输入数据库名称 文本框后的 按钮, 打开一 选择 Access 数据库 对话框, 从中找到指定路径下的数据库名, 如 :SC.MDB 将 ADOConnection1 组件中 LoginPrompt 属性设置为 False, 否则每次运行需要输入口令 图 ADOConnection ConnectionString 对话框

278 第 10 章实训 265 (a) 图 数据链接属性 对话框 (b) (4) 添加组件首先往窗体中添加 1 个 GroupBox 组件 GroupBox1 2 个 ADOTable 组件 ADOTable1 和 ADOTable2 2 个 DataSource DataSource1 和 DataSource2 然后在 GroupBox1 组件上添加 6 个 Label 组件 Label1~Label6 4 个 DBEdit 组件 DBEdit1~DBEdit4 1 个 DBRadioGroup 组件 DBRadioGroup1 1 个 DBLookup ComboBox 组件 DBLookupComboBox1 1 个 DBComboBox 组件 DBComboBox1 1 个 DBMemo 组件 DBMemo1 1 个 DBImage 组件 DBImage1 1 个 DBGrid 组件 DBGrid1 最后再在 GroupBox1 组件外添加一个 DBNavigator 组件 DBNavigator1 8 个 Button 组件 Button1~Button8 (5) 设置组件属性先将所有 Data Controls 组件的 DataSource 属性设置为 DataSource1,DataSource1 的 DataSet 属性设置为 ADOTable1,DataSource2 的 DataSet 属性设置为 ADOTable2 然后再按表 设置窗体中的组件属性 表 组件属性 组 件 属 性 属 性 值 组 件 属 性 属 性 值 Connection ADOConnection1 DataField ZZ ADOTable1 TableName xs Items 党员 DBComboBox1 Connection ADOConnection1 团员 ADOTable1 TableName bj 群众 Label1 Caption 学号 Caption 性别 Label2 Caption 班号 DataField XB DBRadioGroup1 Label3 Caption 姓名 Items 男 Label4 Caption 生日 女

279 266 Delphi 程序设计基础 续表 组 件 属 性 属 性 值 组 件 属 性 属 性 值 Label5 Caption 现状 Buttonl Caption 新增 (&A) Label6 Caption 总分 Button2 Caption 删除 (&D) DBEdit1 DataField XH Button3 Caption 修改 (&U) DBEdit2 DataField XM Button4 Caption 定位 (&L) DBEdit3 DataField SR Button5 Caption 查询 (&Q) DBEdit4 DataField ZF Button6 Caption 保存 (&S) DataField BH Button7 Caption 取消 (&C) DBLookupComboBox1 ListSource DataSource2 Button8 Caption 退出 (&E) ListField BH DBMemo1 DataField JL KeyField BH DBImage1 DataField ZP DBNavigator1 组件 :VisibleButtons 属性 = nbfirst, nbprior, nbnext, nblast 注意组件 DBLookupComboBox1 的属性设置,ADOTable2 是为 DBLookupComboBox1 建立的 设置完组件属性后, 窗体中组件及其布局如图 所示 图 窗体中组件及布局 (6) 添加和编写组件事件代码为 Form1 添加 OnCreate 事件, 每次启动时设置数据表的 Active 属性为 True: procedure TForm1.FormCreate(Sender: TObject); ADOTable1.Active:=true; ADOTable2.Active:=true; 为组件 DataSource1 添加 OnStateChange 事件, 响应过程为 DataSource1StateChange, 当数据源状态发生变化时, 在状态栏上显示相应提示 : procedure TForm1.DataSource1StateChange(Sender: TObject); if ADOTable1.State=dsInsert then

280 第 10 章实训 267 StatusBar1.Panels [ 0 ].Text:=' 数据表处于插入状态 '; if ADOTable1.State=dsEdit then StatusBar1.Panels [ 0 ].Text:=' 数据表处于编辑状态 '; if ADOTable1.State=dsBrowse then StatusBar1.Panels [ 0 ].Text:=' 数据表处于浏览状态 '; if ADOTable1.State=dsSetKey then StatusBar1.Panels [ 0 ].Text:=' 数据表处于查询状态 '; 为按钮 Button1 添加 OnClick 事件, 响应过程为 Button1Click, 单击 新增 按钮时, 使数据表添加一条空记录, 同时设置相应按钮灰显 : procedure TForm1.Button1Click(Sender: TObject); if ADOTable1.CanModify then ADOTable1.App Panel1.Enabled:=true; DBNavigator1.Enabled:=false; Button1.Enabled:=false; Button2.Enabled:=false; Button3.Enabled:=false; Button4.Enabled:=false; Button5.Enabled:=false; Button8.Enabled:=false; end else showmessage(' 当前数据表不能新增记录 '); 为按钮 Button2 添加 OnClick 事件, 响应过程为 Button2Click, 单击 删除 按钮时, 确认后删除当前记录 : procedure TForm1.Button2Click(Sender: TObject); if MessageDlg(' 确实要删除当前记录吗?',mtInformation, [ mbok,mbcancel ],0) =mrok then ADOTable1.Delete; 为按钮 Button3 添加 OnClick 事件, 响应过程为 Button3Click, 单击 修改 按钮时, 使数据表进入编辑状态, 同时设置相应按钮灰显 : procedure TForm1.Button3Click(Sender: TObject); if ADOTable1.CanModify then

281 268 Delphi 程序设计基础 ADOTable1.Edit; Panel1.Enabled:=true; DBNavigator1.Enabled:=false; Button1.Enabled:=false; Button2.Enabled:=false; Button3.Enabled:=false; Button4.Enabled:=false; Button5.Enabled:=false; Button8.Enabled:=false; end else showmessage(' 当前数据表不能被修改 '); 为按钮 Button4 添加 OnClick 事件, 响应过程为 Button4Click, 单击 定位 按钮时, 打开一输入框, 输入定位步长 ( 允许负数 ), 指针移到相应记录 : procedure TForm1.Button4Click(Sender: TObject); var i,code:integer; scope:string; repeat scope:=inputbox(' 移动指针位置 ',' 请输入移动距离 :','0'); Val(scope,i,code); if code<>0 then // 当 code<>0 时,scope 为非数值字符 ShowMessage(' 你输入了一个错误的移动范围, 请重试!'); until code=0; ADOTable1.MoveBy(i); 为按钮 Button5 添加 OnClick 事件, 响应过程为 Button5Click, 单击 查询 按钮时, 打开一输入框, 然后根据输入的学号进行查询 : procedure TForm1.Button5Click(Sender: TObject); var Loctstr:string; loctstr:=inputbox(' 按学号查询 ',' 请输入学号 :','0'); if not ADOTable1.Locate('XH',loctstr, [ locaseinsensitive ] ) then ShowMessage(' 无匹配记录!'); 为按钮 Button6 添加 OnClick 事件, 响应过程为 Button6Click, 单击 保存 按钮时, 使控制组件的数据保存到数据表中, 同时设置相应按钮正常显示 :

282 第 10 章 实 训 269 procedure TForm1.Button6Click(Sender: TObject); if ADOTable1.Modified then ADOTable1.Post; Panel1.Enabled:=false; DBNavigator1.Enabled:=true; Button1.Enabled:=true; Button2.Enabled:=true; Button3.Enabled:=true; Button4.Enabled:=true; Button5.Enabled:=true; Button8.Enabled:=true; 为按钮 Button7 添加 OnClick 事件, 响应过程为 Button7Click, 单击 取消 按钮时, 取 消刚编辑或新增等操作, 同时设置相应按钮正常显示 : procedure TForm1.Button7Click(Sender: TObject); ADOTable1.Cancel; Panel1.Enabled:=false; DBNavigator1.Enabled:=true; Button1.Enabled:=true; Button2.Enabled:=true; Button3.Enabled:=true; Button4.Enabled:=true; Button5.Enabled:=true; Button8.Enabled:=true; 为按钮 Button8 添加 OnClick 事件, 响应过程为 Button8Click, 单击 退出 按钮时, 退 出窗体 : procedure TForm1.Button8Click(Sender: TObject); Close; (7) 保存程序 将单元文件保存为 Unit8_ex2.pas, 将项目文件保存为 Project8_ex2.dpr (8) 运行程序 单击工具栏中 Run 按钮运行程序 运行后, 通过选择相应按钮, 可进入不同状态,

283 270 Delphi 程序设计基础 可对数据表进行浏览和编辑, 其中, 照片通过复制 (Ctrl+C) 粘贴 (Ctrl+V) 输入 运行效 果如图 所示 图 运行效果 4. 实训练习实训练习按题号顺序难度逐级加大 (1) 针对实训 设计数据表结构 实训练习 (1) 中完成的 BJ 数据表, 设计该数据表的维护窗体 其中班号 班级名称 班主任 人数用 DBEdit 组件, 专业用 DBLookupComboBox 组件, 教室用 DBListBox 组件, 奖惩记录用 DBMemo 组件 (2) 用 BDE 组件设计窗体, 对 VFP 中定义的 学生信息 和 班级信息 数据表进行维护 (3) 用 Standard 组件 ( 不使用 Data Controls 组件 ), 如 Edit 组件 Memo 组件 Radio Group 组件等设计数据表维护窗体, 包括对数据表的浏览 编辑 增删等操作 (4) 当在学号处输入字母 汉字时提示输入错误, 重新输入 在姓名处输入数值符时提示输入错误, 重新输入 在总分处输入小于 0 或大于 700 时提示输入错误, 重新输入 设计数据表查询窗体 1. 实训目的掌握数据表查询窗体的设计, 了解不同数据库格式的数据库应用程序的设计技术, 灵活应用 SQL 语句和 Query 组件 2. 实训要求给出一数据表, 根据该数据表, 用 ADO 组件设计该数据表查询窗体 3. 实训示例针对实训 设计数据表结构 中完成的 XS 数据表, 设计该数据表的查询窗体 (1) 新建应用程序进入 Delphi 后, 单击 File 菜单的 New Application 命令开始一个新的应

284 第 10 章实训 271 用程序 (2) 设置窗体属性窗体属性 Caption 为 数据库查询练习,Font 属性为 宋体 五号 (3) 添加 ADOConnection 组件, 并设置 ConnectionString 属性从 ADO 组件板中选择 ADOConnection 组件, 添加到窗体中, 双击该组件出现 ADOConnection ConnectionString 对话框, 如图 所示, 单击 Build 按钮, 出现 数据链表属性 对话框, 如图 10-34(a) 所示, 在列表中选择 Microsoft Jet 4.0 OLE DB Provider, 单击 下一步, 进入 连接 标签, 如图 10-34(b) 所示, 单击 选择或输入数据库名称 文本框后的 按钮, 打开一 选择 Access 数据库 对话框, 从中找到指定路径下的数据库名, 如 :SC.MDB 将 ADOConnection1 组件中 LoginPrompt 属性设置为 False, 否则每次运行需要输入口令 (4) 添加组件首先往窗体中添加 1 个 GroupBox 组件 GroupBox1 1 个 ADOQuery 组件 ADOQuery1 1 个 DataSource 组件 DataSource1 然后在 GroupBox1 组件上添加 7 个 CheckBox 组件 CheckBox1~CheckBox7 5 个 Edit 组件 Edit1~Edit5 1 个 RadioGroup 组件 RadioGroup1 1 个 ComboBox 组件 ComboBox1 2 个 DateTimePicker 组件 DateTimePicker1 和 DateTimePicker2 最后再在 GroupBox1 组件外添加 1 个 DBMemo 组件 DBMemo1 1 个 DBImage 组件 DBImage1 1 个 DBGrid 组件 DBGrid1 1 个 DBNavigator 组件 DBNavigator1 2 个 Button 组件 Button1 和 Button2 (5) 设置组件属性先将所有 Data Controls 组件的 DataSource 属性设置为 DataSource1,DataSource1 的 DataSet 属性设置为 Query1, 在 ADOQuery1 组件的 SQL 属性中输入 select * from xs 然后再按表 设置窗体中的组件属性 表 组件属性 组 件 属 性 属 性 值 组 件 属 性 属 性 值 ADOQuery1 Connection ADOConnection1 Items 党员 Active True ComboBox1 团员 CheckBox1 Caption 学号 群众 CheckBox2 Caption 班号 DBMemo1 DataField JL CheckBox3 Caption 姓名 DBImage1 DataField ZP CheckBox4 Caption 性别 Buttonl Caption 查询 (&Q) CheckBox5 Caption 生日 Button2 Caption 退出 (&E) CheckBox6 Caption 政治 Edit1 Text [ 空 ] CheckBox7 Caption 总分 Edit2 Text [ 空 ] Items 男 Edit3 Text [ 空 ] RadioGroup1 女 Edit4 Text [ 空 ] Columns 2 Edit5 Text [ 空 ] DBNavigator1 组件 :VisibleButtons 属性 = nbfirst, nbprior, nbnext, nblast

285 272 Delphi 程序设计基础 设置完组件属性后, 窗体中组件及其布局如图 所示 图 组件及布局 (6) 添加和编写组件事件代码为按钮 Button1 添加 OnClick 事件, 响应过程为 Button1Click, 单击 查询 按钮时, 对数据表进行查询, 查询结果通过 DBGrid1 显示 : procedure TForm1.Button1Click(Sender: TObject); var tj,tj1,tj2,tj3,tj4,tj5,tj6,tj7:string; tj1:=' 1=1 '; if checkbox1.checked then // 按学号查询 tj1:=' XH like '''+'%'+Edit1.Text+'%'+''''; tj2:=' 1=1 '; if checkbox2.checked then // 按班号查询 tj2:=' BH like '''+'%'+Edit2.Text+'%'+''''; tj3:=' 1=1 '; if checkbox3.checked then // 按姓名查询 tj3:=' XM like '''+'%'+Edit3.Text+'%'+''''; tj4:=' 1=1 '; if checkbox4.checked then // 按性别查询 if RadioGroup1.ItemIndex=0 then tj4:=' XB like '''+'% 男 %'+''''; if RadioGroup1.ItemIndex=1 then tj4:=' XB like '''+'% 女 %'+'''';

286 第 10 章实训 273 tj5:=' 1=1 '; if checkbox5.checked then // 按生日查询 tj5:=' SR>=#'+DateToStr(DateTimePicker1.Date)+'# and SR<=#'+DateToStr(DateTimePicker2.Date)+'#'; tj6:=' 1=1 '; if checkbox6.checked then // 按政治状况查询 tj6:=' ZZ like '''+ComboBox1.Text+''''; tj7:=' 1=1 '; if checkbox7.checked then // 按总分查询 tj7:=' ZF>='+Edit4.Text+' and ZF<='+Edit5.Text; tj:='select * from xs where ' +tj1+' and '+tj2+' and '+tj3+' and '+tj4+' and ' +tj5+' and '+tj6+' and '+tj7 ; ADOQuery1.Close; ADOQuery1.SQL.Clear; ADOQuery1.SQL.Add(tj); ADOQuery1.Open; (7) 保存程序将单元文件保存为 Unit8_ex3.pas, 将项目文件保存为 Project8_ex3.dpr (8) 运行程序单击工具栏中 Run 按钮运行程序 运行后, 通过选择相应复选框, 选择查询项, 设置查询项, 单击 查询 按钮将符合条件的数据显示在 DBGrid 中, 单击 DBNavigator 按钮可在查询到的数据中浏览, 运行效果如图 所示 图 运行效果

287 274 Delphi 程序设计基础 4. 实训练习实训练习按题号顺序难度逐级加大 (1) 针对实训 设计数据表结构 中实训练习 (1) 完成的 BJ 数据表, 设计该数据表的查询窗体 (2) 用 BDE 组件设计窗体, 对 VFP 中定义的 学生信息 和 班级信息 数据表进行查询 (3) 多表查询, 能同时查询学生信息和班主任信息 实训报告记录各实训任务的内容 步骤, 以及完成情况的小结 写出实训成功或失败的原因, 实训后的心得体会 建议等 10.9 实训 9 报表设计 熟悉 Delphi 报表设计 1. 实训目的熟悉 Delphi 报表组件的功能, 掌握报表设计的操作 2. 实训要求设计一系列报表 3. 实训示例用 QuickReport 打印数据库 SC.dbm 中 xs 数据表各种数据类型的数据 (1) 新建应用程序启动 Delphi, 从 File 菜单中选取 New Application 命令, 开始一个新的应用文件 (2) 设置窗体属性窗体的 Caption 属性为 QuickReport 例程 (3) 向窗体中添加组件往窗体中添加 3 个 Button 组件 Button1~Button3 1 个 Memo 组件 Description 1 个 GroupBox 组件 GroupBox1 1 个 Image 组件 Image1 2 个 Lable 组件 Lable1 和 Lable2 4 个 RadioButton 组件 RadioButton1~RadioButton4 (4) 设置组件属性窗体中组件属性见表 表 窗体中组件属性 组 件 属 性 属 性 值 Button1 Caption 预览 Button2 Caption 打印 Button3 Caption 取消 Lable1 Caption 学生信息报表 Lable2 Caption SC.mdb Report /June 16, 2005 delphiline@sohu.com RadioButton1 Caption 实训 9-&1 打印学生信息列表

288 第 10 章 实 训 275 续表 组 件 属 性 属 性 值 RadioButton2 Caption 实训 9-&2 打印学生证标签 RadioButton3 Caption 实训 9-&3 打印学生成绩明细报表 RadioButton4 Caption 实训 9-&4 打印学生成绩统计报表 组件属性设置后, 窗体中组件布局如图 所示 图 报表例子界面 (5) 添加事件为按钮 Button1 添加 OnClick 事件, 事件响应过程为 Button1Click, 为按钮 Button2 添加 OnClick 事件, 事件响应过程为 Button2Click, 为按钮 Button3 添加 OnClick 事件, 事件响应过程为 Button3Click (6) 编写事件代码先在程序的 interface 块中的 var 说明中加入 Report:TCustomQuickRep; 说明 procedure TfrmEx10.btnPreviewClick(Sender: TObject); if report <> nil then report.preview; // 预览 procedure TfrmEx10.btnPrintClick(Sender: TObject); if report <> nil then report.print; // 打印 procedure TfrmEx10.btnCancelClick(Sender: TObject); close; // 关闭 这样, 报表例程的调用界面就做好了, 接下来我们开始制作本实训的报表 (7) 建立报表从 File 菜单中选取 New Form 命令, 新建一个 Form 组件 将其 Name 属性设为 Form9_ex1

289 276 Delphi 程序设计基础在 Form9_ex1 中加入 QuickRep 组件 QuickRep1, 并将其 Bands.HasColumnHeader 属性和 Bands.HasDetail 属性设为 True, 这时会在 QuickRep1 中出现 ColumnHeaderBand1 和 DetailBand1 两个区域, 接着再加入 ADOTable 组件 ADOTable1; 在 ColumnHeaderBand1 区域中加入 3 个 QRLable 组件 QRLable1~QRLable3; 在 DetailBand1 区域中加入 6 个 QRLable 组件 QRLable4~QRLable9 6 个 RQDBText 组件 RQDBText1~RQDBText6 1 个 QRDBImage 组件 QRDBImage1 1 个 QRDBRichText 组件 QRDBRichText1 和 1 个 QRShape 组件 QRShape1 首先设置 ADOTable1 的 ConnectionString 属性, 单击该属性的 按钮, 出现 ADOConnection ConnectionString 对话框, 如图 所示, 单击 Build 按钮, 出现 数据链接属性 对话框, 如图 10-41(a) 所示, 在列表中选择 Microsoft Jet 4.0 OLE DB Provider, 单击 下一步, 进入 连接 标签, 如图 10-41(b) 所示, 单击 选择或输入数据库名称 文本框后的 按钮, 打开一 选择 Access 数据库 对话框, 从中找到指定路径下的数据库名, 如 :SC.MDB 图 ADOConnection ConnectionString 对话框 (a) 图 数据链接属性 对话框 (b) 各组件属性设置见表 10-16

290 第 10 章实训 277 表 报表中组件属性 组 件 属 性 属 性 值 属 性 属 性 值 ADOTable1 Active True QuickRep1 ReportTitle 学生信息 QRLable1 Caption 基本信息 QRLable2 Caption 照片 QRLable3 Caption 简历 QRDBText1 DataSet ADOTable1 DataField XH QRDBText2 DataSet ADOTable1 DataField XM QRDBText3 DataSet ADOTable1 DataField XB QRDBText4 DataSet ADOTable1 DataField SR QRDBText5 DataSet ADOTable1 DataField ZZ QRDBImage1 DataSet ADOTable1 DataField ZP QRDBRichText1 DataSet ADOTable1 DataField JL QRShape1 Shape qrshorline 组件属性设置后, 窗体中组件布局如图 所示 回到图 所示的调用界面, 给 RadioButton1 组件添加 OnClick 事件如下 : procedure TfrmEx9.RadioButton1Click(Sender: TObject); Report := Form9_ex1.QuickRep1; // 将报表传递给 Report, 以便 浏览 或 打印 按钮调用 图 窗体组件布局 (8) 保存程序将窗体 frmex9 的单元文件保存为 Unit9ex.pas, 将窗体 Form9_ex1 的单元文件保存为 Unit9_ex1.pas, 将项目文件保存为 Project9ex.dpr (9) 编译运行程序单击工具栏上 Run 按钮即可运行程序 运行后, 单击 实训 9-1 打印学生信息列表 RadioButton1 组件, 再单击 预览 按钮, 将直接显示数据库报表的打印预览效果, 而且在窗口顶端还有一排按钮用于进行打印预览操作, 如图 所示 单击窗口顶端的 Print 按钮也可直接打印数据库报表 4. 实训练习实训练习按题号顺序难度逐级加大

291 278 Delphi 程序设计基础 图 运行效果 (1) 使用 ExprMemo 组件打印学生证标签 学生证标签的数据来自于 SC.dbm 中的数据 表 xs 设计界面如图 所示, 运行界面如图 所示 图 实训练习 (1) 窗体布局图 实训练习 (2) 预览效果

292 (2) 制作一个学生成绩主 / 明细类型的报表 先在 SC.dbm 数据库中建立 Cj 数据表, 内容见表 第 10 章实训 279 表 Cj 数据表 编 号 xh km fs 高数 高数 数据结构 数据结构 数据库 数据库 网络 网络 电子商务 电子商务 信息安全 信息安全 76 设计界面如图 所示, 运行界面如图 所示 图 实训练习 (2) 窗体组件布局图 实训练习 (2) 预览效果 提示 : 主 / 明细表最关键的部分是给 ADOTable2 建立一个 MasterSource, 具体方法是 : 在 ADOTable2 组件的 MasterSource 属性中选择 DataSource1, 在 MasterField 属性中点击... 按钮, 出现 Field Link Designer 对话框, 如图 9-13 所示, 在 Detail Fields 的列表框中

293 280 Delphi 程序设计基础选择 Xh 字段, 在 Master Fields 的列表框中选择 Xh, 单击 Add 按钮, 使 Joined Fiel d 列表框中出现 Xh->Xh (3) 制作一个学生成绩主 / 明细及分组统计的报表 设计界面如图 所示, 运行界面如图 所示 图 实训练习 (3) 窗体组件布局图 实训练习 (3) 预览效果 (4) 按 SC.mdb 数据库中的 xs 数据表, 生成 学生总分 图表 实训报告记录实训任务的内容 步骤, 以及完成情况的小结 写出实训成功或失败的原因, 实训后的心得体会 建议等

epub83-1

epub83-1 C++Builder 1 C + + B u i l d e r C + + B u i l d e r C + + B u i l d e r C + + B u i l d e r 1.1 1.1.1 1-1 1. 1-1 1 2. 1-1 2 A c c e s s P a r a d o x Visual FoxPro 3. / C / S 2 C + + B u i l d e r / C

More information

OOP with Java 通知 Project 4: 4 月 18 日晚 9 点 关于抄袭 没有分数

OOP with Java 通知 Project 4: 4 月 18 日晚 9 点 关于抄袭 没有分数 OOP with Java Yuanbin Wu cs@ecnu OOP with Java 通知 Project 4: 4 月 18 日晚 9 点 关于抄袭 没有分数 复习 类的复用 组合 (composition): has-a 关系 class MyType { public int i; public double d; public char c; public void set(double

More information

C++ 程序设计 告别 OJ1 - 参考答案 MASTER 2019 年 5 月 3 日 1

C++ 程序设计 告别 OJ1 - 参考答案 MASTER 2019 年 5 月 3 日 1 C++ 程序设计 告别 OJ1 - 参考答案 MASTER 2019 年 月 3 日 1 1 INPUTOUTPUT 1 InputOutput 题目描述 用 cin 输入你的姓名 ( 没有空格 ) 和年龄 ( 整数 ), 并用 cout 输出 输入输出符合以下范例 输入 master 999 输出 I am master, 999 years old. 注意 "," 后面有一个空格,"." 结束,

More information

OOP with Java 通知 Project 2 提交时间 : 3 月 14 日晚 9 点 另一名助教 : 王桢 学习使用文本编辑器 学习使用 cmd: Power shell 阅读参考资料

OOP with Java 通知 Project 2 提交时间 : 3 月 14 日晚 9 点 另一名助教 : 王桢   学习使用文本编辑器 学习使用 cmd: Power shell 阅读参考资料 OOP with Java Yuanbin Wu cs@ecnu OOP with Java 通知 Project 2 提交时间 : 3 月 14 日晚 9 点 另一名助教 : 王桢 Email: 51141201063@ecnu.cn 学习使用文本编辑器 学习使用 cmd: Power shell 阅读参考资料 OOP with Java Java 类型 引用 不可变类型 对象存储位置 作用域 OOP

More information

PowerPoint 演示文稿

PowerPoint 演示文稿 按钮对象 (button) 当 JavaScript 读到 标记中的 type 属性值为 button 时, 自动建立一个按钮对象, 并将该对象放到表单对象的 elements 数组当中 按钮对象包括 : 普通按钮 (button) 提交按钮 (submit) 重置按钮 (reset) 1. 使用按钮对象的格式 document.forms[ 索引值 ].elements[ 索引值

More information

Microsoft PowerPoint - OPVB1基本VB.ppt

Microsoft PowerPoint - OPVB1基本VB.ppt 大 綱 0.VB 能 做 什 麼? CH1 VB 基 本 認 識 1.VB 歷 史 與 版 本 2.VB 環 境 簡 介 3. 即 時 運 算 視 窗 1 0.VB 能 做 什 麼? Visual Basic =>VB=> 程 式 設 計 語 言 => 設 計 程 式 設 計 你 想 要 的 功 能 的 程 式 自 動 化 資 料 庫 計 算 模 擬 遊 戲 網 路 監 控 實 驗 輔 助 自 動

More information

OOP with Java 通知 Project 4: 4 月 19 日晚 9 点

OOP with Java 通知 Project 4: 4 月 19 日晚 9 点 OOP with Java Yuanbin Wu cs@ecnu OOP with Java 通知 Project 4: 4 月 19 日晚 9 点 复习 类的复用 组合 (composition): has-a 关系 class MyType { public int i; public double d; public char c; public void set(double x) { d

More information

VB程序设计教程

VB程序设计教程 高 等 学 校 教 材 Visual Basic 程 序 设 计 教 程 魏 东 平 郑 立 垠 梁 玉 环 石 油 大 学 出 版 社 内 容 提 要 本 书 是 按 高 等 学 校 计 算 机 程 序 设 计 课 程 教 学 大 纲 编 写 的 大 学 教 材, 主 要 包 括 VB 基 础 知 识 常 用 程 序 结 构 和 算 法 Windows 用 户 界 面 设 计 基 础 文 件 处

More information

手册 doc

手册 doc 1. 2. 3. 3.1 3.2 3.3 SD 3.4 3.5 SD 3.6 3.7 4. 4.1 4.2 4.3 SD 4.4 5. 5.1 5.2 5.3 SD 6. 1. 1~3 ( ) 320x240~704x288 66 (2G SD 320x2401FPS ) 32M~2G SD SD SD SD 24V DC 3W( ) -10~70 10~90% 154x44x144mm 2. DVR106

More information

四川省普通高等学校

四川省普通高等学校 四 川 省 普 通 高 等 学 校 计 算 机 应 用 知 识 和 能 力 等 级 考 试 考 试 大 纲 (2013 年 试 行 版 ) 四 川 省 教 育 厅 计 算 机 等 级 考 试 中 心 2013 年 1 月 目 录 一 级 考 试 大 纲 1 二 级 考 试 大 纲 6 程 序 设 计 公 共 基 础 知 识 6 BASIC 语 言 程 序 设 计 (Visual Basic) 9

More information

Microsoft PowerPoint - 07 派生数据类型

Microsoft PowerPoint - 07 派生数据类型 能源与动力工程学院 目录 派生类型 陈 斌 固有数据类型 数值型 (numerical) 整型 INTEGER 实型 REAL 复数型 COMPLEX 非数值型 字符型 CHARACTER 逻辑型 ( 布尔型 )LOGICAL 自定义数据类型 ( 派生类型, derived type) 派生类型是指用户利用 Fortran 系统内部类型, 如整型 实型 复数型 逻辑型 字符型等的组合自行创建出一个新的数据类型,

More information

FY.DOC

FY.DOC 高 职 高 专 21 世 纪 规 划 教 材 C++ 程 序 设 计 邓 振 杰 主 编 贾 振 华 孟 庆 敏 副 主 编 人 民 邮 电 出 版 社 内 容 提 要 本 书 系 统 地 介 绍 C++ 语 言 的 基 本 概 念 基 本 语 法 和 编 程 方 法, 深 入 浅 出 地 讲 述 C++ 语 言 面 向 对 象 的 重 要 特 征 : 类 和 对 象 抽 象 封 装 继 承 等 主

More information

帝国CMS下在PHP文件中调用数据库类执行SQL语句实例

帝国CMS下在PHP文件中调用数据库类执行SQL语句实例 帝国 CMS 下在 PHP 文件中调用数据库类执行 SQL 语句实例 这篇文章主要介绍了帝国 CMS 下在 PHP 文件中调用数据库类执行 SQL 语句实例, 本文还详细介绍了帝国 CMS 数据库类中的一些常用方法, 需要的朋友可以参考下 例 1: 连接 MYSQL 数据库例子 (a.php)

More information

基于UML建模的管理管理信息系统项目案例导航——VB篇

基于UML建模的管理管理信息系统项目案例导航——VB篇 PowerBuilder 8.0 PowerBuilder 8.0 12 PowerBuilder 8.0 PowerScript PowerBuilder CIP PowerBuilder 8.0 /. 2004 21 ISBN 7-03-014600-X.P.. -,PowerBuilder 8.0 - -.TP311.56 CIP 2004 117494 / / 16 100717 http://www.sciencep.com

More information

一 登录 crm Mobile 系统 : 输入 ShijiCare 用户名和密码, 登录系统, 如图所示 : 第 2 页共 32 页

一 登录 crm Mobile 系统 : 输入 ShijiCare 用户名和密码, 登录系统, 如图所示 : 第 2 页共 32 页 第 1 页共 32 页 crm Mobile V1.0 for IOS 用户手册 一 登录 crm Mobile 系统 : 输入 ShijiCare 用户名和密码, 登录系统, 如图所示 : 第 2 页共 32 页 二 crm Mobile 界面介绍 : 第 3 页共 32 页 三 新建 (New) 功能使用说明 1 选择产品 第 4 页共 32 页 2 填写问题的简要描述和详细描述 第 5 页共

More information

SDK 概要 使用 Maven 的用户可以从 Maven 库中搜索 "odps-sdk" 获取不同版本的 Java SDK: 包名 odps-sdk-core odps-sdk-commons odps-sdk-udf odps-sdk-mapred odps-sdk-graph 描述 ODPS 基

SDK 概要 使用 Maven 的用户可以从 Maven 库中搜索 odps-sdk 获取不同版本的 Java SDK: 包名 odps-sdk-core odps-sdk-commons odps-sdk-udf odps-sdk-mapred odps-sdk-graph 描述 ODPS 基 开放数据处理服务 ODPS SDK SDK 概要 使用 Maven 的用户可以从 Maven 库中搜索 "odps-sdk" 获取不同版本的 Java SDK: 包名 odps-sdk-core odps-sdk-commons odps-sdk-udf odps-sdk-mapred odps-sdk-graph 描述 ODPS 基础功能的主体接口, 搜索关键词 "odpssdk-core" 一些

More information

概述

概述 OPC Version 1.6 build 0910 KOSRDK Knight OPC Server Rapid Development Toolkits Knight Workgroup, eehoo Technology 2002-9 OPC 1...4 2 API...5 2.1...5 2.2...5 2.2.1 KOS_Init...5 2.2.2 KOS_InitB...5 2.2.3

More information

言1.PDF

言1.PDF MSP430 WINDOWS WORKBENCH MSP430 Flash Green MCU Flash Flash MCU MSP430 16 RISC 27 125ns 1.8V~3.6V A/D 6 s MSP430 10 ESD MSP430 MSP430 10 MSP430 2001 MSP430 Windows Workbench Interface Guide Windows Workbench

More information

<4D F736F F F696E74202D BDE1B9B9BBAFB3CCD0F2C9E8BCC D20D1ADBBB7>

<4D F736F F F696E74202D BDE1B9B9BBAFB3CCD0F2C9E8BCC D20D1ADBBB7> 能源与动力工程学院 结构化编程 结构化程序设计 循环 循环结构 确定性循环 非确定性循环 I=1 sum=sum+i I = I +1 陈 斌 I>100 Yes No 目录 求和 :1+2+3++100 第四节循环的应用 PROGRAM GAUSS INTEGER I, SUM 计数器 SUM = 0 DO I = 1, 100, 1 SUM = SUM + I print*, I, SUM DO

More information

Microsoft PowerPoint - 4. 数组和字符串Arrays and Strings.ppt [兼容模式]

Microsoft PowerPoint - 4. 数组和字符串Arrays and Strings.ppt [兼容模式] Arrays and Strings 存储同类型的多个元素 Store multi elements of the same type 数组 (array) 存储固定数目的同类型元素 如整型数组存储的是一组整数, 字符数组存储的是一组字符 数组的大小称为数组的尺度 (dimension). 定义格式 : type arrayname[dimension]; 如声明 4 个元素的整型数组 :intarr[4];

More information

使用Delphi .NET开发-aimingoo

使用Delphi .NET开发-aimingoo Delphi.NET Using Delphi for Microsoft.NET Framework Development Delphi.NET Delphi.NET Delphi.NET Hello, World! Delphi.NET MS Internet Explorer 6.0 SP1 MS.NET Framework v1.1 MS.NET Framework SDK v1.1 MS

More information

RUN_PC連載_12_.doc

RUN_PC連載_12_.doc PowerBuilder 8 (12) PowerBuilder 8.0 PowerBuilder PowerBuilder 8 PowerBuilder 8 / IDE PowerBuilder PowerBuilder 8.0 PowerBuilder PowerBuilder PowerBuilder PowerBuilder 8.0 PowerBuilder 6 PowerBuilder 7

More information

CC213

CC213 : (Ken-Yi Lee), E-mail: feis.tw@gmail.com 49 [P.51] C/C++ [P.52] [P.53] [P.55] (int) [P.57] (float/double) [P.58] printf scanf [P.59] [P.61] ( / ) [P.62] (char) [P.65] : +-*/% [P.67] : = [P.68] : ,

More information

Microsoft Word - 《C语言开发入门》课程教学大纲-2.doc

Microsoft Word - 《C语言开发入门》课程教学大纲-2.doc C 语言开发入门 课程教学大纲 ( 课程英文名称 ) 课程编号 :201409210011 学分 :5 学分学时 :60 学时 ( 其中 : 讲课学时 :37 学时上机学时 :23 学时 ) 先修课程 : 计算机导论后续课程 :C++ 程序设计适用专业 : 信息及其计算机相关专业开课部门 : 计算机系 一 课程的性质与目标 C 语言开发入门 是计算机各专业必修的基础课程, 是数据结构 C++ Java

More information

WinMDI 28

WinMDI 28 WinMDI WinMDI 2 Region Gate Marker Quadrant Excel FACScan IBM-PC MO WinMDI WinMDI IBM-PC Dr. Joseph Trotter the Scripps Research Institute WinMDI HP PC WinMDI WinMDI PC MS WORD, PowerPoint, Excel, LOTUS

More information

Microsoft Word - CX1000-HMI_程序开发_PLC通讯

Microsoft Word - CX1000-HMI_程序开发_PLC通讯 用 VB.Net 开发 CX1000 的 HMI 第二部分和 TwinCAT PLC 通讯 一 TwinCAT 动态库 TwinCAT.Ads.dll The TwinCAT.Ads.dll 是一个.NET 类库, 它提供和 ADS 设备通讯的类 如果 TwinCAT PLC 运行在 IPC 上, 则需要添加的类库是路径 \TwinCAT\ADS Api\.NET\v1.1.4322 下的 TwinCAT.Ads.dll

More information

Microsoft PowerPoint - 5. 指针Pointers.ppt [兼容模式]

Microsoft PowerPoint - 5. 指针Pointers.ppt [兼容模式] 指针 Pointers 变量指针与指针变量 Pointer of a variable 变量与内存 (Variables and Memory) 当你声明一个变量时, 计算机将给该变量一个内存, 可以存储变量的值 当你使用变量时, 计算机将做两步操作 : - 根据变量名查找其对应的地址 ; - 通过地址对该地址的变量内容进行读 (retrieve) 或写 (set) 变量的地址称为变量的指针! C++

More information

6-1 Table Column Data Type Row Record 1. DBMS 2. DBMS MySQL Microsoft Access SQL Server Oracle 3. ODBC SQL 1. Structured Query Language 2. IBM

6-1 Table Column Data Type Row Record 1. DBMS 2. DBMS MySQL Microsoft Access SQL Server Oracle 3. ODBC SQL 1. Structured Query Language 2. IBM CHAPTER 6 SQL SQL SQL 6-1 Table Column Data Type Row Record 1. DBMS 2. DBMS MySQL Microsoft Access SQL Server Oracle 3. ODBC SQL 1. Structured Query Language 2. IBM 3. 1986 10 ANSI SQL ANSI X3. 135-1986

More information

目录 1 IPv6 快速转发 IPv6 快速转发配置命令 display ipv6 fast-forwarding aging-time display ipv6 fast-forwarding cache ipv6 fas

目录 1 IPv6 快速转发 IPv6 快速转发配置命令 display ipv6 fast-forwarding aging-time display ipv6 fast-forwarding cache ipv6 fas 目录 1 IPv6 快速转发 1-1 1.1 IPv6 快速转发配置命令 1-1 1.1.1 display ipv6 fast-forwarding aging-time 1-1 1.1.2 display ipv6 fast-forwarding cache 1-1 1.1.3 ipv6 fast-forwarding aging-time 1-3 1.1.4 ipv6 fast-forwarding

More information

(Load Project) (Save Project) (OffLine Mode) (Help) Intel Hex Motor

(Load Project) (Save Project) (OffLine Mode) (Help) Intel Hex Motor 1 4.1.1.1 (Load) 14 1.1 1 4.1.1.2 (Save) 14 1.1.1 1 4.1.2 (Buffer) 16 1.1.2 1 4.1.3 (Device) 16 1.1.3 1 4.1.3.1 (Select Device) 16 2 4.1.3.2 (Device Info) 16 2.1 2 4.1.3.3 (Adapter) 17 2.1.1 CD-ROM 2 4.1.4

More information

C/C++ - 文件IO

C/C++ - 文件IO C/C++ IO Table of contents 1. 2. 3. 4. 1 C ASCII ASCII ASCII 2 10000 00100111 00010000 31H, 30H, 30H, 30H, 30H 1, 0, 0, 0, 0 ASCII 3 4 5 UNIX ANSI C 5 FILE FILE 6 stdio.h typedef struct { int level ;

More information

Microsoft Word - 第3章.doc

Microsoft Word - 第3章.doc 第 3 章流程控制和数组 3.1 实验目的 (1) 熟练掌握控制台应用程序的代码编写和调试, 以及运行方法 (2) 掌握选择结构的一般语法格式和应用 (3) 掌握 switch 语句的用法 (4) 掌握选择结构的嵌套的用法, 能灵活使用选择结构解决实际问题 (5) 掌握 while 循环语句的一般语法格式 (6) 掌握 for 循环语句的一般语法格式 (7) 掌握循环嵌套的语法格式 (8) 掌握一维数组的定义

More information

<C8EBC3C5C6AAA3A8B5DA31D5C2A3A92E696E6464>

<C8EBC3C5C6AAA3A8B5DA31D5C2A3A92E696E6464> 第 1 章 进入 Photoshop 的全新世界 本章导读 Photoshop 1 1.1 Photoshop CS6 Photoshop Photoshop 1.1.1 Photoshop POP 1-1 图 1-1 平面广告效果 1.1.2 Photoshop 1-2 Photoshop CS6 Photoshop CS6 Photoshop CS6 Extended 3D 3 Photoshop

More information

没有幻灯片标题

没有幻灯片标题 指针作为函数参数 : 原因 : 1 需要修改一个或多个值,( 用 return 语句不能解决问题 ) 2 执行效率的角度 使用方法 : 在函数原型以及函数首部中需要声明能够接受指针值的形参, 具体的写法为 : 数据类型 * 形参名 如果有多个指针型形参, 则用逗号分隔, 例如 : void swap(int *p1, int *p2) 它说明了形参 p1 p2 是指向整型变量的指针 在函数调用时,

More information

Microsoft Word - 01.DOC

Microsoft Word - 01.DOC 第 1 章 JavaScript 简 介 JavaScript 是 NetScape 公 司 为 Navigator 浏 览 器 开 发 的, 是 写 在 HTML 文 件 中 的 一 种 脚 本 语 言, 能 实 现 网 页 内 容 的 交 互 显 示 当 用 户 在 客 户 端 显 示 该 网 页 时, 浏 览 器 就 会 执 行 JavaScript 程 序, 用 户 通 过 交 互 式 的

More information

untitled

untitled 1 Outline 數 料 數 數 列 亂數 練 數 數 數 來 數 數 來 數 料 利 料 來 數 A-Z a-z _ () 不 數 0-9 數 不 數 SCHOOL School school 數 讀 school_name schoolname 易 不 C# my name 7_eleven B&Q new C# (1) public protected private params override

More information

目录 1 IPv6 快速转发 IPv6 快速转发配置命令 display ipv6 fast-forwarding aging-time display ipv6 fast-forwarding cache ipv6 fas

目录 1 IPv6 快速转发 IPv6 快速转发配置命令 display ipv6 fast-forwarding aging-time display ipv6 fast-forwarding cache ipv6 fas 目录 1 IPv6 快速转发 1-1 1.1 IPv6 快速转发配置命令 1-1 1.1.1 display ipv6 fast-forwarding aging-time 1-1 1.1.2 display ipv6 fast-forwarding cache 1-1 1.1.3 ipv6 fast-forwarding aging-time 1-3 1.1.4 ipv6 fast-forwarding

More information

C#程序设计实验

C#程序设计实验 程序设计基础 实验指导 / 实验一 : 认识 C# 1 程序设计基础 实验指导 实验一 : 认识 C# 一 实验目的 1 掌握 Visual Studio 的基本操作方法, 学会使用该编译工具 2 掌握编辑 编译 运行控制台应用程序的基本过程 3 掌握建立 Windows 窗体应用程序的基本过程 4 通过运行 C# 程序, 初步了解 C# 程序的特点 二 实验学时 2 学时 三 实验类型 验证性实验

More information

Microsoft PowerPoint - 03.Fortran程序设计基础1

Microsoft PowerPoint - 03.Fortran程序设计基础1 简单 Fortran 90 程序的构造形式 : 第二讲 Fortran 程序设计基础 (2) [PROGRAM 程序名 ] [ 声明语句 ] [ 执行语句 ] END [PROGRAM [ 程序名 ]] 程序的书写 (P5) PROGRAM MONEY!calculate balance after interest compounded! 根据利息计算余额 REAL BALANCE, INTEREST,

More information

序 软 件 工 程 思 想 林 锐 序 软 件 工 程 思 想 讲 述 软 件 开 发 和 做 程 序 员 的 道 理, 视 野 独 特, 构 思 新 颖, 内 容 风 趣, 不 落 窠 臼, 令 人 耳 目 一 新 堪 称 难 得, 以 至 回 味 无 穷 作 者 从 事 了 八 年 的 软 件 开 发 工 作, 在 他 的 博 士 学 位 论 文 完 成 之 际 写 下 了 这 本 心 之 所 感

More information

无类继承.key

无类继承.key 无类继承 JavaScript 面向对象的根基 周爱 民 / aimingoo aiming@gmail.com https://aimingoo.github.io https://github.com/aimingoo rand = new Person("Rand McKinnon",... https://docs.oracle.com/cd/e19957-01/816-6408-10/object.htm#1193255

More information

27 :OPC 45 [4] (Automation Interface Standard), (Costom Interface Standard), OPC 2,,, VB Delphi OPC, OPC C++, OPC OPC OPC, [1] 1 OPC 1.1 OPC OPC(OLE f

27 :OPC 45 [4] (Automation Interface Standard), (Costom Interface Standard), OPC 2,,, VB Delphi OPC, OPC C++, OPC OPC OPC, [1] 1 OPC 1.1 OPC OPC(OLE f 27 1 Vol.27 No.1 CEMENTED CARBIDE 2010 2 Feb.2010!"!!!!"!!!!"!" doi:10.3969/j.issn.1003-7292.2010.01.011 OPC 1 1 2 1 (1., 412008; 2., 518052), OPC, WinCC VB,,, OPC ; ;VB ;WinCC Application of OPC Technology

More information

// HDevelopTemplateWPF projects located under %HALCONEXAMPLES%\c# using System; using HalconDotNet; public partial class HDevelopExport public HTuple

// HDevelopTemplateWPF projects located under %HALCONEXAMPLES%\c# using System; using HalconDotNet; public partial class HDevelopExport public HTuple halcon 与 C# 混合编程之 Halcon 代码调用 写在前面 完成 halcon 与 C# 混合编程的环境配置后, 进行界面布局设计构思每一个按钮所需要实现 的功能, 将 Halcon 导出的代码复制至相应的 C# 模块下即可 halcon 源程序 : dev_open_window(0, 0, 512, 512, 'black', WindowHandle) read_image (Image,

More information

用户大会 论文集2.2.doc

用户大会 论文集2.2.doc MagGis MapGis GIS MagGis API DLL MapGis VC++ VB BC++ Delphi., Windows API MapGis VC++V Delphi Delphi Delphi MapGis Delphi Delphi Windows Delphi Delphi MapGis MapGis DLL API MapGis function _InitWorkArea(HINST:Integer):Integer;

More information

科学计算的语言-FORTRAN95

科学计算的语言-FORTRAN95 科 学 计 算 的 语 言 -FORTRAN95 目 录 第 一 篇 闲 话 第 1 章 目 的 是 计 算 第 2 章 FORTRAN95 如 何 描 述 计 算 第 3 章 FORTRAN 的 编 译 系 统 第 二 篇 计 算 的 叙 述 第 4 章 FORTRAN95 语 言 的 形 貌 第 5 章 准 备 数 据 第 6 章 构 造 数 据 第 7 章 声 明 数 据 第 8 章 构 造

More information

《计算概论》课程 第十九讲 C 程序设计语言应用

《计算概论》课程 第十九讲  C 程序设计语言应用 计算概论 A 程序设计部分 字符数组与字符串 李戈 北京大学信息科学技术学院软件研究所 lige@sei.pku.edu.cn 字符数组的定义 #include int main() char a[10] = 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j' ; for (int i = 0; i < 10; i++) cout

More information

3.1 num = 3 ch = 'C' 2

3.1 num = 3 ch = 'C' 2 Java 1 3.1 num = 3 ch = 'C' 2 final 3.1 final : final final double PI=3.1415926; 3 3.2 4 int 3.2 (long int) (int) (short int) (byte) short sum; // sum 5 3.2 Java int long num=32967359818l; C:\java\app3_2.java:6:

More information

目 录(目录名)

目  录(目录名) 目录 目录...1-1 1.1 域名解析配置命令... 1-1 1.1.1 display dns domain... 1-1 1.1.2 display dns dynamic-host... 1-1 1.1.3 display dns server... 1-2 1.1.4 display ip host... 1-3 1.1.5 dns domain... 1-4 1.1.6 dns resolve...

More information

C/C++程序设计 - 字符串与格式化输入/输出

C/C++程序设计 - 字符串与格式化输入/输出 C/C++ / Table of contents 1. 2. 3. 4. 1 i # include # include // density of human body : 1. 04 e3 kg / m ^3 # define DENSITY 1. 04 e3 int main ( void ) { float weight, volume ; int

More information

JAVA 单元 2.1 四则运算机 ( 一 ) 单元教学进度设计 教学环节 教学内容 教师学生活动活动 反馈 反馈课前作业完成情况 反馈加分 1. 下面哪些是合法的变量名? ( ) A.2variable 答案 :DEG B..variable2 解答 : C.._whatavariable A:/

JAVA 单元 2.1 四则运算机 ( 一 ) 单元教学进度设计 教学环节 教学内容 教师学生活动活动 反馈 反馈课前作业完成情况 反馈加分 1. 下面哪些是合法的变量名? ( ) A.2variable 答案 :DEG B..variable2 解答 : C.._whatavariable A:/ 单元 2.1 四则运算机 ( 一 ) 单元教学进度设计 教学环节 教学内容 教师学生活动活动 反馈 反馈课前作业完成情况 反馈加分 1. 下面哪些是合法的变量名? ( ) A.2variable 答案 :DEG B..variable2 解答 : C.._whatavariable A:// 不能以数字开头 D._3_ B:// 不能用点和空格 提问 抢答 E.$anothervar C: // 不能用点和空格

More information

Python a p p l e b e a r c Fruit Animal a p p l e b e a r c 2-2

Python a p p l e b e a r c Fruit Animal a p p l e b e a r c 2-2 Chapter 02 變數與運算式 2.1 2.1.1 2.1.2 2.1.3 2.1.4 2.2 2.2.1 2.2.2 2.2.3 type 2.2.4 2.3 2.3.1 print 2.3.2 input 2.4 2.4.1 2.4.2 2.4.3 2.4.4 2.4.5 + 2.4.6 Python Python 2.1 2.1.1 a p p l e b e a r c 65438790

More information

untitled

untitled MODBUS 1 MODBUS...1 1...4 1.1...4 1.2...4 1.3...4 1.4... 2...5 2.1...5 2.2...5 3...6 3.1 OPENSERIAL...6 3.2 CLOSESERIAL...8 3.3 RDMULTIBIT...8 3.4 RDMULTIWORD...9 3.5 WRTONEBIT...11 3.6 WRTONEWORD...12

More information

领导,我不想写CSS代码.key

领导,我不想写CSS代码.key 领导 我不想写 CSS 张鑫旭 25MIN 2018-03-31 YUEWEN USER EXPERIENCE DESIGN 01 1 YUEWEN USER EXPERIENCE DESIGN 砖家 02 CSS - 艺术家 YUEWEN USER EXPERIENCE DESIGN 03 CSS - 砖家 艺术家 YUEWEN USER EXPERIENCE DESIGN 04 领导, 我不想写

More information

INTRODUCTION TO COM.DOC

INTRODUCTION TO COM.DOC How About COM & ActiveX Control With Visual C++ 6.0 Author: Curtis CHOU mahler@ms16.hinet.net This document can be freely release and distribute without modify. ACTIVEX CONTROLS... 3 ACTIVEX... 3 MFC ACTIVEX

More information

Oracle Solaris Studio makefile C C++ Fortran IDE Solaris Linux C/C++/Fortran IDE "Project Properties" IDE makefile 1.

Oracle Solaris Studio makefile C C++ Fortran IDE Solaris Linux C/C++/Fortran IDE Project Properties IDE makefile 1. Oracle Solaris Studio 12.2 IDE 2010 9 2 8 9 10 11 13 20 26 28 30 32 33 Oracle Solaris Studio makefile C C++ Fortran IDE Solaris Linux C/C++/Fortran IDE "Project Properties" IDE makefile 1. "File" > "New

More information

RUN_PC連載_10_.doc

RUN_PC連載_10_.doc PowerBuilder 8 (10) Jaguar CTS ASP Jaguar CTS PowerDynamo Jaguar CTS Microsoft ASP (Active Server Pages) ASP Jaguar CTS ASP Jaguar CTS ASP Jaguar CTS ASP Jaguar CTS ASP Jaguar CTS ASP Jaguar Server ASP

More information

( CIP) /. :, ( ) ISBN TP CIP ( 2005) : : : : * : : 174 ( A ) : : ( 023) : ( 023)

( CIP) /. :, ( ) ISBN TP CIP ( 2005) : : : : * : : 174 ( A ) : : ( 023) : ( 023) ( CIP) /. :, 2005. 2 ( ) ISBN 7-5624-3339-9.......... TP311. 1 CIP ( 2005) 011794 : : : : * : : 174 ( A ) :400030 : ( 023) 65102378 65105781 : ( 023) 65103686 65105565 : http: / /www. cqup. com. cn : fxk@cqup.

More information

ebook140-9

ebook140-9 9 VPN VPN Novell BorderManager Windows NT PPTP V P N L A V P N V N P I n t e r n e t V P N 9.1 V P N Windows 98 Windows PPTP VPN Novell BorderManager T M I P s e c Wi n d o w s I n t e r n e t I S P I

More information

RunPC2_.doc

RunPC2_.doc PowerBuilder 8 (5) PowerBuilder Client/Server Jaguar Server Jaguar Server Connection Cache Thin Client Internet Connection Pooling EAServer Connection Cache Connection Cache Connection Cache Connection

More information

ebook129-11

ebook129-11 11 TThread Wi n 32 16 Wi n d o w s Wi n 3 32 D e l p h i 11.1 3 Win32 API Wi n 32 C P U C P U 16 Windows 32 Delphi Delphi 1 11.1.1 16 Wi n 32 Windows 3.1 1 2 C P U 1 Windows 3.1 Wi n d o w s 16 Wi n d

More information

《C语言程序设计》教材习题参考答案

《C语言程序设计》教材习题参考答案 教材名称 : C 语言程序设计 ( 第 1 版 ) 黄保和 江弋编著清华大学出版社 ISBN:978-7-302-13599-9, 红色封面 答案制作时间 :2011 年 2 月 -5 月 一 选择题 1. 设已定义 int a, * p, 下列赋值表达式中正确的是 :C)p=&a 2. 设已定义 int x,*p=&x;, 则下列表达式中错误的是 :B)&*x 3. 若已定义 int a=1,*b=&a;,

More information

chap07.key

chap07.key #include void two(); void three(); int main() printf("i'm in main.\n"); two(); return 0; void two() printf("i'm in two.\n"); three(); void three() printf("i'm in three.\n"); void, int 标识符逗号分隔,

More information

Microsoft Word - 苹果脚本跟我学.doc

Microsoft Word - 苹果脚本跟我学.doc AppleScript for Absolute Starters 2 2 3 0 5 1 6 2 10 3 I 13 4 15 5 17 6 list 20 7 record 27 8 II 32 9 34 10 36 11 44 12 46 13 51 14 handler 57 15 62 63 3 AppleScript AppleScript AppleScript AppleScript

More information

《C语言程序设计》第2版教材习题参考答案

《C语言程序设计》第2版教材习题参考答案 教材 C 语言程序设计 ( 第 2 版 ) 清华大学出版社, 黄保和, 江弋编著 2011 年 10 月第二版 ISBN:978-7-302-26972-4 售价 :35 元 答案版本 本习题答案为 2012 年 2 月修订版本 一 选择题 1. 设已定义 int a, * p, 下列赋值表达式中正确的是 :C)p = &a A. *p = *a B. p = *a C.p = &a D. *p =

More information

设计模式 Design Patterns

设计模式 Design Patterns 丁勇 Email:18442056@QQ.com 学习目标 描述 JSP 表达式语言的语法 认识使用 JSP 表达式的优点 在 JSP 中使用表达式语言 表达式语言简介 5 1 EL 为表达式语言 由两个组开发 JSP 标准标签库专家组 JSP 2.0 专家组 JSP 表达式语言的语法 ${EL Expression} JSP EL 表达式用于以下情形 静态文本 标准标签和自定义标签 表达式语言简介

More information

Microsoft Word - template.doc

Microsoft Word - template.doc HGC efax Service User Guide I. Getting Started Page 1 II. Fax Forward Page 2 4 III. Web Viewing Page 5 7 IV. General Management Page 8 12 V. Help Desk Page 13 VI. Logout Page 13 Page 0 I. Getting Started

More information

OOP with Java 通知 Project 4: 5 月 2 日晚 9 点

OOP with Java 通知 Project 4: 5 月 2 日晚 9 点 OOP with Java Yuanbin Wu cs@ecnu OOP with Java 通知 Project 4: 5 月 2 日晚 9 点 复习 类的复用 组合 (composition): has-a 关系 class MyType { public int i; public double d; public char c; public void set(double x) { d =

More information

Strings

Strings Inheritance Cheng-Chin Chiang Relationships among Classes A 類 別 使 用 B 類 別 學 生 使 用 手 機 傳 遞 訊 息 公 司 使 用 金 庫 儲 存 重 要 文 件 人 類 使 用 交 通 工 具 旅 行 A 類 別 中 有 B 類 別 汽 車 有 輪 子 三 角 形 有 三 個 頂 點 電 腦 內 有 中 央 處 理 單 元 A

More information

<4D F736F F D D342DA57CA7DEA447B14D2DA475B57BBB50BADEB27AC3FEB14DA447B8D5C344>

<4D F736F F D D342DA57CA7DEA447B14D2DA475B57BBB50BADEB27AC3FEB14DA447B8D5C344> 1. 請 問 誰 提 出 積 體 電 路 (IC) 上 可 容 納 的 電 晶 體 數 目, 約 每 隔 24 個 月 (1975 年 更 改 為 18 個 月 ) 便 會 增 加 一 倍, 效 能 也 將 提 升 一 倍, 也 揭 示 了 資 訊 科 技 進 步 的 速 度? (A) 英 特 爾 (Intel) 公 司 創 始 人 戈 登. 摩 爾 (Gordon Moore) (B) 微 軟 (Microsoft)

More information

DR2010.doc

DR2010.doc DR/2010 HACH 11-8-96-2 HACH. DR/2010, / UL E79852 CSA C22.223 LR 58275 VDE GS 1015-92 FCC"A" 15 : AMADOR CORP, HACH. EN50 011/CISPR 11 "B" (EMI)/89/336/EEC/EMC: AMADOR CORP, HACH.. EN50 082-1( )/89/226/EEC

More information

Microsoft Word - 新1-12.doc

Microsoft Word - 新1-12.doc 实训 5 面向对象编程练习 实训 5 面向对象编程练习 5.1 实训目的 通过编程和上机实验理解 Java 语言是如何体现面向对象编程基本思想 以及如何创建类 和对象 了解成员变量和成员方法的特性 5.2 实训要求 编写一个体现面向对象思想的程序 编写一个创建对象和使用对象的方法的程序 5.3 实训内容 5.3.1 创建对象并使用对象 1 定义一个 Person 类 可以在应用程序中使用该类 成员属性

More information

Microsoft Word - 97.01.30軟體設計第二部份範例試題_C++_ _1_.doc

Microsoft Word - 97.01.30軟體設計第二部份範例試題_C++_ _1_.doc 電 腦 軟 體 設 計 乙 級 技 術 士 技 能 檢 定 術 科 測 試 範 例 試 題 (C++) 試 題 編 號 :11900-920201-4 審 定 日 期 : 94 年 7 月 1 日 修 訂 日 期 : 96 年 2 月 1 日 97 年 1 月 30 日 ( 第 二 部 份 ) 電 腦 軟 體 設 計 乙 級 技 術 士 技 能 檢 定 術 科 測 試 應 檢 參 考 資 料 壹 試

More information

OOP with Java 通知 : Project 2 提交时间 : 3 月 14 日晚 9 点 另一名助教 : 王桢

OOP with Java 通知 : Project 2 提交时间 : 3 月 14 日晚 9 点 另一名助教 : 王桢 OOP with Java Yuanbin Wu cs@ecnu OOP with Java 通知 : Project 2 提交时间 : 3 月 14 日晚 9 点 另一名助教 : 王桢 Email: 51141201063@ecnu.cn 复习 : Java 类型 基本类型 boolean, char, 封装 (wrappers) 类 (class) 定义 class MyType { int i;

More information

OOP with Java 通知 : Project 2 提交时间 : 3 月 15 日晚 9 点

OOP with Java 通知 : Project 2 提交时间 : 3 月 15 日晚 9 点 OOP with Java Yuanbin Wu cs@ecnu OOP with Java 通知 : Project 2 提交时间 : 3 月 15 日晚 9 点 复习 : Java 类型 基本类型 boolean, char, 封装 (wrappers) 类 (class) 定义 class MyType { int i; double d; 数据 (Fields) char c; void set(double

More information

EK-STM32F

EK-STM32F STMEVKIT-STM32F10xx8 软 件 开 发 入 门 指 南 目 录 1 EWARM 安 装... 1 1.1 第 一 步 : 在 线 注 册... 1 1.2 第 二 步 : 下 载 软 件... 2 1.3 第 三 步 : 安 装 EWARM... 3 2 基 于 STMEVKIT-STM32F10xx8 的 示 例 代 码 运 行... 6 2.1 GPIO Demo... 6 2.2

More information

untitled

untitled 8086/8088 CIP /. 2004.8 ISBN 7-03-014239-X.... TP313 CIP 2004 086019 16 100717 http://www.sciencep.com * 2004 8 2004 8 1 5 500 787 1092 1/16 16 1/2 391 000 1 2 ii 1 2 CAI CAI 3 To the teacher To the student

More information

基于ECO的UML模型驱动的数据库应用开发1.doc

基于ECO的UML模型驱动的数据库应用开发1.doc ECO UML () Object RDBMS Mapping.Net Framework Java C# RAD DataSetOleDbConnection DataGrod RAD Client/Server RAD RAD DataReader["Spell"].ToString() AObj.XXX bug sql UML OR Mapping RAD Lazy load round trip

More information

1 1 大概思路 创建 WebAPI 创建 CrossMainController 并编写 Nuget 安装 microsoft.aspnet.webapi.cors 跨域设置路由 编写 Jquery EasyUI 界面 运行效果 2 创建 WebAPI 创建 WebAPI, 新建 -> 项目 ->

1 1 大概思路 创建 WebAPI 创建 CrossMainController 并编写 Nuget 安装 microsoft.aspnet.webapi.cors 跨域设置路由 编写 Jquery EasyUI 界面 运行效果 2 创建 WebAPI 创建 WebAPI, 新建 -> 项目 -> 目录 1 大概思路... 1 2 创建 WebAPI... 1 3 创建 CrossMainController 并编写... 1 4 Nuget 安装 microsoft.aspnet.webapi.cors... 4 5 跨域设置路由... 4 6 编写 Jquery EasyUI 界面... 5 7 运行效果... 7 8 总结... 7 1 1 大概思路 创建 WebAPI 创建 CrossMainController

More information

mvc

mvc Build an application Tutor : Michael Pan Application Source codes - - Frameworks Xib files - - Resources - ( ) info.plist - UIKit Framework UIApplication Event status bar, icon... delegation [UIApplication

More information

Basic System Administration

Basic System Administration 基 本 系 统 管 理 ESX Server 3.5 ESX Server 3i 版 本 3.5 Virtual Center 2.5 基 本 管 理 指 南 基 本 管 理 指 南 修 订 时 间 :20080410 项 目 :VI-CHS-Q208-490 我 们 的 网 站 提 供 最 新 的 技 术 文 档, 网 址 为 : http://www.vmware.com/cn/support/

More information

Microsoft Word - 01.doc

Microsoft Word - 01.doc 1. 数据库系统的核心是 ( ) A. 数据库 B. 操作系统 C. 文件 D. 数据库管理系统 2. 数据模型是 ( ) 的集合 A. 文件 B. 记录 C. 数据 D. 记录及其联系 3. 数据库系统的组成包括 ( ) A. 数据库 DBMS 和数据库管理员 B. 数据库 DBMS 硬件 软件 C.DBMS 硬件 软件和数据库 D. 数据库 硬件 软件和数据库管理员 4.Visual FoxPro

More information

Microsoft Word Visual_Basic程序设计上机实践教程正文.doc

Microsoft Word Visual_Basic程序设计上机实践教程正文.doc 实验 3 顺序和分支结构程序设计 实验目的 1. 掌握顺序结构的程序设计思想 2. 掌握命令按钮 (CommandButton) 标签 (Label) 文本框 (TextBox) 编辑框 (EditBox) 等常用控件的使用方法 3. 了解并掌握对话框函数 MessageBox() 的含义与用法 4. 了解和熟悉线条控件 形状控件的画法以及主要属性的用法 实验内容 1. 顺序结构 实训 3-1 编写一应用程序,

More information

Microsoft Word - 3D手册2.doc

Microsoft Word - 3D手册2.doc 第 一 章 BLOCK 前 处 理 本 章 纲 要 : 1. BLOCK 前 处 理 1.1. 创 建 新 作 业 1.2. 设 定 模 拟 控 制 参 数 1.3. 输 入 对 象 数 据 1.4. 视 图 操 作 1.5. 选 择 点 1.6. 其 他 显 示 窗 口 图 标 钮 1.7. 保 存 作 业 1.8. 退 出 DEFORMTM3D 1 1. BLOCK 前 处 理 1.1. 创 建

More information

5. 利用对象监视器可以设置窗体或组件的 ( ) A. 方法 B. 属性 c. 外观 D. 执行代码 6. 编辑框 (Edi t) 中的文本发生改变时引发的事件是 ( ) A. AutoSize C. SetFocus B. OnChange D. SetText 7. 现建立一个简单报表, 要求其

5. 利用对象监视器可以设置窗体或组件的 ( ) A. 方法 B. 属性 c. 外观 D. 执行代码 6. 编辑框 (Edi t) 中的文本发生改变时引发的事件是 ( ) A. AutoSize C. SetFocus B. OnChange D. SetText 7. 现建立一个简单报表, 要求其 试卷代号 : 2 2 3 5 座位号仁口 国家开放大学 ( 中央广播电视大学 ) 2 0 1 4 年春季学期 " 开放专科 " 期末考试 Delphi 程序设计 试题 题号 一! 二 三 四! 五 总分 分数 I I I I I I I l 得分! 评卷人 I I I- 单项选择题 ( 3 0 分, 每题 3 分 ) 2014 年 7 月 1. 下面哪句话对 De l p hi 的描述是正确的 (

More information

PowerPoint Presentation

PowerPoint Presentation Visual Basic 2005 學 習 範 本 第 7 章 陣 列 的 活 用 7-1 陣 列 當 我 們 需 要 處 理 資 料 時, 都 使 用 變 數 來 存 放 資 料 因 為 一 個 變 數 只 能 代 表 一 個 資 料, 若 需 要 處 理 100 位 同 學 的 成 績 時, 便 要 使 用 100 個 不 同 的 變 數 名 稱, 這 不 但 會 增 加 變 數 名 稱 命 名

More information

Microsoft Word - OPIGIMAC 譯本.doc

Microsoft Word - OPIGIMAC 譯本.doc OPISYSTEMS OPIGIMAC 系 統 使 用 說 明 使 用 者 手 冊 OPI 版 本 7.0.X 140705 翻 譯 版 本 V1.0 Table of Contents 頁 數 1. 簡 介 3 2. 系 統 需 求 4 3. 安 裝 4 4. 開 始 OPIGIMAC 5 5. 功 能 列 7 6. 功 能 圖 示 鍵 10 7. 重 點 操 作 說 明 13 7-1. 設 定

More information

Microsoft Word - Data IO CS Calculate Method AppNote.doc

Microsoft Word - Data IO CS Calculate Method AppNote.doc Data I/O Checksum Calculation Methods Application Note (Chinese translation follows this English text.) General Description and Scope This document describes common checksum calculation methods for devices

More information

Microsoft Word - 正文.doc

Microsoft Word - 正文.doc 第 2 章 Java 语言基础 通过本章的实践, 要掌握 Java 中的标识符 关键字 常量, 熟练掌握算术 关 系 逻辑 条件 赋值 位运算符的使用, 掌握简单顺序结构的程序设计 2.1 典型习题解答 2.1 Java 中怎样进行注释? 解答 Java 语言中的注释有 3 种形式 : (1) 单行 : // (2) 多行 : /* */ (3) 文档注释 : /** */ 第三种形式是第二种形式的变形,

More information

audiogram3 Owners Manual

audiogram3 Owners Manual USB AUDIO INTERFACE ZH 2 AUDIOGRAM 3 ( ) * Yamaha USB Yamaha USB ( ) ( ) USB Yamaha (5)-10 1/2 AUDIOGRAM 3 3 MIC / INST (XLR ) (IEC60268 ): 1 2 (+) 3 (-) 2 1 3 Yamaha USB Yamaha Yamaha Steinberg Media

More information

epub 94-3

epub 94-3 3 A u t o C A D L AY E R L I N E T Y P E O S N A P S T Y L E X R E F - AutoLISP Object ARX A u t o C A D D C L A u t o C A D A u t o d e s k P D B D C L P D B D C L D C L 3.1 Wi n d o w s A u t o C A D

More information

untitled

untitled 21 Visual FoxPro Visual FoxPro 6.0 11 Visual FoxPro Visual FoxPro CIP Visual FoxPro 2004 21 ISBN 7-03-014834-7 V Visual FoxPro TP311.138 CIP 2004 143035 16 100717 http://www.sciencep.com * 2004 12 7871092

More information

untitled

untitled 2006 6 Geoframe Geoframe 4.0.3 Geoframe 1.2 1 Project Manager Project Management Create a new project Create a new project ( ) OK storage setting OK (Create charisma project extension) NO OK 2 Edit project

More information

<4D F736F F D E4345C6BDCCA84323B1E0B3CCD2AAB5E3D6AED2BB2E646F63>

<4D F736F F D E4345C6BDCCA84323B1E0B3CCD2AAB5E3D6AED2BB2E646F63> 基于 WINCE 平台 C# 编程要点之一 本文主要介绍在基于 Windows CE 平台的英创嵌入式主板下进行 C#(Microsoft Visual Stdio.Net 2005) 应用程序开发时会常常用到的一些功能函数以及开发方法, 这些方法适用于英创采用 WinCE 平台的所有型号嵌入式主板, 包括 EM9000 EM9260 EM9160 等 本文要点包括 : 文件的删除和复制 如何获取存取设备的空间大小

More information

f2.eps

f2.eps 前 言, 目 录 产 品 概 况 1 SICAM PAS SICAM 电 力 自 动 化 系 统 配 置 和 使 用 说 明 配 置 2 操 作 3 实 时 数 据 4 人 机 界 面 5 SINAUT LSA 转 换 器 6 状 态 与 控 制 信 息 A 版 本 号 : 08.03.05 附 录, 索 引 安 全 标 识 由 于 对 设 备 的 特 殊 操 作 往 往 需 要 一 些 特 殊 的

More information

Windows XP

Windows XP Windows XP What is Windows XP Windows is an Operating System An Operating System is the program that controls the hardware of your computer, and gives you an interface that allows you and other programs

More information

穨文件1

穨文件1 2-1 Access 2000 Visual Basic Access 2000 97 Office Visual Basic Visual Basic Visual Basic VBA Visual Basic Visual Basic 2-1-1 Visual Basic Access Visual Basic ( ) 2-1 2-1 Visual Basic 2-1 Microsoft Access

More information

2 1999 9 21 2001 21 2001 7 20 90 2002 9 2 21 4 38 30 3 ~ 6 3 2004 12 Ⅰ 1!!!!!!!!!!!!!!!!!!! 2 1. 1 2!!!!!!!!!!!!!!! 1. 2 8!!!!!!!!!!!! 1. 3 19!!!!!!!!!!!!!!!!! 2!!!!!!!!!!!!!!!!!!! 26 2. 1 26!!!!!!!!!!!!

More information

MVB-1001.DOC

MVB-1001.DOC 20 1.5 10 15 20 25 80 100 CSF 1. 2. 0105 3. 4. 5. 30% 1.5 0.75 1. Visual Basic Visual Basic (A) Visual Basic Enterprise Edition (B) Visual Basic Script Edition (C) Visual Basic Learning Edition (D) Visual

More information

F515_CS_Book.book

F515_CS_Book.book /USB , ( ) / L R 1 > > > 2, / 3 L 1 > > > 2 + - 3, 4 L 1 了解显示屏上显示的图标 Wap 信箱收到一条 Wap push 信息 ( ) GSM 手机已连接到 GSM 网络 指示条越多, 接收质量越好 2 ...........................4.............................. 4 Micro SD (

More information

Microsoft PowerPoint - string_kruse [兼容模式]

Microsoft PowerPoint - string_kruse [兼容模式] Strings Strings in C not encapsulated Every C-string has type char *. Hence, a C-string references an address in memory, the first of a contiguous set of bytes that store the characters making up the string.

More information