在VB编程里,模块和子过程是非常重要的概念,把他俩用好了可以让VB\VBA代码变得井井有条、易于管理、易于复制。 本教程用VBA教大家做一个统计函数模块,其中包含9种统计计算:合计值、平均值、最大值、最小值、众数、中位数、方差、标准差、离散系数。做完模块之后,在Access数据库窗体中进行调用的完整过程,也会进行讲解。 通过本课的学习,老铁们可以零距离领略VB模块化开发的优点,理解面向对象编程的好处。 本课分为3个部分:
学完本课做出的效果演示—1—模块和子过程的概念 模块里一般放一些比较常用的、有自变量因变量的函数,函数就是我们中学学的y=f(x)之类的方程,可以导出导入方便使用,并像积木一样可以拆下来用在别的程序里,因此取名叫模块。
方程Function一般放在模块里子过程就是从一段很长的代码中,把可能重复的部分,单独搞出来做一个部分,需要的时候再调用一下,能有效缩短代码行数,便于管理、便于修改、便于展示。 子过程和模块的界限在VBA里不是很严格,把子过程放在模块也是可以的,把函数方程放在过程里、不放模块里也一点问题没有。
当然不应用模块和子过程,对于VB编程来说也没什么问题。对于初学者来说(比如我),理解模块和函数确实要花一些时间,一开始上手编程,可能也不容易体会模块和子过程的好处。我是花了很久之后,才知道为什么要有模块和子过程这种东西。 这种不应用子过程,也不搞模块,一条道搞到底的编程,我如果没有理解错的话,学名应该叫做面向过程编程((Procedure Oriented Programming)。 面向过程编程本身没有什么问题。但如果能熟练应用模块和子过程,可以让VB使用者编程过程更加清楚、层次分明,便于修改,对此我深有体会。本文的案例,也会非常直观的告诉读者应用模块和子过程的好处。如果我没理解错的话,这种大量应用子过程和模块的编程,应该叫面向对象编程((Object Oriented Programming)。(如果我理解的不对,还请各位读者指正)
— 2 —完整代码分享 9个常用的统计函数代码(封装在模块里)求平均值、最大值、最小值、求和的代码,比较简单。 - Function Average(a() As Integer) '求平均值
- For i = 0 To UBound(a)
- s = s + a(i)
- c = c + 1
- Next i
- Average = s / c
- End Function
- Function sum(a() As Integer) '求和
- For i = 0 To UBound(a)
- sum = sum + a(i)
- Next i
- End Function
- Function Max(a() As Integer) '最大值
- Max = a(0)
- For i = 0 To UBound(a)
- If a(i) > Max Then Max = a(i)
- Next i
- End Function
- Function Min(a() As Integer) '最小值
- Min = a(0)
- For i = 0 To UBound(a)
- If a(i) < Min Then Min = a(i)
- Next i
- End Function
复制代码
求中位数、方差、标准差、离散系数的代码,相对比较简单。 - Function Median(a() As Integer, n As Integer) '中位数
- If n Mod 2 = 1 Then
- Median = a(n / 2)
- Else
- Median = (a(n / 2) + a(n / 2 + 1)) / 2
- End If
- End Function
- Function Variance(a() As Integer) '方差
- For i = 0 To UBound(a)
- s = s + (a(i) - Average(a)) ^ 2
- Next
- Variance = s / (UBound(a) + 1)
- End Function
- Function StandardDeviation(a() As Integer) '标准差
- For i = 0 To UBound(a)
- s = s + (a(i) - Average(a)) ^ 2
- Next
- StandardDeviation = (s / (UBound(a) + 1)) ^ (1 / 2)
- End Function
- Function DiscreteCoefficient(a() As Integer) '离散系数
- For i = 0 To UBound(a)
- s = s + (a(i) - Average(a)) ^ 2
- Next
- DiscreteCoefficient = ((s / (UBound(a) + 1)) ^ (1 / 2)) / Average(a)
- End Function
复制代码
最难的就是众数的代码,因为众数不一定只有一个,编程非常复杂,具体原理本课程暂不介绍。 - Function Mode(a() As Integer) '众数
- Dim b, c(), f(), i, j, k, x()
- k = UBound(a)
-
- ReDim c(k), f(k)
- For i = 0 To k - 1
- If f(i) = 0 Then
- c(i) = 1
- For j = i + 1 To k
- If a(j) = a(i) Then
- c(i) = c(i) + 1
- f(j) = 1
- End If
- Next
- End If
- Next
- If f(i) = 0 Then c(i) = 1
- b = 1
-
- For i = 0 To k
- If c(i) > b Then b = c(i)
- Next
- '若所有数据都是众数,则没有众数
- For i = 0 To k
- If c(i) <> b And c(i) <> 0 Then Exit For
- Next
- If i = k + 1 Then
- ReDim x(0)
- x(0) = "没有众数"
- Mode = x
- Exit Function
- End If
- '找出所有众数
- j = 0
- For i = 0 To k
- If c(i) = b Then
- ReDim Preserve x(j)
- x(j) = a(i)
- j = j + 1
- End If
- Next
- Mode = x
- End Function
复制代码
调用代码 本案例利用Access数据库的窗体功能,先生成了25个随机数并进行排序,然后再对这25个数进行以上的统计操作。 生成不重复数的子过程如下: - Public Sub NoRepeatedNumbers(a) '生成25个不重复的数
- For i = 0 To 24
- a(i) = Int(30 * Rnd + 1)
- For j = 0 To i - 1 '这段是防止重复的代码
- If a(i) = a(j) Then '如果重复了再次选择
- i = i - 1
- End If
- Next j
- Next i
- End Sub
复制代码
子过程跟函数不一样,没有返回值,而函数有x也必须有个结果y。 生成重复数的子过程如下: - Public Sub RepeatedNumbers(a) ''生成25个可能有重复的数
- For i = 0 To 24
- a(i) = Int(30 * Rnd + 1)
- Next i
- End Sub
复制代码
排序利用的是冒泡算法: - Public Sub Bubble(a) '冒泡算法
- Dim i, j As Integer
- For i = 0 To 24
- For j = i + 1 To 24
- If a(i) > a(j) Then
- t = a(i) 't作为中间变量,冒泡算法常见
- a(i) = a(j)
- a(j) = t
- End If
- Next j
- Next i
- End Sub
复制代码
Access窗体利用按钮控件,进行自动的计算,并将计算结果输出至从Text1到Text10共10个文本框中,其中Text1是生成的25个随机数(已经排好序),Text2-Text10是统计函数的直接调用,非常简便,其中数组a是变量,输出结果直接显示在Text1中。 - Option Compare Database
- Dim a(24) As Integer '数组一共25个数字
- Dim i As Integer
- Dim j As Integer
- Dim tempStr As String '中间变量,用于数列分行
- Dim t As Double '中间变量,排序用
- Private Sub Command1_Click()
-
- Text1 = ""
- tempStr = " "
-
- Call NoRepeatedNumbers(a)
- '下面这段是生成不重复的25个数字,从1-30的数字里选择
-
- Call Bubble(a) '这段是排序,运用冒泡算法
- '这段是在文本框里生成25个数字
- For i = 0 To 24
- Text1 = Text1 + tempStr + CStr(a(i)) 'CStr转换成字符串
- If (i + 1) Mod 5 = 0 Then
- tempStr = Chr(13) + Chr(10) + " " '换行
- Else
- tempStr = " "
- End If
- Next i
- '进行统计计算
- Text2 = Average(a)
- Text3 = sum(a)
- Text4 = Max(a)
- Text5 = Min(a)
- Text6 = Median(a, 25)
- Text7 = Mode(a)
- Text8 = Variance(a)
- Text9 = StandardDeviation(a)
- Text10 = DiscreteCoefficient(a)
- End Sub
复制代码
注意两个Call,是调用子过程“冒泡算法”和“生成25个数”,这种调用的优点非常明显: - 代码比较有层次感,不会挤在一起,防止误操作。
- 可以重复调用,避免重复输入,防止误操作。
比如本案例,有两个按钮,第二个按钮生成的是可能重复的25个数字(去掉了防止重复的代码) 然后第二个按钮代码如下,和上一段代码很类似,只改动了第二个Call召唤的子过程。 - Private Sub Command2_Click()
-
- Text1 = ""
- tempStr = " "
-
- Call RepeatedNumbers(a) '是生成可能重复的25个数字,从1-30的数字里选择
-
- Call Bubble(a) '这段是排序,运用冒泡算法
- '这段是在文本框里生成25个数字
- For i = 0 To 24
- Text1 = Text1 + tempStr + CStr(a(i)) 'CStr转换成字符串
- If (i + 1) Mod 5 = 0 Then
- tempStr = Chr(13) + Chr(10) + " " '换行
- Else
- tempStr = " "
- End If
- Next i
- '进行统计计算
- Text2 = Average(a)
- Text3 = sum(a)
- Text4 = Max(a)
- Text5 = Min(a)
- Text6 = Median(a, 25)
- Text7 = Mode(a)
- Text8 = Variance(a)
- Text9 = StandardDeviation(a)
- Text10 = DiscreteCoefficient(a)
- End Sub
复制代码
注意观察第6行。两个按钮的区别就是一个是“Call RepeatedNumbers(a)”,一个是“Call NoRepeatedNumbers(a)”。 — 3 —部分代码讲解 9个常用的统计函数代码(封装在模块里)求平均值、最大值、最小值、求和的代码,比较简单。利用For循环遍历即可,求和操作:利用for循环,遍历数组从0一直到最大下标Ubound,将数组数字层层相加。求平均值操作:在求和的基础上除以数组总数量,每遍历一次,分母+1.求最大最小值:基本思想是把数组中的所有数字都和Max和Min比较一遍,Max和Min值取数组第一个数。这种方法只适合排序好的数组。 求中位数、方差、标准差、离散系数的代码编写思路:基本都是对照函数方程进行编写,有的计算平均数是调用了之前的函数代码。这些代码中蕴含的数学更多一些,也比代码本身重要。 调用代码 子过程的调用是采用Call语句。
函数的调用就是直接调用函数名称。 本章先讲到这里,VBA用函数编程的难度不高,但是代码的长度超出了我的想象,看来以后讲解还是以个案为主比较好。
|