Excel 2010 VBA编程与实践
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

2.4 图片查找与引用

Excel 支持图文混排,在一个表中可以存放无数个图片。本节对工作表中图片的查找、引用,以及从磁盘中引用图片到工作簿、窗体等进行案例演示。在本书第8章将进行更全面的图形对象应用详解。

疑难50 如何瞬间删除当前表中所有图片

工作表中有图片、自选图形和图表、艺术字等,可以删除所有图片吗?

解决方案

遍历当前表所有图形对象,逐一判断其类型,如果是图片(即msoPicture)类型那么删除。

操作方法

步骤1 按【Alt+F11】组合键打开VBE窗口。

步骤2 选择菜单“插入”→“模块”,并输入以下代码:

Sub 删除图片()
  Dim sh As Shape  '声明图形对象变量
  For Each sh In ActiveSheet.Shapes  '遍历本表所有图形对象
    If sh.Type = msoPicture Then  '如果是图片
      sh.Delete  '删除
    End If
  Next sh
End Sub

步骤3 光标置于代码中任意位置,并按【F5】键执行,活动工作表中的所有图片可以瞬间删除。

原理分析

※ DrawingObjects与Shape对象的区别 ※

所有图片、形状、图表、文本框、艺术字等都属于DrawingObjects对象和Shape对象,通过 DrawingObjects.Delete 可以一次全部删除,通过 Shapes(Item).Delete 一次可以删除一个,配合循环则可以全部删除。本例中要求只删除图片,所以必须利用图形对象的 Type 属性将图片与其他图形对象区别开再进行删除。所以要判断图形对象的类别时不能通过DrawingObjects对象删除图形,而是要通过Shapes(Item).Delete。

知识扩展

图形对象的Type属性表示对象的类型,其不同类型的表示方法如表2-4表示。

█ 表2-4 Shape对象的Type属性列表

疑难51 可以将签名图片复制到表中所有签名处吗

工作表已手动分页,每页末在“制表签名:”处都需要签名。在表中有一个签名的图片,那么所有需要签名处都可以引用这张签名的图片吗?

解决方案

选择签名图片,然后查找所有包括“制表签名:”的单元格,将图片复制到该单元格处,并调整图片大小,使其刚好容纳至单元格。

操作方法

步骤1 按【Alt+F11】组合键打开VBE窗口。

步骤2 选择菜单“插入”→“模块”,并输入以下代码:

Sub 复制签名()
  Dim cell As Range, FirstAdd As String, ActiveShape As String
  '如果选择的对象不是图片则退出,否则复制当前对象
  If TypeName(Selection) <> "Picture" Then Exit Sub Else Selection.Copy
  ActiveShape = Selection.name
  '查找“制表签名:”
  Set cell = Cells.Find("制表签名:", lookat:=xlWhole)
  If Not cell Is Nothing Then '如果已找到
    FirstAdd = cell.Address '记录第一个找到的单元格的地址
    Do
      ActiveSheet.Paste  '粘贴图片
      With Selection '设置图片的位置,让图片比单元格稍小一点
        .Top = cell.Offset(0, 1).Top + 1
        .Left = cell.Offset(0, 1).Left + 1
        .Width = cell.Offset(0, 1).Width - 2
        .Height = cell.Offset(0, 1).Height - 2
      End With
      Set cell = Cells.FindNext(cell)  '查找下一个
    Loop Until cell.Address = FirstAdd  '直到找到的地址等于首个单元格地址
  End If
  ActiveSheet.Shapes(ActiveShape).Delete  '删除原有的图片
End Sub

步骤3 返回工作表界面,在表中插入一张用于签名的图片。选择该图片,选择功能区“开发工具”选项卡,单击“宏”按钮,执行过程“复制签名”,签名图片会瞬间排列在所有要签名的单元格中,而当前选择的签名图片将被删除。图2-57所示的H51单元格中的图片即为页末签名图片之一。

█ 图2-57 每页末产生签名图片

原理分析

※ 复制图形对象与复制数据的区别 ※

将图片复制到多个单元格,不能像复制数据那样找到所有单元格后再一次性粘贴,图片只能一次复制一份。将图片粘贴后,需要对其Top、Left、Width、Height四个属性进行设置,否则图片的位置会偏离目标单元格,以及大小与单元格不一致,影响美观。

知识扩展

※ Selection代表什么 ※

Selection 表示当前选择的对象,它可以是单元格对象,也可以是图形对象、图表系列对象、SmartArt对象、控件等。所以复制对象前有必要利用Typename函数判断Selection对象的类型。需要特别注意的是Typename区分大小写。

