VBA,我的第一门语言(带你走进VBA的世界)

VBA是我正式学习的第一门计算机语言,也是一门我感情很深的计算机语言。它带我领略了编程的乐趣,让我相信一切皆有可能,一切皆可实现。它也给我带来的很多乐趣,很多工作机会。让我给你介绍一下它。

什么是VBA

百度百科

Visual Basic for Applications(VBA)是Visual
Basic的一种宏语言,是微软开发出来在其桌面应用程序中执行通用的自动化(OLE)任务的编程语言。主要能用来扩展Windows的应用程式功能,特别是Microsoft
Office软件。也可说是一种应用程式视觉化的Basic
脚本。该语言于1993年由微软公司开发的的应用程序共享一种通用的自动化语言——–Visual Basic For
Application(VBA),实际上VBA是寄生于VB应用程序的版本。微软在1994年发行的Excel5.0版本中,即具备了VBA的宏功能。
由于微软Office软件的普及,人们常见的办公软件Office软件中的Word、Excel、Access、Powerpoint都可以利用VBA使这些软件的应用更高效率,例如:通过一段VBA代码,可以实现画面的切换;可以实现复杂逻辑的统计(比如从多个表中,自动生成按合同号来跟踪生产量、入库量、销售量、库存量的统计清单)等。

掌握了VBA,可以发挥以下作用:
- 规范用户的操作,控制用户的操作行为;
- 操作界面人性化,方便用户的操作;
- 多个步骤的手工操作通过执行VBA代码可以迅速的实现;
- 实现一些VB无法实现的功能。[1]
- 用VBA制做EXCEL登录系统。[2]
- 利用VBA可以Excel内轻松开发出功能强大的自动化程序。

VBA可以做到什么

1、基于Ribbon实现个性化的操作界面

  • office2007开始,微软推出了一个新型的UI系统—Ribbon
    这里写图片描述
    我们可以在word、ppt、excel等office组件中看到这个UI界面,提供用户一个快捷可视化的功能界面。
  • 可以通过 Custom UI Editor For Microsoft Office等工具自定义Ribbon界面
    并通过VBA编写对界面按钮点击、输入、修改等操作时触发的事件,或者定义UI界面的动态变化规则,实现动态调整界面。
<?xml version="1.0" encoding="utf-8"?>
<customUI xmlns="http://schemas.microsoft.com/office/2006/01/customui">
  <ribbon startFromScratch="false">
    <tabs>
      <tab id="itab" label="自动化工具">

        <group id="igrp1" label="数据源管理">
          <button 
    id="isource_clear" 
    label="清空数据源" 
    imageMso="_3DMaterialMetal" 
    size="large" 
    supertip="可用于清空所有订单表和招聘表中的信息" 
    onAction="isource_clear"/>
          <button 
    id="isource_input" 
    label="导入数据源" 
    imageMso="_3DMaterialPlastic" 
    size="large" 
    supertip="将选中文件《招聘订单信息一览表》和《招聘在途及外招信息一览表》中的信息导入到本工具对应的数据源中,累计添加." 
    onAction="isource_input"/>
        </group>
      </tab>
    </tabs>
  </ribbon>
</customUI>

2、调动windows其他组件

  • 对word和outlook的调用实现邮件自动发送
Sub eMailMergeWithAttchments(t As Worksheet)

Dim myDatarange As Range
Dim i As Long, j As Long, k As Long, l As Long
Dim ISectionsCount As Long
Dim bStarted As Boolean
Dim oOutlookApp As Outlook.Application
Dim wWordApp As Object
Dim SrcDoc As Object
Dim oItem As Outlook.MailItem
Dim oAccount As Outlook.Account
Dim sMySubject As String, sMessage As String, sTitle As String
Dim RowNum As Long, ColNum As Integer
Dim TmpBody As String
Dim m As Integer, n As Integer, m1 As Integer, n1 As Integer
Dim VarName As String, RepName As String
Dim VarCol As Integer
Dim IsRight As Boolean
Dim MyPath As String
Dim StartVarCol As Integer
Dim PrePath As String
Dim StartText As String
Dim EndText As String
Dim Myrange01 As Object, Myrange02 As Object, Myrange03 As Object, FoundRange As Object
Dim isFind As Boolean
Dim RepStr As String, OldStr As String
Dim TmpFileName As String
Dim MyFile As New FileSystemObject
Dim SavePath As String
'
'Dim TestWRange As Word.Range

StartText = "<-|"
EndText = "|->"
'
'StartVarCol = 11
TmpFileName = "TmpHtmlDoc.htm"
'Set docSource = ActiveDocument


