第一章 Visual Basic 的基础知识
§1 Visual Basic的基础知识概念和术语对象(Object)
事物都可称作对象,比如桌椅就是对象,在Visual Basic里对象主要分为两类:Form和Control。
Form:窗体或称表单,其实指的就是window。
Control:控件,指的是各种按钮、标签等等。
属性(Property)
指的是对象的属性,比如姓名、性别、民族、籍贯都是你这个对象的属性。Caption、Left、Name是一个命令按钮的属性。
事件(Event)
事件是发生在对象上的动作。比如敲桌子是一个事件,它是发生在桌子这个对象上的一个动作。比如Click、Dblclick或LostFocus是发生在文本框控件上的事件。然而事件的发生不是随意的,某些事件仅发生在某些对象上而已,比如“逃避早操被抓住”可以发生在学生这个对象上,但它不会发生在老师这个对象上。
方法(Method)
这是一个直译,是一个较难理解的概念,它是对象本身内含的函数或过程,它也是一个动作,但不称作事件,在Visual Basic 里,方法和事件是这样的:
事件:
Private Sub对象名_事件名
(事件内容)
End Sub
方法:对象名.方法名所以方法是一个简单的不必知道细节的无法改变的事件,同样,方法也不是随意的,一些对象有一些特定的方法。如果以上概念你记不住,不要紧,实践中你会明白一切,请继续学习。
Visual Basic 的开发周期想清楚你想做到什么;
拿起笔在纸上画出你的用户界面;
拿起鼠标在屏幕上画出你的用户界面,确定对象的属性;
告诉计算机你要做的事;
让程序运行,看看能否工作;
如果不能工作,不必难过;
找出那个错误,重新开始。
你应该养成一些良好的习惯,这样在你编大程序时不至于丢三落四,为一些本来可避免的错误反复做第六步和第七步。
Visual Basic的存储和运行编写的程序和对象的属性一块儿存在frm文件里;
整个程序里包含着一个或许多frm文件,Visual Basic将所有frm文件名存入一个vbp文件里,若丢失了一个vbp文件,尽管frm文件仍在磁盘上,但程序将不能运行了;
如果你的程序已经自以为成功了,你可以把它编译成EXE文件,这样做的好处是:
在没有Visual Basic 的环境下可以运行;
速度提高;
别人不知道你的编程方法,还以为你是个编程专家,对你的编程效率大加赞叹。
更商业化的做法是做一张安装盘,Visual Basic 6.0在这方面也为你准备了工具,我们以后会讲到这个工具
Visual Basic的不同之处建立用户界面。对Visual Basic来讲,用户界面是由你直接在屏幕上画出来的,所以Visual Basic的用户界面看上去总是十分完美。
程序对用户界面反应。在Visual Basic里有许多事件等待你去填写代码,它自动也知道向机器解释这个事件,仅此一点就已经省去你的许多时间。
结构化的语言。在Visual Basic里似乎没有主程序一说,所有的代码都在一个一个模块里,所以所有的程序看起来都是不很长。
Visual Basic的不足之处
Microsoft的C++程序员是不会开发出一样东西之后,让自己失业的,大多数简单好用的东西都有它的限制,Visual Basic也是一样。
C++和Pascal有更多的对计算机的控制,所以Windows是用C和汇编语言编的,UNIX也是用C语言编的,想用Visual Basic做一个操作系统是不可能的;
C++和Pascal是一种速度更快的语言,所以如果速度在程序中很重要,则Visual Basic 难以胜任;
Visual Basic不能在Macintosh、OS/2上运行,也不能在小型机或巨型机上运行。
当然,任何一门语言的精通都需要长时间的“玩耍”,然而现在,我们只须从玩Visual Basic开始。
§2 制作第一个Visual Basic程序我们要做什么我们要做的第一步是确立我们想做什么,我们想做的第一个自已的Visual Basic程序是让一张幸福的小脸眨眼睛的程序。
绘制用户界面,这是第二步。
在开始菜单里选程序项,选择Visual Basic 6.0组,选择Visual Basic 6.0,进入Visual Basic环境。下面是画控件的方法:
单击工具栏里想画的控件(这个工具栏出现在Visual Basic界面的左边);
在窗体里单击并拖曳鼠标,画出控件(打开Visual Basic时,会有一个名为Form1的空白窗体出现)。
绘制用户界面单击工具栏里的选项按钮控件(OptionButton),单击并拖曳鼠标,在Form1里,画一个选项按钮,使它看起来象图示一样;

再画三个选项按钮;
单击工具栏里图标控件(Image),单击并拖曳鼠标,在窗体里,画一个图标轮廓;
再在旁边画四个图标;
单击工具栏里命令钮控件(CommandButton),单击并拖曳鼠标,在窗体里,画一个按钮;
从File菜单里选择Save File项;
在Save对话框填上HellloVB,它的扩展名是frm,单击OK钮;
从File菜单选择Save Project项;
在对话框里填上HelloVB,它的扩展名是vbp,单击OK钮。
现在,我们已完成了用户界面的一部分设计设计,运行的时侯它看起来就是现在这个样子的。
精确设置对象的属性首先,我们不一定要设置对象的属性,Visual Basic有对其对象属性的缺省值,其次,尽管每个对象有数十个属性,但我们往往只须改变其中的几个值而已。可以在设计阶段改变对象属性,也可以在运行阶段改变对象属性属性。在这个程序里我们通过设计阶段的改变属性的方法和运行阶段的改变属性的方法来实行全部的功能。下面是设置属性的方法:
选择需要改变属性的对象(用鼠标在控件上单击,这时在控件周围出现八个小黑块,表示你已选上了这个控件);
按F4打开属性窗口;
选择想要改变的属性;
赋新值。
现在开始设置属性。
选择Form对象,按F4键,出现Property窗口;

选择Caption属性;
通过输入“My First Visual Basic Application”来改变设置;
选择Icon属性,单击属性栏旁边标有“…”的键,出现Load Icon对话框;
选择VB\icons\misc\face03.ico;
按OK键选择Option1选项按钮,按F4键,出现Property窗口,选择Name属性,键入“optBoth”。其余的属性设置是这样的:
控件
属性
设置值
Option1
Caption
睁眼睛
Option2
Caption
眨左眼
Name
optLeft
Option3
Caption
眨右眼
Name
optRight
Option4
Caption
闭眼睛
Name
optNone
Command1
Caption
退出
Name
cmdExit
Image1
Picture
FACE03.ICO
Stretch
True
Name
imgShow
Image2
Picture
FACE03.ICO
Visible
False
Name
imgBoth
Image3
Picture
FACE05.ICO
Visible
False
Name
imgLeft
Image4
Picture
FACE04.ICO
Visible
False
Name
imgRight
Image5
Picture
FACE06.ICO
Visible
False
Name
imgNone
注:
Image控件的Picture属性的设置和Form1的Icon属性的设置方法是一样的(即在 属性栏旁边找到标有“…”的按钮,并按它。);
face04,face05,face06图标并不在vb\icons子目录下,那是自已做的。在Borland C++、Visual C++、Visual FoxPro、Delphi等编程工具里都有制作图标的工具,可以用来制作自已的图标;
Visible属性的真假决定对象在运行时是否可以被看见,False值表示对象不可见;
Stretch属性决定Image控件里的图像能否被放大或缩小,当然,放得很大的图标会显得很粗糙。
现在我们终于完成了界面的设计,然而,这个程序还不能工作,因为计算机还达不到人的思维水平,它想象不出这个程序是做什么的,与此同时,你已想像出这个出这个程序执行时的样子了。

四、编写程序代码──最令人费解和最没有成就感的必要工作,除了程序员、专家,大多数人对程序代码都感到厌倦,幸好我们都不想成为世界级的程序员,所以目前的Visual Basic 程序代码都不是很难。
选定一个对象,比如optLeft,然后按F7键或双击它,Visual Basic 显示代码窗口,Visual Basic 将显示:
Private Sub optLeft_Click()
End Sub
Private表明这段代码的应用范围,我们先不用深究这个词的内涵,Sub是一个开头,是subprogram的简写,optLeft是对象名,_是一个下划线,用来分开对象名和事件名,Click是指一个事件,Click就是“单击”的意思,()是一对括号,通常里面是过程所使用的参数,现在它是空的。
这一行的意思是:“这是当用户单击了optLeft选项按钮时,程序应该做的事。”
End Sub是这段代码的结束标志,意思是“这是这段代码的最后一行。”
我们要在这两行间输入指令。
现在输入如下指令
Private Sub optLeft_Click()
imgShow.Picture = imgLeft.Picture
End Sub
从代码窗口顶部选择Object列表框,选择optRight控件,Visual Basic将显示另一个空的Click过程。
4,输入如下代码:
Private Sub optRight_Click()
imgShow.Picture = imgRight.Picture
End Sub
用同样方法再输入三条指令:
Private Sub optBoth_Click()
imgShow.Picture = imgBoth.Picture
End Sub
Private Sub cmdExit_Click()
End
End Sub
Private Sub optNone_Click()
imgShow.Picture = imgNone.Picture
End Sub
按下F5键运行这个程序,看它是否能运行。如果运行不正确,那么你要找出错误,再试一次。

我们已经成功地完成了这个例子,你已经首次尝试了Visual Basic的编程过程。是否十分简单?其实编程序就象眨眼的小脸一样有趣。
第二章 用户界面设计
§1 用户界面设计概述一,在设计前应该了解的通常程序总是由用户操纵的,所以用户需要一个界面来进行操纵。往往那些漂亮的简单的界面更加吸引用户,让他们认为程序有魔术般的力量,这样他们才会使用这个程序。下面有四条设计界面的原则。
1,了解用户的习惯
2,保持简单
3,允许用户的错误,并给以提示
4,让用户了解他在程序中的位置二,Visual Basic用户界面设计基础通过我们的第一个Visual Basic程序的设计,我们已经知道界面的设计有两步:先绘制控件,然后确定控件属性。我们发现绘制控件并不是很难。在工具箱里单击想画的控件,在窗体里按下鼠标并拖曳,然后松开鼠标即可。双击工具箱里的控件,将在窗体中央出现那个控件。如果用这种方法的话,要注意双击第二个控件时把上一个控件移开,否则两个控件会叠在一起,引起一些混淆。确定属性的方法是先选中控件,然后按F4键进入Properties窗口,接着在Properties窗口中找到要设置的属性并进行设置。

下面解释一些常用的属性,这些属性几乎总是要被设置和改变。
(1)Name属性对象都有名字,尽管我们可以通过描绘一些特性来描绘对象,这样做总是非常麻烦。计算机也是一样,它把名字看成对象于对象之间的根本差异。由于计算机的这种顽固观点,它拒绝在同一窗体里出现重名的情况(除非这是一个控件数组),它也拒绝超过40个字的名字。
在简单的程序里,给控件命名不很必要,我们完全可以使用控件Name属性的缺省值。例如Text1。但在有几十个控件的复杂窗体里,这种方法会使你花更多的时间去区分它们。所以,Visual Basic向你推荐由三个小写字母的前缀和一个第一个字母为大写的描述性单词组成的名字。例如cmdMyButton是一个命令按钮(前缀是cmd)
推荐的前缀是:
对象
前缀
例子
确认框(Check Box)
chk
chkCareerChioce
组合框(Combo Box)
cbo
cboCrimesCommitted
命令钮(Command Button)
cmd
cmdExit
数据库控件(Data Control)
dat
datTopSecretInfo
目录列表框(Directory List Box)
dir
dirTree
驱动器列表框(Drive List Box)
drv
drvHardDisk
文件列表框(File List Box)
fil
filDocuments
窗体(Form)
frm
frm1040Tax
框架(Frame)
fra
fraGroupButtons
水平滚动条(Horizontal Scroll Bar)
hsb
hsbTemperature
图形(Image)
img
imgPrettyDrawing
标签(Label)
lbl
lblFakeName
线(Line)
lin
linBorder
列表框(List Box)
lst
lstCandidates
菜单(Menu)
mnu
mnuHamAndEggs
选项钮(Option Button)
opt
optStation101
图形框(Picture Box)
pic
picPrettyPicture
几何图形(Shape)
shp
shpUpOrShipOut
正文框(Text Box)
txt
txtWarning
垂直滚动条(Vertical Scroll Bar)
vsb
vsbMoneyRaised
(2)Caption属性这仅仅是一个装饰性的属性,它可以长达255字符,包括空格和标点符号,比如一个叫cmdOk的命令钮,它的Caption属性就可以是“Ok”。
编程序时也要考虑到使用键盘的用户,在设置Caption属性在需要加下划线的字母前加上,&” 符号,例如,&File”,输出的就是“File”,这样就可以通过按ALT键和标题上那个带下划线的字母来选取它了。你不必为此编任何代码。
(3)Top,Left属性只有两种情况需要在属性窗口里设置这两个属性:第一种是用户没有鼠标,第二种是程序员需要十分精确地设定这两个值。这两个属性决定对象的位置。当你选中对象,单击并拖曳它的时候,你便在修改这两个值了。

(4)Height,Width属性这两个属性决定了对象的大小,当你选中控件时,它周围出现八个小黑方块,你把鼠标指向这些方块,鼠标指针将变成一个双向的箭头,这时按下鼠标并拖曳它,即可改变控件的大小,也就改变了Height,Width属性。同Top,Left属性一样,我们主要通过鼠标的操作来设置Height,Width属性。
§2 窗体和命令钮介绍一、窗体窗体是Windows的基本组成部分,这也是为什么这个操作系统叫Windows的原因。它的主要属性除上面介绍的以外,还包括:
1,Appearance属性这个属性用来决定控件是否采用三维效果。
2,BorderStyle属性这个属性决定了窗体的边框形式,共有6种属性值。改变窗体的BordrStyle属性后,窗体在屏幕上没有变化,它只在运行时才变为你所要求的样子。
3,ControlBox属性程序员用来决定采用不采用控制框的属性,仅在程序运行时才有效。
4,Font属性程序员可以改变该窗体上显示信息的字体,它控制着直接在窗体上打印的文本显示。
5,Icon属性这个属性是用户经常要使用的一种属性。当用户的应用程序在工具条上最小化或在Windows桌面上变为一个独立应用程序时,该属性决定将采用何种图标,窗体控制框里的图标也由它决定。为自己的窗体设置该属性时,要控制住自己挑三拣四的冲动。
6,Visible属性该属性决定窗体是否可见。错误地改变其值是很危险的,窗体会从眼前消失,这种莫名其妙的事情会使用户惊惶失措,所以肩负重任的程序员一定要慎重哟!
7,WindowState属性指定窗体在运行时的三种状态:正常、最小化、最大化。
二、窗体的主要事件
1,Load事件这个事件发生在窗体被装入内存时,且发生在窗体出现在屏幕之前。窗体出现之前,Visual Basic会看一看Load事件里有没有代码,如果有,那么它先执行这些代码,再让窗体出现在屏幕上。
2,Click事件,Dblclick事件这两个事件在单击或双击窗体时发生。不过你单击窗体里的控件时,窗体的Click事件并不会发生,Visual Basic会去看控件的Click事件里有没有代码。
3,Activate (活动事件)与Deactivate(非活动事件)
显示多个窗体时,可以从一个窗体切换到另一个窗体。每次激活一个窗体时,发生Activate 事件,而前一个窗体发生Deactivate事件。
三、窗体控制装入或卸出窗体要装入或卸出窗体,用Load?或Unload语句。Load语句的语法如下:
Load formName
而UnLoad语句的语法是:
UnLoad formName
FormName变量是要装入或卸出的窗体名。 Load语句只是把窗体装入内存,并不显示出 来,要显示窗体可以使用窗体的Show方法。
2,显示或隐藏窗体要显示窗体,用Show方法。若尚未装入内存则先装入再显示。它的语法如下:
formName.show mode
FormName变量是窗体名,可选变元mode为0(缺省值)时窗体为非模态,为1时窗体为模态。模态窗体完全占有应用程序控制权,不允许切换到别的应用程序,除非关闭!而非模态窗体则反之。
同理,隐藏窗体用formName.hide。
四、命令钮命令钮有两类:一类是简单的命令钮,一类是图形钮。图形钮常常成组地出现在屏幕的顶端,成为一些程序炫耀自己贴近用户的标志。图形钮充分利用了图形用户界面的特征,而且比命令钮小,但它的缺点是用户必须知道图形钮是什么意思,而且没有鼠标的用户恐怕用不了图形钮。命令钮也有Appearance、Caption、Font、Left、Visible之类的属性。命令钮的最主要事件就是Click事件,它还有MouseDown和MouseUp等事件
§3 建立菜单一般Windows的菜单条包含File,Edit,Window和Help菜单标题。其它的菜单,程序员应将它们插在Edit和Window菜单之间。在Visual Basic里,为了创建菜单,必须打开菜单编辑窗口。可以按下Ctrl+E键,也可以从Tools菜单中选择Menu Editor项,或者单击Visual Basic主窗口的从左边数第六个图形钮。
一、给菜单命名菜单标题和菜单命令也有Caption和Name属性,你设置了这两个属性就等于创建了菜单。于控件一样Caption是屏幕上可见的,而Name则是一个抽象名称。别忘了在Caption里加入,&” 以帮助没有鼠标的用户。
二、增加和删除菜单在Menu Editor中部有三个命令钮分别是Next,Insert,Delete。Insert可用来增加新的菜单。在这三个键下面的Caption列表框里选中菜单项(这时它的底色就变成深蓝色),单击Insert键,Visual Basic将上一个增亮菜单下推并增亮一空行,你就可以输入新菜单名和标题了。Delete键可用来删掉菜单。你选中要删掉的菜单,单击Delete键就可以删掉它了。
三、移动菜单标题有四种情况,向上移动,向下移动,向左缩排,向右缩排,这就是Menu Editor中间上下左右箭头的功能。选中某一菜单标题,安上下箭头,则这个菜单将上下移动到你喜欢的位置上,这也决定了它在界面中的位置。如果你按左右箭头,情况则有所不同。由于菜单是分级的,所以,如果它没有缩排,则它是一个菜单标题;如果它缩排一次,那么它将变成一个菜单命令;如果缩排两次,那么它将成为一个子菜单命令。Visual Basic里你可以总共设计四层子菜单。

四、设置分离条分离条是指在菜单中将命令分组的线。
奇怪的是,Visual Basic将分离条也看成一个菜单项,它也需要Caption和Name属性,而且它也有其它属性,分离条与菜单项的区别是分离条的Caption属性必须是连字号即减号。也就是,当你设置了一个Caption属性为,-” 的菜单项时,实际上你就设置了一个分离条,分离条的名字可以是barFile1之类,以表明分离条的位置。

五、菜单的各种简单属性在Menu Editor里有许多确认框和一些正文框及一个下拉式的列表框,这些东西决定了菜单的各种属性。
1,Checked属性这个属性值设置为真,将在菜单命令左边产生一个打勾的确认标志,你可以看看File Manager里的View菜单就可以了解什么是确认标志了。
2,Enabled属性各种各样的用户会产生千奇百怪的操作,在许多Edit菜单里都会有不同形式的让菜单命令模糊的情况。Enabled属性就是用来做这件事的。Enabled属性为真,则菜单命令是清晰的,Enabled属性为假,则菜单命令是模糊的,这时用户就不能选中这个菜单项了。
3,Visible属性用户看见一个模糊的菜单而不能选的时候,有时会非常生气。所以,如果用户看不见这个菜单命令时,他也就不会发无名之火了。如果把Visible属性设为假,则菜单根本不会出现在屏幕上。这样做比把Enabled属性设为假显得更加干脆!
4,Index属性可以生成菜单命令数组,用索引号区分开。例如向File菜单中添加一系列最近打开的文件名。添加菜单可用Load方法。
以上属性可以在运行时设置,形成动态的菜单的情况。
例如:
mnuUndo.Enabled = False
mnuProperty.Visible = False
你还可以改变Caption等属性。
mnuUndo.Caption =,Redo”
在对窗体,命令钮和菜单有所了解后,工具箱里的其它控件就更加容易理解了。下面这些控件的熟练运用,将使你做出漂亮的界面。
六、生成弹出式菜单(或浮动菜单)
几乎每个Windows应用程序都提供弹出式菜单,用户可以右键单击窗体或控件取得这个菜单。弹出式菜单也属于普通菜单,只是不固定在窗体上,而是可以在任何地方显示。
弹出式菜单用PopupMenu方法调用。假设我们已经用Menu Editor生成了名为mnuedit的菜单,则可以在MouseUp事件加入如下代码:
If Button = 2 Then PopupMenu mnuedit
下面将用一个实例展示动态菜单和弹出式菜单。

左图表单显示了一个弹出式菜单,在表单的空白处右击鼠标就可得到。左图表单显示了一个动态菜单,单击Add runtime option钮一下就会使菜单Runtime Menu增加一项,而单击Remove runtime option钮一下就会使菜单Runtime Menu减少一项。其源代码如下:
Dim rtmenu
Private Sub cmdadd_Click()
rtmenu = rtmenu + 1
If rtmenu = 1 Then mnuoption(0).Caption = "Runtime Option"
Load mnuoption(rtmenu)
mnuoption(rtmenu).Caption = "option #" & rtmenu
End Sub
Private Sub cmdremove_Click()
If rtmenu = 0 Then
MsgBox "menu is empty"
Exit Sub
End If
Unload mnuoption(rtmenu)
rtmenu = rtmenu - 1
End Sub
Private Sub Form_MouseUp(Button As Integer,Shift As Integer,X As Single,Y As Single)
If Button = 2 Then PopupMenu mnuedit
End Sub
§4 框架,确认框和选项钮

一、确认框和选项钮就好比多项选择和单项选择,在考试时选择题总比简答题要好做,因为你可以用瞎蒙的策略。用户界面设计的保持简单的原则使确认框和选项钮成为有用的框件。确认框和选项钮用于向程序输入信息。确认框选中时会在小方框里打一个钩,菜单设计窗口里就有这种确认框的例子。
选项钮选中时会在小圆圈里点一个点。它们的主要属性除了Name,Caption等,还有:
1,Value属性决定它们是否被选中的属性。
2,Alignment属性决定它们的对齐方式。
二、有两道选择题或更多时,我们就必须对它们进行分组。这种分组需要借助框架控件。分组的方法是:
在工具箱里单击Frame控件;
在窗体里拖曳鼠标画出框架;
在工具箱里单击确认框或选项钮控件;
在框架里画确认框或选项钮;
把所需的确认框或选项钮都画好。
§5 正文框和标签

正文框通常用于向计算机输入信息,而标签通常用于输出信息。正文框是一个十分重要的控件,因为由确认框和选项钮向程序输入的信息毕竟只有少数的几条信息而已。标签和正文框的区别很小,标签可以看成是一个在运行时不能修改正文的正文框。因此标签主要用于输出信息。标签是生活中不可缺少的部分,比如教室里的“团结,勤奋,严谨,活泼”就是一个每天不得不面对的标签。
1,BorderStyle属性决定了正文框和标签的边框形式。
2,正文框的Text属性和标签的Caption属性这两个属性其实是一样的,它决定了用户在屏幕上看到的东西,只不过正文框的Text属性在运行时可以直接在正文框里修改。
3,Alignment属性这个属性决定正文或标题的排列方式。
4,正文框的Multiline属性如果正文框里的字太多了,超过了正文框的宽度,那么计算机就在某个我们不知道的地方显示这行字,所以我们要设置Multiline属性为True,这样正文框就有了字换行的能力。
5,正文框的PasswordChar属性如果用户从事的是一种掌握大量金钱或机密的工作的话(此类用户肯花大钱来买关于计算机的东西),那么他就需要对自己的工作遮遮掩掩,在Visual Basic里你可以作一个口令正文框来实现这种遮掩。方法是:
(1)选中作为口令正文框的正文框。(它的周围出现八个小方块)
(2)按F4键打开属性窗口。
(3)设置Multiline属性为False。
(4)设置PasswordChar为用于掩盖的字符。(只能是一个字符,比如 * 号)