疑难52 如何像vlookup引用数据一样引用图片

工作中常用vlookup函数引用单价等数据,如果工作表中有数据和图片名称,那么图2-58所示的表格可以像公式一样根据名称引用图片吗?

解决方案

插入一个窗体,让用户设置存放图片名称的单元格,以及待引用的图片区域地址和图片在该区域中第几列等三个参数。然后根据设置添加一个包括图片引用的名称。最后将公式应用在图片的公式中,实现在图片中引用目标图片。而且图片可以随图片名称变化而变化。

█ 图2-58 待引用图片的工作表

操作方法

步骤1 按【Alt+F11】组合键打开VBE窗口。

步骤2 选择菜单“插入”→“用户窗体”,并从工具箱中将标签、文本框、命令按钮和微调按钮拖到窗体中,其中标签、文本框、命令按钮控件各三个,微调按钮控件一个,并将各自的Caption属性和位置布局按图2-59所示设置。

█ 图2-59 窗体控件布局

步骤3 双击窗体打开代码窗口,删除自动产生的代码,然后输入以下代码:

Private Sub UserForm_Activate() '窗体激活时将活动单元格地址赋予文本框
  TextBox1 = ActiveCell.Address
End Sub
Private Sub CommandButton1_Click() '指定图片存放地址
  Dim rng As Range
  On Error Resume Next
star:
  Set rng = Application.InputBox("请选择单元格:", "图片查询存放地址",Active
  Cell.Address, , , , , 8)
  If Err <> 0 Then GoTo star '如果存在错误,则返回Star标签重新指定
  TextBox1 = rng(1).Address '将指定的区域中左上角单元格赋予文本框
End Sub
Private Sub CommandButton2_Click() '指定图片引用区域,多行多列
  Dim rng As Range
  On Error Resume Next
star:
 '让用户选择,默认是AB列已用区域
  Set rng = Application.InputBox("请选择存放图片名称的区域:", "图片引用源
  ", Intersect([a:b], Union([a1], ActiveSheet.UsedRange)).Address(0,
  0), , , , , 8)
  If Err <> 0 Then GoTo star '如果存在错误,则返回Star标签重新指定
  TextBox2 = rng.Address '将指定区域赋予文本框
End Sub
Private Sub SpinButton1_Change() '修改微调按钮时执行
  TextBox3 = SpinButton1.Value '文本框显示微调按钮的值
End Sub
Private Sub CommandButton3_Click() '根据上面的设定数据添加名称
  On Error Resume Next
  '防错,避免数据填写有误时无法正确执行
 If Len(TextBox1) = 0 Or Len(TextBox2) = 0 Or Len(TextBox3) = 0 Then MsgBox
"请填写完整!": Exit Sub
  If Range(TextBox2)(1) = "" Then MsgBox "请选择图片名称区域,不能空白。
  ",64:Exit Sub
  If Me.TextBox3.Value < 0 Or Me.TextBox3.Value > Columns.Count -
  ActiveCell.Column Then MsgBox "图片所在列超出有效范围!": Exit Sub
  ActiveWorkbook.Names("照片").Delete   '删除原有名称"照片",如果有的话
  '添加名称,该名称根据TextBox1的值查找与它同名的图片所在单元格地址。
  ActiveWorkbook.Names.Add Name:="照片", RefersTo:="=OFFSET(" & Range
  (TextBox2)(1).Address & ",MATCH(" & TextBox1.Text & "," & Range
  (TextBox2).Resize(Range(TextBox2).Rows.Count, 1).Address & ",0)-1,"
  & Me.TextBox3.Value - 1 & ",1,)"
  With Range(TextBox1.Text).Validation
  '对TextBox1指定的单元格设置数据有效性
    .Delete '删除原有设置,添加新的引用,引用区域为TextBox2代表的区域中第一列
    .Add Type:=xlValidateList, AlertStyle:=xlValidAlertStop, Operator:
    =xlBetween, Formula1:="=" & Range(TextBox2).Resize(Range(TextBox2).
    Rows.Count, 1).Address
    .InCellDropdown = True
    .ShowInput = True
  End With
  Range(TextBox1.Text).Value = Range(TextBox2)(1).Value '指定默认值
  Unload Me '关闭窗口
End Sub

步骤4 选择菜单“插入”→“模块”,并在模块中输入以下代码:

Sub 引用图片()
 UserForm1.Show 0 '显示窗体
End Sub

步骤5 返回工作表界面,选择单元格D2,选择功能区“开发工具”选项卡,单击“宏”按钮,从弹出的对话框中选择“引用图片”并执行该SUB过程。

