存档在 ‘ExcelVBA程序’ 分类中.

在工作表中动态添加窗体控件

下面的内容及程序代码模仿自《Excel 2007 VBA Programmer’s Reference》,可能在某些情形下极其有用,因此特辑录于此,供参考。
如下图所示,双击工作表Sheet1的列A中的任一单元格,将出现一组合框,允许用户选择其中的项目。当用户选取某项目后,将自动输入到该单元格,并在该单元格右侧的单元格中输入相应的价格数字,组合框同时消失。
addcomboxdynamic1
下面是程序代码。在工作表Sheet1的代码模块中输入BeforeDoubleClick事件代码:
Private Sub Worksheet_BeforeDoubleClick(ByVal Target As Range, Cancel As Boolean)
     If Not Intersect(Target, Columns(”A”)) Is Nothing Then
         Call AddDropDown(Target)
         Cancel = True
    End If
End Sub

在任一模块中,输入下面的代码:
Sub AddDropDown(Target As Range)
    Dim ddBox As DropDown
    Dim vProducts As Variant
    Dim i As Integer
    ‘创建产品数组
    vProducts = Array(”香蕉”, “苹果”, “菠萝”, “葡萄”)
    ‘在目标单元格中添加下拉控件
    With Target
        Set ddBox = Sheet1.DropDowns.Add(.Left, .Top, .Width, .Height)
    End With
    ‘定义执行的宏并填充列表
    With ddBox
        .OnAction = “EnterProdInfo”
        For i = LBound(vProducts) To UBound(vProducts)
            .AddItem vProducts(i)
        Next i
    End With
End Sub

Private Sub EnterProdInfo()
    Dim vPrices As Variant
    ‘创建价格数组
    vPrices = Array(6, 8, 5, 4)
    ‘输入所选项到相应的单元格
    With Sheet1.DropDowns(Application.Caller)
        .TopLeftCell.Value = .List(.ListIndex)
        .TopLeftCell.Offset(0, 1).Value = vPrices(.ListIndex + LBound(vPrices) - 1)
        ‘删除
        .Delete
    End With
End Sub

如下图所示:
addcomboxdynamic2

从关闭的工作簿中取值

有许多种从关闭的工作簿中取值的方法,下面是其中之一。下面的VBA代码从关闭的工作簿中获取值。
Sub ExtractDataFromClosedWorkBook()
    
    Application.ScreenUpdating = False
    
     ‘创建链接来从关闭的工作簿中获取数据
     ‘可以将相关代码修改为相应的路径和单元格
    With [Sheet1!A1:B4]
        .Value = “=’” & ActiveWorkbook.Path & “\[testDataWorkbook.xls]Sheet1′!A1:B4″
        
         ‘删除链接
        .Value = .Value
    End With
    
    Application.ScreenUpdating = True
    
End Sub

其中,可以将代码中的路径修改为需要从中获取值的工作簿的路径,单元格也作相应的修改。

Increment File Names

在dicks的blog中看到了一段解决同名文件问题的程序解决方案,贴出来共享。
有时,必须存储一个名称与现有文件名相同的文件,此时可以在名称末尾添加数字使其唯一。但问题是该文件将放在三个不同的文件夹中:Working、Review和Archive,需要在这三个文件夹中检查相同的文件名称。
现在,创建一个函数来返回下一个可用的后缀,如果没有相同的文件存在,返回空字符串;如果有相同的文件存在,则返回能够添加到文件名后使其唯一的数字。
该函数遍历文件夹并使用Dir函数来获取相同的名称。为了使用Dir,将搜索的文件更改为包含有星号(*),例如名称为MyFile.xls的成为MyFile*.xls,并且将查找MyFile.xls、MyFile1.xls等等。如果找到匹配项,将分隔数字并记录下最终找到的最大的一个数字。如果没有数字,Replace语句返回一个空字符串并且Val函数将其转换为0。
Function GetUniqueSuffix(sName As String, vaFolders As Variant) As String
    Dim lSuffix As Long, lMax As Long
    Dim sDirName As String
    Dim sBaseName As String
    Dim i As Long
    Dim sTempName As String
    
    Const sEXTENSION As String = “.xls”
    
    sDirName = Replace(sName, sEXTENSION, “*” & sEXTENSION)
    sBaseName = Replace(sName, sEXTENSION, “”)
    
    For i = LBound(vaFolders) To UBound(vaFolders)
        sTempName = Dir(vaFolders(i) & sDirName)
        Do Until Len(sTempName) = 0
            lSuffix = Val(Replace(Replace(sTempName, sBaseName, “”), sEXTENSION, “”)) + 1
            If lSuffix > lMax Then
                lMax = lSuffix
            End If
            sTempName = Dir
        Loop
    Next i
    
    If lMax > 0 Then
        GetUniqueSuffix = CStr(lMax)
    Else
        GetUniqueSuffix = “”
    End If
    