第三步使口令正文框只有一行,因为Multiline属性为True将使Password属性失效。Visual Basic认为口令不必太长,因为太长的口令更加容易忘记。
6,正文框的Maxlength属性为了防止一些古怪用户输入太多的废话,程序员有限制正文框正文长度的权力,这就是Maxlength属性。如果Maxlength属性设置为零,那么正文框就只受计算机内存的限制了。
7,Label的AutoSize属性和WordWrap属性这两个属性在一起搭配使用总是让人混淆,以至于Visual Basic附带的示例程序里有一个程序里有这两个属性的例子,它的路径通常是c:\vb\samples\controls\control.vbp。在Visual Basic里运行这个例子,选择Options菜单的WordWrap and AutoSize。AutoSize属性使标签自动地扩大缩小以适应标签的Caption属性,但是它只会水平伸展。WordWrap属性使标签具有字换行处理的能力。
为了使标签具有垂直伸展和字换行处理,必须设置它的AutoSize属性和WordWrap属性同时为True。
AutoSize属性为False,WordWrap属性为False时,若标签不够高而Caption太长时,Caption将被切割掉。
AutoSize属性为False,WordWrap属性为True时,情况同上。
AutoSize属性为True,WordWrap属性为False时,表示可以水平伸展,但只显示一行信息。
Locked属性程序员可以阻止用户改变文本框的内容,用户只可以看文本而不能改变它。这是Visual Basic 4.0的新功能。
§6 图形框(Picture Box)和图象框(Image Box)
Picture Box和Image Box是用来把图形放入程序里的。Picture Box和Image Box可以显示几种不同格式的图形。Bitmap文件(.BMP或.DIB)、Icon文件(.ICO或.CUR)、Metafile图元文件(.WMF)、增强型图元文件(.EMF)、JEPG(.JPG)及GIF(.GIF)文件。在Visual Basic里Microsoft大概送给了我们几百个上述前三类文件,它们的路径通常是:c:\vb\bitmaps、c:\vb\icons、c:\vb\metafile。它们的主要属性有:
1,设置Picture Box和Image Box的Picture属性
(1)单击Picture Box或Image Box。
(2)按F4键打开属性窗口。
(3)单击Picture属性。
(4)单击设置框右边的省略号,Visual Basic将显示Load Picture对话框。
(5)选择用户需要的文件,单击Ok键。
则Visual Basic将图形装入Picture Box或Image Box。如果想在程序运行期间装入或删除图形,就需要用程序代码来实现了。我们可以使用Load Picture函数。例:
装入图形
imgMyHand.Picture = LoadPicture (,c:\graphics\hand.bmp” )
删除图形
imgMyHand.Picture = LoadPicture (,,)
2,Picture Box和Image Box的BorderStyle属性如同正文框和标签一样,你可以设计Picture Box和Image Box的边框。
3,Stretch属性和AutoSize属性
Image Box只有Stretch属性,而Picture Box只有AutoSize属性。
AutoSize属性设为True,则Picture Box改变自己的大小来适应其中的图形。
Stretch属性设为True,则Image Box中的图形将改变自己的大小来适应外面的边框。
§7 Line和Shape控件总有一些除了装饰作用没有别的功能的东西。如Line 和Shape控件。
1,Line和Shape的BorderColor属性一般来说边界颜色是黑的,但你也可显示你喜爱的颜色。在属性窗口里单击BorderColor属性,再单击省略号,Visual Basic将显示一块调色板,在调色板里选择你喜爱的颜色。
2,Line和Shape的BorderWidth属性这个属性决定线的粗细。
3,Line和Shape的BorderStyle属性这个属性决定线的轮廓。
4,Shape的FillStyle属性在形状中我们可能更加喜欢实心的样子,这也可以做到。
我们已经了解了窗体,菜单,及十种不同的控件,这正是Windows的基本元素,再加上它们的各种属性,就可以画出各式各样的用户界面了!
§6&§7总结:Image、Shape 和 Line 控件有时被称作轻量图形控件。它们需要较少的系统资源,因此比 PictureBox 控件显示得快并且包含 PictureBox 中可用的属性、方法和事件的子集。每一个控件都适用于一个特定的目的。
1、其它控件的容器,PictureBox 2、Printing 或 graphics 方法,PictureBox 3、显示图片 Image 或 PictureBox 4、控件显示简单图形元素:Shape 或 Line 控件
第三章 编程的基础在我们设计完用户界面后,我们就将开始了编写指令代码的过程。这是一个相对枯燥但却是必须的过程。
§1 Visual Basic编程概述一、事件驱动应用程序简单地说就是当事件发生时程序才工作,否则程序将等待事件的发生。在事件驱动程序中,用户的操作或系统事件执行一个事件过程,这样,程序执行的顺序就由哪一个事件的发生决定,由用户的操作决定。就是用户管理,代码响应。
二、事件过程用户界面对事件响应的三个部分是:
窗体控件菜单编写程序代码的通常过程是:
1,确定哪一个对象(窗体,控件或菜单)做出反应——单击此对象选中它;
2,打开代码窗口——简单的方法是按False7键或者双击对象;
找到响应的事件;

代码窗口的Object列表框可以选择对象,旁边的Proc列表框可以选择对象的事件。如果事件已经有了代码的话,那么在Proc列表框里这个事件名用黑体显示。空的事件代码都由两行组成,如:
Private Sub Form_Load()
|
End Sub
4,编写程序代码。
三、变量程序总是要做三件事:
1,得到数据;
2,处理数据;
3,输出数据。
在程序运行时,这些数据被储存在变量里,变量可理解为计算机内存条上的一个微观的东西。一旦关机,变量就消失了。变量在Visual Basic里有两种类型:
1,程序员建立的变量;
2,对象的属性往往也看成变量。
变量必须满足:
1,字母开头;
2,不超过40个字;
3,只包括字母,数字,下划线;
4,不是保留字。
创建变量的方法:
1,用Dim语句说明它;
2,可以省略声明语句而用变量声明字符生成确定类型的变量。在程序执行时若要生成变量并指定数据类型,可加入下表所示的变量声明字符后缀。
符号
数据类型
举例
$
String
A$,message Text$
%
Integer
Counter%,var%
&
Long
Population&,colorValue%
!
Single
Distance!
#
Double
ExactDistance#
3,把一个值赋给一个名称,Visual Basic就把这个名称看成变量。
Dim语句的语法是:
Dim VariableName As Type
例如: Dim MyName
As Type部分可以省略,它涉及到我们将要讲的关于数据类型的问题。Dim语句的作用是声明变量并分配存储空间。
赋值语句的语法是:VariableName = Value 或 VariableName1 = VariableName2
与数学中的等号意义不同,这里等号只表示把后者的值赋给前者,所以,A = A + 1在Visual Basic里是合法的。例如:cmdExit.Caption =,Exit” (这是一个改变对象属性的例子)
四、数据类型变量可以存放数字或字符串等东西,但是MyName变量并不需要存放数字,所以你可以限制存放的数据类型。你可以规定MyName只能字符串。Visual Basic提供了七种数据类型:
整型(Integer)
2字节整数,标识符(同上面的变量声明字符)为百分号(%),范围从-32768到32767,运算很快。
长整型(Long)
4字节整数,标识符为&,范围从-2147483648到2147483647,运算很快。
单精度型(Single)
4字节浮点数,标识符为!,范围可达38位数字,前7位可靠,运算比整型和长整型慢。
双精度型(Double)
8字节浮点数,标识符为#,范围可达300多位,但是可靠的只有前16位数字。
字符串型(String)
标识符为$,在32位版本的Visual Basic 4.0中,字符串可容纳高达200兆字节的内容。
货币型(Currency)
8字节定点数,标识符为@,小数点右边4位,左边15位。
日期型(Date)
用于存放日期,范围从#January 1,100#到#December 31,9999#,日期的格式取决于系统的设定,赋值方法是:New = #January 1,2000# 。
字节型(Byte)
Visual Basic 4.0新增加的数据类型,用于存放0到255的整数。
布尔型(Boolean)
只有True或False两个值。
变体型(Variant)
如果你不告诉Visual Basic你的变量是什么类型,Visual Basic就自动把它看成变体型。变体型的意思就是它没有类型,或者是任何类型。如果声明了Variant变量而未赋值,则其值为Empty。
例如:Dim MyName As String
事实上,语句Dim MyName只是将MyName变量声明为变体类型罢了,因为变体类型是Visual Basic的缺省类型。但是,我们使用数据类型的原因是什么呢?
1,使用最小的数据类型可节省内存;
2,程序员可以容易地找出每一变量所存放的数据类型;
3,可以防止数据类型存放错误引起的错误。
例如:
Private Sub Form_Load()
Dim MyName As String
MyName =,DongShan”
End Sub
变换变量类型有时需要将一种变量类型变成另一种变量类型,下表列出了进行变量类型转换的函数:
函数
说明
函数
说明
Cbool
将变元变成布尔值
CLng
将变元变成长整型值
Cbyte
将变元变成字节值
CSng
将变元变成单精度值
CCur
将变元变成货币型值
CStr
将变元变成字符串值
CDate
将变元变成日期值
Cvar
将变元变成变体值
CDbl
将变元变成双精度值
CVErr
将变元变成错误值
CInt
将变元变成整型值
例如要将如下的初始化变量:
Dim A As Integer
变成双精度值,可用下列函数:
B=CDbl(A)
用户自定义的数据类型------记录
保存多个相同或不同类型数值的结构称为记录(record)。
在VISUAL BASIC 中定义记录,用Type语句,其语法如下:
Type varType
Variable1 As varType
Variable2 As varType

Variablen As varType
End Type
例如定义一个名为CheckRecord的记录:
Type CheckRecord
CheckNumber as Integer
CheckDate as Date
CheckAmount as Single
End Type
CheckRecord结构可以像普通变量类型一样使用。要定义这个类型的变量,使用如下语句:
Dim check1 As CheckRecord
要对结构的各个字段访问, 可使用如下语句:
check1,CheckNumber=123
check1,CheckDate=#08/14/1996#
check1,CheckAmount=240.00
强制的变量声明
Visual Basic并不要求变量声明,但对于编写大型应用程序时,变量声明的确很有好处。
因此Visual Basic提供强制声明的方法,只要在窗体或模块的声明部分加上一条语句:
Option Explicit
这个语句使编译器检查每个变量的声明,如果要用的变量没有声明,则发出一个错误消息!
数组
单个变量只能存放单个实体,而数组可以存放一组相关的数据。像变量一样,数组有名称,存放在数组中的数值通过一个索引来访问。
数组的定义必须用Dim语句声明,如下:
Dim Names(9) As String '也可以不指定数据类型
Names是保存了10个元素的数组,Names(0)是第一个元素,Names(9)是最后一个元素。数组元素的赋值如下:
Names(0)="John"
Names(1)="Tom"

Names(9)="Xionghui"
数组的第一个元素的索引可以不是0,可以在Dim语句中指定下限:
Dim Names(1 To 16)
Dim Names(5 To 16)
动态数组
有时可能不知道需要多大的数组,这时可以生成动态数组,其长度可以在运行程序时改变。定义动态数组,和平常一样用Dim语句(或Private和Public),但不要指定长度(或维数):
Dim DynArray()
后面等能确定维数的时候,再用ReDim语句重新确定实际长度(或维数):
ReDim DynArray(UserCount)
ReDim语句只能出现在过程之中,它是可执行语句。
但每次执行ReDim语句,数组中原先存放的所有当前值会消失。但有时可能想改变数组的长度,而不损失原有的数据,幸好Visual Basic提供了Preserve关键字,它就能作到!例如下面语句将数组加大一个元素而不改变原有数据:
ReDim Preserve DynArray(Ubound(DynArray)+1)
五、变量的使用范围
Visual Basic的变量有三种使用范围。
1,局部变量;
2,模块级变量,也可以叫做窗体级变量,因为窗体和模块是同级的;
3,全局变量。
局部变量只存在于说明它的过程里,为说明一个局部变量,应在一个事件过程中说明。
模块级变量可存在于这个窗体或模块中,可以被所有窗体内的事件过程所引用和改变,说明模块级变量的方法是:
1,按F7键打开代码窗口;
2,在Object列表框中选择(general);
3,在Proc列表框里选择(declarations);
4,用Dim语句说明。
全局变量从程序开始时存在至程序结束,不过全局变量的错误也许会导致致命的错误,你不得不读遍程序来寻找到底在说明地方改变了全局变量。创建全局变量的方法是:
1,从Insert菜单里选Module项,这个命令为一个BAS模块文件显示代码窗口;
2,在Object列表框中选择(general);
3,在Proc列表框中选择(declarations);
4,用Public语句说明全局变量。
六、算术,逻辑,比较运算符
1,算术运算尽管一台上万元的计算机看来很高科技,但它在算术运算方面并不比一个几十元的计算器强多少。
运算符
运算
运算符
运算
+
加(也是字符串拼接)
\
整数除
-
减(也是取负值)
Mod
取余数
*
乘
^
乘方
/
浮点数除
&
字符串拼接
2,逻辑运算逻辑运算是对True和False进行操作的运算。Visual Basic将True的值看成-1,将False的值看成0。
运算符
使用
意义
And
变量1 And 变量2
两个量均为True,才返回True
Or
变量1 Or 变量2
只要有一个量为True,返回值就为True
Xor
变量1 Xor 变量2
两个量一个为True,一个为False才返回True
Not
变量1 Not 变量2
简单地把True 变为False,把False 变为True
3,比较运算比较运算是比较两个数或字符串的大小。
运算符
意义
运算符
意义
<
小于
>=
大于等于
<=
小于等于
=
等于
>
大于
<>
不等于
有时候,复杂的运算会把我们搞晕,良好的习惯是加括号。如:x = ( 5 * ( 8 + 9 ) ) ^ 2,则计算机先处理 ( 8 + 9 ),再处理 ( 5 * ( 8 + 9 ) ),最后才是乘方。再如:x = ( 5 * 6 ) / 2,这个括号加得似乎没什么意义,但它使我们清晰地知道是从哪儿开始运算的。
七、字符串操作有时程序需要对字符串进行操作,比如从一个文件的完整路径名中找出文件的名称。下面介绍几个常用的函数。
1,Len函数返回字符串的长度。如Length = Len(“string”),则Length = 6。
2,LCase函数,UCase函数
LCase函数把字符串变为小写字母。UCase函数把字符串变为大写字母。如:
x = LCase (“DONGSHAN”)
x = UCase (“visual Basic”)
3,Left函数,Right函数
语法是:
Left (VariableName,N)
Right (VariableName,N)
Left函数从字符串的左边提出N个字符。Right函数从字符串的右边提出N个字符。
4,Mid函数语法是:
x=Mid (VariableName,n,m)
Mid函数从VariableName字符串的第n个字符开始取出m个字符。
5,Instr函数语法是:
Instr (VariableName1,VariableName2)
Instr函数从VariableName1里找出VariableName2的位置。如:x = Instr (“ABCD”,”CD”),此时x = 3。如果计算机没找到要找的字符串,则这个函数返回0。
6,LTrim函数,RTrim函数,Trim函数
LTrim函数将去掉字符串前的空格。
RTrim函数将去掉字符串后的空格。
Trim函数将去掉字符串前后的空格。如:x = RTrim (“John,),此时x =,John”。
7,Val函数语法是:
x = Val (VariableName )
这个函数将字符串里的数字字符串转化为数字。如:Y = Val (“123”),则 Y = 123。
当Visual Basic发现下一个字符不是数字时就停止继续转化。
8,Str函数与Val函数相反,Str函数将数字转化为字符串。
语法是:
x = Str (VariableName )
八、常量及注释
1,使用常量如果我们编一个程序从每笔收入中拿出40%用于饭卡的消耗,则在程序中我们会总是用到0.4这个数字。这时粮食涨价了,我们不得不把0.4全都改成0.5,这就显得非常麻烦。我们本可以定义并使用一个常量为0.4,在涨价时把它小小调整一下就可以了。常量命名的要求与变量一样。常量的使用范围也与变量一样,分为:局部常量(在过程里用Const说明)、 模块级常量(在窗体,模块的声明区用Const说明)、全局常量(在模块的声明区用Public Const说明)
2,使用注释用,‘,注释。如:‘ This Sub is used to get Windows version
撇号右边的东西Visual Basic通常用绿色的字来显示,而且Visual Basic将忽略注释的东西。在Visual Basic 4.0所附的示例程序里使用了大量的注释,这样使其他人(也包括自己)能更好地读懂程序,所以使用注释是一个好习惯。
注释的忽略性也有一些小用处,如:
x = ( 3.5 ^ 2 - 4 ) * ( 5 + 6.73 * 7 \ 2 ) - 10.89
现在你需要测试这一语句是否是必要的,于是你把它删除,再运行看是否能得出正确的答案,如果它是不必要的,那就很顺利,如果它是必要的,你就不得不痛苦地再输入一遍而且还有输错的可能。现在你可以选择把它注释掉,这样程序运行将忽略它的存在,也可达到上面测试的目的。
§2 Visual Basic的语句一、条件选择语句人们面临选择的时候精神会变得脆弱,这就是为什么我们总是轻信偷看来的答案。因此,选择对于人类来说是一件复杂的事情,而对于计算机来说,则非常简单。它头脑简单,因而永远不会发出哈姆雷特式的疑问——“是生,还是死?”
1,条件式条件式必然代表一个值,是真(True)或者是假(False)计算机可以检测出这个值以做出相应的行动。下面就是判断的例子,其中加下划线的部分就是指条件式。
If Love = True Then...
与之相同的简略的形式是:
If Love Then...
而 If Love = False Then... 与 If Not Love Then... 的意义是相同的。
条件式中可加入逻辑运算符,如:
If x < 20 And x > 15 Then 表示当 15 < x < 20 程序将做什么。
If x < 15 Or x > 20 Then 表示当 x < 15 或 x > 20 时程序将做什么。
2,If - Then 语句语法是:
If Condition Then Instruction
例如: If n > 25 Then txtABC.Text =,ABC”
3,If - Then - End If 语句
If Condition Then
Instruction 1
Instruction 2
End If
这种结构可指示计算机执行一串语句。
4,If - Then - Else 语句
If Condition Then
Instructions1
Else
Instructions2
End If
这种结构指示计算机在条件不成立时应该做的事,这样保证了计算机至少执行一些语句。
5,If - Then - Else If 语句
If Condition 1 Then
Instructions 1
ElseIf Condition 2 Then
Instructions 2
ElseIf Condition 3 Then
Instructions 3
Else
Instructions 4
End If
类似这样的完整的语句可做出多次判断,又保证计算机至少执行一些代码。
6,Select - Case 语句被选择的值为许多定值时,这个语句就更有用一些。
Select Case VariableName
Case Value 1
Instructions 1
Case Value 2
Instructions 2
Case Value 3
Instructions 3
End Select
Select - Case 语句的不足是它需要确切的值。
7,嵌套结构我们可以把许多各式各样的条件语句嵌套在一起,而且这种嵌套在理论上没有限制。但事实上嵌套使用得越少,代码就越容易被理解。在嵌套时最好使用便于观察的缩排的格式。如:
Select Case Grade
Case "95"
If Class = "31" Then
Dorm = "1106-1108"
ElseIf Class = "33" Then
Dorm = "1104-1105"
End If
End Select
二、循环语句计算机擅长反复地做一件事,循环语句将发挥它的这种优势。
1,Do - Loop 循环
Do - Loop 循环基本上是一个死循环,所以需要在循环时判断一些条件。
(1)Do While 循环 当Condition 条件为真时执行循环
Do While Condition
Instructions
Loop
While 也可以放在Loop 语句上。
(2)Do - Loop While 循环
Do
Instructions
Loop While Condition
这两种循环的不同之处是:Do While 循环先判断条件,所以,Do While 循环可能一次都不执行。Do Loop While 循环先执行指令,再判断循环条件。所以Do Loop While 循环至少执行一次指令。但它们都是当一定条件为真时的循环。
(3)Do Until 循环 当一定条件为假时执行循环
Do Until Condition
Instructions
Loop
Do Until 先判断条件,所以循环可能一次都不执行,它是当一定条件为假时的循环。
Do Until 等同于:
Do While Not Condition
Instructions
Loop
(4)Do Loop Until 循环
Do
Instructions
Loop Until Condition
Do Loop Until 先执行指令再判断循环条件,所以指令至少被执行一次。Do Loop Until 是当一定条件为假时的循环。
2,计数的循环 For - Next
(1)For - Next 循环必须有一个控制变量,这个控制变量一般为整型。语法是:
For Counter = Start To End
Instructions
Next Counter
这里的 Counter 就是控制变量。如果想运行5次,可用下面的循环:
For i = 1 To 5
Instructions
Next i
这时,每循环一次,i 的值就加1。
(2)向前向后计数
For Counter = Start To End Step Increment
Instructions
Next Counter
Increment 表明每次循环控制变量所加的值。如下面代码也可循环5次:
For i = 5 To 1 Step -1
Instructions
Next i
只有当Counter <= End 时循环才执行,当Counter > End 的时候循环就不执行了。所以
For i = 1 To 10 Step 7
Instructions
Next i
循环将执行两次,一次是当 i = 1 时,一次是当 i =8 时。
最好不要在循环内改变控制变量的值,这样往往会导致逻辑上的错误。
3,与条件语句一样,循环语句也可以嵌套。如:
Do While Condition
For i = 1 To 5
Instructions
Next i
Loop
循环总是先从内部开始的。比较:
For i = 1 To 4 For i = 1 To 4
For j = 1 To 5 For j = 1 To 5
Next j Next i
Next i Next j
是允许的 这种For - Next 的缠绕是不允许的
4,从循环中快速退出通过使用命令Exit Do 和 Exit For,我们可以在循环未结束前跳出循环。但我们应该保证所需的动作完成后再跳出来,否则也许会遇到新的错误。而且不要试图用Goto语句从循环外跳入循环。
下面的代码可以检测出3 至20 之间的质数。其中使用了循环的嵌套及条件语句,并且当发现 i 不是质数时立即用 Exit For 转向对下一个数的检测。
Sub Form_Click ()
Dim i,j,x As Integer
For i = 3 To 20
x = False
For j = 2 To i - 1
If (i Mod j) = 0 Then Exit For
If j = i - 1 Then x = True
Next j
If x Then Print i
Next i
End Sub
三、建立过程与函数如同常量的定义一样,有时不仅仅是几个数字反复出现在程序中,而且是很多段代码在做几乎同样的事,如果有一些通用的代码可供调用的话,那么程序就会简练得多,而且更为清晰,这就是过程与函数。过程和函数保存在FRM文件和BAS文件里。若一个过程保存在BAS文件里,那么这个过程可供程序里所有的代码调用;如果一个过程保存在FRM文件里,那么这个过程只能被本窗体里的代码调用到。创建过程或函数的简单方法是选择Insert菜单的Procedure项。过程名,函数名的命名规则与变量名,常量名的命名规则一样。
1,过程结构
Sub subname (argumentlist)
Instructions
End Sub
argumentlist 指的是参数列表,所谓参数,就是指过程操作所需的指导条件。如下面过程:
Sub PrintHello (n As Integer)
Dim i As Integer
For i = 1 To n
Print "Hello"
Next i
End Sub
n 参数就是指导这个过程打印,Hello” 的个数。当有许多参数时,可用,,” 将它们分开。
如果在 Form_Click 事件过程里调用 PrintHello 过程,就可用键入:
Call PrintHello(5) ‘其中 Call 是Visual Basic的保留字
PrintHello 5
后一种省略 Call 和括号的方法使这个过程看起来更象一个Visual Basic的语句,所以我们可以这样认为:建立好的过程可以当作语句来使用。
2,函数结构函数结构与过程结构基本上是一样的。
Function functionname (argumentlist) As type
Instructions
End Function
函数就是有返回值的过程,它自己是有数据类型的。但 As type 部分是可以省略的,这时函数的返回值将是变体类型的值。在调用没有参数的函数时也必须加括号。如:
Function Total (a As Integer,b As Integer,c As Integer) As Integer
Total = a + b + c
End Function
调用时可以这样:
Answer = Total (10,20,30)
又如:
Function CurrentTime ( ) As String
CurrentTime = Time
End Function
调用时应该这样:
s = CurrentTime( )
我们看出建立好的函数与Visual Basic 本身的函数在调用时也没有什么不同。程序员可以建立自己的过程与函数库以加快编程效率。
3,传值方式当过程内改变了参数的值时,Visual Basic并不会产生错误信息,但这样可能引起一些混乱,如:
Sub PassedNotByValue (x As Integer)
x = x + 1
End Sub
在事件过程中调用:
Sub Form_Click ()
Dim i As Integer
i = 1000
PassedNotByValue i
Print i
End Sub
结果会是什么呢?是1001。在复杂的过程里不小心改变了参数的值,而调用过程的代码里这个参数又不应该改变的情况是很有可能发生的。改进的方法是:
Sub PassedByValue (ByVal x As Integer)
x = x + 1
End Sub
调用改为:
Sub Form_Click ()
Dim i As Integer
i = 1000
PassedByValue i
Print i
End Sub
结果将是1000,这就是传值方式,传值方式在参数行开始处加上 ByVal 保留字。属性总是用传值方式传递的。
第四章 Windows 95的新控件Visual Basic的输入输出
§1 ToolBar(工具条)控件