步骤6 窗口中第一个文本框的单元格地址保持不变,第二个文本框可以手工写入单元格地址,也可以单击“浏览”按钮来选择区域,本例选择 A2:A25;在图片所在列的文本框中输入数字2。

步骤7 单击“生成查询系统”按钮,窗体会自动关闭,同时在D2单元格产生下拉列表。

█ 图2-60 设定图片引用选项

步骤8 在工作表中任意插入一张图片,并在选择图片的同时在编辑栏输入公式“=照片”,此时图片将变成D2单元格所代表的图片。如果修改D2的姓名,E2的图片相应变化,如图2-61所示。

█ 图2-61 修改图片的公式为“=照片”

原理分析

公式可以任意引用单元格的数据,却无法引用悬浮在单元格上层的图片。不过将公式定义成名称,将名称用于图片的公式引用时却可以实现。在本例中窗体的功能是设置一个引用图片区域的名称,而插入的图片则通过该名称引用对应的图片。

知识扩展

※ 对图片设置公式引用其他图片 ※

在Excel 2003中可通过控件和图片实现引用图片,而Excel 2010只能使用插入的图片引用其他图片。所幸的是对图片添加公式引用图片在Excel 2003和2010都通用,所以在实际工作中尽量使用图片来引用其他图片。

疑难53 如何通过窗体预览指定目录中的所有图片

解决方案

在窗体中添加一个复合框和图片控件,复合框的下拉列表用于显示文件夹中所有图片名称,而修改复合框的显示值时,图像控件则通过LoadPicture函数引用文件夹下同名图片。

操作方法

步骤1 按【Alt+F11】组合键打开VBE窗口,选择菜单“插入”→“用户窗体”。按【F4】键打开“属性”窗口,在属性窗口中将窗体的“Caption”修改为“图片浏览器”。

步骤2 双击窗体进入代码窗口,将自动产生的代码删除,然后输入以下代码:

Dim n As Integer, arr(), PathStr As String
Private Sub UserForm_Activate()  '激活窗体时执行过程
  Dim str As String, fd
  On Error GoTo err    '程序出错时则退出
  Set fd = Application.FileDialog(msoFileDialogFolderPicker)
  With fd  '显示一个选择文件夹的对话框,如果选择了文件夹则取其名称,否则退出
    If .Show = -1 Then PathStr = .SelectedItems(1) Else Exit Sub
  End With
  str = Dir(PathStr & "\*.jpg")  '开始查找文件,格式为所有jpg文件
  While Len(str) > 0
    n = n + 1  '累加变量,该变量代表文件数量
    ReDim Preserve arr(1 To n)  '重置数组范围
    arr(n) = Split(LCase(str), ".jpg")(0)  '将文件的后缀名去掉,然后导入数组中
    str = Dir()  '查找下一个
  Wend
  If n > 0 Then Me.ComboBox1.List = arr:  Me.ComboBox1.Text = arr(1)
'将数组的值赋予复合框
err:
End Sub
Private Sub ComboBox1_Change()  '修改复合框时执行
'如果复合框非空白,那么图像控件中调用与复合框中字符串同名的图片
  If Len(ComboBox1.Text) > 0 Then Image1.Picture = LoadPicture(PathStr &
IIf(Right(PathStr, 1) = "\", "", "\") & ComboBox1.Text & ".jpg")
End Sub

步骤3 选择菜单“插入”→“模块”,并输入以下代码:

Sub 图片浏览()
UserForm1.Show 0
End Sub

步骤4 光标置于过程“图片浏览”中任意位置,并按【F5】键执行,将打开自定义窗体“图片浏览器”,同时弹出选择文件夹的对话框。在对话框中选择存放图片的文件夹“D:\图片”,当单击“确定”按钮返回窗体界面后,复合框和图像控件都默认调用文件夹中第一张图片。如果修改复合框,图像相应变化,如图2-62所示。

█ 图2-62 图像控件中浏览图片

原理分析

窗体中的图像控件通过LoadPicture函数可以调用指定路径的图片,所以通过FileDialog对话框让用户选择路径,而Dir函数可以逐个取出所有图片文件名,那么将两者组合即可成为图片的完整路径供LoadPicture函数调用,从而显示在窗体中。

知识扩展

※ 通过LoadPicture函数加载图片 ※

LoadPicture 函数的参数必须是包括盘符的完整路径,所以对工作表中的图片是无法调用的。如果要在窗体中显示工作表中的图片,通常将图片导入到硬盘再引用到窗体中。