End Function

使用示例:
Sub UniqueSuffixExample()
    
    Dim vaFolders As Variant
    Dim sFile As String
    Dim lUnique As Long
    
    vaFolders = Array(”C:\Working\”, “C:\Review\”, “C:\Archive\”)
    sFile = “MyFile.xls”
    
    lUnique = GetUniqueSuffix(sFile, vaFolders)
    sFile = Replace(sFile, “.xls”, lUnique & “.xls”)
    
    ActiveWorkbook.SaveAs “C:\Working\” & sFile
    
End Sub

Excel应用程序开发心得(一)

近期正在利用Excel开发一套工作管理系统,已初步有了结果,并开始使用。前不久,在一篇博客文章中,我贴出了该系统的主界面。在这里,随便谈谈在开发过程中的一些心得体会,供大家参考。

  • 不要将所有任务全部集中在一个工作簿中

在同一工作簿中不要试图处理所有需要实现的任务。当然,如果您的系统只需实现少有的几项功能,在一个工作簿中集中实现这几项功能是简单方便的。但是,如果需要实现多项任务,特别是需要处理大量数据的情形下,建议将任务进行整合分类,分别放在不同的工作簿中来实现这些任务。
此时,需要规划好各工作簿要实现的功能任务,合理设计各个工作簿之间的关系,理顺各工作簿之间的数据调用,并且使用一个主工作簿来调用各个工作簿,这样使得系统非常灵活、精简,也不致于因使用而致使工作簿体积快速不断增大。
要注意的是,对于存在数据调用的工作簿,一定要清楚调用的顺序,避免因为某一工作簿数据的更换而影响其他相关工作簿数据的准确性。例如,工作簿B需要调用工作簿A中的数据,如果工作簿A中的数据发生变化,那么要及时更新工作簿B中的数据。

  • 利用工作簿的自定义属性来确定工作簿

为工作簿添加自定义文档属性(即CustomDocumentProperties
属性),从而利用该属性来查找工作簿,或者判断是否为要查找的工作簿,或者能够合并同类工作簿。特别是在有大量名称会发生变化的工作簿时。
单击菜单“文件”─—“属性”,选择“自定义”选项卡,在“名称”中输入相应的名称,在“取值”中输入“Yes”,然后单击“添加”按钮加入属性,如下图所示。
AddWorkbookProperty1
这样,在多个工作簿相互调用时,可以避免因工作簿名称改变而出现的无法找到工作簿的错误。

  • 避免无谓的循环

记得及早、适时地退出循环,特别是在存在大量数据而不得不逐一进行循环时。例如,下面的代码,必须在工作表中的第3行至第31行、第2列至第32列依次循环,当满足特定条件后,使用Exit Sub语句退出,从而避免继续循环。如果在更大范围内循环时更应如此。
        For i = 3 To 31
            ‘循环每一列
            For j = 2 To 32
                If Target.Value = “” Then
                    If iTotalRow > 1 Then
                        For k = 2 To iTotalRow
                            If Target.Row = Worksheets(”Data”).Range(”A” & k) And Target.Column = Worksheets(”Data”).Range(”B” & k) Then
                                Worksheets(”Data”).Rows(k).EntireRow.Delete
                                bDecide = True
                                Exit Sub
                            End If
                        Next k
                    End If
                End If
            Next j
        Next i

  • 记得清除垃圾

