C++Builder 5.0编程指南(1)
打开BCB总是出现下面的四个窗口,并且默认创建一个可以立即执行的空应用程序,这个程序只有一个和窗口设计界面一样的窗口。(^60090205a^)
1. 对象观察窗口(Object Inspector)
浏览和修改对象的属性(Properties)和事件(Events)。打开查看窗口的快捷键是F11,
每个对象都有特定的属性和事件,我们将在后面做介绍(^60090205b^)。
2. 代码编辑窗口
(^60090205c^)
代码窗口左边的代码浏览器,列出了代码结构,可以通过它快速定位到特定的代码段。代码编辑器具有很强的自动感应功能,只要程序员键入“->”或者“.”符号,立即就显示出成员变量和成员函数的索引,极大提高了代码的书写效率和准确率,使用“Ctrl+空格”组合键也相同的功能。可是在中文Windows系统下“Ctrl+空格”是打开默认中文输入法,这就要在控制面板中的输入法设定中修改热键了。同样,在编写调用某个函数的代码中键入左括号,编辑器将提示函数的参数名和类别,此功能的组合键是“Ctrl+Shift+空格”。
3.BCB5.0的主菜单和工具栏按钮
BCB的全部功能都能在主菜单中找到相应的菜单项。下面作一个简单介绍:
(1)File菜单
(^60090205d^)
创建项目的选择窗口:
包含各种类型的程序单元及一些对象创建向导,New页面包含最常用的项目:
Application:创建一个新的工程,包含一个窗口和窗口的单元文件(.cpp和.h);
Batch File:创建扩展名为.bat的批处理文件;
Component:打开组件创建向导;
Console Wizard:打开控制台程序创建向导;
Cpp File:添加一个.cpp文件;
Data Module:创建一个新的数据模块;
DLL Wizard:打开DLL(动态连接库)创建向导;
Form:添加一个空白窗口到当前工程;
Frame:创建一个组件框架;
Header File:添加一个头文件;
Library:创建一个库;
Package:创建一个组件包,可以封装方法并将包中组件安装到BCB的组件栏中;
Project Group:创建一个新的工程组;
Remote Data Module:创建一个远程数据模块;
Report:创建数据报表;
Resource DLL Wizard:打开创建资源DLL的向导;
Text:新建一个文本文件;
Thread Object:在当前工程中创建一个线程;
Unit:添加一个单元(包含一个.cpp文件和一个.h文件)。
(2)Edit菜单
(^60090205e^)
(3)Search菜单
(^60090205f^)
(4)View菜单
(^60090205g^)
(5)Project菜单
(^60090205h^)
(6)Run菜单
(^60090205i^)
(7)Component菜单
(^60090205j^)
(8)Database菜单
(^60090205k^)
(9)Tools菜单
(^60090205l^)
(10)Help菜单
BCB带有非常详尽的Help文本,还有非常详细的WinAPI函数文档,在IDE的任何位置按F1键都可以找到相关的资料。
#1 二、界面设计
大多数Windows下的应用程序是由Windows提供的基本元素组成,例如应用程序的窗口、按钮或者是菜单。BCB为我们提供了大量的窗口、按钮、文字输入框等,它们就是BCB中的组件。每个组件都由自己特定的功能,程序员只用关注组件具有什么功能、能够实现什么效果,而不必去考虑这个组件是怎样制作,或者它是由什么制作。这样我们编写程序就像搭积木一样,一块一块的将零散的部件通过我们的代码就连接成为一个整体。
在这里我们首先了解怎样将BCB提供的组件添加到程序的窗口上。
组件分为可视组件和不可视组件:可视组件在工程设计或者运行阶段是可以显示的,如按钮、窗口等;不可视组件只是提供某种功能的实现而没有可视的界面,如对话框组件。
在组件栏中选择一个组件(鼠标单击),然后在设计界面的窗口中用鼠标拖出组件的大小,或者双击组件栏上组件的图标,按组件默认大小和位置添加到设计窗口。同时组件也支持复制、粘贴等操作,粘贴的组件和复制的组件有相近的属性。
1.调整组件的位置
调整组件位置有很多的技巧,可以用鼠标拖动,也可以在属性编辑窗口中调整组件的位置属性,也可以使用Ctrl+上、下、左、右方向键,或者是Ctrl+Shift+方向键,或者使用Edit菜单中的Align(对齐)功能来实现。
为了避免误操作改变组件的位置,可以在Edit菜单中选择Lock Controls功能,这时候就只能用修改属性和菜单中的调整功能了。
2.选择组件
可以用鼠标框线、Shift或者Ctrl键加鼠标单击组件的方式一次选择多个组件进行控制。在设计窗口的空白处单击鼠标左键不放,拖动鼠标,让虚线框框住一个或多个组件,放开鼠标按键就完成选择,但是一些组件是添加在其它组件中间的,鼠标拖拽会带动组件移动,可以按住Ctrl键完成框选工作来避免。
当我们需要选择一个组件,然而这个组件恰好被其它组件完全覆盖时,可以在对象观察窗口中选择它,或者选择到这个组件中包含的子组件,然后按下Esc键。同样再次按下Esc键会选择到这个组件的父组件,最终会选择到包含这些组件的窗口。
3.使用对象观察窗口
对象观察窗口会显示当前选中组件的属性和事件,如果选中的是多个组件,则显示这些组件相同的属性和事件。
现在我们学会了把组件放上窗口,在让它们为我们工作以前,我们得先学会一种能管理和指挥它们的语言C/C++。Borland C++ Builder(BCB)是工具,而C/C++才是语言。
#1 三、什么是C/C++?
C语言是使用非常广泛的编程语言,C++是在C语言的基础上发展而来的,可以说C++是C的超集。C++兼容C的很多语法,但是也有C没有的限制,不过C编写的代码可以在C++中进行少量修改或者无需修改就可以正常运行。
1.编写C/C++代码
void __fastcall TForm1::FormCreate(Tobject *Sender)
{
Form1->Caption = "Hello World!";
}
这条简单的语句意思是在创建窗口时将窗口(Form1)的标题(Caption)设定为"Hello World!"。其中
void __fastcall TForm1::FormCreate(Tobject *Sender)
{
}
是由编辑器自动生成的。在设计窗口的空白处双击鼠标,代码窗口中就会定位在窗口的创建函数中。在对象观察窗口的Events(事件)页面,双击某个事件,编辑器也会自动生成该事件的处理函数。关于具体组件的属性和事件将在VCL组件的应用中详细说明,这里我们重点关注C/C++的语法特点。
C/C++代码的书写给程序员很大的灵活性,代码并不需要写在同一行上,每个语句总是以分号结束。上面的语句可以写成:
Form1->Caption =
"Hello World!";
2.变量、赋值
变量可以储存一定的数据,变量名由英文字母、数字和下划线组成,必须以英文字母或者下划线开头,一般编译器将下划线开头的变量作为特殊变量或者函数的开始。特别注意的是C/C++是区分大小写的,XYZ和xyz是两个不同的变量。
变量声明由变量类型、变量名称组成:int a; //声明变量a为整型变量
双斜杆(//)是行注释符,它后面到行结束都是注释。C/C++也支持多行注释/*(注释开始)和?*/(注释结束)
声明过的变量如果不赋一个初值,那么变量的值将是不确定的,这和VB等语言不同,必须养成在使用变量或者其它对象前进行初始化。C/C++允许变量在声明的时候赋一个初始值:int a = 100; 声明整型变量a,值为100
也可以同时声明几个变量:int a, b = 10, c = 2; 声明了a,b,c三个变量,b,c有初始值。
3.变量的作用域
变量的作用域决定了变量的使用范围,分为局部变量(Local)、全局变量(global)、静态变量(static)和外部变量(external)。
局部变量的作用域只是在一个函数的内部,变量值的改变不会影响函数外同名变量。
Void __fastcall TForm1::FormCreate(Tobject *Sender)
{
int x, y; //声明局部变量x, y
x = 10;
y = 25;
ShowMessage((String)(x * y)); //显示x, y相乘的结果
}
x, y就是局部变量,只能在函数中使用,函数结束它们就被释放了。
C/C++的初学者可能会对ShowMessage((String)(x * y))有疑惑。ShowMessage是Windows的API函数,作用是显示一个消息窗口,消息内容是这个函数的参数,参数是字符串型变量,(x * y)是整数型,不能直接赋值,因此需要使用强制转换语句(String)转化。
静态变量与局部变量不同的是,变量只在第一次调用函数时赋初值,函数完成时保持变量值不变。
Void teststatic()
{
statics int Count = 0; //声明一个静态变量,赋初值为0
Count = Count + 1; //每调用一次函数Count加1
ShowMessage((String)Count); //显示函数调用次数
}
同时Count又是teststatic函数的私有变量,因此不会被其它函数改变。
全局变量在整个单元中可以被本单元的所有函数访问和修改,全局变量需要在函数体外声明,或者在单元的头文件中声明(.h),在一个新工程的窗口代码中可以看到有一个:
TForm1 *Form1;
Form1是一个全局变量,也是一个指针类型的变量。
外部变量将局部变量的作用范围扩大到整个应用程序,需要通过extern关键字声明。在代码编辑窗口中点击鼠标右键,在弹出菜单中选择 Open Source/Header File, 打开单元头文件就能看到 extern PACKAGE TForm1 *Form1; 将变量Form1声明为一个外部变量,让整个工程的单元都能够访问它。
4.变量类型
C/C++支持一系列基本的数据类型,这些类型是由语言本身定义的,其它的任何数据类型都建立在这些基本类型的基础上。(^60090205m^)
signed和unsigned是变量有无符号的修饰词,除了char类型外其它类型都是默认有符号(signed)。浮点类型变量受到计算机处理的精度限制,无法处理非常接近0的数字,只要对精度要求不是很高,我们都认为浮点类型是准确的。、
5.运算符
C/C++支持大量的运算符,功能强大,相对其它语言显得很复杂。对于初学者主要建立对这些运算符的印象,并不需要立即把它们都弄明白。
(^60090205n^)
#1 四、最常用的控制结构
控制结构可以用清晰的方式描述判断和循环。这里介绍最常用的if、while、for、do、switch。
1.If语句
语法:if(表达式)语句 [else 语句]
if(表达式){执行代码} [else {执行代码}]
方括号中的部分是可以省略的。
例子:
if(a == 0)ShowMessage("a 等于 0");
if(a == 0)ShowMessage("a 等于 0"); else ShowMessage("a 不等于 0");
if(a == 0){
…
} else {
…
}
大括号{}中间可以由多条语句组成,if语句也可以嵌套使用,如:
if(表达式){执行代码} else if(表达式){执行代码}
2.while语句
循环控制语句,原型:
while(表达式)语句
while(表达式){执行代码}
如:
while(count < 10){ //做十次循环
…
count++;
}
3.Do语句
循环控制语句,原型:
do 语句 while(表达式)
do {执行代码} while(表达式)
与while不同,do语句判断是否继续循环的控制条件是放在做完一次循环以后,就是说无论怎样,do都要完成第一次循环。当表达式值为假时就停止循环。
4.For语句
for循环是一个确定,不像while用一个表达式来控制循环,它的原型:
for([初始化条件] ; [循环结束条件] ; [增量])执行代码
for(int a = 0; a < 10; a++){…} //做十次循环
原形中方括号部分可以省略,上面的程序也可以写为:
int a = 0;
for(;a++ < 10;a++){…}
5.Switch语句
条件选择语句,根据控制表达式的值选择执行相应的代码,原型:
switch(表达式)
{
case 值1 :
执行代码
[break;]
case 值2 :
执行代码
[break;]
…
[default :
默认执行代码]
}
switch先计算表达式的值,然后执行对应的case部分。如果没有对应的case部分就转到default部分,用break表示结束,否则将执行到下面的分枝。Switch只能对整数操作,不支持对字符串和对象的操作。
Char c;
…
switch(c)
{
case 'a' :
case 'b' :
case 'c' :
ShowMessage("有效值");
break;
case 'd' :
ShowMessage("无效值");
break;
default : ShowMessage("不确定值");
}
只要c等于'a', 'b'或者'c'都显示有效值。
#1 五、指针
指针使得C/C++语言变得强大,也让人难以理解,是众多朋友学习C/C++一大障碍。
我们应该怎么理解指针?
简单来说指针就是存贮内存地址的变量。
(^60090205o^)
看起来指针像个整型变量,它的特殊意义在于告诉处理器在内存的哪个位置可以找到数据。*p就可以访问p指针指向的值,如上面例子中的128。
【指针和实例】
int a = 128, b;
b = a;
a, b是int型变量,a对b赋值是数据拷贝,修改一个变量的值不会影响另一个变量。
Int a = 128;
int *p = &a;
由于*p和a是指向同一个内存地址的值,所以
a = 32; 或 *p = 32;
它们是等价的。
实际上我们很少用int类型的指针,因为这样意义并不大(除非作为函数可变参数,下一节函数将介绍),只是作为例子帮助大家理解指针。指针在大多数时候用作大量数据的传送。
使用指针必须先为指针分配内存,且在使用完以后需要释放分配的内存:
String *vStr;
vStr = new String; //为vStr分配内存空间
*vStr = "Hello World!";
String S = *vStr; //赋值给字符串实例S
delete vStr; //释放指针
对于例子中的实例S,访问它的成员要使用直接访问符号(.)
S.Length() //计算字符串的长度
而指针vStr访问成员就必须使用间接访问符号(->)
vStr->Length()
【指针与数组】
int a[100]; //声明包含100个整型变量的数组
int I = 0;
while(I < 100)a[I++] = 25; //将数组中的每个元素初始化为25
如果用指针来做:
int a[100]
int I = 0;
int *p = a; //将数组a的开始地址传给指针
while(I < 100)*p++ = 25;
p首先指向a[0],*p赋值为25,指针下移指向a[1]
#1 六、函数
在使用函数前必须对函数进行声明,还需要写函数的具体代码。声明函数的原型:
函数返回类型 函数名([参数]);
例如:int add(int a, b);
函数的实现代码:
int add(int a, int b) //必须和声明的函数原形一致
{
return a + b; //返回a + b的值
}
以后我们就可以对函数add进行调用:add(3, 5);
如果函数不返回任何值,那么它的类型为void
void doSomething(int param);
函数不需要return语句返回值,但是可以用return;提前退出函数。
Void doSomething(int ¶m)
int a = 100;
void doSomething1(int ¶m)
void doSomething2(int param)
void doSomething1(int ¶m)
{
*param = 25;
}
void doSomething2(int param)
{
param = 25;
}
doSomething2(a);
ShowMessage((String)a); //a等于100,值没有被改变;
doSomething1(a);
ShowMessage((String)a); //a等于25;
【函数的重载】
函数名称相同,有两种或几种不同的参数或返回值,编译器根据调用函数时的参数,选择对应的函数执行。下面的例子是一个类似条件运算符(?:)的函数。
Int iif(bool express, int truevalue, int falsevalue);
String iif(bool express, String truevalue, String falsevalue);
int iif(bool express, int truevalue, int falsevalue)
{
if(express)return truevalue; else return falsevalue;
}
String iif(bool express, String truevalue, String falsevalue)
{
if(express)return truevalue; else return falsevalue;
}
int a;
……
ShowMessage(iif(a > 2, "a大于2", "a小于等于2"));
int c = iif(a > 2, a * 10, a);
【怎样声明、使用函数指针】
一般函数的指针是在调用动态连接库里的函数和回调函数时使用。声明函数指针和声明变量指针有很大差别:
void(*p)(); //声明一个没有参数,无返回值的函数指针p
可以将函数 void doSometing(); 的地址赋给p
p = &doSomething;
p(); //调用doSomething
我们可以用更灵活的方式来使用指针:
int __fastcall doSomething(int param); //doSomething函数的原形
Pointer p = &doSomething; //声明p为一个指针指向doSomething的地址
由于Pointer是没有规定类型的指针,所以在使用p调用doSomgthing函数时要先结果类型转换。
((int(__fastcall *)(int param))p)(5);
#1 七、枚举、结构、类
【枚举变量】
枚举是一系列的条目。每个条目由编译器或者程序员分配一个识别数字,在编程的时候需要定义一系列常量(const),且保证这些常量各不相同,那么使用枚举将是非常有效率的。枚举的语法格式:
enum [枚举名称] {
项目名称, 项目名称, ……
} [枚举变量名称];
方括号([])中的内容是可以省略的
enum TMyColor {Red, White, Yellow}MyColor;
MyColor = Red;
enum TMyNum {twelve = 12, thirteen, twenty = 20, twenty_one}; //注意:省略了枚举变量名但是不能省略最后的分号
twelve指定值为12,那么thirteen就是它前面一个值加1即13
TMyNum MyNum; //声明MyNum是枚举变量
MyNum = twelve; 或者可以写成 MyNum = (TMyNum)12;
【结构】
结构由struct或者union关键字声明,结构包含各种成员,是公有访问类型数据成员的集合。它的语法格式如下:
struct 名称 [: 基类] {
数据类型的声明
}[变量名];
enum Tsex {male , female};
struct Temployee {
String name;
Tsex sex;
int age;
};
定义一个包含雇员的姓名、性别和年龄的结构:
Temployee employee; //声明变量
emploree.name = "小丽";
employee.sex = female;
employee.age = 21;
结构是具有继承性的,它可以继承基类中的成员:
struct Tperson : Temployee //从Temployee继承
{
String work;
float income;
};
Tperson person;
person.name = "小丽"; //从Temployee继承过来的成员
person.work = "秘书"; //Tperson自身的成员
……
union和struct在语法上是一致的,不同的是union内部的所有成员都使用相同的内存地址和共同的内存空间,在你需要不同的时候保存不同类型的变量时这将非常有用。
Enum {Int, Float, Char};
struct Tcommondata {
int data_type;
union {
int intdata;
float floatdata;
char chardata;
};
}commondata;
commondata.data_type = Int; //表明存放的是整型变量
commondata.intdata = 10;
commondata.data_type = Char; //表明存放的是字符变量
commondata.chardata = 'A';
struct和union可以包含多个struct或union结构:
enum {Int, Float, Char};
struct Tcommondata {
int data_type;
union {
int intdata;
float floatdata;
char chardata;
};
struct {
Pointer p;
} datapoint;
}commondata;
……
commondata.data_type = Int; //表明存放的是整型变量
commondata.intdata = 10;
commondata.datapoint.p = NULL; //赋一个空指针