6.1 在奔跑之前先学会走路:打开和关闭工作薄

代码清单6.1:一个完整的工作薄批处理框架 

'代码清单6.1:一个完整的工作薄批处理框架 
Sub ProcessFileBatch() 
    Dim nIndex As Integer 
    Dim vFiles As Variant 
    Dim wb As Workbook 
    Dim bAlreadyOpen As Boolean 
     
    On Error GoTo ErrHandler 
     
    'Get a batch of Excel files 
    vFiles = GetExcelFiles("Select Workbooks for Processing" ) 
     
    'Make sure the dialog wasn't cancelled - in which case 
    'vFiles would equal False and therefore wouldn't be an array. 
    If Not IsArray(vFiles) Then 
        Debug.Print "No files Selected." 
        Exit Sub 
    End If 
     
    Application.ScreenUpdating = False 
     
    'OK - loop through the filenames 
    For nIndex = 1 To UBound (vFiles) 
     
        If isWorkbookOpen(CStr(vFiles(nIndex))) Then 
            Set wb = Workbooks(GetShortName(CStr (vFiles(nIndex)))) 
            Debug.Print "workbook already open: " & wb.Name 
            bAlreadyOpen = True 
             
        Else 
            Set wb = Workbooks.Open(CStr(vFiles(nIndex)), False ) 
            Debug.Print "Opened workbook: " & wb.Name 
            bAlreadyOpen = False 
             
        End If 
         
        Application.StatusBar = "processing workbook: " & wb.Name 
         
        'code to process the file goes here 
        Debug.Print "if we wanted to do something to the workbook, we would do it here" 
         
        'close workbook unless it was already open 
        If Not bAlreadyOpen Then 
            Debug.Print "closing workbook: " & wb.Name 
            wb.Close True 
        End If 
    Next nIndex 
     
    Set wb = Nothing 
ErrHandler: 
    Application.StatusBar = False 
    Application.ScreenUpdating = True 
     
End Sub 

 

6.2 工作薄打开了吗

代码清单6.2:查看一个工作薄是否是打开的 