有时,需要在工作表中反复汇总或操作来自另一工作表或工作簿中的数据。记住,在将其他地方的数据复制到工作表中之前,记得清除以前的数据,避免产生重复数据或带来错误。

  • 积累通用代码,方便调用,提高开发效率

在我们编写程序的过程中,总有些代码适合于不同的程序开发。我们可以将这些程序代码做成通用程序,当需要时直接调用,从而节省时间,便于组织,提高了开发效率。这里,举几个例子。
(1)判断某文件是否存在
‘判断文件是否存在
Private Function FileExists(fname) As Boolean
    ‘如果存在则返回True
    FileExists = (Dir(fname) <> “”)
End Function

(2)判断工作表是否存在
‘判断工作表是否存在
Private Function SheetExists(sName) As Boolean
    ‘如果当前工作簿中存在该工作表则返回True
    Dim x As Object
    On Error Resume Next
    Set x = ActiveWorkbook.Sheets(sName)
    If Err = 0 Then
        SheetExists = True
    Else
        SheetExists = False
    End If
End Function

(3)返回满足查找条件的所有单元格组成的区域
‘通用的查找函数
Function FindAll(SearchRange As Range, FindWhat As Variant, _
    Optional LookIn As XlFindLookIn = xlValues, Optional LookAt As XlLookAt = xlWhole, _
    Optional SearchOrder As XlSearchOrder = xlByRows, _
    Optional MatchCase As Boolean = False) As Range
”””””””””””””””””””””””””””””””””””””””””””””
‘ 返回SearchRange区域中含有FindWhat所代表的值的所有单元格组成的Range对象
‘ 其参数与Find方法的参数相同
‘ 如果没有找到单元格,将返回Nothing.
”””””””””””””””””””””””””””””””””””””””””””””
  Dim FoundCell As Range
  Dim FoundCells As Range
  Dim LastCell As Range
  Dim FirstAddr As String
  With SearchRange
    Set LastCell = .Cells(.Cells.Count)
  End With
  Set FoundCell = SearchRange.Find(what:=FindWhat, after:=LastCell, _
    LookIn:=LookIn, LookAt:=LookAt, SearchOrder:=SearchOrder, MatchCase:=MatchCase)
  If Not FoundCell Is Nothing Then
    Set FoundCells = FoundCell
    FirstAddr = FoundCell.Address
    Do
      Set FoundCells = Application.Union(FoundCells, FoundCell)
      Set FoundCell = SearchRange.FindNext(after:=FoundCell)
    Loop Until (FoundCell Is Nothing) Or (FoundCell.Address = FirstAddr)
  End If
  If FoundCells Is Nothing Then
    Set FindAll = Nothing
  Else
    Set FindAll = FoundCells
  End If
End Function

大家在平时可以积累这些程序,既方便学习,又可以重用。

从Excel中建立PowerPoint演示文档

Technorati 标签: ,,

在《Excel & Access Integration:With Office 2007》的最后一章中,介绍了Microsoft Excel与Word、PowerPoint和Outlook整合的基本技术。其中,介绍Excel和PowerPoint整合技术时,演示了如何在Excel工作簿中创建演示文档,然后使用自动化将其转换为PowerPoint演示文档,如题。

我觉得这是一项非常有用的技术,充分发挥了两种应用程序各自的优点。在Excel工作簿中,每张工作表代表演示文档中的一张幻灯片,在工作表中能够充分利用Excel的数据分析和处理功能生成生动且有意义的图表或表格。然后,将这些工作表转换为PowerPoint幻灯片,从而利用PowerPoint的演示功能。

下面的示例沿用《Excel & Access Integration:With Office 2007》中的示例文档WorkbookToPowerPoint.xlsm,以演示这项技术。在该工作簿中,包含有四张工作表,分别包含四个区域(Asia、South America、United Kingdom、United States)的收入数据以及相应的图表分析(如下图所示)。

WorkbookSheetsList

当然,这些工作表都是设计好了的,与PowerPoint中的幻灯片形式相同,每一张工作表代表一张幻灯片,分别演示一个区域的收入数据及分析情况。下面,我们将这些工作表转换为相应PowerPoint演示文档中的幻灯片。

