第三章 记事本程序设计.docx
《第三章 记事本程序设计.docx》由会员分享,可在线阅读,更多相关《第三章 记事本程序设计.docx(104页珍藏版)》请在冰豆网上搜索。
第三章记事本程序设计
第三章记事本程序设计
3.1记事本程序特点及设计目的
记事本程序是Windows系统提供给用户的一个简单的文本编辑器,用于编辑、阅读文本格式的文件(一般以.txt为文本文件后缀)。
本章以VisualBasic的文本框控件为主要对象,设计自己的记事本程序,除了Windows系统的记事本主要功能外,还增加了自动翻页功能,即在设定时间内自动向后滚动一行,而无需人工翻页阅读。
3.1.1记事本程序设计目的
记事本程序设计的主要目的如下:
1)进一步掌握VisualBasic窗口对象、文本框对象的基本属性和事件。
2)掌握VisualBasic组合框、检查框、单选按钮对象基本属性、方法和事件。
3)了解文件的基本概念、分类。
掌握文本文件和二进制文件的存储格式以及它们的读写方法。
4)掌握分支条件、Do…Loop循环、With与EndWith等基本语句。
5)掌握子程序的定义与调用方法。
6)掌握下拉菜单和弹出菜单的设计及其代码编写。
7)掌握Windows提供的通用对话框对象,应用该对象实现文件选择、字体选择和颜色选择功能。
8)掌握VisualBasic6.0的自定义类型,并利用自定义类型实现应用程序的参数保存功能。
9)掌握MsgBox等基本函数。
10)掌握给VisualBasic工程添加控件和对象的方法。
11)了解VisualBasic6.0工具栏和状态栏的设计与代码编写。
12)了解VisualBasic6.0的剪贴板对象,并应用该对象实现剪切、复制、粘贴等编辑功能。
13)了解App对象。
14)通过API函数SendMessage,了解与文本框有关的消息,利用这些消息,获取光标所在位置、文档的修改标志等信息。
15)了解对象类型变量,了解FSO对象模型
16)了解OLE拖放操作
17)了解文件操作语句和文件系统控件
3.1.2记事本程序的功能
记事本程序的主要功能是显示、编辑文本文件。
设计的主要内容如下:
1)利用文本框TextBox对象,实现文本的显示与编辑。
2)编辑菜单,实现文件新建、打开、保存功能;文字复制、剪切与粘贴功能等
3)利用通用对话框,选择文字显示的字体和颜色。
4)实现自动翻页或滚动功能。
5)利用状态栏,显示文档当前位置。
6)具备参数设置功能,将是否滚动、滚动速度等参数保存到特定的二进制文件中
3.2基本语法要求
3.2.1对象变量的定义与赋值
VisualBasic6.0除了可以定义普通变量保存整数、小数、字符串、日期以外,还可以定义特殊的变量类型,即对象类型变量,用于保存对象信息。
所有的VisualBasic6.0对象都属于Object类型,可以定义一个Object类型的变量,用于保存一个文本框对象Text1或一个AutoCAD对象。
所有控件类型的对象又都属于Control类型,可以定义一个Control类型的变量,用于保存一个文本框对象Text1或一个命令按钮对象Command1。
VisualBasic6.0使用的每种对象都具有自己所属的类型,如文本框对象都属于TextBox类型、命令按钮对象都属于CommandButton类型等。
可以定义一个TextBox类型的变量,用于保存一个文本框对象Text1。
VisualBasic6.0究竟可以使用多少对象类型并不确定,与计算机系统中安装了多少应用程序有关,如果安装了AutoCAD,则可以使用AutoCAD对象。
对象类型变量定义与普通类型变量定义采用相同的关键词:
Dim、Private、Static、Public和Global。
例如:
DimO1AsObject
DimC1AsControl
DimT1AsTextBox
DimE1AsExcel.Application
DimF1AsForm
DimD1AsDataBase
以上语句分别定义了对象类型、控件类型、文本框类型、Excel应用程序类型、窗口类型、数据库类型的变量。
也可以采用类型定义语句DefObj将以某些字母开头的变量统一定义成Object类型,如DefObjO-Q语句将所有以字母O、P、Q开头的变量均定义成Object类型。
对象类型变量定义的目的是用于保存某个对象,而上述定义的各个对象类型变量仅仅进行了定义,变量中并没有真正保存任何对象,也就是说,对象并不存在,这样的变量不能用于实际操作,只有给对象类型变量赋值以后,对象才存在,也就可以操作这些变量。
如上面的变量T1,只是说明它能够保存TextBox类型的对象,并不存在一个称为T1的文本框对象,只有将某个TextBox类型的对象赋值给T1后才存在这样的对象,才可以操作它。
对象类型变量是一种特殊的变量,其赋值方法与普通变量有所区别,在赋值语句前加上关键词Set。
如将文本框Text1赋值给TextBox类型的变量T1,采用如下格式:
SetT1=Text1
前面的Set一定不能省,否则运行时出错。
某些对象类型的变量,可以在定义时直接创建一个新对象,定义格式如下:
DimfsAsNewFileSystemObject
上面的语句定义了一个FileSystemObject类型(文件系统对象)的对象变量fs,由于采用了New关键词,表示在定义时就创建fs对象,以后不需要再给fs变量赋值,直接使用该变量即可。
能够采用New关键词定义的变量并不多,如Object、Control、TextBox、CommandButton等类型都不能采用New关键词创建。
通常情况下,对象类型变量定义时As或New后面是该变量的类型,而不是一个具体的对象,如前面的FileSystemObject、TextBox、Control、Form、DataBase等,但有一个特例:
具体的某个窗口对象可以作为一个新的类型,即可以定义一个新的变量,其类型为某个已经存在的具体窗口:
Dimf1AsNewForm2
这里的变量f1是以窗口Form2为类型的一个新变量,由于采用了New关键词,该变量在定义时就可以存在,可以直接采用如下语句显示这个新的窗口:
f1.Show
采用这种方法定义的只有某个具体窗口,其它的各种控件对象都不能采用这种方法定义,下面这些定义是错误的:
DimT1AsText1
DimC1AsCommand1
对象类型的变量用于保存对象的有关信息,需要占用一定的资源,在使用完对象类型变量后,应该释放其占用的资源,即将常量Nothing赋值给对象变量:
Sett1=Nothing
在VisualBasic6.0的集成开发环境中,新创建的工程只能使用少量几种对象类型,如果需要使用其它对象类型,必须将其引入到当前工程中(“Project”菜单的“References”子菜单,参见第一章1.3.4节),如前面的FileSystemObject、Excel.Application等都需要通过“References”子菜单将它们引入到当前工程。
3.2.2SelectCase分支语句
第二章介绍并使用了If条件语句,If条件广泛应用于各种条件判断的场合,在条件分支比较少的情况下,If条件层次结构比较清楚,当条件分支比较多时,若干个ElseIf使得整个条件分支结构变得很复杂,为此,VisualBasic提供了另外一种层次清晰的条件分支语句SelecteCase,其格式如下:
SelectCase变量或表达式
Case表达式列表1
语句块1
Case表达式列表2
语句块2
….
CaseElse
语句块n+1
EndSelect
SelectCase后面的变量或表达式为测试表达式,它类型可以是数值型、字符串型、日期型等,根据测试表达式的值,决定程序的流程。
一旦测试表达式与某个Case后的表达式列表匹配,则执行这个Case后面的语句,完成后跳出这个分支结构,执行EndSelect以后的语句;如果所有Case后的表达式都不与测试表达式匹配,则执行CaseElse后的语句。
每个Case分支后面的表达式列表可以由四种不同形式组成:
●单个常量、变量或表达式
●用“,”逗号分隔的几个常量
●用To连接的某个范围的常量
●用Is和比较符号>、<等组成的比较表达式
例如:
分支Case1,3To10,Is>30表示某个变量或表达式等于1或3到10或大于30。
每个SelectCase语句必须与一个EndSelect配对使用。
SelectCase往往应用于分支较多且只有一个比较变量或表达式的场合。
SelectCase可以自己嵌套使用,即每个Case分支的执行语句块部分又可以使用其它SelectCase分支语句。
也可以与If条件嵌套使用。
【例3.1】采用SelectCase分支条件,根据变量Score的值,在标签Label1中显示“优”、“良”、“中”、“及格”和“不及格”。
SelectCaseScore
Case90To100
Label1.Caption="优"
Case80To89
Label1.Caption="良"
Case70To79
Label1.Caption="中"
Case60To69
Label1.Caption="及格"
CaseIs<60
Label1.Caption="不及格"
CaseElse
Label1.Caption="成绩超过范围"
EndSelect
上述代码的每个分支都是用To表示的一个范围,可以对其进行适当处理,用Score\10作为测试表达式,这里的“\”是整除运算符,0到100的数据整除10的结果为0到10。
SelectCaseScore\10
Case9To10
Label1.Caption="优"
Case8
Label1.Caption="良"
Case7
Label1.Caption="中"
Case6
Label1.Caption="及格"
CaseIs<6
Label1.Caption="不及格"
CaseElse
Label1.Caption="成绩超过范围"
EndSelect
3.2.3Do…Loop循环语句
程序中经常需要重复执行一段代码,这种流程一般采用循环语句进行,具有两种不同情况:
循环次数已知和循环次数未知。
VisualBasic中对于循环次数已知的情况采用For…Next循环,而对循环次数未知的情况则采用Do…Loop或While…Wend循环。
Do…Loop循环是根据条件决定是否继续循环,往往与两个关键词While和Until配合使用,While表示条件满足时循环,而Until则表示条件满足时结束循环。
DoLoop循环共有五种不同格式。
格式一:
Do
循环体
[ExitDo]
Loop
格式二:
DoWhile条件
循环体
[ExitDo]
Loop
格式三:
DoUntil条件
循环体
[ExitDo]
Loop
格式四:
Do
循环体
[ExitDo]
LoopWhile条件
格式五:
Do
循环体
[ExitDo]
LoopUntil条件
格式一没有While或Until,DoLoop循环实际形成了无限循环(死循环),循环体内必须根据条件采用语句ExitDo退出循环。
格式二、三的条件判断在放Do关键词后面,而格式四、五的条件判断则放在Loop关键词后面。
Do后面的While/Until表示先进行条件判断,再决定是否进行循环,如果条件不合适,有可能一次也不执行循环体内的代码;而Loop后面的While/Until则表示先进入循环,再判断条件,决定是否重复执行循环体内代码,这种格式循环最起码会执行一次循环体内代码。
对于Do…Loop循环,循环体内一定要有能够使条件由不满足变成满足的语句,即必须保证在重复若干次以后能够结束循环。
【例3.2】应用Do…Loop循环计算1+2+…+100的和
对于这样的循环计算,其循环次数已知,一般采用ForNext循环,本章为了介绍Do…Loop循环,故采用Do…Loop循环计算,可以使用前述的五种格式中的任意一种。
下面分别采用格式一、二、三实现了该计算功能。
PrivateSubCommand1_Click()
DimiAsInteger,SumAsInteger
i=1
Do
Sum=Sum+i
i=i+1
Ifi>100ThenExitDo
Loop
Label1.Caption=Sum
EndSub
PrivateSubCommand1_Click()
DimiAsInteger,SumAsInteger
i=1
DoWhilei<=100
Sum=Sum+i
i=i+1
Loop
Label1.Caption=Sum
EndSub
PrivateSubCommand1_Click()
DimiAsInteger,SumAsInteger
i=1
DoUntili>100
Sum=Sum+i
i=i+1
Loop
Label1.Caption=Sum
EndSub
为了调试本示例,需要先在窗口中添加一个标签对象Label1和一个命令按钮对象Command1。
【例3.3】应用Do…Loop循环计算π的近似值,要求满足精度10-6,其近似公式如下:
观察这个公式,分式的分母实际是一个等差级数,后项比前项大2。
由于循环次数未知,采用Do…Loop,在循环体内判断精度,满足精度时采用ExitDo语句结束循环。
代码如下:
PrivateSubCommand1_Click()
DimpiAsDouble,pi1AsDouble,mAsLong,iAsLong
pi=4:
m=3:
pi1=pi:
i=1
Do
pi=pi+4*(-1)^i/m
IfAbs(pi1-pi)<10^(-6)ThenExitDo
m=m+2:
i=i+1
pi1=pi
Loop
Label1.Caption=pi
EndSub
代码中的“^”为乘方运算符,Abs为计算绝对值的函数(参见3.4.6节的表3.1)。
用(-1)^i表示每次计算是加法还是减法,变量i开始时为1,采用减法,随后i加1变成2,第二次循环采用加法,以此类推。
利用变量pi1记录上次计算的结果,与本次计算结果差值的绝对值就是其精度,与要求的精度10-6比较,小于要求精度则退出。
在文件读取和数据库访问时,经常使用Do…Loop循环,在其循环体内每次读取一行数据,其结束的条件是到达文件或数据库的结尾。
3.2.4While…Wend循环
While…Wend循环是早期的一种循环格式,与前面Do…Loop循环的格式二功能完全一致,现在已经很少使用这种循环格式,其格式如下:
While条件
循环体
Wend
采用WhileWend循环实现例3.2功能的代码如下:
PrivateSubCommand1_Click()
DimiAsInteger,SumAsInteger
i=1
Whilei<=100
Sum=Sum+i
i=i+1
Wend
Label1.Caption=Sum
EndSub
3.2.5With与EndWith语句
在程序代码中,经常需要对同一个对象的多个属性和方法进行处理,每个属性和方法前面都需要加上对象名称和点号“.”,大量重复的对象名称书写较为麻烦,特别是对象名称较长时,更是如此。
VisualBasic提供了With和EndWith语句,用于简化这类语句的书写方法,语法格式如下:
With对象名称
.属性
.方法
EndWith
在With和EndWith语句中,点号前面的对象可以省略。
如代码:
Text1.Left=0
Text1.Top=0
Text1.Width=Me.ScaleWidth
Text1.Height=Me.ScaleHeight
可以替换成:
WithText1
.Left=0
.Top=0
.Width=Me.ScaleWidth
.Height=Me.ScaleHeight
EndWith
3.2.6Type与EndType语句(自定义类型)
VisualBasci提供了整数、小数、字符等各种数据类型,而在实际应用时,往往这些已有类型并不能满足需求,因此需要用户自己定义新的数据类型存放特殊的数据。
自定义类型用Type和EndType语句定义,可以将各种基本类型组合成一个新的类型,作为一个整体看待,可以采用新定义的类型定义变量。
Type和EndType的格式如下:
Public|PrivateType类型名称
成员As类型
成员As类型
…
EndType
Public和Private表示自定义类型的使用范围。
一般将自定义类型定义在模块(Module)中,使得整个工程的任何地方都可以使用,可以省略Public。
如果在某个窗口或类模块中自定义新类型,前面的Private不能省。
在自定义类型中,对每个成员指定其类型,可以是基本数据类型,也可以是已经定义的新类型。
如果需要将用新类型定义的变量保存到二进制文件中,其中的字符串类型成员必须定义成定长字符串。
例如,定义一个新的类型保存学生信息,采用如下格式:
TypeSTUDENT
NameAsString*10
AgeAsInteger
ClassAsString*30
EndType
一旦采用Type和EndType语句定义了新类型,就可以用该类型定义变量,其定义方法与普通类型变量定义方法一致。
Dimstu1AsSTUDENT
以上定义的新变量stu1是STUDENT类型的,对这样的变量操作需要针对其各个成员,采用点号“.”访问其成员:
stu1.Name="张三"
stu1.Age=20
stu1.Class="机06-1"
3.2.7Enum与EndEnum语句(枚举类型)
枚举类型是一种特殊的自定义类型,它包含某个数据的所有可能取值,例如,对于星期数据,只有星期一到星期日这七个取值。
Enum和EndEnum的格式如下:
Public|PrivateEnum类型名称
成员[=常量表达式]
成员[=常量表达式]
…
EndEnum
每个成员的常量表达式被看作Long类型数据,可以省略,默认第一个成员等于0,后面以此类推。
Public和Private的说明与自定义类型相同。
例如,定义星期枚举类型如下:
EnumWEEKNAME
Sunday
Monday
Tuesday
Wednesday
Thusday
Friday
Saturday
EndEnum
其中的成员Sunday等于0,Monday等于1…Saturday等于6。
采用枚举定义的类型也可以作为新类型看待,能够用于定义新的变量:
DimaAsWEEKNAME
a=Saturday
3.3子程序定义与调用
VisualBasic6.0中将子程序和函数统称为过程,用于提高代码的利用率,所有的子程序和函数都可以被其它子程序或函数直接或间接调用。
某些子程序也可以被自身调用,这样的调用称为递归调用。
在第二章的示例中,已经接触了子程序,每个对象的事件处理程序就是一个标准的子程序。
3.3.1子程序的定义
子程序采用关键词Sub和EndSub定义,其格式如下:
[Public|Private|Static]Sub子程序名(参数表)
子程序体
[ExitSub]
EndSub
Public关键词表示该子程序可以被当前工程的所有其它子程序或函数调用;Private关键词表示该子程序只能被当前窗口或模块中的子程序或函数调用;Static关键词表示该子程序内部的所有局部变量均为静态变量。
如果省略这三个关键词,则默认为Private。
第二章的所有事件处理子程序前均有Private关键词。
子程序在正常状态下应该运行到EndSub语句才结束,有时也可以根据条件提前采用语句ExitSub结束子程序。
参数表是在调用子程序时要传递给子程序的参数变量列表,在这里称为形参(调用时实际赋给它的内容称为实参,二者的位置和类型一定要一致)。
参数表的格式如下:
[ByVal|ByRef]参数1,[ByVal|ByRef]参数2,…
关键词ByVal表示按值传递,调用时将实参的值传递过来,这样的参数在子程序内部不能被改变;关键词ByRef表示该参数按地址传递,调用时将实参在内存中的地址传递过来,这样的参数在子程序内部可以被改变。
如果某个参数前面没有ByVal或ByRef关键词,则默认为按地址传递,即参数在子程序内部可以改变。
子程序的名称与变量名称一样,也是由字母、数字和下划线组成,且必须以字母开头(汉字及其它国家的文字也能够作为子程序名称的组成部分,但使用不方便,一般不采用)。
VisualBasic6.0中创建子程序的方法参见第二章2.8.7节有关Main子程序的创建方法。
编写如下两个子程序,实现两个数据交换:
SubSwap1(aAsInteger,bAsInteger)
DimcAsInteger
c=a:
a=b:
b=c
EndSub
SubSwap2(ByValaAsInteger,ByValbAsInteger)
DimcAsInteger
c=a:
a=b:
b=c
EndSub
子程序Swap1包括两个Integer类型的参数a和b,都没有采用ByVal或ByRef关键词,表示它们在Swap内部可以被改变。
子程序Swap2同样包括两个Integer类型的参数a和b,都用ByVal修饰,表示它们不能被改变。
3.3.2子程序的调用
子程序的调用采用两种方法:
●子程序名[实参表]
●Call子程序名[(实参表)]
注意这两种方法的区别:
采用第一种方法时,实参表前后不能用小括弧括起来,子程序名与第一个参数之间用空格隔开。
采用第二种方法时,如果有实参,则实参前后一定要用小括弧括起来。
实参表将实际的参数内容或地址传递给形参,必须与形参在个数、顺序和类型方面保持一致。
对于上面的子程序Swap1,可以采用如下方法调用:
Swap1x,y
CallSwap1x,y
使用下面的代码比较子程序Swap1和Swap2:
PrivateSubForm_Click()
Dimx1AsInteger,y1AsInteger
Dimx2AsInteger,y2AsInteger
x1=10:
y1=20
x2=10:
y2=20
Swap1x1,y1
Swap2x2,y2
MsgBox"x1