'代码清单6.2: 查看一个工作薄是否是打开的 
' This function checks to see if a given workbook 
' is open or not. this function can be used 
' using a short name such as MyWorkbook.xls 
' or a full name such as C: \Testing\MyWorkbook.xls 
Function isWorkbookOpen(sWorkbook As String) As Boolean 
    Dim sName As String 
    Dim sPath As String 
    Dim sFullName As String 
     
    On Error Resume Next 
    isWorkbookOpen = True 
     
    'see if we were given a short name or a long name 
    If InStr(1, sWorkbook, "\", vbTextCompare) > 0 Then 
        'we have a long name need to break it down 
        sFullName = sWorkbook 

        'BreakdownName参见代码清单5.8 
        BreakdownName sFullName, sName, sPath 
        If StrComp(Workbooks(sName).FullName, sWorkbook, vbTextCompare) <> 0 Then 
            isWorkbookOpen = False 
        End If 
    Else 
        'we have a short name 
        If StrComp(Workbooks(sWorkbook).Name, sWorkbook, vbTextCompare) <> 0 Then 
            isWorkbookOpen = False 
        End If 
    End If 
     
End Function 

 

另一个IsWorkbookOpen:

Function IsWorkbookOpen(sWorkbookName AsString) As Boolean 
    Dim wb As Workbook 
    
    IsWorkbookOpen = False 
    For Each wb In Workbooks 
        If StrComp(sWorkbookName, wb.Name, vbTextCompare) = 0 Then 
            IsWorkbookOpen = True 
            Exit Function 
        End If 
    Next 
    Set wb =Nothing 
End Function 

 三个VBA字符串函数:

InStr([start, ]string1, string2[, compare]): 指出string2在string1中第一次出现的位置。

InStrRev(string1, string2[, compare]): 指出string2在string1中最后一次出现的位置。

StrComp(string1, string2[, compare]): 比较两个字符串,返回-1、0、1中的值。

说明:

VBA中,字符串的索引是基于0的。

compare可以取值vbTextCompare或者vbBinaryCompare,前者表示不区分大小写,后者表示区分大小写。compare的默认值为vbUseCompareOption,就是取模块选项的设置。

6.2.1 指定特定的集合对象

下面的例子示范了可以指向集合中的一个项目的4种方法。这个例子使用Worksheets集合对象。

Sub ReferringToItems() 
    'refer to a worksheet by index number 
    Debug.Print ThisWorkbook.Worksheets(1 ).Name 
    'once again, but with feeling 
    Debug.Print ThisWorkbook.Worksheets.Item(1 ).Name 
     
    'refer to a worksheet by name 
    Debug.Print ThisWorkbook.Worksheets("Sheet1" ).Name 
    'and gain using item ... 
    Debug.Print ThisWorkbook.Worksheets.Item("Sheet1" ).Name 
     
End Sub

 

6.3以编程方式解开链接(第1部分)

代码清单6.3:以程序设计方式得到链接资源信息

'代码清单6.3:以程序设计方式得到链接资源信息 
Sub PrintSimpleLinkInfo(wb As Workbook) 
    Dim avLinks As Variant 
    Dim nIndex As Integer 
     
    'get list of excel based link sources 
    avLinks = wb.LinkSources(xlExcelLinks) 
    If Not IsEmpty(avLinks) Then 
        'loop through every link source 
        For nIndex = 1 To UBound (avLinks) 
            Debug.Print "link found to '" & avLinks(nIndex) & "'" 
        Next nIndex 
    Else 
        Debug.Print "the workbook '" & wb.Name & "' don't have any links." 
    End If 
     
End Sub

 

代码清单6.4:用新的文件位置更新链接

'代码清单6.4: 用新的文件位置更新链接 
Sub fixLinks(wb As Workbook, sOldLink As String, sNewLink As String ) 
    On Error Resume Next 
    wb.ChangeLink sOldLink, sNewLink, xlLinkTypeExcelLinks 
     
End Sub

 

代码清单6.5:用新的文件位置更新链接(一个替代过程)

'代码清单6.5: 用新的文件位置更新链接—一个替代过程 
Sub FixLinksII(wb As Workbook, sOldLink As String, sNewLink As String ) 
    Dim avLinks As Variant 
    Dim nIndex As Integer 
     
    'get a list of link sources 
    avLinks = wb.LinkSources(xlExcelLinks) 
     
    'if there are link sources, see if there are any named sOldLink     
    If Not IsEmpty(avLinks) Then 
        For nIndex = 1 To UBound (avLinks) 
            If StrComp(avLinks(nIndex), sOldLink, vbTextCompare) = 0 Then 
                'we have a match 
                 wb.ChangeLink sOldLink, sNewLink, xlLinkTypeExcelLinks 
                'once we find a match we won't find another, so exit the loop 
                Exit For 
            End If 
        Next 
    End If 

End Sub

 

代码清单6.6:链接状态查看器

'代码清单6.6: 链接状态查看器 
Function GetLinkStatus(wb As Workbook, sLink As String) As String 
    Dim avLinks As Variant 
    Dim nIndex As Integer 
    Dim sResult As String 
    Dim nStatus As Integer 
 
    'get a list of link sources 
    avLinks = wb.LinkSources(xlExcelLinks) 
     
    'make sure there are links in the workbook 
    If IsEmpty(avLinks) Then 
        GetLinkStatus = "No links in workbook." 
        Exit Function 
    End If 
     
    'default result in case the links is not found 
    sResult = "link not found" 
     
    For nIndex = 1 To UBound (avLinks) 
        If StrComp(avLinks(nIndex), sLink, vbTextCompare) = 0 Then 
            nStatus = wb.LinkInfo(sLink, xlLinkInfoStatus) 
             
            Select Case nStatus 
                Case xlLinkStatusCopiedValues 
                    sResult = "Copied values" 
                     
                Case xlLinkStatusIndeterminate 
                    sResult = "Indeterminnate" 
                     
                Case xlLinkStatusInvalidName 
                    sResult = "Invalid name" 
                     
                Case xlLinkStatusMissingFile 
                    sResult = "Missing file" 
                     
                Case xlLinkStatusMissingSheet 
                    sResult = "Missing sheet" 
                     
                Case xlLinkStatusNotStarted 
                    sResult = "Not started" 
                     
                Case xlLinkStatusOK 
                    sResult = "OK" 
                     
                Case xlLinkStatusOld 
                    sResult = "Old" 
                     
                Case xlLinkStatusSourceNotCalculated 
                    sResult = "Source Not Calculated" 
                     
                Case xlLinkStatusSourceNotOpen 
                    sResult = "Source Not Open" 
                     
                Case xlLinkStatusSourceOpen 
                    sResult = "Source Open" 
                     
                Case Else 
                    sResult = "Unknown status code" 
            End Select 
        End If 
    Next 
 
End Function

 

代码清单6.7:查看一个工作薄中所有的链接状态

'代码清单6.7: 查看一个工作薄中所有的链接状态 
Sub CheckAllLinks(wb As Workbook) 
    Dim avLinks As Variant 
    Dim nLinkIndex As Integer 
    Dim sMsg As String 
     
    avLinks = wb.LinkSources(xlExcelLinks) 
     
    If IsEmpty(avLinks) Then     
        Debug.Print wb.Name & " does not have any links." 
    Else 
        For nLinkIndex = 1 To UBound (avLinks) 
            Debug.Print "workbook: " & wb.Name 
            Debug.Print "link source: " & avLinks(nLinkIndex) 
            Debug.Print "status: " & GetLinkStatus(wb, CStr (avLinks(nLinkIndex))) 
        Next 
    End If 
      
End Sub

 

6.4 简单普通的工作薄属性

代码清单6.8:一个标准工作薄属性的简单例子

'代码清单6.8: 一个标准工作薄属性的简单例子 
Sub TestPrintGeneralWBInfo() 
    PrintGeneralWorkbookInfo ThisWorkbook
End Sub

Sub PrintGeneralWorkbookInfo(wb As Workbook) 
    Debug.Print "Name: " & wb.Name 
    Debug.Print "Full Name: " & wb.FullName 
    Debug.Print "Code Name: " & wb.CodeName 
    Debug.Print "File Format: " & GetFileFormat(wb) 
    Debug.Print "path: " & wb.Path 
     
    If wb.ReadOnly Then 
        Debug.Print " the workbook has been opened as read-only." 
    Else 
        Debug.Print " the workbook is read-write." 
    End If 
     
    If wb.Saved Then 
        Debug.Print "the workbook does not need to be saved." 
    Else 
        Debug.Print " the workbook should be saved." 
    End If 
End Sub 

Function GetFileFormat(wb As Workbook) As String 
    Dim lFormat As Long 
    Dim sFormat As String 
    lFormat = wb.FileFormat 
    Select Case lFormat 
        Case xlAddIn:   sFormat = "Add-In" 
         
        Case xlCSV:         sFormat = "CSV" 
        Case xlCSVMac:      sFormat = "CSV Mac" 
        Case xlCSVMSDOS:    sFormat = "CSV MSDOS" 
        Case xlCSVWindows:  sFormat = "CSV Windows" 
         
        Case xlCurrentPlatformText:  sFormat = "Current Platform Text" 
         
        Case xlDBF2:      sFormat = "DBF 2" 
        Case xlDBF3:      sFormat = "DBF 3" 
        Case xlDBF4:      sFormat = "DBF 4" 
         
        Case xlDIF:             sFormat = "xlDIF" 
        Case xlExcel2:          sFormat = "xlExcel2" 
        Case xlExcel2FarEast:   sFormat = "xlExcel2FarEast" 
        Case xlExcel3:          sFormat = "xlExcel3" 
        Case xlExcel4:          sFormat = "xlExcel4" 
        Case xlExcel4Workbook:  sFormat = "xlExcel4Workbook" 
        Case xlExcel5:          sFormat = "xlExcel5" 
        Case xlExcel7:          sFormat = "xlExcel7" 
        Case xlExcel9795:       sFormat = "xlExcel9795" 
         
        Case xlHtml:        sFormat = "xlHtml" 
        Case xlIntlAddIn:   sFormat = "xlIntlAddIn" 
        Case xlSYLK:        sFormat = "xlSYLK" 
        Case xlTemplate:    sFormat = "xlTemplate" 
        Case xlTextMac:     sFormat = "xlTextMac" 
        Case xlTextMSDOS:   sFormat = "xlTextMSDOS" 
        Case xlTextPrinter: sFormat = "xlTextPrinter" 
        Case xlTextWindows: sFormat = "xlTextWindows" 
        Case xlUnicodeText: sFormat = "xlUnicodeText" 
        Case xlWebArchive:  sFormat = "xlWebArchive" 
        Case xlWJ2WD1:      sFormat = "xlWJ2WD1" 
        Case xlWJ3:         sFormat = "xlWJ3" 
        Case xlWJ3FJ3:      sFormat = "xlWJ3FJ3" 
         
        Case xlWK1:              sFormat = "xlWK1" 
        Case xlWK1ALL:           sFormat = "xlWK1ALL" 
        Case xlWK1FMT:           sFormat = "xlWK1FMT" 
        Case xlWK3:              sFormat = "xlWK3" 
        Case xlWK3FM3:           sFormat = "xlWK3FM3" 
        Case xlWK4:              sFormat = "xlWK4" 
        Case xlWKS:              sFormat = "xlWKS" 
        Case xlWorkbookNormal:   sFormat = "xlWorkbookNormal" 
        Case xlWorks2FarEast:    sFormat = "xlWorks2FarEast" 
        Case xlWQ1:              sFormat = "xlWQ1" 
        Case xlXMLSpreadsheet:   sFormat = "xlXMLSpreadsheet" 
         
        Case Else 
            sFormat = "Unknown format code" 
    End Select 
    GetFileFormat = sFormat 
End Function

 

6.5 响应用户动作事件

代码清单6.9:测试Workbook对象事件 

Private Sub Workbook_Activate() 
    If UseEvents Then 
        MsgBox "Welcome back! ", vbOKOnly, "Activate Event" 
    End If
End Sub 

Private Sub Workbook_BeforeClose(Cancel As Boolean ) 
    Dim lResponse As Long 
     
    If UseEvents Then 
        lResponse = MsgBox("Thanks for visiting!" & "Are you sure you don't want to stick around?", vbYesNo, "see ya.." ) 
    End If     
End Sub 

Private Sub Workbook_Deactivate() 
    If UseEvents Then 
        MsgBox "see you soon...", vbOKOnly, "Deactivate Event" 
    End If
End Sub 

Private Sub Workbook_Open() 
    Dim lResponse As Long 
    lResponse = MsgBox("Welcome to the Chapter Six Example Workbook! Would you like to use events?", vbYesNo, "Welcome" ) 
     
    If lResponse = vbYes Then 
        TurnOnEvents True 
    ElseIf lResponse = vbNo Then 
        TurnOnEvents False
    End If
End Sub

Private Sub TurnOnEvents(bUseEvents As Boolean) 
    On Error Resume Next 
    If bUseEvents Then 
        ThisWorkbook.Worksheets(1).Range("TestEvents").Value = "Yes" 
    Else 
        ThisWorkbook.Worksheets(1).Range("TestEvents").Value = "No"     
    End If
End Sub

Private Function UseEvents() As Boolean 
    On Error Resume Next 
     
    UseEvents = False 
    If UCase(ThisWorkbook.Worksheets(1).Range("TestEvents").Value) = "YES" Then 
        UseEvents = True 
    End If
End Function

Private Sub Workbook_SheetActivate(ByVal Sh As Object) 
    If UseEvents Then 
        MsgBox "Activated " & Sh.Name, vbOKOnly, "SheetActivate Event" 
    End If     
End Sub

Private Sub Workbook_SheetBeforeDoubleClick(ByVal Sh As Object, ByVal Target As Range, Cancel As Boolean ) 
    If UseEvents Then 
        MsgBox "Ouch! Stop that.", vbOKOnly, "SheetBeforeDoubleClick Event" 
    End If     
End Sub

Private Sub Workbook_SheetBeforeRightClick(ByVal Sh As Object, ByVal Target As Range, Cancel As Boolean ) 
    If UseEvents Then 
        MsgBox "Right click " & Sh.Name & "; Target " & Target.Address & "; Cancel " & Cancel, vbOKOnly, "RightClick Event" 
    End If     
End Sub

Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range) 
    If UseEvents Then 
        MsgBox "You change the range" & Target.Address & " on " & Sh.Name, vbOKOnly, "Workbook_SheetChange Event" 
    End If     
End Sub

Private Sub Workbook_SheetDeactivate(ByVal Sh As Object ) 
    If UseEvents Then 
        MsgBox "Leaving " & Sh.Name, vbOKOnly, "Workbook_SheetDeactivate Event" 
    End If     
End Sub 

Private Sub Workbook_SheetSelectionChange(ByVal Sh As Object, ByVal Target As Range) 
    If UseEvents Then     
        If Target.Row Mod 2 = 0 Then 
            MsgBox "I'm keeping my eyes on you! you selected the range " & Target.Address & " on " & Sh.Name, _ 
            vbOKOnly, "Workbook_SheetSelectionChange Event" 
        Else 
            MsgBox "you selected the range " & Target.Address & " on " & Sh.Name, _ 
            vbOKOnly, "Workbook_SheetSelectionChange Event"         
        End If      
    End If  
End Sub