首先,需要添加对Microsoft PowerPoint ╳╳ Object Library的引用(其中╳╳代表该对象库的版本号),如下图所示。

AddPPTRef

然后,在标准模块中输入下面的代码:

   1: Sub WorkbooktoPowerPoint()
   2:     
   3:     ‘声明变量
   4:     Dim pp As PowerPoint.Application
   5:     Dim PPPres As PowerPoint.Presentation
   6:     Dim PPSlide As PowerPoint.Slide
   7:     Dim xlwksht As Excel.Worksheet
   8:     Dim MyRange As String
   9:     Dim MyTitle As String
  10:     Dim SlideCount As Integer
  11:     
  12:     ‘开启PowerPoint,添加新的演示文档并使其可见
  13:     Set pp = New PowerPoint.Application
  14:     Set PPPres = pp.Presentations.Add
  15:     pp.Visible = True
  16:         
  17:     ‘设置数据和标题的单元格区域
  18:     MyRange = “A1:I27″
  19:     
  20:     ‘开始循环每张工作表
  21:     For Each xlwksht In ActiveWorkbook.Worksheets
  22:         ‘设置每张幻灯片的标题
  23:         MyTitle = xlwksht.Range(“C19″).Value
  24:  
  25:         ‘复制单元格区域为图片
  26:         xlwksht.Range(MyRange).CopyPicture _
  27:         Appearance:=xlScreen, Format:=xlPicture
  28:     
  29:         ‘统计幻灯片并添加新幻灯片作为下一个可用的幻灯片号
  30:         SlideCount = PPPres.Slides.Count
  31:         Set PPSlide = PPPres.Slides.Add(SlideCount + 1, ppLayoutTitleOnly)
  32:         PPSlide.Select
  33:          
  34:         ‘粘贴图片并调整其位置
  35:         PPSlide.Shapes.Paste.Select
  36:         pp.ActiveWindow.Selection.ShapeRange.Align msoAlignCenters, True
  37:         pp.ActiveWindow.Selection.ShapeRange.Top = 100
  38:         
  39:         ‘为该幻灯片添加标题并移到下一张工作表
  40:         PPSlide.Shapes.Title.TextFrame.TextRange.Text = MyTitle
  41:     Next xlwksht
  42:             
  43:     ‘激活PPT演示文档
  44:     pp.Activate
  45:     
  46:     ‘释放内存
  47:     Set PPSlide = Nothing
  48:     Set PPPres = Nothing
  49:     Set pp = Nothing
  50:             
  51: End Sub

第4行至第10行声明了7个变量。其中变量pp代表PowerPoint应用程序对象,变量PPPres代表PowerPoint的演示文档(Presentation)对象,变量PPSlide代表PowerPoint幻灯片(Slide)对象,变量xlwksht代表Worksheet对象,变量MyRange是一个字符串变量用来存储和传递单元格区域,变量MyTitle是一个字符串变量用来存储代表幻灯片标题的字符串,变量SlideCount是用于计数的整型变量。

第13行创建一个PowerPoint对象的新实例,第14行添加新的演示文档,第15行设置Visible属性为True,使PowerPoint可见。

第18行将希望作为幻灯片内容的区域赋值给变量MyRange。

第21行开始遍历工作簿中的每张工作表。

第23行将工作表中单元格C19中的内容赋值给变量MyTitle,作为每张幻灯片的标题。

第26行和第27行使用CopyPicture方法将指定的单元格区域作为图片。

第31行使用Slide对象的Add方法在演示文档中添加新幻灯片,其中变量SlideCount+1指定添加的幻灯片的索引号,并使用ppLayoutTitleOnly参数确保所创建的幻灯片带有标题文本框。

第35行至第37行粘贴图片到当前幻灯片中,并使图片水平居中且与顶部垂直距离为100像素。

第40行为该幻灯片添加标题。

第47至第49行释放对象变量所占用的内存。

运行WorkbooktoPowerPoint过程后,结果如下图所示:

WorkbookSheetsToPPTResult

标签: 没有标签