RowNum = t.Cells(12, 1).CurrentRegion.Rows.Count - 1
ColNum = t.Cells(12, 1).CurrentRegion.Columns.Count

If RowNum = 0 Then
    MsgBox "无待发送邮件"
    Exit Sub
End If


PrePath = ThisWorkbook.Path & "\邮件模板"

On Error Resume Next
'检测是否打开Outlook
Set oOutlookApp = GetObject(, "Outlook.Application")

'没打开则打开
If Err <> 0 Then
    Set oOutlookApp = CreateObject("Outlook.Application")
    bStarted = True
End If

'打开word
Set wWordApp = CreateObject("Word.Application")

'显示发送情况
UserForm1.Show 0
With UserForm1.ProgressBar1
    .Min = 1
    .Max = RowNum + 1
    .Scrolling = 0
End With

For i = 13 To RowNum + 12
    t.Cells(i, 1) = "发送中"
    IsRight = True
    Set oAccount = oOutlookApp.Session.Accounts.Item(t.Cells(6, "H").Value) '设定发送邮箱
    '获取正文
    MyPath = t.Cells(i, 5)

    If Left(MyPath, 1) = "." Then
        MyPath = PrePath & Right(MyPath, Len(MyPath) - 1)
        Debug.Print MyPath
    End If
    MyPath = VBA.Replace(MyPath, ",", "")
    Debug.Print MyPath

    Set SrcDoc = wWordApp.Documents.Open(MyPath)

    '持续替换变量
    Do

        Set Myrange01 = SrcDoc.Range
        Set Myrange02 = SrcDoc.Range
        Set Myrange03 = SrcDoc.Range

        '查找第一个开始符
        Myrange01.Find.ClearFormatting
        With Myrange01.Find
        '查找第一个字符并替换掉
            .Text = StartText
            .Replacement.Text = ""
            .Forward = True
            .Wrap = wdFindStop
            .Format = False
            .MatchCase = False
            .MatchWholeWord = False
            .MatchByte = True
            .MatchWildcards = False
            .MatchSoundsLike = False
            .MatchAllWordForms = False
        End With
        Myrange01.Find.Execute
        isFind = Myrange01.Find.Found

        '若找到替换符
        If isFind = True Then
            '查找第一个结束符
            Myrange02.Find.ClearFormatting
            With Myrange02.Find
                .Text = EndText
                .Replacement.Text = ""
                .Forward = True
                .Wrap = wdFindStop
                .Format = False
                .MatchCase = False
                .MatchWholeWord = False
                .MatchByte = True
                .MatchWildcards = False
                .MatchSoundsLike = False
                .MatchAllWordForms = False
            End With
            Myrange02.Find.Execute

            m = Myrange01.Start
            n = Myrange02.Start
            m1 = Myrange01.End
            n1 = Myrange02.End

            '找到变量名称
            Set FoundRange = SrcDoc.Range(m, n1)
            OldStr = FoundRange.Text
            VarName = Mid(OldStr, Len(StartText) + 1, Len(OldStr) - 6)
            Debug.Print VarName

            '找到数据源列
            For k = 1 To ColNum
                If t.Cells(12, k) = VarName Then
                    VarCol = k
                    Exit For
                End If
            Next k


            If VarCol = 0 Then
                t.Cells(i, 1) = "失败:变量名称有误。"
                IsRight = False
                GoTo Prev
            End If

            RepStr = t.Cells(i, VarCol)

            '替换所有此变量
            Myrange03.Find.ClearFormatting
            With Myrange03.Find
                .Text = OldStr
                .Replacement.Text = RepStr
                .Forward = True
                .Wrap = wdFindStop
                .Format = False
                .MatchCase = False
                .MatchWholeWord = False
                .MatchByte = True
                .MatchWildcards = False
                .MatchSoundsLike = False
                .MatchAllWordForms = False
            End With
            Myrange03.Find.Execute Replace:=wdReplaceAll
        End If

    Loop While isFind = True