ToolBar就是那些在菜单下面的图形钮,这已经成为Windows应用程序的样板。
建立工具条在工具箱里单击工具条图标,拖到窗体的任何位置,Visual Basic自动将ToolBar移到顶部。
按F4键打开属性窗口。
双击(Custom),打开ToolBar属性窗口。
选择Buttons标签。
单击Insert按钮,Visual Basic就会在你的工具条上显示一个空按钮,现在为你的每一个按钮重复这一步。
单击确定按钮。
如果你想把按钮分组,首先生成一个分隔的按钮,再在刚才提到的对话框里将这个按钮的Style属性改为3-Separator。
为工具条增加图画在Visual Basic工具箱里单击ImageList图标,并将它拖到窗体的任何位置(位置不重要,因为它总是不可见的)。
按F4打开属性窗口。
双击(Custom),打开ImageListCtrl属性窗口。
选择Image标签。
单击Insert Picture,在现在图形的对话框里选择你想使用的位图或图标,然后单击打开按钮。为每个你想添加图形的工具条按钮重复此步。
单击确定按钮。
单击你的工具条,按F4,双击(Custom),显示ToolBar属性对话框。
选择General标签,在ImageList框里选择刚才添加的ImageList控件。
选择Buttons标签,单击紧挨Index框的向左或向右箭头以选择一个按钮序号。出现在工具条最左边的按钮序号为1。
在Image框里输入一个数,输入为1,则显示刚才ImageList控件里的第一个图形,输入为2,则显示刚才ImageList控件里的第二个图形。
为每个按钮重复第10和第11步。
单击确定按钮,现在Visual Basic就会在工具条上显示精美的图形了。
为工具条添加文本信息在刚才提到的ToolBar属性对话框中选择Buttons标签,在Caption框里输入你想显示在按钮上的文本。
添加ToolTips
ToolTips是一种当你点到工具按钮是弹出的小标签。ToolTips很方便,可以告诉那些新手每个按钮是干什么用的。在刚才提到的ToolBar属性对话框中选择Buttons标签,在ToolTipText框里输入你想作为ToolTip的文本。
如何编写代码双击你的工具条,以下面的格式输入代码就可以了。
Private Sub Toolbar1_ButtonClick(ByVal Button As Button)
Select Case Button.Index
Case 1
'Code to follow if user clicks the first button
Case 2
'Code to follow if user clicks the second button
Case 3
'Code to follow if user clicks the third button
End Select
End Sub
§2 StatusBar(状态条)控件

和ToolBar一样,选中状态条,按F4键进入属性窗口,双击(Custom)可以进入主要的设置窗口SBarCtrl属性窗口。
选择面板形状在SBarCtrl属性窗口里选择General标签,在Style列表框里选择多面板(缺省形式)或单面板简单文本形式。
添加或删除状态条面板在SBarCtrl属性窗口里选择Panels标签,单击Insert按钮添加一个面板,或单击Remove按钮删除一个面板。
在单面板里显示文本在SBarCtrl属性窗口里选择General标签,在SimpleText框里输入你想显示在状态条面板里的文本。用代码显示的方式是:
StatusBar1.SimpleText = "New string to appear"
四、在多面板里显示文本或图形在SBarCtrl属性窗口里选择Panels标签,用Index旁的按钮选择面板序号。
在Text框里输入你想显示在状态条面板里的文本。
如果你想加入图形,单击Browse按钮打开一个图形选择对话框,选择你想加入的图形,然后单击打开按钮。
最后按确定按钮。
用代码显示的方式是:StatusBar1.Panels(x).Text = "New string to appear"
如何编写代码如果是一个单面板状态条,当用户单击状态条时,只需用下面的事件过程来响应:
Private Sub StatusBar1_Click()
End Sub
如果是一个多面板状态条,就需要鉴别用户单击的是哪一个面板,可用下面的事件过程来识别用户所单击的面板:
Private Sub StatusBar1_PanelClick(ByVal Panel As Panel)
Select Case Panel.Index
Case 1
'Code to follow if user clicks the first panel
Case 2
'Code to follow if user clicks the second panel
Case 3
'Code to follow if user clicks the third panel
End Select
End Sub
§3 ProgressBar(进程条)控件

进程条的三个属性
Min属性代表进程条全空时的值,缺省时为0。
Max属性代表进程条全空时的值,缺省时为100。
Value属性代表进程条当前的值(不用在属性窗口里找这个属性,它不出现在属性窗口中,但它的确存在),它大于Min属性,小于Max属性。改变Value属性的值将改变进程条的进度显示。
为了了解进程条的功能,在窗体里添加一个进程条和一个命令钮,双击命令钮进入代码窗口,键入如下代码:
Private Sub Command1_Click()
If ProgressBar1.Value < ProgressBar1.Max Then
ProgressBar1.Value = ProgressBar1.Value + 5
Else
ProgressBar1.Visible = False ‘当进程条满了的时候让进程条消失
End If
End Sub
§4 Slider(滑块)控件

一、选择滑块的外观
Orientation属性决定滑块的方位,可以是垂直的或水平的滑块。
TickStyle属性决定滑块标记的样子。
TickFrequency属性规定了沿着滑块的标记的间隔大小,缺省的状态是1,表明每个可能值都出现标记,如果你把值设置为3,则每三个可能值出现一个标记。
滑块的Min,Max,Value属性这三个属性和进程条的这三个属性差不多,Min,Max表示滑块的最小和最大值,Value表示进程条的当前值。
三、滑块的LargeChange,SmallChange属性
LargeChange规定了当用户用鼠标单击滑块时,滑块可移动的距离。SmallChange规定了用户按左箭头或右箭头时滑块的移动距离。
§5 TabStrip控件(象笔记本书签或一组文件夹的标签)

和ToolBar一样,选中TabStrip,按F4键进入属性窗口,双击(Custom)可以进入主要的设置窗口TabStrip属性窗口。
一、设置样式在TabStrip属性窗口里选择General标签,在Style列表框里选择Tabs或Buttons样式。
二、规定TabStrip的标题,ToolTips和在TabStrip属性窗口里选择Tabs标签,在Caption框里输入标题。
在TabStrip属性窗口里选择Tabs标签,在ToolTipText框里输入ToolTip。
增减标签总数在TabStrip属性窗口里选择Tabs标签,单击Insert Tab按钮增加标签,单击Remove Tab按钮删除标签。
在TabStrip上显示图形
1,在窗体里拖入一个ImageList控件,
2,按F4打开属性窗口。
3,双击(Custom),打开ImageListCtrl属性窗口并选择Image标签。
4,单击Insert Picture,在现在图形的对话框里选择你想使用的位图或图标,然后单击打开按钮。为每个你想添加图形的Tab按钮重复此步。
单击确定按钮。现在ImageList里存储了你需要的图形。
选择你的TabStrip,进入TabStrip属性窗口并选择General标签,在ImageList列表框里选择ImageList1。
现在选择Tabs标签,单击紧挨Index框的向左或向右箭头以选择一个Tab序号。在Image框里输入一个数,输入为1,则显示刚才ImageList控件里的第一个图形,输入为2,则显示刚才ImageList控件里的第二个图形。
单击确定按钮。
用户响应可用类似下面的代码来识别用户在哪一个项目上单击。
Private Sub TabStrip1_Click()
Select Case TabStrip1.SelectedItem.Index
Case 1
'Code to follow if user clicks the first tab
Case 2
'Code to follow if user clicks the second tab
Case 3
'Code to follow if user clicks the third tab
End Select
End Sub
在TabStrip上放置其它控件在用户选择了标签后,TabStrip要求你编写代码来显示或隐藏控件。下面的代码上是一个TabStrip上有一个命令钮和一个选项钮的例子,当用户选择了第一个Tab时,选项钮出现,当用户选择了第二个Tab时,命令钮出现。
Private Sub TabStrip1_Click()
Select Case TabStrip1.SelectedItem.Index
Case 1
Command1.Visible = False
Option1.Visible = True
Case 2
Command1.Visible = True
Option1.Visible = False
End Select
End Sub
§6 Visual Basic的输入机制程序的基本操作就是数据的输入,数据处理和数据的输出。Visual Basic的可用于输入的控件主要有:
正文框Text Box、确认框Check Box、选项钮Option Button、列表框List Box、组合框Combo Box、滚动条Scroll Bar、通用对话框控件。还有一个函数叫InputBox函数,也可用于数据的输入。
一、通过正文框输入数据
1,我们只要取得正文框的Text属性就可以对其进行操作了。如下面代码可将Text1正文框的正文变成大写输出至Text2正文框。
Private Sub Form_Click ()
Text2.Text = UCase(Text1.Text)
End Sub
二、通过确认框和无线钮输入数据我们只要检测到Check Box和Radio Button的Value属性值就可以知道它们是否被选上了。
通过列表框和组合框输入数据

列表框List Box和组合框Combo Box在Windows的Open,Save As对话框里最为常见。组合框又包括三种类型,这三种类型要在它的Style属性里设置。列表框仅仅把可以选择的项目列出来,而组合框里有的类型可以允许用户输入数据。它们的异同是:
名称
是否有下拉选项
是否允许用户输入
列表框
否
否
组合框类型0
是
是
组合框类型1
否
是
组合框类型2
是
否
2,列表项目的增减使用AddItem,RemoveItem语句。通常将项目增减的语句放入Form_Load事件里。
ListBoxName,AddItem item
ComboBoxName,AddItem item
item是新项目名称,必须是字符串类型,非字符串类型可通过Str函数或Format函数来转换。
列表框,组合框的每一项目都有一个Index值,第一个项目的Index值是0,第二个是1,依此类推。删除项目可通过删除其Index值来实现。
ListBoxName,RemoveItem item
ComboBoxName,RemoveItem item
如:ListBoxName,RemoveItem 0则删除了第一项,这时原来的第二项就变成了第一项。
在Visual Basic 4.0里程序员终于可以在设计阶段设定列表项目了。方法是:
在属性窗口选择List属性,将出现一个下拉列表,在列表中输入第一项,按Ctrl+Enter,输入第二项……,最后用Enter结束。
3,取得列表框,组合框的数据可以通过取得Text属性或通过取得ListIndex属性来判断哪一项被选择了。ListIndex属性的值也同样是第一个为0,第二个为1……如:
If List1.Text =,Visual Basic” Then Instructions
If List1.ListIndex = 1 Then Instructions
组合框有时允许用户自己输入数据,这时所输入数据的ListIndex值为-1。
通过滚动条Scroll Bar取得数据

在Visual Basic的工具箱里有两种滚动条:一种是垂直的,一种是水平的,它们的差异无非是摆放的方向不一样。
1,滚动条的主要属性及事件
(1)Min,Max属性
Min属性决定滚动条最左端或最顶端所代表的值。Max属性决定滚动条最右端或最下端所代表的值。
(2)LargeChange,SmallChange属性
SmallChange决定在滚动条两端的箭头钮上单击时改变的值。LargeChange决定在滑块上方或下方区域单击时改变的值。
(3)Value属性
Value属性代表当前滑块所处位置的值,这个值由滑块的相对位置决定。
(4)Change事件当滑块位置发生变化时就引发了Change事件。
2,取得滚动条的数据滚动条并不是一个数据输入的好控件,因为你无法从滚动条上直接看出输入的数据,但它的优点是可以表示一定范围里的相对位置。为了得到数据,只要取得滚动条的Value属性就可以了。
五、InputBox函数
InputBox函数提供一个简单的对话框供用户输入信息。在把其它版本的BASIC程序移植到Visual Basic时,InputBox函数通常用来代替INPUT语句。这个对话框的样子基本上是下面的样子。
它的完整语法是:x = InputBox (prompt,title,default,xpos,ypos,helpfile,context)
其中,prompt是提示的字符串,这个参数是必须的。title是对话框的标题,是可选的。default是正文框里的缺省值,也是可选的。xpos,ypos决定输入框的位置。helpfile,context用于显示与该框相关的帮助屏幕。返回值 x 将是用户在正文框里输入的数据,x是一个字符串类型的值。如果用户按了Cancel钮,则 x 将为空字符串。
六、使用通用对话框控件
Windows应用程序里的Open对话框,Save As对话框在各个应用程序里看起来都是一样的,通用对话框控件就可以提供这些对话框的标准功能。
1,Open对话框及Save As对话框打开Open对话框使用ShowOpen方法,打开Save As对话框使用ShowSave方法。
Private Sub mnuOpen_Click ()
On Error GoTo ErrorHandler
CommonDialog1.CancelError = True
CommonDialog1.Filter = "Text Files (*.txt)|*.txt|Batch Files (*.bat)|*.bat|All Files (*.*)|*.*"
CommonDialog1.ShowOpen ' display Open common dialog box.
Call OpenFile(CommonDialog1.FileName)
ErrorHandler:
Exit Sub
End Sub
其中第三行决定了在文件格式类型栏里出现的文件类型。第五行需要一个你自己的打开文件的过程,这个过程需要的参数就是通用对话框返回的文件名。通用对话框的CancelError属性设为True的话,用户单击Cancel按钮将产生一个错误信息程序,凭借这个信息程序可以检测到用户的放弃操作。
2,Color对话框下面的过程可用用户选择的颜色作为窗体的底色。
Private Sub mnuColor_Click ()
On Error GoTo CancelButton
CommonDialog1.CancelError = True
CommonDialog1.ShowColor
Form1.BackColor = CommonDialog1.Color
CancelButton:
Exit Sub
End Sub
代码的第三行出现了通用对话框的Flags属性决定了通用对话框的一些可选项,不过即使不赋值给Flags,代码也一样会按缺省的情况去执行的。
3,Fonts对话框下面的过程可用字体对话框改变正文框的字体。
Private Sub mnuFonts_Click ()
On Error GoTo CancelButton
CommonDialog1.CancelError = True
CommonDialog1.Flags = cdlCFBoth ' Flags property must be set to cdlCFBoth
CommonDialog1.ShowFont ' Display Font common dialog box.
Text1.FontName = CommonDialog1.FontName
Text1.FontSize = CommonDialog1.FontSize
Text1.FontBold = CommonDialog1.FontBold
Text1.FontItalic = CommonDialog1.FontItalic
Text1.FontUnderline = CommonDialog1.FontUnderline
Text1.FontStrikethru = CommonDialog1.FontStrikethru
Text1.ForeColor = CommonDialog1.Color
CancelButton:
Exit Sub
End Sub
§7 Visual Basic的输出机制通过正文框等控件的输入,经过程序代码的处理,现在我们要把结果输出了。作为输出的对象,Visual Basic提供了标签,正文框,窗体,图片框(Picture Box)等用于输出,而且Visual Basic里也有一堆命令、属性涉及信息的输出,较常用的有:MsgBox函数,Print方法,Cls方法,Tab函数,Format函数,FontName,FontSize,FontBold,FontItalic,FontStrikethru,FontUnderline属性,CurrentX,CurrentY属性等。
一、通过MsgBox函数输出了解Windows应用程序的人都知道当用户操作错误时,应用程序往往打出一个消息框来提示用户的错误,象这样:

Dim Action As Integer
Action = MsgBox("单击确定键将引爆此计算机!",vbYesNo + vbCritical + vbDefaultButton2,"警告!")
If Action = 6 Then Explode
这个功能在Visual Basic里是通过MsgBox函数来实现的,这样程序员就不必自己去画一个消息框了。语法是:
Action = MsgBox (msg,type,title)
其中,msg是消息的内容,是一个字符串型的变量,type及title参数是可以省略的,type参数指定显示的按钮是什么及使用什么样的图标(这个参数往往让新程序员思考几分钟),title参数指定消息框的标题。type参数的含义是:
数值
符号常量
意义
0
vbOKOnly
只显示 Ok 按钮
1
vbOKCancel
显示 Ok,Cancel 按钮
2
vbAbortRetryIgnore
显示 Abort,Retry,Ignore 按钮
3
vbYesNoCancel
显示 Yes,No,Cancel 按钮
4
vbYesNo
显示 Yes,No 按钮
5
vbRetryCancel
显示 Retry,Cancel 按钮
16
vbCritical
Stop Sign对极其重要的问题提醒用户

32
vbQuestion
Question Mark增亮没有危险的问题

48
vbExclamation
Exclamation Mark强调警告用户必须知道的事情

64
vbInformation
Information Mark可以使乏味的信息变得有趣

