第6章 数 组 6.1 一维数组 6.2 控件数组 6.3 二维数组
问题:统计班级学生的考试成绩、 平均分等 特点:对批量数据进行处理 各数据间存在内部联系 使用数组
数组的概念 由一组(若干个)类型相同的相关变量结合在一起而构成的集合; 构成数组的每一个变量称为数组元素; 同一数组中的元素都使用统一的变量名,只是通过不同的下标来加以区分; 只有一个下标的数组称为一维数组,有两个下标的数组称为二维数组。
6.1 一维数组 【例6.1】随机产生10个两位数,计 算总和。 方法一:使用简单变量 定义10个整型变量分别保存随 机产生的数据 6.1 一维数组 【例6.1】随机产生10个两位数,计 算总和。 方法一:使用简单变量 定义10个整型变量分别保存随 机产生的数据 数据量大,不方便
方法二:使用数组 Dim a(1 To 10) As Integer For i=1 To 10 a(i)=Int(Rnd*90)+10 sum = sum + a(i) Next i 书写简洁、 操作方便 下标为i的元素
说明 使用同一数组名代表逻辑上相关的一批变量(10个),为了表示不同的数组元素,只需简单地指出该元素的下标;a(1)、a(2)、…、a(9)、a(10) a数组中的每个元素中只能存放整型数据;
定义一维数组的一般形式 Dim 数组名(下界 To 上界)As 数据类型 缺省则默认下界为0 规定下标的取值范围 数组中元素个数:上界 -下界 + 1 每个元素的数据类型 例如:Dim b(-2 To 3) As Integer Dim x(5) As String 声明一维数组b,包含6个Integer型元素b(-2)、b(-1)、b(0)、b(1)、b(2)、b(3); 声明一维数组x,包含6个字符型元素x(0)、x(1)、...、x(5)
数组名的命名规则与变量名相同 数组元素代表内存中的一个存储单元 引用一维数组元素的一般形式 数组名(下标) 不得越界
Dim a(1 To 10) As Integer 系统为数组中的元素分配连续的内存单元 a(1) a(2) a(3) a(4) a(5)
【例6.2】随机产生 20 个两位整数显示在上部的标签中,单击“偶数”单选按钮时找出其中的所有偶数显示在下部的标签中,若单击“奇数”单选按钮,则显示所有奇数。
程序代码 只能是0或1,0则下标从0开始 Option Base 1 Dim a(20) As Integer Private Sub Form_Load() For i = 1 To 20 a(i) = Int(Rnd * 90) + 10 dstr = dstr & Str$(a(i)) Next i lblData.Caption = dstr End Sub 声明时缺省下界的所有数组,元素下标均从1开始 等价于 Dim a(1 To 20) As Integer
程序代码 Private Sub optEven_Click() lblStr2.Caption = "偶数有:" For i = 1 To 20 If a(i) Mod 2 = 0 Then dstr = dstr & Str$(a(i)) End If Next i lblOut.Caption = dstr End Sub
程序代码 Private Sub optOdd_Click() lblStr2.Caption = "奇数有:" For i = 1 To 20 If a(i) Mod 2 = 1 Then dstr = dstr & Str$(a(i)) End If Next i lblOut.Caption = datastr End Sub
Option Base 语句必须出现在数组声明 之前,且位于所有事件过程的前面; 作用范围仅限于出现在同一代码窗口 且在声明时未指出下标下界的数组; 在一个代码窗口中,Option Base语句 只能出现一次。
数组操作总是借助于循环语句来实现; 利用循环变量与数组元素下标的对应关 系实现数组元素的逐一引用,并对数组 元素进行相应处理。
【例6.3】掷50次骰子,统计各点数出 现的次数。 要求:在例4.2的基础上使用数组进 一步统计各点数出现的次数。
程序分析 声明一个包含6个元素的整型数组num num(1) 统计点数1出现的次数 num(2) 统计点数2出现的次数 掷骰子时,每出现点数i(介于1至6之间) num(i) = num(i) + 1
修改后的程序代码 Private Sub Form_Load() lblText.Visible = False 隐藏各标签 修改后的程序代码 Private Sub Form_Load() lblText.Visible = False lblPoint.Visible = False lblDot1.Visible = False lblDot2.Visible = False lblDot3.Visible = False lblDot4.Visible = False lblDot5.Visible = False lblDot6.Visible = False End Sub 用于显示各点数出现的次数
Private Sub cmdStart_Click() Dim dot As Integer Dim n As Integer Dim dotstr As String Dim dotnum(1 To 6) As Integer lblText.Visible = True lblPoint.Visible = True lblDot1.Visible = True lblDot2.Visible = True 显示各标签
imgText.Visible = False Randomize For i = 1 To 50 lblDot5.Visible = True lblDot6.Visible = True imgText.Visible = False Randomize For i = 1 To 50 dot = Int(Rnd * 6) + 1 dotnum(dot)= dotnum(dot)+1 dotstr=dotstr & Str(dot)+" " Next i 隐藏图片
lblPoint.Caption = dotstr lblDot1.Caption = "…" & Str(dotnum(1)) lblDot2.Caption = "…" & Str(dotnum(2)) lblDot3.Caption = "…" & Str(dotnum(3)) lblDot4.Caption = "…" & Str(dotnum(4)) lblDot5.Caption = "…" & Str(dotnum(5)) lblDot6.Caption = "…" & Str(dotnum(6)) End Sub 显示各点数
【例6.4】计算1 ~n的阶乘,并以一行一个的形式输出到窗体中(n不超过20)。
程序分析 使用数组存放各阶乘值 将数组声明为Double型,防止计 算结果越界 a(1) 存放1! a(2) 存放2! Dim a(1 To 20) As Double
阶乘的值由函数调用求得 定义函数fac(n):计算n的阶乘 反复调用fac(i)以计算出不同i值的阶乘,将函数值保存到数组元素a(i)中(i从1变到n) Private Function fac(n) As Double result = 1 For i = 1 To n result = result * i Next i fac = result End Function For i = 1 To n a(i) = fac(i) Next i
程序代码 Option Base 1 Dim a(20) As Double Private Sub cmdInput_Click() 数组下标下界为1 程序代码 Option Base 1 Dim a(20) As Double Private Sub cmdInput_Click() Cls n = Val(InputBox("请输入n:", "输入框")) For i = 1 To n a(i) = fac(i) Print i; "!="; a(i) Next i End Sub
Private Function fac(a) As Double result = 1 For i = 1 To a result = result * i Next i fac = result End Function
【例6.5】运行程序时在左边列表框中显示随机产生的100个两位整数,用鼠标选中某数后立即以消息框形式显示该数所处位置;单击“删除”按钮将把当前选中的数据从数列中删除;单击“找素数”按钮,在右边的列表框中显示100个整数中存在的所有素数。 运行初期不可见 列表框
控件介绍 —— 列表框 为用户提供选项的列表 以列表的形式显示若干数据项; 用户可从中选择一项或多项; 当项数超过列表框可显示的数目时,可自动出现垂直或水平滚动条 每个数据项称为一个项目或一个列表项 系统建议的列表框前缀:lst
算法分析 Private Function isprime (x) k = Int(Sqr(x)) For i = 2 To k If x Mod i = 0 Then isprime = 0 Exit Function End If Next i End Function 定义函数isprime(x),判断x是否为素数。若x是素数则函数值为1,否则值为0。 先假设x是素数,令函数值为1; isprime = 1 用1 ~ Sqr(x)依次去除x,一旦x被某个整数整除则表明其不是素数,结束函数(Exit Function )并返回0; isprime = 0,
产生100个随机数并添加到列表框lstData中 把数据a作为一个项目添加到列表框lstData中 程序代码 Private Sub Form_Load () Dim a As Integer lblPrime.Visible = False lstPrime.Visible = False For i = 1 To 100 a = Int(Rnd * 90) + 10 lstData.AddItem a Next i End Sub 产生100个随机数并添加到列表框lstData中 方法 把数据a作为一个项目添加到列表框lstData中
Private Sub lstData_Click () cmdDel.Visible = True lblPrime.Visible = False lstPrime.Visible = False i = lstData.ListIndex + 1 ch$ = lstData.Text & "是第" & i & "个数据!" MsgBox (ch$) End Sub 属性: 返回当前所选 项目的索引号 位置 属性:被选中项 目的内容
Private Sub cmdPrime_Click () cmdDel.Visible = False lblPrime.Visible = True lstPrime.Visible = True lstPrime.Clear For i = 0 To lstData.ListCount – 1 a = Val( lstData.List(i) ) If isprime(a) = 1 Then lstPrime.AddItem a End If Next i End Sub 方法:删除列表框中的所有项目 最后一个项目的下标 依次处理每个列表项 将第i个列表项的值赋给a 属性: 列表框中当前已有列表项的总数目 属性:字符型数组,其元素 一一对应列表框中的 每个项目
将用户当前选中的项目从lstData列表框中删除 用户选中项目的索引号 Private Sub cmdDel_Click () lstData.RemoveItem lstData.ListIndex End Sub 方法:删除列表框中指 定的一个项目 将用户当前选中的项目从lstData列表框中删除
列表框常用属性及方法 ListIndex属性 返回当前所选项目的索引号,没有选中任何项目时返回-1 只能在代码中引用,设计阶段不可用 位置 = 列表框.ListIndex + 1
Text属性 ListCount属性 当前被选中项目的内容 只读属性 返回列表框中当前已有列表项的总数目
List属性 字符型数组,元素一一对应列表框中的每个项目 List(0)对应索引号为0的项目,List(i)对应索引号为i的项目 List(ListIndex)为当前选中的项目,等价于列表框的Text属性值 设计阶段可通过该属性直接为列表框添加项目
AddItem方法 将一个项目添加到列表中 调用格式 从0开始 列表框.AddItem 项目字串 [,项目索引号] 例 lstData.AddItem ”VB程序设计” , 0 出现在第i个位置上的数据项索引号为i-1 若语句中省略索引号,则新项目被添加到表尾 从0开始
将当前选中的项目从lstData列表框中删除 RemoveItem方法 从列表框中删除指定的一个项目 调用格式 列表框名称.RemoveItem 删除项索引号 例 lstData.RemoveItem lstData.ListIndex Clear方法 删除列表框中的所有项目 lstPrime.Clear 将当前选中的项目从lstData列表框中删除
【例6.6】使用输入框输入若干整数并添加到列表框中(输入“End” 时结束输入),然后找出其中最大数显示在标签中。
算法设计 找a(1) ~ a(n) n个数据中的最大数 假设第1个数据a(1)就是最大值,记录其所在位置(或下标): k = 1 i = 2 ~ n 将第i个数据与当前最大值(处于k位置上的数据)进行比较 若a(i)>a(k),则更新k值 k=i 将第3个数据与当前最大值(处于k位置上的数据)进行比较 若a(3)>a(k),则更新k值 k=3 将第2个数据与当前最大值(处于k位置上的数据)进行比较 若a(2)>a(k),则更新k值 k=2 For i = 2 To n If a(i) > a(k) Then k = i Next i a(k)即为最大值
程序代码 Private Sub cmdIn_Click() lblMax.Visible = False a = InputBox( "…","…", 0) Do While LCase(a) <> "end" lstData.AddItem a a = InputBox("…", "….", 0) Loop End Sub 输入数据
索引号 Private Sub cmdMax_Click() k = 0 For i = 1 To lstData.ListCount - 1 If Val(lstData.List(i)) > Val(lstData.List(k)) Then k = i Next i lblMax.Visible = True lblMax.Caption = "最大值" & Str(lstData.List(k)) End Sub 找最大值 当前最大值
【例6.7】用选择法对数组中的数进行从大到小排序。两个框架中分别添加标签,上部框架内的标签中显示10个随机生成的两位整数,下部框架内的标签中显示排序后的10个数据。
算法分析 —— 选择法排序 对包含n个数据的数组按从大到小排列 第1步:找出n个数据( a(1)至a(n) )中的 最大数,并与第1个数据a(1)交 换位置; 第2步:在剩下的n-1个数据(a(2)至a(n)) 中找出最大数,并与第2个数据 a(2)交换位置; 第i步: 在剩下的n-i+1个数据(a(i)至a(n))中找出最大数,并与第 i 个数据a(i)交换位置; i = 1 ~ ? n-1
选择法排序的基本算法 For i = 1 To n-1 找出a(i)至a(n)中的最大值 将最大值与第i个数据a(i)交换位置 Next i k = i For j = i + 1 To 10 If a(j) > a(k) Then k = j Next j 将最大值与第i个数据a(i)交换位置 temp = a(i) a(i) = a(k) a(k) = temp
程序代码 Private Sub Form_Load () 产 Dim a(1 To 10) As Integer 生 随 机 数 据 并 显 示 Private Sub Form_Load () Dim a(1 To 10) As Integer Randomize For i = 1 To 10 a(i) = Int(Rnd * 90) + 10 datastr1 = datastr1 & Str$(a(i)) Next i lblData1.Caption = datastr1
If a(j) > a(k) Then k = j Next j If k <> i Then temp = a(i) 对 10 个 数 据 进 行 选 择 法 排 序 For i = 1 To 9 k = i For j = i + 1 To 10 If a(j) > a(k) Then k = j Next j If k <> i Then temp = a(i) a(i) = a(k) a(k) = temp End If Next i 最大值不是a(i) 时才交换,提高效率
【例6.8】考场计时程序。用户在组合框输入或选择考试时间后,单击“开始计时”按钮开始计时,并在下部标签中动态显示考试已进行的时间;距考试结束5分钟时发出10秒警告音;到达考试时间后显示另一有关交卷信息的窗体。 组合框 界面设计 运行初期隐藏
控件介绍 —— 组合框 文本框和列表框组合而成,具有它们的双重功效; 用户既可通过列表框选定项目,也可在文本框中直接输入; 当组合框中项目数超过其能够显示的数目时,控件上自动出现滚动条; 可折叠显示组合框,单击右部箭头时显示全部列表; 系统建议的控件前缀是cbo。
程序代码 Dim hh As Integer Dim mm As Integer Dim ss As Integer 用户设置的考试时间 单位:秒 Dim hh As Integer Dim mm As Integer Dim ss As Integer Dim examtime As Integer Dim counttime As Integer 已进行的考试时间 单位:秒
Private Sub Form_Load () Height = 1800 lblTime.Visible = False lblShow.Visible = False tmrShow.Enabled = False End Sub 隐藏窗体的下半部分
展开并显示窗体的下半部,动态显示考试已进行时间 Private Sub cmdTime_Click () Height = 3500 lblTime.Visible = True lblShow.Visible = True cboTime.Locked = True cmdTime.Enabled = False tmrShow.Enabled = True examtime = Val(Trim(cboTime.Text)) * 60 End Sub 展开并显示窗体的下半部,动态显示考试已进行时间 不可用,避免用户误操作
Private Sub tmrShow_Timer () counttime = counttime + 1 ss = ss + 1 If ss = 60 Then mm = mm + 1 : ss = 0 End If If mm = 60 Then hh = hh + 1 : mm = 0 lblShow.Caption = ……
If counttime > examtime - 300 And 距离考试结束5分钟 If counttime > examtime - 300 And counttime <= examtime - 290 Then For i = 1 To 10 Beep Next i End If If counttime >= examtime Then Unload frmEx6_8_1 frmEx6_8_2.Show End Sub 延长发声时间 通过计算机喇叭发出一个声调 考试时间到
组合框常用属性及方法 Style属性 指定组合框的显示类型(缺省值为0) 0 下拉式组合框,由文本框和下拉列表组成 可输、可选、可折叠 运 0 下拉式组合框,由文本框和下拉列表组成 可输、可选、可折叠 1 简单组合框 ,由文本框和固定列表组成, 可输、可选、不可折叠 2 下拉式列表框,仅由下拉式列表构成 不可输、可选、可折叠 运 行 阶 段 不 可 用
组合框拥有列表框和文本框的大部分属性及方法 Locked属性 值为True 时将锁住组合框,此时既不能在文本框中输入,也不能在列表中进行选择 组合框拥有列表框和文本框的大部分属性及方法
6.2 控件数组 【例6.9】在窗体中添加1个组合框、1个标签和8个图像框。在组合框中选择任意国名后,在标签中显示该国的首都名,同时该国的国旗闪烁。 利用计时器 0.3秒显示一次 组合框 Style = 2 8个相同的图像框,使用控件数组
具有相同类型和名称的一组控件称为控件数组 添加控件数组的方法 添加第1个图像框,名称为imgFlag 添加(或复制)第2个图像框,并将名称属 性仍设为imgFlag 具有相同类型和名称的一组控件称为控件数组 创建两个同名图像框 依次向窗体中添加具有统一名称的其余图 像框
通过索引号(Index属性)标识和区分同一控件数组内的各个元素(控件) 同一控件数组中的各控件,索引号必须互 不相同。缺省设置下,系统将按照各控件 的创建顺序依次赋予索引号0、1、2、...
控件数组名(索引号) 引用控件数组中各控件的方法 例如:imgFlag(0) —— 索引号为0的图像框 imgFlag(5).Picture —— 索引号为5的 图像框的Picture属性 控件数组中各元素除Name属性相同外,其他属性值可各不相同
将组合框的第1 个选项(索引号为 0)显示在组合框的文本框内 程序代码 Private Sub Form_Load () cboCountry.AddItem "中国" cboCountry.AddItem "美国" cboCountry.Text = cboCountry.List(0) imgFlag(0).Picture = LoadPicture("中国.gif") imgFlag(1).Picture = LoadPicture("美国.gif") End Sub 将组合框的第1 个选项(索引号为 0)显示在组合框的文本框内
Private Sub cboCountry_Click () tmrFlash.Enabled = True For i = 0 To 7 imgFlag(i).Visible = True Next i Select Case cboCountry.Text Case "中国" lblCapital.Caption = "首都是北京" Case "美国" lblCapital.Caption = "首都是华盛顿" End Select End Sub 索引号为i 的图像框
imgFlag中各控件的索引号与cboCountry各列表项的索引号一一对应 InterVal属性:300 Private Sub tmrFlash_Timer () Static i As Integer If i = 0 Then imgFlag(cboCountry.ListIndex).Visible = True Else imgFlag(cboCountry.ListIndex).Visible = False End If i = Not i End Sub 组合框中所选国家对应的国旗图像框 imgFlag中各控件的索引号与cboCountry各列表项的索引号一一对应
【例6.10】在窗体中创建由6个标签所构成的控件数组,单击右侧的某一标签时将使6个标签中的字体颜色全部变成该标签中所规定的颜色;单击左侧标签时,将同时改变左侧标签中显示的文本。 控件数组lblTxt
程序代码 根据Index的不同值去执行相应操作 Private Sub lblTxt_Click (Index As Integer) 引发该事件的控件索引号 根据Index的不同值去执行相应操作 程序代码 Private Sub lblTxt_Click (Index As Integer) Select Case Index Case 0 For i = 0 To 2 lblTxt(i).Caption = "AAAAAA" Next i Case 1 lblTxt(i).Caption = "BBBBBB" 单击任意标签都触发此事件过程
Case 2 For i = 0 To 2 lblTxt(i).Caption = "CCCCCC" Next i Case 3 For i = 0 To 5 lblTxt(i).ForeColor = QBColor(4) '红 Next i Case 4 lblTxt(i).ForeColor = QBColor(1) '兰
Case 5 For i = 0 To 5 lblTxt(i).ForeColor = QBColor(6) '黄 Next i End Select End Sub
说明 使用控件数组比直接向窗体中添加相同类型的多个控件所消耗的资源少; 同一控件数组中的各控件共享相同的事件过程,从而简少程序的编码量。
6.3 二维数组 【例6.11】窗体上有1个框架、2个命令按钮和1个图片框。单击“矩阵”按钮后随机产生12个整数,并以3行4列的矩阵形式输出在图片框中;单击“平均值”按钮计算并在框架的标题中输出所有数据的平均值。
程序代码 Dim a( 1 To 3 , 1 To 4 ) As Integer 定义二维数组a,包括3×4共12个元素: a(1,1)、a(1,2)、a(1,3)、a(1,4)、a(2,1)、a(2,2) a(2,3)、a(2,4)、a(3,1)、a(3,2)、a(3,3)、a(3,4) 其中每个元素都是整型。 Private Sub Form_Load () cmdAve.Enabled = False fraArr.Caption = "等待产生矩阵" End Sub 具有行和列的二维表格或矩阵 a(1,1) a(1,2) a(1,3) a(1,4) a(2,1) a(2,2) a(2,3) a(2,4) a(3,1) a(3,2) a(3,3) a(3,4) 逻辑结构
Private Sub cmdArr_Click () picArr.Cls fraArr.Caption = " 矩 阵" cmdAve.Enabled = True For i = 1 To 3 For j = 1 To 4 a(i, j) = Int(Rnd * 90) + 10 picArr.Print a(i, j); Spc(2); Next j picArr.Print Next i End Sub 控制行的变化 控制列的变化 位于a数组中第i行、第j列上的元素
Private Sub cmdAve_Click () cmdAve.Enabled = False sum = 0 For i = 1 To 3 For j = 1 To 4 sum = sum + a(i, j) Next j Next i ave = sum / 12 fraArr.Caption = "平均值是" & Str(Format(ave, "##.##")) End Sub
说明 行下标取值范围 定义二维数组的一般格式 Dim 数组名([下界1 To ]上界1 , [下界2 To ] 上界2)As 数据类型 列下标取值范围 0 To 2 例如:Dim b(2,1 To 2) As Single 定义二维数组b,包含6个( 3行2列 ) Single型元素 b(0,1)、b(0,2)、b(1,1)、b(1,2)、b(2,1)、b(2,2)
引用二维数组元素的一般形式 数组名(下标1,下标2) 行下标 列下标 数组中各元素在内存中占据连续的存 储单元 物理结构 行优先 a(1,1) a(1,3) a(1,2) a(1,4) a(2,1) a(2,3) a(3,1) a(3,3) a(2,2) a(2,4) a(3,2) a(3,4) 物理结构
【例6.12】在窗体中添加一个图片框,其大小与窗体保持一致。运行程序时,将杨辉三角形输出到图片框中。
程序分析 用二维数组a存放杨辉三角形各行的值; Dim a(1 To 6, 1 To 6) As Integer 杨辉三角形的数据特点 ☆ 位于第1列和对角线上的元素值为1 ☆ 其他元素值等于其上一行同列元素及 前列元素之和 a(i,1) = 1 a(i,i) = 1 a(i,j) = a(i-1,j-1) + a(i-1,j) 3 ~ 6 0 ~ i-1
程序代码 Load事件中无法完成 Option Base 1 Private Sub Form_Activate () Dim a(6, 6) As Integer For i = 1 To 6 a(i, 1) = 1 a(i, i) = 1 Next i 二维数组行、列下标值从1开始 给位于第1列和对角线上的元素赋值
For i = 3 To 6 For j = 2 To i a(i, j) = a(i - 1, j - 1) + a(i - 1, j) Next j Next i For i = 1 To 6 For j = 1 To i picShow.Print Format(a(i, j),"@@");Spc(1); picShow.Print End Sub 给其他位置上的元素赋值 输出三角形
【例6.13】运行时单击按钮随机生成20个整数并显示在图片框中,同时按钮的标题变成“找最大值” ;再次单击按钮,则标签中输出数据中的最大值以及最大值所在行、列坐标,同时按钮标题恢复成“生成数据” 。 4行5列
程序代码 Option Base 1 Dim a(4, 5) As Integer Private Sub cmdRun_Click () 存放随机生成的20个数据 Option Base 1 Dim a(4, 5) As Integer Private Sub cmdRun_Click () Dim x, y As Integer If cmdRun.Caption = "生成数据" Then picData.Cls lblMax.Caption = "" 最大值所在行、列坐标 为显示数据做准备
picData.Print a(i, j); Spc(1); Next j picData.Print Next i For i = 1 To 4 For j = 1 To 5 a(i, j) = Int(Rnd * 90) + 10 picData.Print a(i, j); Spc(1); Next j picData.Print Next i cmdRun.Caption = "找最大值" Else 生成数据并显示
If a(x, y) <= a(i, j) Then x = i : y = j End If Next j Next i 假设第1个元素为最大值,记录其坐标值 x = 1 : y = 1 For i = 1 To 4 For j = 1 To 5 If a(x, y) <= a(i, j) Then x = i : y = j End If Next j Next i lblMax.Caption = "最大值是:" & a(x, y) & Chr(13) & Chr(10) 查找最大值并 输出行列坐标
lblMax.Caption = lblMax.Caption & "行 坐标:" & x & Chr(13) & Chr(10) lblMax.Caption = lblMax.Caption & "列 坐标:" & y & Chr(13) & Chr(10) cmdRun.Caption = "生成数据" End If End Sub 未考虑生成重复数据的问题,有可能存在多个最大值,此时以最后找到的数据为最大值。