'   TmpBody = SrcDoc.Range.Text
    SavePath = PrePath & "\" & TmpFileName
    Debug.Print SavePath

    SrcDoc.SaveAs Filename:=SavePath, FileFormat:=wdFormatHTML, _
        LockComments:=False, Password:="", AddToRecentFiles:=True, WritePassword _
        :="", ReadOnlyRecommended:=False, EmbedTrueTypeFonts:=False, _
        SaveNativePictureFormat:=False, SaveFormsData:=False, SaveAsAOCELetter:= _
        False
    SrcDoc.Close savechanges:=False

    TmpBody = GetHtmlText(PrePath & "\" & TmpFileName)
    MyFile.DeleteFile (PrePath & "\" & TmpFileName)

   '生成收件人和抄送人
    Dim a As String, b As String
    a = t.Cells(i, 2).Value
    b = t.Cells(i, 3).Value
    '新建邮件
    If IsRight = True Then
        '对于收件人、抄送人,增加后缀@pingan.com.cn 确保如邮箱错误等情况可以看出来
        If t.Cells(5, "H").Value <> "是" Then
            a = Replace(a, ";", """@pingan.com.cn;""")
            b = Replace(b, ";", """@pingan.com.cn;""")
            a = a & """@pingan.com.cn"""
            If b <> "" Then b = b & """@pingan.com.cn"""
        End If

        Set oItem = oOutlookApp.CreateItem(olMailItem)
        With oItem
            .SendUsingAccount = oAccount '设定发送邮箱
            .Subject = t.Cells(i, 4)
            .HTMLBody = TmpBody
            '去除"号
            .To = VBA.Replace(a, """", "")
            .CC = VBA.Replace(b, """", "")
            Debug.Print VBA.Replace(a, """", "")
            Debug.Print VBA.Replace(b, """", "")
            If t.Cells(i, 6) <> "" Then
            .Attachments.Add ThisWorkbook.Path & "\附件\" & t.Cells(i, 6).Value
            End If
            .Send
        End With
        Set oItem = Nothing
        t.Cells(i, 1) = "成功"

        '显示发送到第几份
        On Error Resume Next
        UserForm1.ProgressBar1.Value = i - 12
        On Error GoTo 0
        UserForm1.Caption = "共有" & RowNum - 1 & " 封邮件待发送,正进行第" & i - 12 & "发送,请稍候!"
    End If

Prev:

Next i
'卸载窗口
Unload UserForm1

Set MyFile = Nothing
wWordApp.Quit
Set wWordApp = Nothing
If bStarted = True Then
    oOutlookApp.Quit
End If

Set oOutlookApp = Nothing

windows文件管理

  • 实现文件和文件夹的修改、移动、删除等
Private Sub CommandButton1_Click() '上传文件
Dim iarray, flname As String, a
Dim ipath As String
Dim folderexist As Boolean, FileExist As Boolean
Dim imsg As Integer, ioption As String

ipath = "\\dqsh-d8403\share\招聘"

If ListBox1.Value <> "" And TextBox1.Value <> "" Then
iarray = VBA.Split(TextBox1.Value, "\")
flname = iarray(UBound(iarray, 1))
    If OptionButton1.Value = True Then
        ioption = OptionButton1.Caption
    ElseIf OptionButton2.Value = True Then
        ioption = OptionButton2.Caption
    ElseIf OptionButton5.Value = True Then
        ioption = OptionButton5.Caption
    ElseIf OptionButton6.Value = True Then
        ioption = OptionButton6.Caption
    ElseIf OptionButton7.Value = True Then
        ioption = OptionButton7.Caption
    ElseIf OptionButton8.Value = True Then
        ioption = OptionButton8.Caption
    Else
        MsgBox "请选择上传类型"
        Exit Sub
    End If

    Debug.Print ipath & "\" & iChannel & "\" & ListBox1.Value & "\" & ioption & "\*"
    FileExist = (Dir(ipath & "\" & iChannel & "\" & ListBox1.Value & "\" & ioption & "\*", vbNormal + vbReadOnly + vbHidden) <> "")

    If FileExist = False Then
        mkfile ipath & "\" & iChannel & "\" & ListBox1.Value & "\" & ioption
        FileCopy TextBox1.Value, ipath & "\" & iChannel & "\" & ListBox1.Value & "\" & ioption & "\" & flname
    Else
        imsg = MsgBox("已存在" & ioption & ",是否替换?", 4 + 32)
        If imsg = 6 Then '替换
            Kill ipath & "\" & iChannel & "\" & ListBox1.Value & "\" & ioption & "\*"
            FileCopy TextBox1.Value, ipath & "\" & iChannel & "\" & ListBox1.Value & "\" & ioption & "\" & flname
        Else
            FileCopy TextBox1.Value, ipath & "\" & iChannel & "\" & ListBox1.Value & "\" & ioption & "\" & flname
        End If
    End If
Else
    MsgBox "请选择员工和上传文件"
    Exit Sub
End If
MsgBox "已上传"

End Sub
Private Sub CommandButton2_Click() '下载文件
Dim flpath As String, ipath As String
Dim ioption As String
Dim FileExist As Boolean
Dim i As Integer
Dim iarray, flname As String
Dim myfile As String

ipath = "\\dqsh-d8403\share\招聘"
If ListBox2.Value = "" Then
    MsgBox "请选择员工"
    Exit Sub
End If
If OptionButton3.Value = True Then
    ioption = OptionButton3.Caption
ElseIf OptionButton4.Value = True Then
    ioption = OptionButton4.Caption
ElseIf OptionButton9.Value = True Then
    ioption = OptionButton9.Caption
ElseIf OptionButton10.Value = True Then
    ioption = OptionButton10.Caption
ElseIf OptionButton11.Value = True Then
    ioption = OptionButton11.Caption
ElseIf OptionButton12.Value = True Then
    ioption = OptionButton12.Caption
Else
    MsgBox "请选择下载类型"
    Exit Sub
End If

myfile = Dir(ipath & "\" & iChannel & "\" & ListBox2.Value & "\" & ioption & "\*")
Debug.Print ipath & "\" & iChannel & "\" & ListBox2.Value & "\" & ioption & "\*"
If myfile <> "" Then
    flpath = Application.GetSaveAsFilename(Title:="选择下载到", InitialFileName:="根据实际文件名决定-无需填写")
    iarray = VBA.Split(flpath, "\")
    flname = iarray(0)
    For i = 1 To UBound(iarray) - 1
        flname = flname & "\" & iarray(i)
    Next
        FileCopy ipath & "\" & iChannel & "\" & ListBox2.Value & "\" & ioption & "\" & myfile, flname & "\" & myfile
    myfile = Dir
    Do While myfile <> ""
        FileCopy ipath & "\" & iChannel & "\" & ListBox2.Value & "\" & ioption & "\" & myfile, flname & "\" & myfile
        myfile = Dir
    Loop
Else
    MsgBox "缺少相关附件"
    Exit Sub
End If

MsgBox "已下载"

End Sub
Private Function mkfile(flpath As String)
Dim iarray, folderexist As Boolean
Dim i As Integer, tmppath As String

iarray = VBA.Split(flpath, "\")
tmppath = iarray(0)
For i = 1 To UBound(iarray, 1)
    tmppath = tmppath & "\" & iarray(i)
    If i > 3 Then
        folderexist = (Dir(tmppath, vbDirectory + vbHidden) <> "")
        If folderexist = False Then
            MkDir tmppath
        End If
    End If
Next
End Function

与数据库建立连接

实现查、删、改、增等基础sql操作,以及事件调用、数据表创建等复杂操作。

  • 把excel表作为数据源进行sql操作
Sub Test()
Dim Conn As Object, Rst As Object
Dim strConn As String, strSQL As String
Dim i As Integer, PathStr As String
Set Conn = CreateObject("ADODB.Connection")
Set Rst = CreateObject("ADODB.Recordset")
PathStr = ThisWorkbook.FullName   '设置工作簿的完整路径和名称
Select Case Application.Version * 1  '设置连接字符串,根据版本创建连接
    Case Is <= 11
        strConn = "Provider=Microsoft.Jet.Oledb.4.0;ExtendedProperties=excel8.0;Datasource=" & PathStr
    Case Is >= 12
        strConn = "Provider=Microsoft.ACE.OLEDB.12.0;DataSource=" & PathStr & ";ExtendedProperties=""Excel12.0;HDR=YES"";"""
End Select  '设置SQL查询语句
strSQL = "请写入SQL语句"
Conn.Open strConn  '打开数据库链接
Set Rst = Conn.Execute(strSQL) '执行查询,并将结果输出到记录集对象
With Sheet3.Cells.Clear
    For i = 0 To Rst.Fields.Count - 1 '填写标题
        .Cells(1, i + 1) = Rst.Fields(i).Name
    Next i
    .Range("A2").CopyFromRecordset Rst
    .Cells.EntireColumn.AutoFit '自动调整列宽
End With
Rst.Close '关闭数据库连接
Conn.Close
Set Con = Nothing
End Sub
  • 对sql service数据库进行操作
'此类用于所有与sql数据库的主连接及相关的数据操作

Dim MainCnn As ADODB.Connection
Dim MainPath As String
Dim MyRs As ADODB.Recordset


Property Get MyCon() As ADODB.Connection
Set MyCon = MainCnn
End Property

Public Function GetConState() As Boolean

If MainCnn Is Nothing Then
    GetConState = False
ElseIf MainCnn.State = adStateClosed Then
    GetConState = False
Else
    GetConState = True
End If


End Function

Public Sub Ini(Path As String)
MainPath = Trim(Path)
End Sub

Public Function ConOpen()

Set MainCnn = New ADODB.Connection
Set MyRs = New ADODB.Recordset
ConOpen = True
On Error GoTo errDo:
With MainCnn
    .ConnectionString = "Provider=Microsoft.ACE.OLEDB.12.0; Data Source=" & MainPath & "; Jet OLEDB:Database Password=" & MaxPwdCell
'    .ConnectionString = "DBQ=" & ThisWorkbook.Path & "\归集表数据库.mdb;" & _
'                        "Driver={Microsoft Access Driver (*.mdb)};" & _
'                        "uid=admin;Password=seudit;"
'此处代码用于和access数据库连接

    'Debug.Print .ConnectionString
    .Open
End With
On Error GoTo 0

ConOpen = "Fine"

Exit Function

errDo:
'    Debug.Print MainPath
    ConOpen = "数据源尚未连接或有误,请配置正确的数据源地址。"

End Function


Public Function ConOpenByStr()

Set MainCnn = New ADODB.Connection
Set MyRs = New ADODB.Recordset
ConOpenByStr = True
On Error GoTo errDo:

With MainCnn
    .ConnectionString = MainPath
    .CommandTimeout = 180
    .ConnectionTimeout = 180
    .Open
    .CursorLocation = adUseClient
End With
On Error GoTo 0

ConOpenByStr = "Fine"

Exit Function

errDo:
    ConOpenByStr = "数据源尚未连接或有误,请配置正确的数据源地址。"

End Function

'传入Sql的select
Public Function GetRs(sql As String, Optional IsReadOnly As Boolean = True) As ADODB.Recordset

If IsReadOnly = True Then
    MyRs.Open sql, MainCnn, adOpenKeyset, adLockReadOnly
Else
    MyRs.Open sql, MainCnn, adOpenKeyset, adLockOptimistic
End If

Set GetRs = MyRs

End Function

Public Function CloseRs() As String
MyRs.Close
End Function

Public Function ConClose() As String
MainCnn.Close
End Function

'传入Sql的Delete
Public Function DelRs(sql As String) As String

MainCnn.Execute (sql)

End Function

'传入Sql的Insert
Public Function InsertRsBySql(sql As String) As String

MainCnn.Execute (sql)

End Function


'传入数据区域的的Insert,必须保证数据库表结构与导入区域结构一致
Public Function InsertRsByRange(UseRange As Range, InsertTName As String, NeedID As Boolean) As String
Dim sql As String
Dim RNum As Integer, CNum As Integer

RNum = UseRange.Rows.Count
CNum = UseRange.Columns.Count

For i = 1 To RNum
    If NeedID = True Then
        sql = "insert into " & InsertTName & " values(" & i & ",'"
    Else
        sql = "insert into " & InsertTName & " values('"
    End If
    For j = 1 To CNum
        sql = sql & Trim(UseRange.Cells(i, j)) & "','"
    Next j
    sql = Left(sql, Len(sql) - 2) & ")"
    Debug.Print sql
    MainCnn.Execute (sql)
Next i

End Function

操作网页

  • 实现网页操作自动化,网页信息自动抓取等
    除了下面这种所得即所见的网页操作方式,还有一种模拟发包收包的操作方式。
Sub 主程序()
Dim ie As InternetExplorer, id As String, i As Integer, r As Integer
Set ie = CreateObject("internetExplorer.application")   '创建一个空的ie
ie.Visible = True                               '让ie可见
ie.Navigate "http://xxxxxxxxx"
Do While ie.ReadyState <> 4 Or ie.Busy  '等待ie完毕加载
    DoEvents
Loop

r = Me.Cells(1, 1).CurrentRegion.Rows.Count
For i = 2 To r '滚动维护数据
    If Me.Cells(i, 2).Value = "是" Then
    Else
    id = Me.Cells(i, 1).Value
    zdtx2015 ie, id '维护主模块
    Me.Cells(i, 2).Value = "是"
    End If
Next

End Sub
Function zdtx2015(ie As InternetExplorer, id As String)
Dim ie2, i As Integer, ie3, ie4, ie5, ie7, ie6, ie8, ie9


Set ie2 = ie.Document.frames(0).Document.getElementById("EMPLMT_SRCH_COR_EMPLID")
Do Until Not ie2 Is Nothing
DoEvents
Set ie2 = ie.Document.frames(0).Document.getElementById("EMPLMT_SRCH_COR_EMPLID")
Loop
ie2.Value = id '输入员工ID"

Set ie4 = ie.Document.frames(0).Document.getElementsByTagName("INPUT")(33)
ie4.Click '点击搜索

Set ie5 = ie.Document.frames(0).Document.getElementsByTagName("INPUT")(26)
Do Until ie5.Value = "职位数据覆盖"
DoEvents
Set ie5 = ie.Document.frames(0).Document.getElementsByTagName("INPUT")(26)
Loop
ie5.Click '职务数据覆盖点一下\

Set ie8 = ie.Document.frames(0).Document.getElementById("#ICList")
ie8.Click '返回
'SendKeys "%1"
End Function

制作窗体实现交互

这里写图片描述
这里写图片描述

自动化实现复杂的数据处理操作

  • 对表格内数据进行决策树分析
Dim tree, itree, iColCount As Integer
'Set tree = CreateObject("scripting.dictionary") '创建树
'已1开始的数组中,节点i的n个子节点的下标为ni和ni+1;而其父节点的下标为int(i,n)

Sub 决策树()
Dim arr, arr0, dichx, tree, dic, loc As Long, brr, crr
arr = Me.Cells(1, 1).CurrentRegion '数据源
arr0 = Me.Cells(2, 1).Resize(UBound(arr, 1) - 1, UBound(arr, 2)) '训练元组
Set dichx = CreateObject("scripting.dictionary") '候选属性的集合
For i = 2 To UBound(arr, 2) - 1
    dichx(arr(1, i)) = i
Next
Set dic = CreateObject("scripting.dictionary") '有多少结果值
For i = 1 To UBound(arr0, 1)
    If dic.exists(arr0(i, UBound(arr0, 2))) Then
        dic(arr0(i, UBound(arr0, 2))) = dic(arr0(i, UBound(arr0, 2))) + 1
    Else
        dic(arr0(i, UBound(arr0, 2))) = 1
    End If
Next

Set tree = CreateObject("scripting.dictionary") '创建类树
Set itree = CreateObject("scripting.dictionary") '创建分叉树

loc = 1: iColCount = UBound(arr, 2) - 2 '属性量
generate_decision_tree arr0, dichx, loc, dic, tree, itree

crr = tree.keys
Me.Cells(1, 9).Resize(1, UBound(crr) + 1) = crr
crr = tree.items
Me.Cells(2, 9).Resize(1, UBound(crr) + 1) = crr
crr = itree.keys
Me.Cells(3, 9).Resize(1, UBound(crr) + 1) = crr
crr = itree.items
For i = 0 To UBound(crr)
    For j = 0 To UBound(crr(i))
        Me.Cells(4, 9).Offset(j, i) = crr(i)(j)
    Next
Next

If Not tree.exists(1) Then Exit Sub
tree_print tree, itree, 1, Me.Cells(9, 9), iColCount


End Sub
Function tree_print(tree, itree, x As Long, ByRef rg As Range, iColCount As Integer)
If tree.exists(x) Then
    If itree.exists(x) Then
    rg.Value = tree(x) & "#" & x
        If IsArray(itree(x)) Then
            arr = itree(x)
            rg.Offset(1, 0).Resize(1, UBound(arr, 1) + 1) = arr
            For i = 0 To UBound(arr, 1)
                rg.Offset(2, i) = tree(x * iColCount + i) & "#" & x * iColCount + i
            Next
            Set rg = rg.Offset(4, 0)

            For i = 0 To UBound(arr, 1)
                tree_print tree, itree, x * iColCount + i, rg, iColCount
            Next
        End If
    End If
End If


End Function


Function generate_decision_tree(arr0, dichx, loc, dic0, tree, itree) '建立决策树
Dim brr0(), split_list(), brr(1 To 20, 1 To 100, 1 To 10)
'Set generate_decision_tree = CreateObject("scripting.dictionary")

If dichx.Count = 0 Then Exit Function
ikey = attri_selection_method(arr0, dichx, dic0) '找到一个最好的划分元祖为个体的属性
iitem = dichx(ikey)
dichx.Remove ikey

tree(loc) = ikey

Set dic = CreateObject("scripting.dictionary") '创建一个包含所有该属性分类的字典
For i = 1 To UBound(arr0, 1)
If arr0(i, 1) = "" Then Exit For
    If dic.exists(arr0(i, iitem)) Then '维护组信息
        dic(arr0(i, iitem)) = dic(arr0(i, iitem)) + 1
        For j = 1 To dic.Count
            If arr0(i, iitem) = split_list(j - 1) Then
                For x = 1 To UBound(arr0, 2)
                    brr(j, dic(arr0(i, iitem)), x) = arr0(i, x)
                Next
            End If
        Next
    Else
        'ReDim Preserve split_list(1 To dic.Count + 1) '创建组类记录表
        'split_list(dic.Count + 1) = arr0(i, iitem) '保存组名称
        dic(arr0(i, iitem)) = 1 '记录组数量
        split_list = dic.keys
        'ReDim Preserve brr(1 To dic.Count, 1 To UBound(arr0, 1), 1 To UBound(arr0, 2)) '维护组信息
        For j = 1 To dic.Count
            If arr0(i, iitem) = split_list(j - 1) Then
                For x = 1 To UBound(arr0, 2)
                    brr(j, dic(arr0(i, iitem)), x) = arr0(i, x)
                Next
            End If
        Next
    End If
Next

iDicCount = dic.Count
For i = 1 To iDicCount
    ReDim brr0(1 To UBound(arr0, 1), 1 To UBound(arr0, 2)) '创建分组表
    Set dic = CreateObject("scripting.dictionary")
    For x = 1 To UBound(brr0, 1)
        If brr(i, x, 1) = "" Then
            Exit For
        Else
            For y = 1 To UBound(brr0, 2)
                brr0(x, y) = brr(i, x, y)
                If dic.exists(brr(i, x, UBound(brr0, 2))) Then
                    dic(brr(i, x, UBound(brr0, 2))) = dic(brr(i, x, UBound(brr0, 2))) + 1
                Else
                    dic(brr(i, x, UBound(brr0, 2))) = 1
                End If
            Next
        End If
    Next
    If dic.Count = 1 Then '如果这个分组都是一个ans
        itree(loc) = split_list
        tree(iColCount * loc + i - 1) = brr0(1, UBound(brr0, 2))
        'Set itree = tree
        'itree(split_list(i)) = dic.keys(0)
    Else
        'ReDim Preserve brr0(1 To x - 1, 1 To UBound(brr0, 2))
        'Set itree(split_list(i)) = CreateObject("scripting.dictionary")
        'Set iitree = itree(split_list(i))
        itree(loc) = split_list
        generate_decision_tree brr0, dichx, iColCount * loc + i - 1, dic, tree, itree
    End If
    Set dic = Nothing
Next

End Function



Function attri_selection_method(arr0, dichx, dic_ans) '最优信息度提升模型


Dim icomput
ReDim icomput(1 To dichx.Count)

endcol = UBound(arr0, 2)
arr_key = dichx.keys

ordcomput = 0 '获取初始信息度
For Each Item In dic_ans.items
    ordcomput = ordcomput - Item / UBound(arr0, 1) * Log(Item / UBound(arr0, 1)) / Log(2)
Next


k = 0
For Each Item In dichx.keys '对每个条件列
Set dic_comput = CreateObject("scripting.dictionary")
irow = dichx(Item)
    For j = 1 To UBound(arr0, 1) '获取每个子条件的结果分布
        If dic_comput.exists(arr0(j, irow)) Then
            If dic_comput(arr0(j, irow)).exists(arr0(j, endcol)) Then
                dic_comput(arr0(j, irow))(arr0(j, endcol)) = dic_comput(arr0(j, irow))(arr0(j, endcol)) + 1
            Else
                dic_comput(arr0(j, irow))(arr0(j, endcol)) = 1
            End If
        Else
            Set dic_comput(arr0(j, irow)) = CreateObject("scripting.dictionary")

        End If
    Next
    allans = 0
    For Each ikey In dic_comput.keys  '对每个子条件
        ans = 0
        totalans = 0
        For Each supikey In dic_comput(ikey).keys
            totalans = totalans + dic_comput(ikey)(supikey)
        Next
        For Each supikey In dic_comput(ikey).keys '求和子条件信息度
        Debug.Print totalans
        Debug.Print dic_comput(ikey)(supikey)
            ans = ans - dic_comput(ikey)(supikey) / totalans * Log(dic_comput(ikey)(supikey) / totalans) / Log(2)
        Next
        allans = allans + totalans / UBound(arr0, 1) * ans
    Next
    k = k + 1
    icomput(k) = allans '获取最终的信息度
Next

Min = 2
For i = 1 To UBound(icomput, 1)
    If icomput(i) < Min Then
        Min = icomput(i)
        attri_selection_method = arr_key(i - 1)
    End If
Next
End Function

其他

  • 调用excel自带的pivotable、数据透视表进行数据处理和操作
  • 调用微软的API接口进行系统控制和获取系统信息。
  • 结合系统定时任务功能,实现自动化定时报表
  • 开发小型作业系统平台
  • 开发档案管理、进销存、CRM,HRM等管理平台

学习VBA

谁需要学习VBA

  • 客观的来说,VBA是一个很老有点过时的语言了,即比不上C语言的系统效能,也比不上python这样面对对象高效编写,更不上JAVA这样有成熟蓬勃的社区支持。
  • VBA唯一的优点,在于对于微软系统、尤其是office软件的支持性和亲密性,简单的说他实现了office软件的定制化、自动化和无限强化。
  • 那么,适合使用VBA的人群就出来了:长期埋头与大量的EXCEL报表、图表、PPT报告、邮件处理的办公人群,如企划、财务、人事、库管、运营分析等
  • 适合使用VBA的企业和部门,报表处理和表格化作业密集的企业和部门,不具备覆盖全面的系统支持;中小型企业;部分咨询公司。
  • 对于以上的这些人,学习VBA可以极大的减轻工作压力、提升工作效率,给专业技能的发挥提供更多空间。

如何学习

  • 学习VBA,学习office本身的应用功能是基础。实际上,很多情况下最高效的VBA处理方式是在原有的office应用的功能上进行拓展,而不是重新开发一套功能。
    所以,如果你熟悉Excel公式、透视表、数组公式、图表、了解Excel\PPT\outlook等自带的系统功能如邮件合并等,那么在编写VBA过程中是事半功倍的。
  • 看书、上论坛、看视频,网上的资源很多,在我另一个帖子中有所介绍
    https://blog.csdn.net/qq_36080693/article/details/53349901

重要的知识点

  • 编辑Excel有效性、格式、图表等等
  • Ribbon界面设计和功能改造
  • 数据库ADO+SQL交互(还要学点SQL语法)
  • 窗体控件设计和制作
  • 字典dictionary和集合collection
  • 数组化处理思想
  • 正则表达式
  • webbrowser相关操作
  • 文件操作
  • 11
    点赞
  • 57
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
VBA是什么   直到90年代早期,使应用程序自动化还是充满挑战性的领域.对每个需要自动化的应用程序,人们不得不学习一种不同的自动化语言.例如:可以用EXCEL的宏语言来使EXCEL自动化,使用WORD BASIC使WORD自动化,等等.微软决定让它开发出来的应用程序共享一种通用的自动化语言--------Visual Basic For Application(VBA),可以认为VBA是非常流行的应用程序开发语言VASUAL BASIC 的子集.实际上VBA是"寄生于"VB应用程序的版本.VBA和VB的区别包括如下几个方面:   1. VB是设计用于创建标准的应用程序,而VBA是使已有的应用程序(EXCEL等)自动化   2. VB具有自己的开发环境,而VBA必须寄生于已有的应用程序.   3. 要运行VB开发的应用程序,用户不必安装VB,因为VB开发出的应用程序是可执行文件(*.EXE),而VBA开发的程序必须依赖于它的"父"应用程序,例如EXCEL.   尽管存在这些不同,VBA和VB在结构上仍然十分相似.事实上,如果你已经了解了VB,会发现学习VBA非常快.相应的,学完VBA会给学习VB打下坚实的基础.而且,当学会在EXCEL中用VBA创建解决方案后,即已具备在WORD ACCESS OUTLOOK FOXPRO PROWERPOINT 中用VBA创建解决方案的大部分知识.   * VBA一个关键特征是你所学的知识在微软的一些产品中可以相互转化.   * VBA可以称作EXCEL的"遥控器".   VBA究竟是什么?更确切地讲,它是一种自动化语言,它可以使常用的程序自动化,可以创建自定义的解决方案.    此外,如果你愿意,还可以将EXCEL用做开发平台实现应用程序. …… …… …… …… …… …… 欢迎使用 VBScript 语言参考 通过对信息进行分组,可以使您方便地研究 Visual Basic 脚本的各个主题。 可以在“字母顺序关键字列表”中找到 VBScript 语言的所有主题。如果只需要查看某个主题(例如对象),则有对该主题进行详细说明的章节可供查阅。 如何操作呢?单击左边任意一个标题,即可显示该标题所包含的项目列表。从该列表中选择要查看的主题。打开所选主题之后,就能够很容易地链接到其他相关章节。 好了,现在就开始行动,赶快进去看一看吧!学习几个语句,研究几种方法,或者熟悉几个函数。您会发现 VBScript 语言的功能是多么强大。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值