0
vbDefaultButton1
第一个按钮缺省
256
vbDefaultButton2
第二个按钮缺省
512
vbDefaultButton3
第三个按钮缺省
例如:Action = MsgBox (“Are you girl?”,vbYesNo + vbQuestion,“Question”)。使用这个函数时Visual Basic将产生一个标题为Question,具有问号和Yes,No按钮的消息框。作为一个函数,本质上还是要返回值的,MsgBox的返回值确定了用户的选择,程序可根据返回值做出相应的动作。
返回值
含义
返回值
含义
1
选择 Ok 按钮
5
选择 Ignore 按钮
2
选择 Cancel 按钮
6
选择 Yes 按钮
3
选择 Abort 按钮
7
选择 No 按钮
4
选择 Retry 按钮
二、Print方法,Cls方法,Tab函数
1,Print方法我清晰地记得小学时所学的第一个计算机语句就是Print,并且成功地用这个语句及一堆,*” 号,#” 号在屏幕上打出一间小屋。Print 方法的语法是:object,Print expressionlist
object表示Print作用的对象,比如是Form或者是Picture Box,object是可以省略的,省略时的Print往往在窗体上输出。expressionlist是输出的内容,允许许多项数据的输出,在数据间你可以加入“,”或”;”。加入分号将使下一数据项紧挨着上一数据项输出。而加入逗号,则Visual Basic将下一数据项在下一打印区输出,其实就是空了几个空格后再输出。两个打印区之间有14个字符的宽度,其实这也很难衡量,比如14个“W”所占的宽度大概是14个“i”所占宽度的三倍多。幸好中国日本之类的方块字所占的宽度基本上是一样的,所以较好处理一些。
2,Tab函数
Tab函数只用在Print方法中,它用来移动下一个字符到打印位置,这将省去你数空格的功夫。语法是:Tab (column)
Tab函数将Visual Basic自定义的14字符宽的打印区扔到一边,用自己的方式定义了新的灵活的打印区宽度。
3,Cls方法
Cls也是一个古老的BASIC语句原来它的作用总是把屏幕变成黑色,然后在左上角或左下角闪烁一个光标,Visual Basic里它的作用是清除绘图语句和Print语句产生的文字和图形。语法是:object,Cls
object指清除的对象,可以是Form或Picture Box。如果object省略,通常Visual Basic都把当前的窗口作为Cls操作的对象。
三、Format函数
Format函数用于制定字符串或数字的输出格式。语法是:x = Format (expression,fmt)
expression是所输出的内容。fmt是指输出的格式,这是一个字符串型的变量,这一项若省略的话,那么Format函数将和Str函数的功能差不多。如:
语句
输出
Format (2,“0.00”)
2.00
Format (.7,“0%”)
70%
Format (1140,“$#,##0”)
$1,140
简单地,fmt里的字符是这样的:
字符
意义
字符
意义
0
显示一数字,若此位置没有数字则补0
.
小数点
#
显示一数字,若此位置没有数字则不显示
,
千位的分隔符
%
数字乘以100并在右边加上”%”号
- + $ ( )
这些字出现在fmt里将原样打出
Format函数也可用来对时间进行输出。
fmt
输出
fmt
输出
m/d/yy
8/16/96
h:mm:ss a/p
10:41:29 p
d-mmmm-yy
16-August-96
h:mm
22:41
d-mmmm
16-August
h:mm:ss
22:41:29
mmmm-yy
august-96
m/d/yy h:mm
8/16/96 22:41
hh:mm AM/PM
10:41 PM
四、FontName,FontSize,FontBold,FontItalic,FontStrikethru,FontUnderline属性很明显,这些属性都与字体有关,许多控件都有这些属性。通常它们在设计阶段可以双击font属性来设置,运行期间可以直接设置。它们的意义是:
FontName
字体的名称
FontItalic
字体是否用斜体显示
FontSize
字体的大小
FontStrikethru
字体是否有删除线
FontBold
字体是否用粗体显示
FontUnderline
字体是否有下划线
如:Text1.FontBold = True,将把Text1正文框的FontBold属性设为True。
五、窗体,图片框的CurrentX,CurrentY属性这两个不可见的属性确定了下一次打印或绘图的水平及垂直坐标。如上面讲的Print方法,当expression后使用,,” 时,Visual Basic将改变CurrentX,CurrentY值为下一打印区域开始的值,于是,输出便指向了下一个打印区域。而Cls方法将把操作对象的CurrentX,CurrentY的值设为(0,0)。
六、通过标签控件输出标签控件的特点是运行时不能直接修改它,通常一个正文框旁边都有一个标签用来标识正文框。标签的Autosize和WordWrap属性是一对有用且令人困惑的属性。
第五章 Visual Basic的鼠标事件和绘图
§1 Visual Basic的鼠标事件
Click就是一个鼠标事件,它可以发生在许多对象上。同时鼠标事件还有DblClick,MouseDown,MouseUp,MouseMove以及拖曳后放下的事件。在Visual Basic所附的示例程序里,有一个介绍鼠标事件的例子,它的通常的路径及文件名是:c:\vb\samples\mouse\mouse.vbp
一、MouseDown,MouseUp事件
MouseDown,MouseUp事件分别发生在按下鼠标按键和松开鼠标按键时,窗体的空的MouseDown,MouseUp事件是这样的:
Private Sub Form_MouseDown(Button As Integer,Shift As Integer,X As Single,Y As Single)
End Sub
Private Sub Form_MouseUp(Button As Integer,Shift As Integer,X As Single,Y As Single)
End Sub
1,MouseDown,MouseUp事件与Click事件的不同
Click事件不能检测到是哪一个按键按下了,也不能检测到按下鼠标的同时键盘上是否按着Shift,Ctrl,Alt键,而且Click事件还不能确定按鼠标时鼠标指针的位置。而这些在MouseDown,MouseUp事件里都可以知道,这也是这两个事件过程发生时后面四个参数的意义。在需要上面所说的参数时,可以用MouseDown事件或MouseUp事件代替Click事件。
2,Button参数这个参数确定按下的鼠标按键是哪一个。
参数值
符号常量
意义
1
vbLeftButton
按下左键
2
vbRightButton
按下右键
4
vbMiddleButton
按下中键
但是这个参数无法判断出两个键或三个键同时按下时的情况。比如当你同时按下左右键时将引发两个MouseDown事件,Button参数分别为1和2,或者是2和1。
3,Shift参数这个参数用来确定MouseDown,MouseUp发生时键盘是否同时按着Shift,Ctrl,Alt键
参数值
意义
参数值
意义
0
没按
4
Alt(常量vbAltMask)
1
Shift(常量vbShiftMask)
5
Shift和Alt同时被按下
2
Ctrl(常量vbCtrlMask)
6
Alt和Ctrl同时被按下
3
Shift和Ctrl同时被按下
7
三个键同时按下
所以Shift参数是可以判断多个键同时被按下的情形的。
4,X,Y参数这两个参数表明MouseDown,MouseUp发生时,鼠标指针所指向的位置。
二、MouseMove事件
1,MouseMove事件发生在鼠标移动的时候。窗体的空的MouseMove事件是这样的:
Private Sub Form_MouseMove(Button As Integer,Shift As Integer,X As Single,Y As Single)
End Sub
MouseMove的四个参数与MouseDown,MouseUp的四个参数的意义是一样的,但MouseMove的Button参数可以判断出多个按键按下时的情形。
参数值
意义
参数值
意义
0
三个键都没按
4
中键
1
左键
5
左中键
2
右键
6
右中键
3
左右键
7
三个键都按着
2,了解了鼠标的这三个事件后就会发现Windows Paintbrush里的绘图也不过如此,下面的代码就可以实现用鼠标当作画笔在窗体上乱画的功能。
把下面代码拷到窗体的声明区就可以了。
Dim Draw As Integer
Sub Form_MouseDown (Button As Integer,Shift As Integer,X As Single,Y As Single)
Draw = True
CurrentX = X
CurrentY = Y
End Sub
Sub Form_MouseMove (Button As Integer,Shift As Integer,X As Single,Y As Single)
If Draw = True Then Line -(X,Y)
End Sub
Sub Form_MouseUp (Button As Integer,Shift As Integer,X As Single,Y As Single)
Draw = False
End Sub
三、关于“拖曳后放下”的属性和方法
1,DragMode属性这个属性决定了拖放操作是手动还是自动方式。前者必须用Drag方法来让程序知道拖曳已经开始或用Drag方法让程序知道拖曳结束了。而后者则计算机自己就可以知道拖曳的开始及结束。这说明手动方式更具有灵活性,而自动方式则简单一些。
属性值
意义
0
(缺省)手动,需使用Drag方法初始化源控件的拖动操作
1
自动,单击源控件就可以自动初始化拖动操作
2,DragIcon属性这个属性确定拖放操作中显示指针的图标。在运行期间可用赋值方式或LoadPicture函数给出DragIcon属性。如:
Image1,DragIcon = Image2,DragIcon
Image1,DragIcon = LoadPicture (“C:\VB\ICONS\OFFICE\CRDFLE01.ICO”)
3,Drag方法语法是:control,Drag action
control决定被拖动的控件,action指出执行的动作。
action值
意义
0
取消拖动
1
开始拖动控件
2
放下控件
四、关于“拖曳后放下”的事件
1,DragDrop事件拖动时总是要放下的,如果拖动的控件放在了另一个窗体或控件上,就引发了后者的DragDrop事件。空的DragDrop事件基本上是这样的:
Private Sub Form_DragDrop(Source As Control,X As Single,Y As Single)
End Sub
Source参数指明了前者——被拖动的对象,Control类型的变量就是说明这个变量代表一个控件,也就是控件的名字,但在传递这个参数时不必打上引号。X,Y参数表明鼠标指针所在的位置。
2,DragOver事件在拖放操作进行之中,被拖动的控件可能会从其它控件上空飘过,或者在目标控件上空盘旋一下,这时,就引发了在被拖动控件下方的控件的DragOver事件,这时它可以修改被拖动控件的DragIcon属性,使它可以表明是否允许控件的着陆。在Explorer里通过鼠标拖动实现文件的拷贝与移动时就可看到DragOver事件的应用。空的DragOver事件差不多是这样的:
Private Sub Form_DragOver(Source As Control,X As Single,Y As Single,State As Integer)
End Sub
Source,X,Y 参数的意义与DragDrop 的意义相同。State 参数表明被拖动的控件相对于它飘过的控件的迁移状态。
State值
描述
0
Source控件飘进本控件的领空
1
Source控件飘出本控件的领空
2
Source控件在本控件上空盘旋
DragOver事件的例子可以参考Visual Basic Help里的例子。
§2 在Visual Basic程序里绘图计算机的绘图和动画是一件奇妙且引人入胜的主题,许多软件公司都开发了优秀的关于图象的软件,三维的有3D Studio Max、LightWare、True Space等,二维的有CorelDRAW、FreeHand等等。这也是计算机渗透到其它领域的一个很好的例子,在许多影片中都可以看到计算机的出色表现。
速度并不是Visual Basic的优势,不过Visual Basic已经为我们提供了不少的素材。已经有一些厚达600页以上的书籍在介绍Visual Basic下的图象处理技术,包括绘图,色彩,动画,三维空间,虚拟现实,甚至计算机仿真的基础。听起来很诱人的东西往往需要大量不诱人的知识,比如数学,物理,逻辑等等。
一、在Visual Basic程序里加入图片
1,图片通常可以放在Form,Picture Box,Image Box里,用代码加入图片的方法有两种,一种是用LoadPicture函数,如:Image1.Picture = LoadPicture(“c:\pic\demo.bmp”)
另一种是用赋值的方式,如:ThisPicture.Picture = ThatPicture.Picture
删除图片的方法是:Image1.Picture = LoadPicture(“”)
2,Visual Basic送给我们的几百个ICO文件是非常有趣的,这些文件通常的子目录是:C:\VB\ICONS
它包括12类。在这些ICO文件里,有许多是成对出现的,用这些图标,可以做出一些简单的动画。
3,这个例子用VB目录下的ICONS\TRAFFIC子目录下的trffc10a.ico,trffc10b.ico,trffc10b.ico图标模拟一个红绿灯的变化。建立如下界面:

控件名
属性
设置值
img(右上)
Index
0
Picture
c:\vb\ icons\traffic\trffc10a
Visible
False
img(右中)
Index
1
Picture
c:\vb\ icons\traffic\trffc10b
Visible
False
img(右下)
Index
2
Picture
c:\vb\ icons\traffic\trffc10c
Visible
False
imgShow(左)
Picrure
c:\vb\ icons\traffic\trffc10a
键入代码:
Private Sub Form_Click()
Static i As Byte
If i = 2 Then
i = 0
Else
i = i + 1
End If
imgShow.Picture = img(i).Picture
End Sub
这里出现的Static语句同Dim语句一样用于声明变量。用Dim语句声明的变量在退出这个过程时,变量的值就不存在了,第二次进入这个过程时变量的值将变成0,而不是上次处理后的值。而用Static语句声明的变量在第二次进入过程时将保持上次退出时变量的值,这就是Static与Dim的不同之处,用Static语句声明的变量被称作静态变量。
二、可用于制作特殊效果的数学及语句
1,Move方法
Move方法的语法是:object.Move left,top,width,length
object是被移动的对象,这个参数是可以省略的。left参数是必须的,指定对象左边的水平坐标。top参数是可以省略的,指定对象上面的垂直坐标。width参数是可以省略的,指定对象的新宽度。length参数是可以省略的,指定对象的新长度。width,length参数的指定也就是指移动的同时改变对象的大小。
三、Visual Basic的坐标系统
1,Visual Basic的坐标系和笛卡尔的平面坐标系不同,计算机屏幕的坐标系是这样的。

窗体的左上角是原点,X轴的正向水平向右,Y轴的正向垂直向下,这是计算机领域里的顽固传统之一。所以窗体里的控件的位置用Left,Top属性描述,Left是控件左上角到窗体左边的距离,Top是控件左上角到窗体上边的距离。
2,建立自己的坐标系这涉及到窗体的许多Scale属性。ScaleLeft属性确定对象左边的水平坐标,ScaleTop属性确定对象顶端的垂直坐标,ScaleWidth属性确定对象内部水平的单元数目,ScaleHeight确定对象内部垂直的单元数目。如:
ScaleLeft = -50
ScaleTop = 50
ScaleWidth = 100
ScaleHeight = -100
将建立一个笛卡尔的坐标系如下:

更简单的方法是用Scale方法:Form1.Scale (-50,50) - (50,-50)
也可建立上面的笛卡尔坐标系,其中前一个括号里是左上角的坐标,后一个括号里是右下角的坐标。
3,刻度系统这是由控件的ScaleMode属性设置的。ScaleMode的值有:
ScaleMode值
意义
ScaleMode值
意义
0
用户自定义
4
字节(Character)
1
点素(Twip)
5
英寸(Inch)
2
点(Point)
6
毫米(Millimeter)
3
象素(Pixel,这与屏幕分辨率有关)
7
厘米(Centimeter)
1 Inch = 1440 Twips
1 Centimeter = 567 Twips
1 Inch = 72 Points
1 字符宽(水平方向)= 120 Twips
1 字符高(垂直方向)= 240 Twips
有一次,我设置ScaleMode = 7,并在屏幕上打印了三个厘米长的线段,我拿尺子在屏幕上量了量,觉得好象和三个厘米的长度有一定的差距,这是为什么呢?后来知道除了0,3之外,其它值都是以打印长度为准的,也就是说打印出来才是三厘米。
四、基本的绘图
1,AutoRedraw属性当AutoRedraw属性设为True时,所有的绘图都将被储存在内存上,当程序比较在意内存且绘图不很复杂的时候,可以在Form,Picture Box的Paint事件里编写绘图代码。Paint事件发生在Form或Picture Box重画时(如盖在上面的窗口移开,或窗体变大变小)。
2,色彩决定用哪种色彩可以用三种办法
(1)使用RGB函数。语法是: RGB(Red,Green,Blue)
这三个参数分别决定红色,绿色,蓝色的亮度强度,三个参数的范围是0-255,0表示最浅最弱,255表示最深最强。如:Form1.BackColor = RGB(255,255,0) ‘黄色
(2)使用QBColor函数这是Quick Basic的颜色系统可决定16种颜色,16种颜色是:

颜色
值
颜色
值
颜色
值
颜色
0
黑
4
红
8
灰
12
淡红
1
蓝
5
品红
9
淡蓝
13
淡紫
2
绿
6
黄
10
淡绿
14
淡黄
3
青
7
白
11
淡青
15
亮白
如:Form1.BackColor = QBColor(5)
(3)直接输入数值颜色值的格式是16进制的,为&HBBGGRR。BB代表蓝色,GG代表绿色,RR代表红色。所以Form1.BackColor = &HFF0000
与Form1.BackColor = RGB(0,0,255)的含义是一样的。
(4)取得特定点的颜色值,使用Point方法。如:x = Point (20,30)
x将是一个长整型数字,它代表了(20,30)点的RGB值。x如果直接输出的话会让人难以理解,它是一个按16进制&HBBGGRR的方式排列的数。如何才能拆出Red,Green,Blue的值呢,可以用下面的公式。
Red = (object.Point(x,y) And &HFF)
Green = (object.Point(x,y) And &HFF00&) \ 256
Blue = (object.Point(x,y) And &HFF0000) \ 65536
计算机有时是通过抖色的方法来实现一些它表现不了的一些颜色。抖色就是比如一块淡红的颜色实际上是一些红点和一些白点组成的。这时从这块淡红的颜色里取一个点读它的RGB值也许会令你失望,你明明用RGB(255,128,128)填充了底色,但你用Point方法取出点的颜色时却是RGB(255,255,255)或RGB(255,0,0)。
3,绘图方法包括Cls方法,Pset方法,Line方法,Circle方法
(1)Cls方法前面已经介绍过的Cls方法将以背景色清除绘图区域。
(2)Pset方法语法是:object.Pset (x,y),color
Pset方法将在object对象的(x,y)点用color参数决定的颜色画一个点。object参数和color参数是可以省略的。
(3)Line方法
Line方法用于画直线或方框。基本的语法是:object,Line (x1,y1) - (x2,y2),color
如:Line (250,300) - (400,500)
画一条从(250,300)到(400,500)点的直线。
Line - (400,500)
从当前位置(由CurrentX,CurrentY决定)画到(400,500)
Line (150,250) - Step (150,50)
出发点是(150,250),终点是向X轴正向走150,向Y轴正向走50的点。
等同于:Line (150,250) - (300,300)
又如: Line (20,40) - (150,200),,B
画一个左上角在(20,40),右下角在(150,200)的矩形,注意在color 参数省略时,逗号并不省略。
Line (20,40) - Step (50,70),RGB(255,0,0),BF
用红色从(20,40)到(70,110)画一个实心的矩形。
Line - (30,50),RGB(0,255,255),ABC
这个语句是错的,因为color 参数后面的参数只有 B,或 BF 两种形式。
(4)Cricle方法
Cricle方法用于画圆或椭圆,它的参数很多,语法是:object.Circle (x,y),r,color,start,end,aspect
(x,y) 参数是不能省略的参数,表示圆心的位置。r 是不能省略的参数,表示半径。color是可以省略的参数,表示画的颜色。start、end用于画弧,是用弧度度量的。

start、end为负值将在圆心至这个负值的点画出半径,这样就可以画出扇形了。如:
Circle (2000,2000),2000,,-1.571,-2.543
可画出扇形。这里的负号并没有更深的含义,仅仅表示多画了一条半径。
 
Circle (2000,2000),2000,,-2.543,-1.571
将画出右边那样的饼图。
五、关于绘图的属性这些属性包括:CurrentX、CurrentY、DrawMode、DrawStyle、DrawWidth、Fillcolor、FillStyle、BackColor、ForeColor等属性。CurrentX、CurrentY已经介绍过了,就不再介绍了。
1,DrawMode属性这个属性用来决定用什么逻辑关系将一个图案画到另一个图案上,DrawMode有16个值可供选择。可以用这些逻辑关系作出一些有趣的效果。
2,DrawStyle属性这个属性决定了线的类型,有六种设置。
3,DrawWidth属性这个属性决定了线的粗细。
4,BackColor、ForeColor属性这两个属性分别决定了对象的背景色和前景色。
5,FillColor属性这个属性确定填充在Shape控件或用Circle和Line方法建立的圆形或矩形里的颜色。
6,FillStyle属性这个属性同Shape控件的FillStyle属性是一样的,指的是填充Shape或用Circle和Line方法建立的圆形或矩形里的模式。
六、在Visual Basic的绘图程序里使用Windows API里的绘图函数将使程序有更灵活的变化性,例如涉及到画笔和刷子的API函数就有十几个,而在Windows NT,Windows 98及未来的32位的Windows操作系统里将有更多的关于绘图的函数。
第六章 Visual Basic的数据库
§1 数据库的一些知识数据库编程,无论是从Visual Basic中还是从其它更为成熟的数据库管理系统中去做,都不太容易。如果你热衷于此,你就会发现更多的专业书籍,仅仅介绍Visual Basic的数据库编程功能就将足够再开设一门讲座了。所以这里的介绍只是简单的介绍。(但我还得介绍,以便使这本书的覆盖面看起来更广一些)
开始,简单的数据库就象一张张表格一样,有行有列。后来一些管理数据库又有数学头脑的人,想出了一些好点子,于是数据库就发展成为一门计算机的分支的学科,到了现在数据库似乎拥有无限的玄机。一些公司靠数据库发了财,做学生的就有越来越多的人学习数据库的知识了。
但我们要知道的是数据库的建立无非是为了让人们更好的获得、使用、分析众多的信息(随着科学的发展,信息越来越多了)。通常的操作是用户有了好奇心,于是他问:“我想知道从有邮票以来,邮票的印刷数量排名前十名的都是什么?”计算机经过一系列艰难的筛选终于显示了结果。用户并不知道计算机是如何做到的,他只不过得到了方便的可以处理的数据(可能是放在表格里的)。
术语中把用户的问题叫做“查询”,把得到的结果叫做“表”或“视图”。在Visual Basic里解决这类问题的是Microsoft Access,Jet”机。查询关系数据库的常用语言叫做SQL(Structured Query Language)结构化查询语言。在Visual Basic的专业版和企业版中SQL是固有的。
§2 通过数据库控件(Data Control)处理Visual Basic的数据库

通过数据库控件(Data Control)处理的数据库类型里,最适合Visual Basic的就是Access类型的数据库,可以说Visual Basic的数据库和Access的数据库是完全相同的。如果使用的是Jet database engine(也就是Access类型)的数据库,则我们不必设置数据库控件的Connect属性,否则我们得设置Connect属性为所使用的数据库类型名。
数据库类型
设置Connect属性
设置路径
Access
";"
"drive:\path\filename.MDB"
dBASE III
"dBASE III;"
"drive:\path"
dBASE IV
"dBASE IV;"
"drive:\path"
Paradox 3.x
"Paradox 3.x;"
"drive:\path"
Paradox 4.x
"Paradox 4.x;"
"drive:\path"
Btrieve
"Btrieve;"
"drive:\path\filename.DDF"
FoxPro 2.0
"FoxPro 2.0;"
"drive:\path"
FoxPro 2.5
"FoxPro 2.5;"
"drive:\path"
FoxPro 2.6
"FoxPro 2.6;"
"drive:\path"
Excel 3.0
"Excel 3.0;"
"drive:\path\filename.XLS"
Excel 4.0
"Excel 4.0;"
"drive:\path\filename.XLS"
Excel 5.0
"Excel 5.0;"
"drive:\path\filename.XLS"
如果你找不到Microsoft Access的话,你就不得不用Visual Basic自带的Data Manager建立自己的Access数据库文件,然而在使用过后会发现Data Manager是十分不便利的,你可以在Visual Basic的Add-Ins菜单下找到Data Manager。
显示数据例如用一个正文框和一个数据库控件读取一个MDB文件里一个表(Table)里的一个域(Field)里的信息,这个功能我们连一条代码也不用编,这正是Visual Basic在数据库方面的优势所在。
画出一个数据库控件,按F4键打开Properties窗口。
选择DatabaseName属性并单击设置框旁边的有省略号的那个钮,Visual Basic显示DatabaseName对话框,在这个对话框里选择你要的数据库文件。
选择RecordSource属性,从下拉的列表里选择一个Table,这个数据库控件在运行时将指向这个Table。现在数据库控件的属性设置完了。
画出一个正文框,按F4键打开Properties窗口。
选择DataSource属性,从下拉列表里选择正文框对应的数据库控件。
选择DataField属性,从下拉列表里选择正文框对应的Field。
所以,简单地说,画两个控件设置四个属性就可以读取一个数据库一个Table的一个Field了。在运行时,数据库控件的四个按钮可以用来移动记录。最左边的钮表示移动到第一条记录上,最右边的钮表示移动到最后一条记录上,另两个在内侧的钮分别表示每次向前或向后移动一条记录。
移动记录除了使用数据库控件四个按钮来移动记录外,代码也可以实现这些功能,假设数据库控件的名字叫Data1。
功能
代码
显示第一个记录
Data1.Refresh
Data1.Recordset.MoveFirst
显示最后一个记录
Data1.Recordset.MoveLast
显示下一个记录
Data1.Recordset.MoveNext
显示上一个记录
Data1.Recordset.MovePrevious
删除记录首先用上面的那些方法找到这个倒霉的记录,然后用下面的代码删除它。
Data1.Recordset.Delete
Data1.Recordset.Update
第一行表明要删除这个记录,第二行表明让数据库文件知道这个不幸的决定。
增加记录
Data1.Recordset.AddNew
Data1.Recordset.Fields(“FieldName”) =,NewData”
Data1.Recordset.Update
第一行决定要增加一个新记录,第二行表示增加的内容,其中FieldName 是Field 的名称,NewData 是增加的内容,第三行把这个决定通知数据库文件,让它去做这件事。
找出指定的记录假定在一个Table 里的Age 域里寻找记录值为18的记录,则:
功能
代码
找出第一个匹配的记录
Data1.Recordset.FindFirst,Age = ‘18’,
找出最后一个匹配的记录
Data1.Recordset.FindLast,Age = ‘18’,
找出下一个匹配的记录
Data1.Recordset.FindNext,Age = ‘18’,
找出上一个匹配的记录
Data1.Recordset.FindPrevious,Age = ‘18’,
从数据库域中取得数据
x = Data1,Recordset.Fields(“FieldName”).Value
这条指令将取出存在域FieldName 中的数据并赋给x。
改变数据库中域的数据
Data1.Recordset.Edit
Data1.Recordset.Fields(“FieldName”).Value = NewValue
Data1.Recordset.Update
这段指令将NewValue 中的值代替FieldName 域中的当前值。
§3 使用数据库网格、数据库组合框、数据库列表框控件

现在我们先加入一个数据库控件(它暂时叫做Data1),我们为它设置好DatabaseName、RecordSource属性。
生成数据库网格在工具箱中单击数据库网格控件,拖动它成为数据库网格;
按F4键;
单击DataSource属性,选择刚才建立的数据库控件Data1。
现在就可以显示你所选择的数据记录,不需要你编写任何代码。
修改显示在网格里的数据你可以编辑在网格里的数据,因为它与数据库控件已经建立了联系。但你必须改变下面三种数据库网格的属性。
属性
值
含义
AllowUpdate
True
可任意修改数据库网格中的数据
False
只显示数据,不能修改
AllowDelete
True
可删除所有记录
False
不可删除记录
AllowAddNew
True
可增加新记录
False
不可增加新记录
数据库组合框数据库组合框用来在数据库中输入新数据。数据库组合框可以显示储存在某一字段的数据内容,这一字段用户可以从中选择,也可以输入一新值。生成数据库组合框的方法:
在工具箱中单击数据库组合框控件,拖动它成为数据库组合框;
按F4键;
单击DataSource属性,选择你的数据库控件Data1;
单击RowSource属性,选择你的数据库控件Data1;
单击ListField属性,选择你想在数据库组合框中出现的字段;
单击DataField属性,选择你想在数据库组合框中作为默认选择而出现的字段。(通常和上一步一样)
数据库列表框数据库列表框可以显示储存在数据库字段中的数据内容,虽然你可以看到数据,但你不能增加、删除和编辑它的内容。生成数据库列表框的方法:
在工具箱中单击数据库列表框控件,拖动它成为数据库列表框;
按F4键;
单击DataSource属性,选择你的数据库控件Data1;
单击RowSource属性,选择你的数据库控件Data1;
单击ListField属性,选择你想在数据库列表框中出现的字段;
单击DataField属性,选择你想在数据库列表框中高亮度显示的字段。(通常和上一步一样)
总之,数据库的建立是十分有用的,然而当你发行你的应用程序的时候,含有数据库控件的应用程序往往所需的发行文件比你想象的要大。
第七章 从文件中存取资料每个程序几乎都要往磁盘上存储数据,这些数据可能是表格、图形、姓名和地址清单、或者是游戏的存储进度。很难想象一个大型的RPG游戏不允许游戏者存盘。这一章将学习关于存储文件的知识。
§1 文本文件,就象盒式磁带机生成文本文件,使用下列命令:
Open "Filename" For Output As #FileNumber
其中Open告诉Visual Basic生成一个新文件;Filename是文件名(可以包含路径);For Output表明文本文件要接受程序输出的数据;FileNumber是文件号(1-511之间),Visual Basic很傻,不知道文件名,它只认文件号,程序可能打开多个文件,如果你忘了该生成哪一号文件,你可以用FreeFile函数来得到一个文件号。如:
Dim Free As Integer
Free = FreeFile
Open "c:\abe.def" For Output As #Free
则生成文件c:\abe.def,Visual Basic替你找一个未用的文件号来代表它。
打开已有的文本文件
Visual Basic不仅仅想知道你要打开文件,它还想知道你打开文件后想做什么。
如果你想从文本文件中读取数据给计算机,则使用下面命令:
Open "Filename" For Input As #FileNumber
如果文件不存在,Visual Basic就会对你的玩笑表示生气,它会发出叫声,然后指出你的错误。
如果你想把数据写到文本文件中,则使用下面命令:
Open "Filename" For Output As #FileNumber
快看这个命令和生成新文件的命令一样!你可以这样理解:如果Visual Basic找不到那个文件,那么它就生成一个新的,如果它找到了,就打开文件并准备向里面写东西。但是如果程序员向已存在的文件内写数据,那么将会把原来的数据覆盖掉。这可要小心!
如果你想把数据追加写到文本文件中,则使用下面命令:
Open "Filename" For Append As #FileNumber
这种操作也是准备写数据到文本文件中,不过Visual Basic将把数据追加到文件的末尾。
向文本文件中写数据
Print #FileNumber,"Text String"
将Text String字符串写入#FileNumber代表的文件中,写到什么地方取决于你打开文件的方式。For Output方式写到文件的开头,For Append方式写到文件的末尾。
关闭文件不论什么时候生成了文本文件或打开了已有的文本文件都要在程序终止前关闭它。否则,可能会出现一些问题,甚至把文件内的数据搞坏。
关闭所有打开的文件,可使用命令:Close
关闭特定的文件,可使用命令:Close #FileNumber
从文本文件中读取数据首先要用For Input方式打开文本文件,然后可将文件内容赋给一个字符串变量。由于在32位系统中,字符串的容量可达百兆,所以可以简单地把文件的内容赋给一个字符串变量。在16位的系统中读取大文件时,恐怕还要考虑内存的问题。
Dim FileContents As String
Open "Filename" For Input As #FileNumber
FileContents = Input(LOF(FileNumber),FileNumber)
Close #FileNumber
第三句就可以将文件的所有内容读入FileContents中,LOF函数用以去得文件的长度。
改变文本文件的内容,这是很烦琐的过程,需用下面的步骤。
打开文件。
取出文件内容赋给一个变量。
关闭文件。
编辑变量内容。
打开文件。
变量存入文件。
关闭文件。
§2 随机存取文件,就象CD
文本文件就象盒式磁带机,因为如果你想读取后面的数据就得把前面的数据先放过去。随机存取文件就象CD,因为你可以立即跳至你想听的那一首歌。随机存取文件是以结构(Structure)来存取的,在文件里数据放在一个一个结构里,
每个结构里的数据是一样的。
使用结构(Structure)保存信息写程序时,也许要生成几个变量来保存信息。如要跟踪如下的信息:姓名、地址、年龄。可以为各信息生成单独的变量,如:
Dim Name As String
Dim Address As String
Dim Age As Integer
然而,Visual Basic看不出这些信息的关联之处,对Visual Basic来说这些信息散乱地堆放在内存中的某个地方,没有很好地组织起来。为了解决这个问题,Visual Basic使用叫做结构(Structure)的东西将分散的东西组织起来。在别的一些语言里这被称为记录类型。如下面的例子:
Type PersonRecord
Name As String
Address As String
Age As Integer
End Type
生成结构只能在代码窗口的声明区生成结构。即在Object列表框中选择(General),在Proc列表框中选择(declarations)后再输入结构。在窗体的声明区生成结构须加上Private关键字。
定义变量为结果类型
Dim VariableName As StructureName
如上面的PersonRecord结构,可用下面的代码定义:
Dim Employees As PersonRecord
赋值给结构中的数据例如赋值给上面定义的Employees变量:
Employees.Name = "Tom"
Employees.Address = "1-107"
Employees.Age = 22
取出结构中的数据例如取出上面赋值过的Employees变量中的数据:
Who = Employees.Name
随机存取文件里的结构随机存取文件里有一个一个的结构,它们安静地象下面一样排列着:
Name
Address
Age
Name
Address
Age
随机存取文件使用的重要变量用一个变量代表你定义的结构,用一个变量跟踪现在的位置,再用一个变量表明最后一个结构的位置。
Dim Friends As FriendStructure
Dim Position As Long
Dim LastOne As Long
必须有一个变量来代表你定义的结构。
生成和打开随机存取文件
Open "Filename" For Random As #FileNumber Len = StructureLength
看起来和生成和打开文本文件的语句差不多,如果Visual Basic找不到文件的话则Visual Basic就生成一个新的文件,如果找到的话就把旧文件打开。For Random告诉Visual Basic你想打开一个随机存取文件。#FileNumber还是文件号,你可以用FreeFile让Visual Basic替你选一个没有用过的文件号。StructureLength是你的结构的长度,如果你不知道的话,可以用Len函数来获得。如:
Dim StructureLength As Long
Dim Friends As PersonRecord ‘PersonRecord是一个结构名称
StructureLength = Len(PersonRecord)
向随机存取文件写入数据
Put #FileNumber,Posetion,DataName
Put表明你想向由#FileNumber决定的随机存取文件里写入数据,Posetion是你想放置数据的位置。在随机存取文件里第一个结构放在位置1,第二个结构放在位置2,等等。需要知道的是:随机存取文件的写入和读出不需要以不同的方式打开文件,Open…For Random打开文件后既可以写入又可以读出,比文本文件方便多了。
下面是向文件的末尾增加数据的代码的示例,LastOne变量用于表明文件已存在多少结构:
Dim StructureName As StructureType ‘StructureType是一个结构的名字
Dim SLength As Long
Dim LastOne As Long
SLength = Len(StructureName)
Open "FileName" For Random As #FileNumber Len = SLength
LastOne = LOF(FileNumber) \ Slength ‘LOF函数返回FileNumber文件号代表的文件的长度
LastOne = LastOne + 1
Put #FileNumber,LastOne,StructureName
Close #FileNumber
下面是替换文件中结构的代码的示例:
Dim StructureName As StructureType ‘StructureType是一个结构的名字
Dim SLength As Long
SLength = Len(StructureName)
Open "FileName" For Random As #FileNumber Len = SLength
Put #FileNumber,Position,StructureName ‘Position是你想替换的结构的位置
Close #FileNumber
从随机存取文件中读出数据
Dim GetData As StructureType ‘StructureType是一个结构的名字
Get #FileNumber,Position,GetData
这样就可以把#FileNumber代表的文件中的在Position位置上的数据读到GetData变量中。
关闭文件一定要在程序终止前关闭打开的文件。否则,可能会出现一些问题,甚至把文件内的数据搞坏。
关闭所有打开的文件,可使用命令:Close
关闭特定的文件,可使用命令:Close #FileNumber
§3 二进制文件二进制文件并不是一种新的文件类型,而是操作任何种类文件的一种方法。二进制文件技术允许程序员修改文件中的任意字节。所以说,二进制文件技术是一种强有力的工具,但是强有力的工具往往必须小心使用。使用二进制文件可以操作许多文件类型,甚至直接读写图形文件等等。具体的实现方法请参考其他详细介绍的书籍。
生成和打开二进制文件
Open "FileName" For Binary As #FileNumber
从二进制文件中读出数据
GetData = Input(Number,#FileNumber)
以上命令从#FileNumber代表的文件中在当前位置上开始Number个字节的数据读到GetData变量中。
定位文件的当前位置
Seek FileNumber,PositionNumber
以上命令将#FileNumber代表的文件的当前位置移到PositionNumber位置。
第八章 发行应用程序
§1 把你的应用程序编译成扩展名为EXE可执行文件终于,你把自己的应用程序编制完成了,而且你已经极其耐心地测试了你的程序或者你的程序已经通过质量部门的检测,于是要把它散发给用户去使用。为了散发程序,你必须把程序编译为可执行的文件(通常以EXE为扩展名)。下面是把程序编译为可执行文件的步骤:
保存文件;
从File菜单选择Make EXE File项,弹出Make EXE File对话框;
按Options按钮,弹出EXE Options对话框;
做你需要的修改后,按OK按钮;
在Make EXE File对话框填入可执行文件名后按OK按钮。
这样你就生成了可执行文件。现在来解释一下EXE Options对话框中各项的含义。

Version Number是程序的版本号,现在的版本号是1.06。Auto Increment被选择上后每次编译,Visual Basic将自动把Revision加1。
Application Title是程序的标题,Application Icon是程序的图标。
Version Information是一系列版本信息,包括:说明、公司名、文件描述、合法版权、合法商标、产品名称。
§2 使用Package & Deployment Wizard
当你完成了你的伟大应用程序后,如何让你的朋友或任何一个人了解你编程的艰辛和胜利的喜悦呢?你可以把程序发行出去。看看Microsoft的各种软件均有简便的安装程序,这时你想:“天哪!我还得编个安装程序。”然而,在Visual Basic中有工具来帮助你完成这相任务,我极力建议你使用这个安装工具来取代你打算自己编个安装程序的念头,原因有三:
此安装工具可在几分钟内替你搞定一切,不论你想用磁盘或光盘来发应用程序;
安装工作复杂的配置会使人走火入魔;
安装工具生成的安装程序还提供卸载功能。
在开始菜单程序组的Visual Basic组里有”Package & Deployment 向导”的图标,单击它可进入”Package & Deployment 向导”。
第一步在选择工程(J)里填入.vbp文件的名字,如果按右边带“…”的按钮将会打开一个对话框搜索.vbp文件;
单击打包(P)到下一步。
二、第二步要生成应用程序的可执行文件,如果已编译并生成了可执行文件,向导会跳过这一步,否则会提示生成它。
第三步选择生成包类型,有两种:“标准安装包”和“相关文件”。
第四步在硬盘中生成文件夹,存储所有生成的部件。
第五步
选择向包中添加文件。
第六步确定安装程序的发行类型。
第七步定义安装程序标题。
第八步为安装包中的文件选择图标。
第九步 选择安装包中的文件的位置。
第十步选择安装后可共享的文件。
第十一步 FINISH
单击“展开”可将安装程序包分发出去。
单击“管理脚本”可对“包装脚本”和“展开脚本”进行管理。
你用Setup wizard生成的安装盘安装的应用程序可通过Windows 95的控制面板中的添加/删除程序功能卸载。现在,把你的程序送给你的朋友们吧!
第九章 使用Windows API和用Visual Basic建立自己的屏幕保护程序
§1 关于Windows API
我们现在将要探讨的是Windows Application Programming Interface (API)的知识,这个冗长的词汇的汉语意思是应用程序编程接口。这是一系列很复杂的函数、消息和结构,它使编程人员可以用不同类型的编程语言编制出在Windows 95和Windows NT上运行的程序。Visual Basic程序员使用API深入Windows的内部过程,充分利用Windows。然而利用Windows API时要小心,因为如果你使用得不正确,就会彻底崩溃Windows。(不崩溃几回你怎么能学到东西呢)
Windows API是一系列的DLL文件,使用API函数和使用DLL文件中的函数是一样的。
那么你怎么知道Windows API里有什么函数呢?如果你只需要了解API的函数清单,那么你可以查看Visual Basic自己带的API Text Viewer;如果你想了解API每一个函数、消息或结构的具体含义,那么Visual Basic目前没有这方面的帮助。你需要购买Windows Software Development Kit(SDK),查询他们的手册(查询这种“手”册可是需要一定的臂力的,很厚哟)。在Visual C++里也有关于API函数、消息和结构的具体含义的帮助。
§2 使用API Text Viewer
Visual Basic自己带的API Text Viewer可以让你寻找Windows API函数,你还可以拷贝所需常数、函数声明语句或结构定义。在开始菜单的Visual Basic 6.0组里有API Text Viewer的菜单项,你可以选择它来打开API Text Viewer。
使用API Text Viewer请遵循以下步骤:
打开API Text Viewer。
从File菜单选择Load Text File,出现Select a Text API File对话框单击下列文件之一:
WIN32API.TXT 32位Windows API函数清单
WINMMSTS.TXT 多媒体Windows API函数清单单击Open按钮(可能会出现对话框,问你是否想要将文本文件转换为数据库),API函数清单出现在Available Items列表框。
单击API列表框,选择下列项目之一:
Constants(常数声明)
Declares(函数声明)
Types(结构定义)
单击你想在程序中使用的项,然后单击Add按钮,你想选择的项就出现在Selected Items列表框中。
对你想在程序中加入的每个常数、函数声明或结构定义重复5、6步。
单击Copy按钮。
切换回Visual Basic,将复制项粘贴到代码窗口的声明区。
最后退出API Text Viewer。
当然你可以不必使用API Text Viewer,但是API Text Viewer可以确保你没有拼写错误。
但是不要轻信API Text Viewer,Visual Basic提供的API声明始终没有做到完全正确(至少上一个版本的Visual Basic就没有提供完全正确的API声明),所以如果调用API不成功的话,可能是API声明有误的原因,请查阅Windows SDK来寻找正确的API定义。这种Bug令使用Visual Basic的程序员十分伤心,所以作为编程者,一定要编制稳定可靠的程序才能让你的用户满意。

§3 用Visual Basic制作自己的屏幕保护程序当我得知用Visual Basic可以制作自己的屏幕保护程序时,我的兴奋不亚于第一次看到流星。最初建立屏幕保护程序是用来保护屏幕不被不常变化的象素点“烧灼”出印记而编制的程序,现在,屏幕保护程序更多地用于娱乐而不是屏幕保护了。现在我们使用Visual Basic来制作我们自己的屏幕保护程序,这里仅仅是一个简单的例子,如果你了解了程序的原理,就可以编制更好的屏幕保护程序了。当你的朋友看到你的屏幕保护程序,他(她)八成会对你表示钦佩的。
对屏幕保护程序的设想我们得想想一个屏幕保护程序需要什么功能?
屏幕保护程序覆盖整个屏幕,甚至把汉字输入条都覆盖住。
屏幕保护程序可以检测到用户单击鼠标、移动鼠标、按键等事件。
鼠标指针不能出现。
适当地处理通过显示器属性对话框访问的Setting、Preview、Password选项。
有一些简单的动画来吸引用户。
还有一个现实的问题,不能让两个或两个以上屏幕保护程序运行,因为如果每隔一段时间就打开一个屏幕保护程序,那么系统的资源迟早得被耗尽。
这些功能有一些需要调用Windows API的函数来实现。现在我们来实现我们简单的屏幕保护程序。它是仿造Windows自带的滚动字幕屏幕保护程序设计的。
生成界面对象
属性
设置值
Form1
AutoRedraw
True
BackColor
黑色
BorderStyle
0 - None
Caption
我的编程世界……
ControlBox
False
KeyPreview
True
MaxButton
False
MinButton
False
Name
frmScreenSaver
ScaleMode
3 - Pixel
WindowState
2 - Maximized
Label1
AutoSize
True
BackStyle
0 - Transparent
BorderStyle
0 - None
Caption
我的编程世界……
ForeColor
红色
Font
幼圆
Timer1
Enabled
False
Interval
1

三、编写代码在窗体下加入下面的代码:
Option Explicit
Dim QuitFlag As Boolean
Const SPI_SETSCREENSAVEACTIVE = 17
Private Declare Function SetWindowPos Lib "user32" ( _
ByVal hwnd As Long,_
ByVal hWndInsertAfter As Long,_
ByVal X As Long,_
ByVal Y As Long,_
ByVal cx As Long,_
ByVal cy As Long,_
ByVal wFlags As Long _
) As Long
Private Declare Function ShowCursor Lib "user32" ( _
ByVal bShow As Long _
) As Long
Private Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
Private Declare Function SystemParametersInfo Lib "user32" Alias "SystemParametersInfoA" ( _
ByVal uAction As Long,_
ByVal uParam As Long,_
ByVal lpvParam As Long,_
ByVal fuWinIni As Long _
) As Long
Private Sub Form_Click()
QuitFlag = True
End Sub
Private Sub Form_KeyDown(KeyCode As Integer,Shift As Integer)
QuitFlag = True
End Sub
Private Sub Form_Load()
Dim Throw As Long
Throw = SystemParametersInfo(SPI_SETSCREENSAVEACTIVE,0,ByVal 0&,0)
Select Case UCase$(Left$(Command$,2))
Case "/A"
MsgBox "此屏幕保护程序不可以设置口令。"
Unload Me
Exit Sub
Case "/C"
MsgBox "此屏幕保护程序没有设置项。"
Unload Me
Exit Sub
Case "/P"
Unload Me
Exit Sub
Case "/S"
Show
Throw = ShowCursor(False)
Throw = SetWindowPos(hwnd,-1,0,0,0,0,(&H2 Or &H1))
Label1.Left = frmScreenSaver.ScaleWidth
Label1.Top = (frmScreenSaver.ScaleHeight - Label1.Height) / 2
Do
Label1.Left = Label1.Left - 3
Sleep (50)
If Label1.Left <= -Label1.Width Then Label1.Left = frmScreenSaver.ScaleWidth + Label1.Width
DoEvents
Loop Until QuitFlag = True
Timer1.Enabled = True
Case Else
Unload Me
Exit Sub
End Select
End Sub
Private Sub Form_MouseMove(Button As Integer,Shift As Integer,X As Single,Y As Single)
Dim Xnow As Single,Ynow As Single
Static Xlast As Single,Ylast As Single
Xnow = X
Ynow = Y
If Xlast = 0 And Ylast = 0 Then
Xlast = Xnow
Ylast = Ynow
Exit Sub
End If
If Xnow <> Xlast Or Ynow <> Ylast Then
QuitFlag = True
End If
End Sub
Private Sub Form_Unload(Cancel As Integer)
Dim Throw As Long
Throw = SystemParametersInfo(SPI_SETSCREENSAVEACTIVE,1,ByVal 0&,0)
Throw = ShowCursor(True)
End Sub
Private Sub Label1_Click()
QuitFlag = True
End Sub
Private Sub Label1_MouseMove(Button As Integer,Shift As Integer,X As Single,Y As Single)
QuitFlag = True
End Sub
Private Sub Timer1_Timer()
Unload Me
End Sub
我们稍过一会儿再分析着段代码。
四、项目设置从Tool菜单中选择Options项。
选中Advanced标签。
把Command Line Arguments设置为/S。
从File菜单中选择Make EXE File项,弹出Make EXE File对话框。
按Options按钮,弹出EXE Options对话框。
把Application组里的Title设置为“SCRNSAVE 我的编程世界”,注意以SCRNSAVE开头是十分重要的。
按OK按钮。
在文件名里输入“我的编程世界.SCR”,注意以SCR为扩展名是十分重要的,这样Windows才把这个程序看成是一个屏幕保护程序。
按OK按钮,Visual Basic为你生成你的屏幕保护程序,你只要把它拷贝到你的Windows目录下就可以了。
使用我们的屏幕保护程序在背景上用鼠标右键单击,从弹出的快捷菜单中选择属性项。
选中屏幕保护程序标签。
从屏幕保护程序的下拉列表框里找到刚才制作的“我的编程世界”屏幕保护程序。(Windows自动在Windows目录和Windows\System子目录下寻找扩展名为SCR的文件作为屏幕保护程序)
按确定按钮。
当你等待一段时间后你就会看到自己屏幕保护程序的运行了。
当你看到自己的屏幕保护程序后,我们来看看这个程序的代码的有趣之处
QuitFlag变量是一个布尔型的变量,它用于判断是否我们应该结束我们的屏幕保护程序。
接下来的一个常量声明和四个API函数声明是从API Text Viewer里拷贝下来的,这些函数使我们需要的一些功能得以实现。
SetWindowPos函数帮助我们使窗体成为最上层的窗体,这种窗体甚至可以覆盖住汉字输入条。ShowCursor函数使鼠标消失和重现。Sleep过程让程序暂停一段时间,它的唯一的参数决定了暂停的毫秒数。SystemParametersInfo函数在程序开始时通知系统已经有一个屏幕保护程序被激活,在程序结束时通知系统该屏幕保护程序不再使用,这样就不会激活新的屏幕保护程序了。
Windows启动屏幕保护程序时会加一个命令行参数来起动程序,所以屏幕保护程序运行起来后在Form_Load过程中先判断该程序的命令行参数,这些命令行参数的描述是:
命令行参数
描述
/A
在显示器属性对话框中按更改口令的按钮
/C
在显示器属性对话框中按设置按钮
/P
当选中屏幕保护程序标签时,在小显示器上显示预览
/S
在显示器属性对话框中按预览按钮,或该屏幕保护程序由系统正常启动
在本程序中,只有/S参数有效。
下面程序将陷入一个循环,它使Label1一直在窗体上运动直到QuitFlag为True,由于不可以在Form_Load过程里卸载程序,所以我们打开一个计时器控件,让它来执行卸载的任务。
当程序启动的时候,尽管鼠标并未移动,但还是会产生一个MouseMove事件(不能理解Visual Basic)。所以我们得忽略第一个MouseMove事件,在Form_MouseMove过程里有一点小技巧来实现这个忽略。
怎么样?Visual Basic比你想象的有乐趣吧!
第十一章 创建ActiveX控件
ActiveX 控件可添加到任一工程类型中。当控件作为某个,exe 文件的一部分编译时,它不能被其它应用程序共享。在本章后面的步骤中,ShapeLabel 控件被编译进一个,ocx 文件,这样它可以被共享。 因此将像 ActiveX 控件工程那样创建 ControlDemo 工程。
一个 ActiveX 控件工程能够包含任意个所需的控件。 创建工程时,.ocx 结果文件包含已添加的所有控件。
§1 创建 ControlDemo 工程
1 在“文件”菜单上单击“新建工程”打开“新建工程”对话框。(这将关闭当前工程或工程组,系统会提示保存所作的改变。)双击“ActiveX 控件”图标用以创建新工程。
Visual Basic 自动地把一个 UserControl 设计器添加到此工程中。 缺省名 UserControl1 作为设计器的标题出现。

2 在“工程”菜单上单击“Project1 属性”,打开“工程属性” 对话框。选择“通用”选项卡,填写如下所示的信息后单击“确定”。

3 在“工程资源管理器”窗口中双击 UserControl1 使设计器置前。
4 在“属性”窗口中双击“名称” 属性并且把用户控件名改为ShapeLabel。新名字出现在设计器的标题和“工程资源管理器”窗口中。
用户指定的名字成为用户控件的类名,正如 CommandButton 是命令按钮的类名一样。“建立 ActiveX 控件”提供了选择控件类名的指南。
要注意“属性”窗口看上去很像 Visual Basic 窗体。只是习惯见到的某些属性消失了,而有的一些属性在一般的 Visual Basic 窗体上又找不到。这些属性将在“建立 ActiveX 控件”中讨论。
5 在该控件设计器中,控件右下角的拖曳点可调整控件的大小,向左上拖动该点使控件变小。
这样就设置了控件的默认尺寸。 为了后面过程中方便,ShapeLabel 控件应有适当的大小。
6 在“文件”菜单上单击“保存工程”可保存工程文件。用下表所示方式给它们命名。Visual Basic 自动提供所指定的扩展名。
文件
文件名
扩展名
用户控件
ControlDemo_ShapeLabel
.ctl
工程
ControlDemo
.vbp
 控件中诸如位图之类的二进制信息会保存到一个同名的二进制文件中,该文件的扩展名为,ctx 。
§2 添加TestCtlDemo工程为了测试 ShapeLabel 控件,需要有一个测试窗体。由于,ocx 工程不能独立运行,所以不能只是把测试窗体添加到 ControlDemo 中后运行该工程。(这样相当于只靠自身运行,ocx 文件。)
为了能够调试运行中的部件,Visual Basic 允许在同一工程组中装入两个或更多的工程。 除了使运行中的调试生效以外,该工程组还使得,ocx 工程和测试工程的装入更加容易。
为了将测试工程添加到工程组中
1 在“文件”菜单上单击“添加工程”用以打开“添加工程”对话框。
重点 不要单击“打开工程” 或“新建工程”,否则会关闭控件工程。
2 可双击“Standard EXE”图标以添加普通的,exe 工程。 现在既可以看见“工程资源管理器”窗口中的工程,也可以看见“工程资源管理器”窗口的标题所显示的缺省工程组名。
该新工程立即成为这个工程组的“启动”工程。“工程资源管理器”窗口以其黑体名字的显示来标识“启动”工程。 一个像 ControlDemo 那样的 ActiveX 控件工程是不能作为启动工程的。
3 在“文件”菜单上单击“保存工程组”用以保存测试工程和工程组。 按如下所示方式给文件命名。Visual Basic 自动提供所指定的扩展名。
文件
文件名
扩展名
窗体
TestCtlDemo_Form1
.frm
工程
TestCtlDemo
.vbp
工程组
ControlDemo
.vbg
§3 设计时运行 ShapeLabel 控件与其它可编程对象不同,控件同时具有设计时和运行时的两种行为。 即开发者在设计时把一个控件实例放入窗体时,控件中的一些代码将会执行。
例如,放置在 UserControl_Resize 事件过程中的代码在设计和运行时都会执行。
为了调试控件设计时的行为,当放置有控件的测试窗体保持在设计模式中时,必须能够执行控件中的代码。
以下两个过程演示了这种灵活技巧。在第一个过程中,把代码添加到 ShapeLabel 控件的 Resize 事件中。在第二个过程中,当测试工程保持在设计模式中时,使 ControlDemo 的一部分进入运行模式后把 ShapeLabel控件的实例添加到测试工程的窗体中。
为了把代码添加到 Resize 事件中
1 在“工程资源管理器”窗口双击“ShapeLabel”使其成为活动的设计器。
2 双击“ShapeLabel”控件打开代码窗口。
3 在过程框中单击 Resize 事件以进入它的事件处理过程。添加下列代码:
Private Sub UserControl_Resize()
Static intCt As Integer
intCt = intCt + 1
Debug.Print "Resize " & intCt
End Sub

注意 事件处理过程名具有“UserControl”前缀,正如相对普通窗体的Form_Resize 事件过程具有前缀“添加窗体”一样。

开发普通的 Visual Basic 应用程序时,需要单击工具栏上的“启动”按钮或者按下 F5 键来运行应用程序。然而要把 ShapeLabel 控件放入Form1,只须运行此控件的代码而把其它代码保持在设计模式中。
在设计时运行 ShapeLabel 控件
1 在“工程”口中双击 ShapeLabel,将设计器前置,然后按下 CTRL+F4 来关闭窗口。关闭设计器窗口使 ShapeLabel 控件进入运行模式。只要控件进入运行模式,其图标(用户控件的默认工具箱图标)就出现在工具箱中。
重点 不要单击工具栏上的“启动”按钮或者按下 F5 键,因为那样会使整个工程组进入运行模式从而无法把新控件添加到窗体中。
当控件进入运行模式时,是否关闭设计器窗口就是无关紧要的了。(因为控件工具箱将变成灰色,所以总知道设计器是否打开。)
2 在“工程资源管理器”窗口双击“Form1”使其置前。
3 双击“ShapeLabel”图标以便把 ShapeLabel 控件添加到 Form1 中。该控件以带有抓取控点的灰色平面矩形形式出现。
在“属性”窗口可以看见新控件的默认属性。刚刚添加到窗体中的 ShapeLabel 控件已被赋予缺省名 ShapeLabel1。
注意 开始设计控件时便为其命名可避免引起混淆。假定把一个具有缺省名(比如 UserControl1)的控件放入窗体,新控件自动编号功能会把一个数字附加到这个控件名之后,得到一个象 UserControl11 这样的易混淆的名字。
4 当 ShapeLabel 控件放入窗体时,Resize 事件被引发。查看“立即”窗口能够见到这一事件。使用抓取控点进行数次调整控件大小的动作。每次调整控件大小时,Resize 事件均再次引发。
如果只是在窗体里简单地移动控件,Resize 事件不会引发。
5 在 Form1 上双击“ShapeLabel”控件以便打开 Form1 的代码窗口。光标将出现在缺省事件过程 ShapeLabel1_GotFocus 上。可以用“过程”框来查看 Visual Basic 自动为控件提供的另外三种事件。 完成工作后要关闭代码窗口。
6 在“工程资源管理器”窗口双击“ShapeLabel”以便打开 ShapeLabel 设计器。 请注意放在 Form1 上的 ShapeLabel 控件标记上了阴影,这表明它是非活动的。
打开一个控件的设计器会使该控件的所有实例变成非活动的。 更改控件代码窗口的代码也会使控件实例变成非活动的。
7 当设计器打开时,不能执行 ShapeLabels 代码模块中的代码。 可用控点来调整 Form1 中带阴影的 ShapeLabel 控件的大小。Resize 事件不激发,因此在“立即”窗口不会出现新消息。
8 确保 ShapeLabel 的设计器在前面,然后按下 CTRL+F4 以关闭窗口,重新激活控件实例。阴影从 Form1 的控件上消失表明实例又被激活了。
如果由于改动控件的代码而使控件变成非激活状态时,那么可用鼠标右键单击测试窗体以便显示其上下文菜单,单击“更新用户控件”可重新激活控件实例。
§4 UserControl 对象的存活期普通的 Visual Basic 窗体存活期由一些关键事件所标记,比如 Initialize、Load、QueryUnload 和 Unload 等事件。为了创建行为符合标准的应用程序,知道这些事件在窗体存活期中何时引发是十分重要的。
这对控件也同样适用。UserControl 存活期中的关键事件是 Initialize,InitProperties,ReadProperties,WriteProperties 和 Terminate。下列过程将探讨这些事件。
为了观察 ShapeLabel 的关键事件,
1 在“工程资源管理器”窗口双击“ShapeLabel”以便打开其设计器。
2 双击设计器,为 ShapeLabel 打开代码窗口,并输入下列事件过程中的代码:
Private Sub UserControl_Initialize()
Debug.Print "Initialize"
End Sub

Private Sub UserControl_InitProperties()
Debug.Print "InitProperties"
End Sub

Private Sub UserControl_ReadProperties(PropBag As _
PropertyBag)
Debug.Print "ReadProperties"
End Sub

Private Sub UserControl_WriteProperties(PropBag _
As PropertyBag)
Debug.Print "WriteProperties"
End Sub

Private Sub UserControl_Terminate()
Debug.Print "Terminate"
End Sub

注意 对于 UserControl 对象而言,Load 和 Unload 事件被ReadProperties 和 WriteProperties 事件所代替。“建立 ActiveX 控件”中的“理解控件的存活期和关键事件”部分将更加详细地讨论这些内容。
3 确保 ShapeLabel 的设计器在前面,然后按下 CTRL+F4 以关闭窗口,使控件进入运行模式。 调试信息将出现在“立即”窗口中。
这里发生了什么事情呢? 尚未将 ShapeLabel 控件的另一个实例放入Form1。所有这些事件来自何处?
这说明了有关控件的一个重要问题。 把控件放入窗体后,它就被视为这个窗体的永久设施了。以控件作者的眼光来看,控件总是在被撤消和重建。
通过关闭 ShapeLabel 的设计器而将 ShapeLabel 置于运行模式时,Form1 上的 ShapeLabel 实例被撤消并重建,这时它接收一个 Initialize 事件。为什么首先看不见 Terminate 事件?这是因为置在 Form1 上的原始ShapeLabel 实例是添加 UserControl_Terminate 事件过程代码之前创建的!欢迎来到充满活力的创建控件的拓荒之地。
注意 单击窗体上下文菜单上的“更新用户控件”时,控件各个实例也都将被撤消和重建。
4 按下 CTRL+F5 键或者单击工具栏上的“启动” 按钮来运行TestCtlDemo。工程运行时,Form1 上的网格消失,因此看不见 ShapeLabel,但是在“立即”窗口可以看见其实物的闪现。
控件实例创建之后,ReadProperties 事件提供机会,从包含此控件实例的窗体所属的,frm 文件获取该控件所保存的属性值。
当设计时的控件实例被撤消时,WriteProperties 事件提供机会以保存在设计时设置的属性值。属性值保存于包含窗体的,frm 文件中,正如在本章后面“保存 ShapeLabel 控件的属性值”中所见到的一样。
控件撤消时引发 Terminate 事件。
注意 根据默认,在(由“工具”菜单访问的)“选项”对话框的“通用”选项卡上选中“请求时编译”选项。用 CTRL+F5 (或“运行”菜单上的“启动全编译”)覆盖“请求时编译”,并在进入运行模式之前编译组中全部工程。这是很有用的,因为编译错误通常要求重新设置工程,这意味着要返回设计模式。在调试控件时,可能宁可关闭“请求时编译”,也不愿意使用 CTRL+F5。
5 关闭 Form1 将工程返回到设计模式。在“立即”窗口中,当运行时期的 ShapeLabel 实例被撤消时,将看见一个 Terminate事件(但不是 WriteProperties,为什么不是呢?)。然后当设计时的控件实例被创建时会看见 Initialize、ReadProperties 和 Resize 事件。
运行时期的控件实例永远不会获得 WriteProperties 事件,因为它并不需要保存其属性值。要知道为什么,应考虑 ShapeLabel 的未来。 当它被便编译成,ocx 文件时,它会被添加到另一个工程,把一个实例放入窗体,将此工程编译成一个,exe 文件并使其运行。 关闭该,exe 文件时,ShapeLabel 实例能够保存其属性值的唯一地方就是该,exe 文件。 而行为标准的操作系统不能容许这类行为。
6 滚动到“立即”窗口的顶端,单击左上角,拖动以选择该窗口的全部文本。 按下 DELETE 键清除此窗口。
7 在“工程资源管理器”窗口双击 Form1 使其置前。
8 在“工具箱”上双击“ShapeLabel”图标把另一个控件实例添加到“Form1”中。这时会看见一个新事件。
把控件的新实例放入容器时,它获得一个 InitProperties 事件。 可把代码放入 UserControl_InitProperties 事件过程以便:
■ 为每个控件属性值设置缺省值
■ 无论何时创建控件实例均执行任务。
1 单击 Form1 设计器的“关闭”按钮或在设计器前置时按下 CTRL+F4 使其关闭。在“立即”窗口会看见两组 WriteProperties 和 Terminate 事件,各自对应 ShapeLabel的一个实例。
2 在“工程资源管理器”窗口双击 Form1 再次打开其设计器。当设计器打开时,Form1上的所有控件均被创建并且它们的 Initialize 事件被触发。之后所有控件接收 ReadProperties 事件,从而允许它们检索其已保存的属性值。 InitProperties 事件不会引发,因为 ShapeLabel 控件的两个实例均已存在。
§5 ShapeLabel 控件的画出可使用诸如 Circle 和 Line 的图形方法绘出控件,或者使用已有的 ActiveX 控件和 Visual Basic 内在的控件创建自己控件的外观。添加给 UserControl 为其创建外观的那些控件称之为子控件。
就象它的名字所表明的一样,ShapeLabel 的外观就是由 Shape 控件和 Label 控件创建的。
给 ShapeLabel 添加字控件
1 在“工程资源管理器”窗口双击“ShapeLabel”打开它的设计器。
2 在“工具箱”上双击 Visual Basic Shape 控件把 Shape 控件放到ShapeLabel 设计器中。如果以前尚未使用过 Shape 控件,把鼠标保持在工具框按钮上直至发现其 ToolTip 是“形状”。
3 在“属性”窗口为 Shape 控件设置以下属性值:
属性
值
BorderStyle
0 - 透明的
FillColor
&H000000FF (红色)
FillStyle
0 - 实线
Name
shpBack
Shape
2 - 椭圆
 注意 要将诸如 FillColor 和 ForeColor 等的属性设置成指定的颜色,应选择“颜色选择”对话框的“调色板”选项卡。
4 在“工具箱’上双击 Label 控件,在 Shape 控件顶部添加一个选项卡。在“属性”窗口为 Label 控件设置以下属性值:
属性
值
Alignment
2 - 居中
BackStyle
0 - 透明的
ForeColor
&H00FFFFFF (白色)
Name
lblCaption
5 使用底部抓取控点调整此选项卡的高度,使它稍高于所包含的正文。
6 双击 ShapeLabel 设计器使代码窗口置前,用以下代码替换 UserControl_Resize 事件过程中的代码:
Private Sub UserControl_Resize()
' 变换 Shape 控件的大小
' 以便填充 ShapeLabel 的可见表面。
shpBack.Move 0,0,ScaleWidth,ScaleHeight
' 使 Label 控件垂直居中,
' 并使它的宽度与 ShapeLabel 一致。
lblCaption.Move 0,(ScaleHeight _
- lblCaption.Height) / 2,ScaleWidth
End Sub
7 在对用户控件进行设计时,要记住只能在由控件的 ScaleWidth 和ScaleHeight 约束的区域内工作。这个区域以外的任何事物对用户都是不可见的。此外,客户区的大小将随着用户的想法而改变。于是 Resize 事件就是控件设计中最重要事件之一。
8 确保 ShapeLabel 的设计器在前面,然后按下 CTRL+F4 以关闭窗口,使 ShapeLabel 进入运行模式。在“工程”窗口双击 Form1 使其置前。
9 现在两个 ShapeLabel 控件将以红色椭圆形式出现,带有居中的 Label1 的白色标题。可以调整 ShapeLabels 大小以测试 Resize 事件代码。
§6 保存 ShapeLabel 控件的属性值与在类模块中借助创建公共过程的方式添加属性名和方法类似,可以在 Active 控件中添加属性和方法。由于 ShapeLabel 将成为一个增强的控件,所以具有 Caption 属性将是很有意义的。
下列过程添加一个 Caption 属性和保存和检索属性值的支持代码。控件的属性值一直是和描述容器的其它数据一起保存,本例中的容器是 Form1。
在 ShapeLabel 控件中添加 Caption 属性
1 在“工程资源管理器”窗口双击“ShapeLabel”打开其设计器,再双击“ShapeLabel”使其代码窗口置前。
2 在“工具”菜单上单击“添加过程”打开“添加过程”对话框。在“名称”框输入名字 Caption。 单击“属性”和“公共的”后再单击“确定”。
3 在代码窗口更改如下面所出现的新创建的属性过程。
Public Property Get Caption() As String
Caption = lblCaption.Caption
End Property

Public Property Let Caption( _
ByVal NewCaption As String)
lblCaption.Caption = NewCaption
PropertyChanged "Caption"
End Property
注意 如上所示,在加入 As String 时要注意同时更改两个声明行。Property Get 和 Property Let 声明必须匹配。使用特定的类型名可加快执行速度,并且能为使用控件的开发者提供类型检查。
无论何时给 Caption 属性赋新值均执行 Property Let 过程。 它把新值直接保存到 ShapeLabel 上的 lblCaption 选项卡的 Caption 属性中。
无论何时检索该属性值均执行 Property Get 过程。它要读取保存在 lblCaption 选项卡的 Caption 属性中的该值。
如“建立 ActiveX 控件”中的“给控件添加属性”所述,控件中的 Property Let 过程必须调用 PropertyChanged 。这就告诉“属性”窗口刷新其显示内容,并通知 Visual Basic,窗体已经改变了。
Property 过程的讨论可在《程序员指南》的,用对象编程”中的“给类添加属性”部分找到。
4 为了初始化 Caption 属性,在 UserControl_InitProperties 事件过程中添加下列代码:
Private Sub UserControl_InitProperties()
'将 ShapeLabel 实例的名字
'赋给 Caption 属性
'作为它的初始值。
Caption = Extender.Name
Debug.Print "InitProperties"
End Sub

该例中的 Extender 对象是什么? 对控件用户而言,extender 属性同 Name,Top 和 Left 属性一样,是用户控件的一部分。 实际上 extender 属性是由控件所属的容器对象提供的。UserControl 的 Extender 对象使得控件设计器能够从控件内部访问这些属性。
Extender 对象的只读的 Name 属性返回容器(或用户)赋予控件的特定实例的名字。用这个名字(例如,ShapeLabel1)作为 Caption 属性初值来模仿 Label 控件的行为。
提示 如果控件要模仿一个提供类似功能的控件,那么用它会更加直观。
当为控件创建 Name 属性会发生什么事情?将能够从控件内部访问它,但用户所能看见的 Name 属性只是 Extender 对象的 Name 属性。
这就引入了一个控件再现的主题:容器能决定控件的大部分行为和外观。 容器确定控件的 Name,以及保持相对容器坐标关系的 Top 和 Left 属性。“建立 ActiveX 控件”会再次提出主题。
最后:为什么要把这些代码放在 InitProperties 事件中? 为什么不使用 Initialize 事件呢?如同所见,每当控件实例被创建时均调用 Initialize,它是频繁引发的。而 InitProperties 是仅当用户把控件放入容器时才被引发。此时设置控件实例的初值较为合适。
此外当 Initialize 事件引发时,UserControl 对象的 Extender 和 AmbientProperties 对象尚且不能使用。,建立 ActiveX 控件”中的“理解控件的存活期和关键事件”部分将讨论 Initialize 事件的恰当用法。
5 要保存 Caption 属性值,可把下列代码添加到 UserControl_WriteProperties 事件过程中:
Private Sub UserControl_WriteProperties(PropBag As _
PropertyBag)
Debug.Print "WriteProperties"
PropBag.WriteProperty "Caption",Caption,_
Extender.Name
End Sub

PropertyBag 意如其名,是一个保存属性值的口袋。 该口袋由容器提供。用户不必了解它的工作原理,也不必了解数据在何处以及是怎样保存的。 所做的全部事情就是放入值和取出值。
WriteProperty 方法的第一个参数是属性名,它将作为检索键使用。 应使用属性名作为这个参数,因为它将出现在,frm 文本文件中(在 Visual Basic 中,其它容器可能使用别的文件名来保存工程数据),而且对于该控件的用户是可见的。
第二个参数是值。 属性值作为一个 Variant 被保存。
第三个参数很特别,是一个缺省值。 保存属性值时为什么要提供一个缺省值呢? 在保存该值之前,WriteProperty 方法要用此缺省值和属性值作比较。 若二者相同,则该属性值就不必保存,因为当控件重新加载时会自动装入此缺省值。 这样就避免了使,frm 文件与数百个缺省条目混杂,对用户来说是十分有利的!
6 将下列代码放入 ReadProperties 事件中,可用来为 Caption 属性检索持久值。
Private Sub UserControl_ReadProperties(PropBag As _
PropertyBag)
Debug.Print "ReadProperties"
Caption = PropBag.ReadProperty("Caption",_
Extender.Name)
End Sub
ReadProperty 方法的第二个参数作为缺省值的使用是当如果没有保存任何值,如果用户已从文本文件删除了该属性,或者如果从未改变过这个缺省值,自然也就从未通过 WriteProperty 保存过它的时候。
7 确保 ShapeLabel 的设计器在前面,然后按下“关闭”按钮或 CTRL+F4 以关闭窗口,使控件进入运行模式。 ShapeLabel 控件的标题会发生改变从而得以匹配两个实例的缺省名字 ShapeLabel1 和 ShapeLabel2。
使用“属性”窗口改变 Form1 上的两个 ShapeLabel 控件的“标题”属性,然后单击 Form1 设计器的“关闭”按钮。 在“工程资源管理器”窗口双击“Form1”重新打开 Form1 设计器。
从“立即”窗口的消息中可以看见控件已经被撤消和重建,但“标题”属性值已被保存及检索。
8 按下 CTRL+F5 键以运行 TestCtlDemo,即工程组的 Startup 工程,并观察 ShapeLabel 控件在运行时期的行为。
9 单击 Form1 的“关闭”按钮以返回到设计模式。
§7为 ShapeLabel 控件添加一个属性页使用属性过程所创建的一些简单属性将自动显示在 Visual Basic 的属性窗口中。 也可以使控件和属性页相连接,属性页以另一种格式显示控件的各种属性。
与控件连接的每一个属性页都成为选项卡化的属性对话框上的一个选项卡。 Visual Basic 处理选项卡化对话框所说明的页面的所有细节,并管理“确定”、“取消”和“应用”等按钮。 用户必须做的全部事情就是设计将用于设置属性值的控件。
当一组属性以复杂的方式相互作用时,正如 Visual Basic 包含的 Toolbar 控件的情况,属性页就十分有用。 对于将在各国发布的控件来说属性页也很有用,因为针对不同语言可将标题本地化。 属性页也使控件能够和没有 Properties 窗口的开发工具一起使用。
向工程添加属性页
1 在“工程资源管理器”窗口单击 ControlDemo 以打开控件工程。在“工程”菜单上单击“添加属性页”以打开“添加属性页”对话框。双击“属性页”图标,以向工程添加属性页。
2 在“属性”窗口双击 Name 属性,并把属性页的名称变成 SLGeneral。双击 Caption 属性并把标题变成“通用”。
在使用标题时,这个标题就是出现在属性页选项卡上的标题。为什么要命名页 SLGeneral 而不是通用?在一个工程中可以有几个控件,而每一个控件可以有一个通用页。这就是 ShapeLabel 控件的通用页。
3 在“文件”菜单上单击“保存工程组”来保存工程组。象下表那样显示属性页的名称。将自动提供已指出的扩展名。
文件
文件名
扩展
属性页
ControlDemo_SLGeneral
.pag

属性页中象位图之类的二进制信息都被保存在名称相同的二进制文件中,该文件的扩展名为,pgx。
除了设计器的标题栏显示的是属性页的“标题”属性而不是以“名称”属性,属性页设计器看上去很像控件设计器。
为设计 ShapeLabel 控件的通用属性页
1 把 Label 控件放入该属性页,并把该 label 的 Caption 属性设置为 Caption 这个字。
2 在该 label 下面放一个 TextBox 控件,并赋予它以下属性值:
属性
值
名字
txtCaption
文本
<空>
 按照这种方式把属性描述选项卡放在文本框之上,使得为其它语言进行控件部件的本地化更加容易,“标题”这个字所在之处可能更长或更短。,建立 ActiveX 控件”将讨论控件本地化的细节。
3. 双击“属性页”以打开代码窗口。 在 Events 的下拉表中选择 SelectionChanged 事件并且添加下列代码:
Private Sub PropertyPage_SelectionChanged()
'在当前选择的控件列表中
'显示第一个控件的标题。
txtCaption.Text = SelectedControls(0).Caption
End Sub
本事件的目的是从 ShapeLabel 控件或当前所选择的那些控件中取得已存在的属性值。这样做是正确的,可能有多个 ShapeLabel 控件被选。多重选择对控件用户来说是重要的事情,但这意味着要多做一些工作。
无论何时打开属性页均接收一个 SelectionChanged 事件。 选择控件列表改变时也接收这个事件。 这是必须的,因为“属性页”对话框为非模式对话框,当对话框打开时用户可能选择其他的一些控件。
必须在按属性逐个进行的基础上决定如何处理多重选择。 例如,如果属性页显示的是 SelectedControls 集合中第一个控件的 Width 属性,即 SelectedControls(0),如以上代码所示,它就能很容易的把所有选择控件的宽度改变为那个值。
从另一方面而言,把窗体中所有 ShapeLabel 控件的标题设置成相同值的操作并没有太大的用处,那样的话如果 SelectedControls 集合的 Count 属性大于一时则与 Caption 属性有关的逻辑处理将会使 txtCaption 无效。
然而这个过程不作逻辑处理。为了说明起见,将允许属性页设置多重标题。 以后若想让上面描述的行为生效,可把下列代码行添加到 PropertyPage_SelectionChanged 事件过程中:
'请先不要这样做!
If SelectedControls.Count > 1 Then
txtCaption.Enabled = False
Else
txtCaption.Enabled = True
End If
4 为了对当前选择的所有控件设置属性值,把下列代码添加到 ApplyChanges 事件中:
Private Sub PropertyPage_ApplyChanges()
'在选择一个以上控件类的情况下,
'使用一般性对象变量。
Dim objControl As Variant
For Each objControl In SelectedControls
objControl.Caption = txtCaption.Text
Next
End Sub
单击“属性页”对话框的“应用”或“确定”按钮,或者切换到其它选项卡时,属性页将接收 ApplyChanges 事件。
怎样得知 SelectedControls 中的各个控件是否具有 Caption 属性呢?作为控件部件的设计器来说,要确定哪些属性页与任一给定的控件相连接。 如果所有当前选择的控件的 Property Pages 清单中都具有某一页,则该属性页出现。 最容易做的事就是确保分配给每个控件的那些页不显示该控件所不具有的属性。
倘若希望一些控件使用一个通用属性页,其中一些控件又不具有该页出现的所有属性时,可以给 ApplyChanges 事件添加代码,以进行控件类型的检测并提供适当的属性值。 作为一种替代,也可使用 On Error 语句捕获和忽略来自不具有该属性控件的一些错误。
仅需要考虑自己部件中的那些控件,因为不在自己部件中的那些控件决不会使用本部件的属性页。
,创建 ActiveX 控件的属性页”将会很详细地讨论属性页的布局和赋值。
5 为了在 Caption 属性改变时使“属性页”对话框的“应用”按钮有效,把下列代码添加到 txtCaption 文本框的 Change 事件中,
Private Sub txtCaption_Change()
' 属性页的改变了的
' 属性控制 Property Pages
' 对话框的“应用”按钮。
Changed = True
End Sub
6 在“工程”窗口中双击 SLGeneral,使属性页设计器在前面。单击设计器的关闭按钮或按下 CTRL+F4 以关闭设计器并使该页进入运行模式。 像 UserControl 对象一样,PropertyPage 对象仅当工程组的其余部分处于设计模式时才能运行。
将属性页和ShapeLabel控件相连接
1 在“工程资源管理器”窗口双击“ShapeLabel”以打开设计器。
2 在“属性”窗口双击 PropertyPages 属性以显示“连接属性页”对话框。
Connect Property Pages 对话框可用于将多个属性页与一个控件相连接、并可为控件安排“连接属性页”对话框中各选项卡的显示顺序。
运行时也能连接属性页。 这将在“创建 ActiveX 控件的属性页”中讨论。
3 复选“SLGeneral”后单击“确定”。
4 使 ShapeLabel 设计器前置,然后单击其“关闭”按钮或按下 CTRL+F4 以使 ShapeLabel 控件进入运行模式。
5 在“工程资源管理器”窗口双击“Form1”以打开其设计器。
6 在 Form1 上任一个 ShapeLabel 的控件上单击右键以显示上下文菜单,并单击“属性”以显示“属性页”对话框。
7 在“通用”选项卡上的“标题”框中用一个新值代替当前标题。 进行这项工作后,“应用”按钮处于有效状态。 单击“应用”按钮以改变该控件的标题。
注意 按下“确定”键也可改变该标题,但那样会关闭“属性页”对话框。对话框应保持打开状态以便进行下一步。
8 保持按下 CTRL 键的同时单击 Form1 上的第二个 ShapeLabel 控件,从而选择两个 ShapeLabels。 改变标题并单击“应用”按钮使两个标题设置成相同的值。
可能希望试一试把诸如命令按钮之类的其它控件添加到 Form1 中,并且观察在“属性页”对话框上作不同复选的效果。
9 当试验完成之后单击“确定”以关闭“属性页”对话框。
§8 为 ShapeLabel 控件添加事件区分清 UserControl 对象(或者它所包含的控件)接收的事件与控件引发的事件这一点非常重要。控件所接收的那些事件提供了做某些感兴趣事情的一些机会,而控件引发的那些事件则为使用该控件的开发者提供了做某些感兴趣事情的一些机会。
有许多可能引起 ShapeLabel 控件用户感兴趣的事件。 Visual Basic 的 Label 控件引发一个 Click 事件,而 ShapeLabel 正是一个高级的选项卡,因此下列过程将添加一个 Click 事件。 为了使该事件更有意思,仅当用户单击椭圆背景时才引发。
在控件中加入特定事件的重要原因是出于与相同类型的其它控件兼容。 引发何种事件的其它选择标准可参见“建立 ActiveX 控件”中的“在控件中产生事件”部分。
为 ShapeLabel 控件添加 Click 事件
1 在“工程资源管理器”窗口单击“ShapeLabel”,选择它后按下 F7 键或单击“工程资源管理器”窗口工具栏的“代码”按钮来打开“代码”窗口。
2 在“对象”框选择“通用”。 在“过程”框选择“声明”以定位到代码模块的顶部。 添加下列代码:
Option Explicit
' 声明一个不带参数的公共 Click 事件。
Public Event Click()
3 在“对象”框选择“lblCaption”。 在“过程”框为这个选项卡控件选择 Click event。 把下列代码添加到 lblCaption_Click 事件过程中:
Private Sub lblCaption_Click()
' 无论何时在此选项卡上单击均
' 引发 Click 事件。
RaiseEvent Click
End Sub
仅当用户单击子控件 lblCaption 时,上述代码才引发 Click 事件。若能够在 ShapeLabel 的椭圆背景的任意处单击,那么看上去显得更自然,所以下一步所示的是单击彩色椭圆时如何引发 Click 事件。
4 在“对象”框选择 UserControl。在“过程”框选择 UserControls'MouseUp 事件。 把下列代码添加到 UserControl_MouseUp 事件过程中:
Private Sub UserControl_MouseUp(Button As Integer,_
Shift As Integer,X As Single,Y As Single)
' 仅当被单击色点的颜色和
' Shape 控件的颜色匹配时才引发
' 一个 Click 事件。 ' 忽略椭圆以外
' 的单击。
If Point(X,Y) = shpBack.FillColor Then
RaiseEvent Click
End If
End Sub

确定一个事件在特定的位置是否会发生称之为击点检测。
或许会希望把击点检测代码放在 shpBack_Click 事件过程中,因为 shpBack 总是要改变大小以便覆盖 ShapeLabel 控件的整个表面。 然而 Shape 控件不会接收 Click 事件。而由包含 Shape 对象的容器来接收 Click 事件,就本例来说是 UserControl 对象。
“建立 ActiveX 控件”中的“绘制控件”部分讨论关于创建非规则形状控件时透明背景的使用。
5 在“工程资源管理器”窗口单击“Form1”以选择它,然后按下 F7 键或单击“工程资源管理器”窗口工具栏的“代码”按钮来打开“代码”窗口。
6 在“对象”框选择一个添加到 Form1 中的 ShapeLabel 控件。 在“过程”框选择 Click 事件。
注意 如果 Click 事件没有出现,则应确定 ShapeLabel 设计器关闭。

把下列代码添加到 ShapeLabel1_Click 事件过程中:
Private Sub ShapeLabel1_Click()
MsgBox "Thanks for clicking! My caption is," _
& ShapeLabel1.Caption
End Sub

注意 如果所选的 ShapeLabel 的命名不是 ShapeLabel1 时,那么输入以上代码时应当使用相应的名字。

可单击 Procedure 框上的箭头,查看 ShapeLabel 控件的所有事件。除了 Click 事件之外,还有四个事件:DragDrop,DragOver,GotFocus 和 LostFocus 作为 Click 事件的补充,它们由 Form1 容器自动提供。
7 在工具栏单击“启动”按钮或按下 CTRL+F5 键运行 TestCtlDemo。尝试单击窗体和 ShapeLabel 控件的各种位置,以验证只有在椭圆背景内单击时才会引发 Click 事件。
8 在 ShapeLabel 的 click 事件的击点检测中有一个微妙错误。要查看这个错误,当鼠标指针在红色椭圆的下半部时按下鼠标键。 保持鼠标键按下,小心地移动鼠标指针,直至箭头的尖端指在 ShapeLabels 标题的白色正文上时再释放鼠标键。 消息框不会出现!
lblCaption_Click 事件过程不能执行,其原因是 MouseDown 事件在 UserControl 之上出现。 因此当 MouseUp 事件发生时,它会被 UserControl 接收,甚至鼠标已经完全移出了 Form1 时亦如此。
MouseUp 事件中的击点检测代码是当鼠标键在由 lblCaption 的透明背景所显示的红色背景上释放时工作,而当鼠标键在正文的白色前景颜色上释放时,击点检测代码不工作。(如果在 ShapeLabel 以外释放鼠标键,则 Point 函数返回 -1,因此在某些随机的红色位置上释放鼠标键不会引发 Click 事件。)
改正这个错误的对象留给读者作为练习。(提示,把击点检测移 UserControl 的 Click 事件没有用处,因为当 MouseUp 事件处在不 MouseDown 的对象上时,Click 事件不会引发。)
§9 编译 ControlDemo 部件一旦创建了包含一个或多个 UserControl 对象的 ActiveX 控件工程时,就可以将其编译成,ocx 文件并在其它应用程序中使用那些控件。下列各过程示范了这些步骤。
编译 ControlDemo 工程
1 如果 TestCtlDemo 工程仍在运行模式中,单击 Form1 上的“关闭”按钮以返回设计模式。
2 在“工程资源管理器”窗口单击“ControlDemo”以选择该工程。
3 在“文件”菜单上单击“生成 ControlDemo.ocx”以便打开“生成工程”对话框。 单击“确定”以创建 ocx 文件。
4 在“文件”菜单上单击“删除工程”以便从工程组中删除ControlDemo,从而使 Visual Basic 采用编译的二进制部件(.ocx 文件)代替该工程。
Visual Basic 会显示一个警告消息,因为 TestCtlDemo 工程包含对 ControlDemo 的一个引用。单击“是”最终删除 ControlDemo。
当从工程组删除了 ControlDemo 时,Visual Basic 在窗口注册中寻找 ControlDemo.ocx。 如果存在,ocx 文件,Visual Basic 便自动更新设置在添加 TestCtlDemo 工程的过程中的引用。
要切换回用工程代替二进制部件状态,可在“文件”菜单上单击“添加工程”并且将 ControlDemo 工程再添加到回工程组中。
5 按下 F5 键运行使用,ocx 文件的 TestCtlDemo。
当 ControlDemo 正在由源代码运行时,不能从其它应用程序或者从另一个 Visual Basic 程序访问 ShapeLabel 控件。 这是因为 ActiveX 控件部件必须在进程中运行。 一旦编译成一个,ocx 部件,便可以从其它应用程序来测试它。
在另一个 Visual Basic 中使用 ControlDemo.ocx
1 打开一个 Visual Basic 的新实例。 在“新建工程”对话框中双击 Standard EXE 图标以打开一个,exe 工程。
2 在“工程”菜单上单击“部件”以打开“部件” 对话框。在 Controls 的选项卡上,复选“ActiveX 控件创建演示”后再单击“确定”。
ShapeLabel 的图标出现在工具框中。在可以把一些 ShapeLabel 控件添加到默认窗体中,并使用“属性”窗口设置它们的属性。也可以在 ShapeLabel 的实例上单击右键,从上下文菜单中选择“属性”以便用属性页来编辑控件的属性。
3 按下 F5 键运行该工程。
就可以编译这个工程并运行其,exe。

§10 重述创建控件的步骤为了以最自然的顺序介绍新概念,本章的过程并没有遵循创建新控件正常的步骤顺序。
当创建一个新控件时一般应遵循的步骤是:
1. 确定控件将要提供的功能。
2. 设计控件的外观。
3. 设计控件的接口,即属性、方法和控件将遗弃的事件。
4. 创建由控件工程和测试工程组成的工程组。
5. 通过把控件和或代码添加到 UserControl 对象中来实现控件的外观。
6. 实现控件的接口和功能。
7. 在添加每一个接口元素或功能时,都要为测试工程增加一些功能,以便测试所添加的新功能。
8. 设计和实现控件的属性页。
9. 编译控件部件(.ocx 文件)并用各种可能的应用程序对它进行测试。
除了以上方法,还可用 VB 6提供的“ActiveX 控件界面向导”来创建ActiveX控件。由于篇幅关系,具体步骤见授课时例子。
.第十一章 ActiveX文档本章将介绍激活Web文档的一种动人的方法,即是把Visual Basic应用程序作为Web文档,那就是ActiveX文档;如果Visual Basic应用程序不被包装成ActiveX文档,则无法在Web页面上显示。
§1通过Wizard把Visual Basic应用程序变成ActiveX文档
本节将把一个使用ActiveX Document Migration Wizard将如下图所示的一个独立的Visual Basic应用程序变成一个ActiveX文档。
将欲变成ActiveX文档的Visual Basic应用程序的项目放入新文件夹,然后打开。
选择Add-Ins( ActiveX Document Migration Wizard,打开向导程序。
点击Next跳过Introduction页面,在Form Selection页面选择一个Form,如下图;
单击上图中的Next钮,在Option页面选择Comment out invalid code(指出无效代码),再单击Next钮。
在Finish页面选择是否看Summary Report,后单击Finish钮,就完成了。
需要特别指出的是,ActiveX Document 可以看成是一个文档,所以只有一页,即只能由一个窗体的应用程序转变,稍后会讲如何处理多个ActiveX Document。而且应用程序中若有对窗体对象的引用都应换成对象UserDocument,否则会报错!还有应去掉应用程序中的End语句。
生成了ActiveX文档后就可以测试它了,选择File(Make project1.exe,Visual Basic产生一个作为服务器程序的EXE文件,ActiveX容器与这个EXE文件相连处理ActiveX文档,
而且Visual Basic产生一个扩展名为vbd的文件,它是必须在Internet Explorer中打开的文件。
在Visual Basic中运行项目,再用Internet Explorer打开扩展名为vbd的文件,如下图:
可见该程序在Internet Explorer中运行起来,它的窗体部分在Internet Explorer的页面部分显示,而它的菜单与Internet Explorer的菜单合并在一起。
§2处理多个ActiveX文档
ActiveX文档处理多个文档的方式类似与Internet Explorer处理超链接的方式,是从一个文档跳到另一文档。要在多个ActiveX文档之间移动,可使用HyperLink对象,这是UserDocument对象的一个属性。HyperLink对象提供了NavigateTo方法,接受目标文档的URL变元,例如要从一个ActiveX文档中跳到北邮的主页,可调用下列方法:
UserDocument.Hyperlink.NavigateTo http://bupt.edu.cn
同样要显示另一ActiveX文档,调用同一方法:
UserDocument.Hyperlink.NavigateTo,nextdoc.vbd”
同样可以用GoBack和GoForward方法在历史清单中移动,如要返回前一访问的文档,可用HyperLink对象的GoBack方法:
UserDocument.Hyperlink,GoBack
§3手工创建ActiveX文档
1、新建一个ActiveX文档.EXE,打开UserDocument设计器。
2、在UserDocument1 中放置控件。
3、打开“文件”菜单,选择“生成Project1.exe”生成Project1.exe文件,VB系统自动在同一目录下生成UserDocument1.vbd。
由于篇幅,具体请看范例internet.vbd.
.第十二章 用对象链接与嵌入(OLE)扩展Visual Basic
OLE使得Visual Basic应用程序能访问Windows环境中其他应用程序的功能。前面所用的控件都是内置在Visual Basic中的,这些内置对象的出现在编辑器的工具栏中,可以把它们放到窗体上。但Windows环境中的有些对象不是Visual Basic所独有的,未放在Visual Basic中,而是由其他应用程序提供的,但可以在应用程序中使用这些对象。
Word文档就属于这种对象,可以将Word文档放在应用程序中,而不需要对其文件内容及组织方式有太多的了解。需要编辑Word文档时,可以暂时借用Word的菜单和工具条,将其显示在应用程序中;随后用户在应用程序中就象在用Word一样编辑文档。
要在Visual Basic中加入OLE功能,必须用OLE控件,以便将其他应用程序中的对象插入程序中。一次只能在OLE容器控件中放入一个对象,但统一窗体上可以含有多个OLE容器控件,各有自己的对象。
§1设计时链接与嵌入用拖放法嵌入对象用拖放法嵌入对象的具体步骤如下:
开始一个新的VB项目,并把OLE容器控件放在窗体上。
在Insert Object 对话框中,单击Cancel钮,以便后面放置OLE对象。
在OLE容器控件的Properties窗口中,将SizeMode属性变为1-Stretch(对于可缩放图形)或2-AutoSize(对于不宜缩放的文本和图形),以调整对象或尺寸。SizeMode属性取值及含义如下表:
数值
说明
Clip
对象按实际大小,大于OLE容器控件的部分被剪切掉
Stretch
对象图形调整成OLE容器控件的大小,对象的缩放可能会使图形扭曲
AutoSize
OLE容器控件缩放以显示整个对象
Zoom
对象图形尽量调整成OLE容器控件的大小,但保持原有比例
接着启动支持OLE的应用程序,并打开文件。本例通过拖放原应用程序的文档到OLE容器控件,以实现在OLE容器控件中嵌入Microsoft Word文档。
在屏幕上同时显示Visual Basic和Word时(或用Alt+Tab切换),拖动文档或其一部分到空OLE容器控件中。
拖动对象时,指针箭头下出现一个长方形,将其放到OLE容器控件中,于是 Word文档出现在OLE容器控件中,如上图所示。
OLE容器控件对象的常用属性
Class属性:产生对象的应用程序名,也是嵌入文档的类型。
SourceDoc:数据或引用的数据,即存入对象的文件名。
SourceItem:选作嵌入的文档部分(全文档时为空)。
OLETypeAllowed,源文档是链接还是嵌入到OLE容器控件中,这就取决于这个属性,它的具体取值如下:
数值
常量
说明
0
VbOLELinked
链接,OLE容器控件只能包含链接对象
1
VbOLEEmbedded
嵌入,OLE容器控件只能包含嵌入对象
2
VbOLEEither
LE容器控件可包含链接或嵌入对象
用Insert Object对话框实现链接用Insert Object对话框实现链接步骤的如下:
开始一个新的VB项目,并把OLE容器控件放在窗体上。
在Insert Object (插入对象)对话框中,选择Creat from File(由文件创建)选项并选定Link(链接)复选框。如下图中:
3.点击浏览按钮,找到所需文件。
保存和获取对象由于嵌入对象中的数据并不自动保存,要保存嵌入对象及服务器应用程序所做的修改,可用SaveToFile方法:
OLE1,SaveToFile filenumber
Filenumber对应二进制方式下打开的文件。
要装入存放成数据文件的对象,可用ReadFromFile方法。其语法如下:
OLE1.ReadFromFile filenumber
现场编辑现场编辑也叫现场激活,它是Visual Basic中嵌入对象的增强功能。最简单的方法就是双击对象,这时应用程序的菜单和工具条可代替OLE容器控件的菜单和工具条。
§2运行时链接与嵌入本节通过一个实例介绍运行时实现链接与嵌入。该例子有两个窗体,界面如下;
左边为主窗口,右边窗口为点按主窗口中的Insert object..,钮后出现的,右边窗口的作用是为动态嵌入的OLE容器控件设置SizeMode属性和OLETypeAllowed属性,即而装入Insert Object (插入对象)对话框。
下面先设计主窗口。
主窗口的设计:
开始一个新的VB项目,并把OLE容器控件放在窗体上。
在Insert Object 对话框中,单击Cancel钮,以便后面放置OLE对象,并按上面左图调整OLE控件的大小。
并按上面左图依次添加三个按钮,Caption属性分别为insert object...,object info..,close 。
先给标为insert object...的按钮添加代码:
Private Sub Command1_Click()
frmtype.Show
End Sub
Frmtype为上图右边窗体的名字。再给标为object info..的按钮添加代码:
Private Sub Command2_Click()
Dim sourcetext As String
Dim msg As String
Dim typetext As String
sourcetext = "The object's source file is " & oledisplay.SourceDoc
typetext = " The type of object is " & oledisplay.Class
msg = sourcetext + vbCrLf + typetext
MsgBox msg,vbInformation,"object information"
End Sub
该段代码是为了显示当前OLE控件的SourceDoc属性和Class属性。当然当OLE控件为空时该按钮无效。
再给标为close的按钮添加代码:
Private Sub Command3_Click()
Dim quit As String
quit = MsgBox("Are you sure to want to quit?",vbYesNo + vbQuestion)
If quit = vbYes Then
End
End If
End Sub
Frmtype窗口的设计:
按上图右边窗体设计其界面,其中四个Option按钮名字从上往下依次为Option1到Option4。
OLE容器控件的属性设置代码如下:
If Option1.Value = True Then
Form1.oledisplay.SizeMode = 1 'sizeMode=1---Stretch
Else
Form1.oledisplay.SizeMode = 2 '2---Autosize
End If
If Option3.Value = True Then
Form1.oledisplay.OLETypeAllowed = 1 '1--embedded
Else
Form1.oledisplay.OLETypeAllowed = 0 '0--linked
End If
装入Insert Object (插入对象)对话框,可使用下面代码:
Form1.oledisplay.InsertObjDlg
要恢复标为object info..的按钮有效,须用如下代码:
If Form1.oledisplay.Class <> "" Then
Form1.Command2.Enabled = True
End If
鉴于节约篇幅,不在罗列全部具体代码。读者可查看授课时提供的DynOLE实例。
第十三章 使用资源文件当我们的Visual Basic应用程序有可能适用于整个人类时,我们应该考虑为我们的应用程序生成不同语言的版本。这种国际化的想法也许会使我们成为亿万富翁,然而这也是个不易实现的目标,世界上有千奇百怪的语言。
程序员把不同语言的字符串看成是应用程序可利用的不同的资源,他们还把声音、图画、菜单、光标等等都看成资源,在运行时可以根据不同的条件选择性的使用。C\C++的程序员看来使用资源文件已经有一段时间了。这样我们就可以把为一种或多种外语重建一个应用程序的任务简化为编辑一个ASCII资源文件的简单任务。资源文件的优点还有:图形图象作为资源加载比从外部文件加载要快,多个图象更易于操作。下面我们来制作一个资源文件的实例。
§1 建立资源文件一、通过任何一个文本编辑器(如Notepad)建立一个RC文件开始。打开Notepad后输入下面这段文本。
//Moon.rc - Resource file
//rc /fo moon32.res moon.rc
//Icons
2 ICON "C:\\VB\\ICONS\\ELEMENTS\\MOON01.ICO"
3 ICON "C:\\VB\\ICONS\\ELEMENTS\\MOON02.ICO"
4 ICON "C:\\VB\\ICONS\\ELEMENTS\\MOON03.ICO"
5 ICON "C:\\VB\\ICONS\\ELEMENTS\\MOON04.ICO"
6 ICON "C:\\VB\\ICONS\\ELEMENTS\\MOON05.ICO"
7 ICON "C:\\VB\\ICONS\\ELEMENTS\\MOON06.ICO"
8 ICON "C:\\VB\\ICONS\\ELEMENTS\\MOON07.ICO"
9 ICON "C:\\VB\\ICONS\\ELEMENTS\\MOON08.ICO"
//Strings
STRINGTABLE
BEGIN
2 "月亮的相位"
3 "输入日期:"
4 "刷新相位"
12 "新月"
13 "月盈,四分之一"
14 "月盈,二分之一"
15 "月盈,四分之三"
16 "满月"
17 "月亏,四分之三"
18 "月亏,二分之一"
19 "月亏,四分之一"
END
STRINGTABLE
BEGIN
22 "Approximate Phase of the Moon"
23 "Enter a date:"
24 "Phase"
32 "New"
33 "Waxing,one quarter"
34 "Waxing,half"
35 "Waxing,three quarters"
36 "Full"
37 "Waning,three quarters"
38 "Waning,half"
39 "Waning,one quarter"
END
请注意下面的几个问题:
以双斜杠开头的是注释行,在编译时将其忽略。
没有使用资源号码1,因为Visual Basic将这个号码用于应用程序内部储存的图标。
图标的路径中用的反斜杠是双写的,“这是一种对我们不得不使用的C语言的嘲弄”。
上面清单假设Visual Basic 6.0安装在c:\vb\子目录下,否则就找不到所需的图标了。
字符串在资源文件中是以一个或多个字符串表定义的,它以STRINGTABLE声明开始,在BEGIN和END中定义。
把文件储存为Moon.rc。
编译RC文件编译RC文件需要一个叫rc.exe的编译程序,这个编译程序通常在VB6\wizards\上有,如没有,也可利用 Visual C++的rc.exe了。Visual C++的rc.exe通常在 C:\MSDEV\BIN\子目录下,当然,你也可自己找。
进入MS-DOS方式,进入C:\MSDEV\BIN\子目录。
键入命令如下:
C:\MSDEV\BIN>rc /fo \..\moon32.res \..\moon.rc,
其中\..\代表Moon.rc的路径。这个命令的意思是:“把\..\moon.rc文件编译成资源文件\..\moon32.res。”/fo命令行参数的意思是编译时换一个名字。
关闭MS-DOS方式。
如果你按我说的步骤进行,那么应该是会编译成功的。现在我们已经有了所需的资源文件了。
§2 在应用程序中使用资源文件本程序需要两个窗体,它既演示了使用资源文件使程序国际化的简单方法,又演示了资源文件中的资源是如何使用的。
生成界面

对象
属性
设置值
Form1
Name
frmCover
Caption
"Approximate Phase of the Moon -- 月亮的相位"
Icon
C:\VB\ICONS\ELEMENTS\MOON06.ICO
Frame1
Caption
"Please select a language,请选择一种语言:"
Command1
Name
cmdChinese
Caption
"中文"
Command2
Name
cmdEnglish
Caption
"English"
Image1
Picture
FLGCHN.ICO(这是我自己做的中国国旗的图标)
Image2
Picture
C:\VB\ICONS\FLAGS\FLGUK.ICO
Form2
Name
frmMoon
Icon
C:\VB\ICONS\ELEMENTS\MOON04.ICO
Command1
Name
cmdPhase
Text1
Name
txtDate
Label1
Name
lblString
Image1
Name
imgMoon
Label1
Name
lblDate

将资源文件加入到项目中从工程(P)菜单中选择 添加文件(A)项(或右击工程资源管理器中的工程,选添加)在Add File对话框中找到刚才制作的资源文件Moon32.res,按打开按钮就可以将资源文件加入到项目中来。每一个Visual Basic项目只可以加入一个资源文件。
编写代码从Insert菜单中选择Module项。
在新增加的Module中加入下面的代码:
Option Explicit
Public i As Byte
声明全局变量i用于表明用户选择了哪一种语言。
在frmCover的代码窗口里加入下面代码:
Option Explicit
Private Sub cmdChinese_Click()
i = 0
frmMoon.Show
Unload frmCover
End Sub
Private Sub cmdEnglish_Click()
i = 20
frmMoon.Show
Unload frmCover
End Sub
在frmMoon的代码窗口里加入下面代码:
Option Explicit
Private Sub cmdPhase_Click()
Dim Phase
Dim ResNum As Byte
Phase = CDbl(CVDate(txtDate.Text))
Phase = Phase / 29.530589 + 0.9291176
Phase = Phase - Int(Phase)
ResNum = 2 + Int(Phase * 8 + 0.5)
If ResNum = 10 Then ResNum = 2
imgMoon.Picture = LoadResPicture(ResNum,vbResIcon)
lblString.Caption = LoadResString(ResNum + i + 10)
End Sub
Private Sub Form_Load()
Me.Caption = LoadResString(2 + i)
lblDate.Caption = LoadResString(3 + i)
cmdPhase.Caption = LoadResString(4 + i)
txtDate.Text = Format(Date,"mm/dd/yyyy")
cmdPhase_Click
End Sub
可以看到加载资源到程序中,使用了LoadResPicture、LoadResString方法。这一组的函数还有LoadResData函数。现在双语教学软件很流行,你可以知道那些程序员是如何做的了。
第十四章 用Visual Basic建立动态链接库(DLL)
§1 什么是动态链接库许多程序员使用Visual Basic来生成用户界面,用另一种语言来生成代数运算,以使程序效果更好。这是因为Visual Basic在大量数字运算时速度不高。但是,你不能指望在Visual Basic的代码窗口输入C++代码,你只能输入Visual Basic代码。所以,你必须用另一种编译器编写你的C++代码,并储存在DLL的特定文件里。然后,编写Visual Basic代码告诉Visual Basic如何使用放在DLL中的代码。
使用DLL的三个原因是:
速度。
用更恰当的语言解决问题。
可重用性。
事实上,Windows的API就是DLL。DLL就象一个黑盒子,你只需使用它而不用关心它是如何实现的。还有,使用DLL是有一定风险的,比如使用Windows的API,可能会使你的计算机崩溃。
§2 用Visual Basic生成DLL
这简直另人惊讶,但对Visual Basic程序员来说,这又另人兴奋。说实在的,Visual Basic的DLL比其它语言生成的DLL速度要慢,但有三个原因使Visual Basic程序员喜欢使用Visual Basic的DLL。一是Visual Basic很好用,很容易;二是你不需要学另一门语言或买另一种编译器;三是Visual Basic程序员讨厌别人说Visual Basic是玩具语言,所以他们要制作自己的DLL而不用C\C++程序员编的DLL。
Visual Basic采用OLE服务器来实现编制DLL的任务,这种方式建立的DLL是真正的DLL,完成它时具有扩展名DLL。OLE服务器DLL与以前的Windows传统DLL不同,我们在Visual Basic中建立一个在DLL中定义的对象来访问它,然后用此对象的属性、方法工作,而不是使用Declare语句声明DLL内定义的函数。同样,其它语言也是通过OLE接口来访问Visual Basic DLL的。
生成代码模块DllMathBas.Bas。由于OLE服务器项目必须由一个Sub Main过程而不是一个窗体作为起始点,而Sub Main过程又必须放在一个代码模块中,所以我们要生成这个代码模块。Sub Main过程用于存放初始化代码。
从Insert菜单中选择Module项,保存为DllMathBas.Bas
在DllMathBas.Bas中加入下面的代码:
Option Explicit
Sub Main()
‘No initialization required
End Sub
在这个DLL的例子里我们不需要初始化的代码。
生成类模块DllMath.Cls
从Insert菜单中选择Class Module项,保存为DllMath.Cls
在DllMath.Cls中加入下面的代码:
Option Explicit
Public Num
Public Den
Public Sub Add(Num2,Den2)
Num = Num * Den2 + Den * Num2
Den = Den * Den2
Reduce
End Sub
Public Sub Sbt(Num2,Den2)
Num = Num * Den2 - Den * Num2
Den = Den * Den2
Reduce
End Sub
Public Sub Mul(Num2,Den2)
Num = Num * Num2
Den = Den * Den2
Reduce
End Sub
Public Sub Div(Num2,Den2)
Mul Den2,Num2
End Sub
Private Sub Reduce()
Dim s,t,u
s = Num
t = Den
If t = 0 Then Exit Sub
Do
u = (s \ t) * t
u = s - u
s = t
t = u
Loop While u > 0
Num = Num \ s
Den = Den \ s
End Sub
设置类模块的属性属性
设置值
Instancing
2 - Createable Multiuse
Name
Fraction
Public
True
三、项目设置从 工程(P)菜单中选择 属性 项。
选中 通用 标签。
把Startup form设置为Sub Main。
把Project Name设置为Math。
把StartMode设置为OLE Server。
把Application Description设置为Fraction Math。
单击确定键。
选中Form1,从File菜单中选择Remove File项,因为这个DLL不需要任何窗体。
把项目编译为DLL文件从File菜单中选择Make OLE DLL File项。
输入DLL的名字DllMath。
单击确定键。
现在我们就生成了我们的Visual Basic DLL文件,下面介绍在Visual Basic程序中运用Visual Basic DLL的方法。
§3 在Visual Basic应用程序中使用Visual Basic DLL
生成界面
对象
属性
设置值
Form1
Caption
"Fraction Math"
Command1
Name
cmdAdd
Caption
"加"
Command2
Name
cmdSubtract
Caption
"减"
Command3
Name
cmdMultiply
Caption
"乘"
Command4
Name
cmdDivide
Caption
"除"
Text1
Name
txtN1
Text2
Name
txtD1
Text3
Name
txtN2
Text4
Name
txtD2
Text5
Name
txtN3
Text6
Name
txtD3
Label1
Caption
“=”
Label2
Caption
“?”
Line1
BorderWidth
3
Line2
BorderWidth
3
Line3
BorderWidth
3

编写代码在窗体下加入下面的代码:
Option Explicit
Public Frac As New Math.Fraction
Private Sub cmdAdd_Click()
Frac.Num = txtN1.Text
Frac.Den = txtD1.Text
Frac.Add txtN2.Text,txtD2.Text
txtN3.Text = Frac.Num
txtD3.Text = Frac.Den
Label1(0).Caption = "+"
End Sub
Private Sub cmdDivide_Click()
Frac.Num = txtN1.Text
Frac.Den = txtD1.Text
Frac.Div txtN2.Text,txtD2.Text
txtN3.Text = Frac.Num
txtD3.Text = Frac.Den
Label1(0).Caption = "/"
End Sub
Private Sub cmdMultiply_Click()
Frac.Num = txtN1.Text
Frac.Den = txtD1.Text
Frac.Mul txtN2.Text,txtD2.Text
txtN3.Text = Frac.Num
txtD3.Text = Frac.Den
Label1(0).Caption = "*"
End Sub
Private Sub cmdSubtract_Click()
Frac.Num = txtN1.Text
Frac.Den = txtD1.Text
Frac.Sbt txtN2.Text,txtD2.Text
txtN3.Text = Frac.Num
txtD3.Text = Frac.Den
Label1(0).Caption = "-"
End Sub
此程序不适用于负数。
引用Math DLL
从 工程(P) 菜单中选择 引用(N) 项。
单击Browse键。
找到刚才生成的DllMath.dll,并打开它。
你可以在Available References列表的最下面找到Fraction Math,并且发现在它旁边已经打了叉表明已经引用了它。
现在这个使用Visual Basic DLL的应用程序已经完成了,你已经可以制作自己的DLL了。你可以对身边的正在学C、C++、Delphi的朋友说:“需要动态链接库吗?要不要我帮你用Visual Basic做一个?”
第十五章 用Winsock控件进行Internet通信
Internet的复杂性主要来自于各种各样的通过Internet交换信息的应用程序,包括电子邮件、新闻和WWW。但Internet本身却具是有良好定义的和可靠的通信协议的数字网络。
在这个基础上Windows 95和Windows NT为Internet提供了诸如Winsock等标准接口。而Visual Basic则通过Winsock ActiveX控件为Winsock提供了标准接口。Winsock的目的非常简单:为两个或多个Internet节点建立连接并使之交换数据。下面我们以一个简单的应用程序来看看这个过程。
§1 Winsock服务器本工程用TCP协议为客户端和服务器端建立连接。对实际的Internet应用程序而言。可能需要两个独立的应用程序。但现在为简单起见,我们在一个应用程序中,为客户端和服务器端建立两个不同的窗体。
我们需要下表所列的控件。
名称
类型
属性
值
lblIPAddress
Label
Caption
“”
lblStatus
Label
Caption
“”
sktTCPChatServer
Winsock
Protocol
0-sckTCPProtocol
txtDataReceived
TextBox
Text
“”
txtDataToSend
TextBox
Text
“”

1,倾听Winsock连接
Internet上每个服务器应用程序都通过IP地址和端口号两个数字来标识。服务器正是通过这两个数字来倾听连接请求。每个Internet节点,即有特定IP地址的计算机,都可运行多个服务器,只要这些服务器倾听的端口号不同。
在程序中,我们将Winsock控件的LocalPort设为1600。由于IP地址由服务器运行的计算机确定,因而无需设定。调用Listen方法,服务器便开始监听Internet的连接请求,这样就激活了服务器程序。
2,建立Winsock连接当客户端向合适的IP地址和端口号发送连接请求时,Winsock控件便会产生ConnectionRequest事件。在ConnectionRequest事件中调用Accept方法,并将所接收的RequestID作为事件过程的参数,就可以在服务器和客户端之间建立连接。
3,交换数据使用Winsock控件的SendData方法,就可以向客户端发送数据。Winsock控件收到客户端的数据时,先调用DataArrival事件过程,然后,再通过GetData方法从通信缓冲区中获得数据。
下面是服务器窗体的代码:
Option Explicit
Private Sub Form_Click()
Print sktTCPChatServer.LocalIP
End Sub
Private Sub Form_Load()
frmClient.Show
sktTCPChatServer.LocalPort = 1600 ' Set the local port.
sktTCPChatServer.Listen ' Use the Listen method.
lblIPAddress.Caption = sktTCPChatServer.LocalIP
lblStatus.Caption = "Host Name," & sktTCPChatServer.LocalHostName
End Sub
Private Sub Form_QueryUnload(Cancel As Integer,UnloadMode As Integer)
'Dim ArrayIndex As Integer
Unload frmClient
End Sub
Private Sub sktTCPChatServer_Close()
lblStatus.Caption = "Disconnecting from " & sktTCPChatServer.RemoteHostIP
' Return to listening state.
sktTCPChatServer.Close
sktTCPChatServer.LocalPort = 1600
sktTCPChatServer.Listen
End Sub
Private Sub sktTCPChatServer_ConnectionRequest(ByVal requestID As Long)
Dim Dummy As String
If sktTCPChatServer.State <> sckClosed Then
sktTCPChatServer.Close
End If
sktTCPChatServer.Accept requestID
lblStatus.Caption = "Connecting " & sktTCPChatServer.RemoteHostIP
End Sub
Private Sub sktTCPChatServer_DataArrival(ByVal bytesTotal As Long)
Dim DataReceived As String
sktTCPChatServer.GetData DataReceived,vbString
If CStr(DataReceived) = "QUIT" Then
sktTCPChatServer_Close
Else
txtDataReceived.Text = DataReceived
End If
End Sub
Private Sub txtDataToSend_Change()
sktTCPChatServer.SendData txtDataToSend.Text
End Sub
§2 Winsock客户端对客户端而言,先创建类似于服务器的窗体,下表列出了客户端所用的六个控件。
名称
类型
属性
值
cmdConnect
CommandButton
Caption
“连接”
cmdCloseConnect
CommandButton
Caption
“关闭连接”
lblStatus
Label
Caption
“”
sktTCPChatClient
Winsock
Protocol
0-sckTCPProtocol
txtDataReceived
TextBox
MultiLine
True
txtDataToSend
TextBox
MultiLine
True
1,连接到服务器上客户端和服务器的主要区别在于建立连接的方式不同。服务器通过倾听建立连接,而客户端则是用Winsock控件的Connect方法以及RemoteHost和RemotePort来发送连接请求。本程序中,因为服务器和客户端运行在同一台机器上,所以将RemoteHost的值设为Winsock控件所检测到的LocalIP。在客户端,通过单击一个按钮来发送连接请求。
2,关闭连接关闭连接的按钮执行的时候,并不需要调用Winsock控件的Close方法。而是发送字符串“QUIT”,以便让服务器调用它的Close方法来实际断开连接。建立连接和断开连接的顺序会影响Winsock应用程序的可用性和可靠性。
3,交换数据客户端使用与服务器相同方法来交换数据。调用SendData方法向服务器发送数据,在DataArrival事件过程中调用Winsock控件的GetData方法来获取服务器传过来的数据。
客户端的代码是:
Option Explicit
Private Sub cmdCloseConnection_Click()
lblStatus.Caption = "Closing Connection"
' Don't terminate the connection like this:
' sktTCPChatClient.Close
sktTCPChatClient.SendData "QUIT"
End Sub
Private Sub cmdConnect_Click()
If sktTCPChatClient.State <> sckClosed Then
sktTCPChatClient.Close
End If
With sktTCPChatClient
,RemoteHost = sktTCPChatClient.LocalIP
,RemotePort = 1600
End With
sktTCPChatClient.Connect
End Sub
Private Sub Form_Load()
lblStatus.Caption = "Local IP Address," & sktTCPChatClient.LocalIP
End Sub
Private Sub Form_QueryUnload(Cancel As Integer,UnloadMode As Integer)
sktTCPChatClient.Close
End Sub
Private Sub sktTCPChatClient_Close()
sktTCPChatClient.Close
Do
lblStatus.Caption = "Status," & _
sktTCPChatClient.State
DoEvents
Loop Until sktTCPChatClient.State = sckClosed
End Sub
Private Sub sktTCPChatClient_Connect()
If sktTCPChatClient.State = sckConnected Then
lblStatus.Caption = "Connection Successful at Remote IP " & sktTCPChatClient.RemoteHostIP
End If
End Sub
Private Sub sktTCPChatClient_DataArrival(ByVal bytesTotal As Long)
Dim vtData As Variant
sktTCPChatClient.GetData vtData,vbString
txtReceived.Text = vtData
End Sub
Private Sub txtDataToSend_Change()
sktTCPChatClient.SendData txtDataToSend.Text
End Sub


.第十六章 Web浏览控件本章将介绍将Web技术应用在Visual Basic应用程序中。Web技术是超文本模型,通过单击超链接与应用程序交互是对VB编程人员的用户接口设计工具的有力补充。
可以用两个对象将Web技术与超链接文档加进Visual Basic应用程序中:WebBrowser控件和InternetExplorer对象。WebBrowser控件是个ActiveX控件,可以将Internet浏览功能加到应用程序中,在Visual Basic窗体上显示Web文档。InternetExplorer对象是OLE式的自动化对象,可以在应用程序中控制Microsoft Internet Explorer。
§1 WebBrowser控件和InternetExplorer对象简介一、WebBrowser控件、
简单的说,WebBrowser控件就是Internet Explorer的窗口。任何可以在Internet Explorer中显示的文档,也可以在WebBrowser控件中显示。由于WebBrowser控件是个ActiveX控件,可以放在任何Visual Basic窗体中。但使用WebBrowser控件之前,必须把它加入工具栏,步骤如下:
右键单击工具栏,从菜单中选择Components命令,打开Components对话框。
选择Microsoft Internet Controls,然后单击单击Ok钮,于是在工具栏中加入了一个新的图标。
WebBrowser控件放在窗体上时,它是一个无边框的矩形,可以用任何方式缩放。要在WebBrowser控件中显示Web文档,使用Navigate方法。还可以用GoBack和GoForward方法在已经显示的URL表中前后移动,WebBrowser控件中会自动维护访问过的URL表。
它的LocationName属性返回当前页面标题,LocationURL属性返回当前页面的URL。
二、InternetExplorer对象
InternetExplorer对象可在应用程序中启动一个Internet Explorer实例,并自动地用OLE对它进行操作。InternetExplorer对象在具有WebBrowser控件所具有的属性和方法的基础上,还有所增加。
要在应用程序中引用InternetExplorer对象,首先要加进InternetExplorer对象的引用,步骤如下:
开始一个新项目,类型为Standard EXE.
选择Project(References命令,打开References对话框。
选定icrosoft Internet Controls,然后单击单击Ok钮。
此时虽然看不见新图标,但若打开Object Browser,则可看见InternetExplorer对象已经加入到项目表中。
要生成InternetExplorer对象的实例,可用如下语句:
Dim IE As New InternetExplorer
以后我们就可以使用它了,象下面一个例子来说,我们通过下图所示的一个窗体控制Internet Explorer,在下拉列表中选择一个地址后单击Go there!按钮,即可使Internet Explorer浏览指定的站点,如下图:
当然这个IE窗口已经通过下面代码隐藏了工具条和菜单条。
IE.ToolBar = False
IE.MenuBar = False
§2 WebBrowser控件和InternetExplorer对象的方法
本节介绍二者的几个常用方法:
GoBack和GoForward 这两个方法在历史表中向前或向后移动一个项目,由WebBrowser控件和InternetExplorer对象的方法自动维护,但若要移到最近一个URL之后,或移到第一个URL之前,均会产生错误,必须加入错误处理代码。
GoHome和GoSearch GoHome方法转移到当前设置的启始页,GoSearch方法也是转移到Internet Option对话框指定的页面。
Navigate 这个方法转移到URL或打开HTML文件,它的语法如下:
Navigate(URL As String,[Flags],[TargetFrameName],[PostData],[Headers])
除了第一个变元以外的其他变元都是可选的。URL变元指定显示资源的URL;Flags变元是个常数,它的值及其含义如下:
常量
数值
说明
NavOpenInNewWindow
1
在新窗口中打开资源或文件
NavNoHistory
2
不把资源或文件名加进历史表
NavNoReadFromChche
4
本次转移不从磁盘缓冲区读数据
NavNoWriteToCache
8
本次转移结果不写入磁盘缓冲区
TargetFrameName变元是显示文档的帧名。PostData 变元是HTTP POST传送期间发送到服务器的字符串。POST用与发送从HTML窗体中获取数据,若这个参数未指定,则Navigate方法发出一个HTTP GET传输,这个参数在URL不是HTTP URL 时省略。
Refresh 这个方法重新装入当前显示的页面。
Refresh2 这个方法类似与ReFresh,但可以指定刷新级别,其语法如下:
WebBrowser1.Refresh level
Level变元的取值如下:
常量
数值
说明
REFRESH_NORMAL
0
完成快速刷新
REFRESH_IFEXPIRED
1
页面到期时完成快速刷新
REFRESH_COMPLETELY
3
完成完全刷新
Stop 这个方法取消等待转移或下载操作,停止播放背景声音或动画等多媒体元素。
§3 WebBrowser控件和InternetExplorer对象的事件
WebBrowser控件和InternetExplorer对象的事件在用户用它们浏览移动到另一URL时触发,它们还监视每次下载的进程。
BeforeNavigate2 这个事件在将要、转移到另一URL时发生,它的语法是
Sub WebBrowser1_BeforeNavigate2(ByVal pDisp As Object,URL As Variant,Flags As Variant,TargetFrameName As Variant,PostData As Variant,Headers As Variant,Cancel As Boolean)
URL变元是指示目标URL;Flags是保留变元;TargetFrameName变元是显示指定文档的帧名。应用程序可以设置Cancel变元取消转移过程。如果将它设置为True,则不启动浏览过程。
NavigateComplete 这个事件在成功地转移到新位置后发生。有些资源可能还在下载,但至少已经收到部分文档。该过程可用Stop方法中断。它的语法如下:
Sub WebBrowser1_DocumentComplete(ByVal pDisp As Object,URL As Variant)
3.DownloadBegin 这个事件发生在下载操作子初,在BeforeNavigate2 事件之后触发,应用程序显示“忙信息”或改变指针形状。它的语法如下:
Sub WebBrowser1_DownloadBegin()
DownloadComplete 这个事件发生在下载操作完成,终止或失败之时。它的语法如下:
Sub WebBrowser1_DownloadComplete()
ProgressChange 这个事件用于跟踪下载操作的过程,它被定期触发,指示应用程序进程。它的语法如下:
Sub WebBrowser1_ProgressChange(ByVal Progress As Long,ByVal ProgressMax As Long)
其中两个变元都是长整型,Progress变元是目前已下载的数据总量,而ProgressMax变元是将要下载的数据总量。
为节省篇幅,这些事件的使用例子见授课时的例子。
附录1
VB6可开发的应用程序如下表:
程序类型名称
说明
标准EXE程序
(Standard EXE)是典型的应用程序,VB以前的版本也可开发。
ActiveX EXE 和 ActiveX DLL 程序
只在专业版和企业版中才有。ActiveX控件是支持OLE的自动化服务器程序。这两种程序在功能上是一致的,只是包装不同。ActiveX EXE程序包装成可执行文件,AcitveX DLL 程序包装成动态链接库。
ActiveX 控件
只在专业版和企业版中才有。主要用于开发人员自定义的ActiveX控件。
VB应用程序向导
使用它可以在开发环境中直接建立新的应用程序框架。在开发自己的程序时,可以使用这个工具,并参考它所提供的应用程序原始类型.
数据工程
为编程人员提供开发数据报表应用程序的框架。自动打开数据环境设计器和数据报告设计器。
IIS应用程序
专业版和企业版新添。可使用VB代码书写服务器方的Internet应用程序,用来响应来自浏览器的用户需求。
外接程序
可创建自己的VB外接程序,并在开发环境中自动打开连接设计器。
AcitveX文档EXE和ActiveX文档DLL程序
ActiveX文档实际上是可以在支持超链接环境中运行的VB应用程序。简单说即Web浏览器。如:IE
DHTML应用程序
专业版和企业版新添。它允许编程人员编写响应HTML页面上动作的VB代码,并且还需要将处理过程传递到服务器上。
VB企业版控件
只在企业版中才有,用于开发企业版应用控件。