ExcelVBAで図形内テキストを検索するアドイン自作
Excelの図形内のテキストを検索するアドインを自作したので、ここに残しておく。
◆簡単な動作確認
◆WorkBookモジュール
ここでショートカットキーを登録する
1Option Explicit
2
3' ブックオープン時(アドイン読み込み時)にショートカットキー設定
4Private Sub Workbook_Open()
5 Application.OnKey "^+f", "showForm" ' [Ctrl]+[Shift]+[f]
6End Sub
7
8' ブッククローズ時にショートカットキー設定解除
9Private Sub Workbook_BeforeClose(Cancel As Boolean)
10 Application.OnKey "^+f" ' [Ctrl]+[Shift]+[f]
11End Sub
◆Formモジュール
キャンセルボタンのCancelプロパティをTrueにすることで、Escキーを押した時にフォームを閉じることができる。
(Escキーを押した時にキャンセルボタンが押された動きになる)
1Option Explicit
2
3' 次を検索
4Private Sub CommandButton1_Click()
5 Call searchShapeText(TextBox1.Value, ComboBox1.ListIndex)
6End Sub
7
8' キャンセル
9Private Sub CommandButton2_Click()
10 Unload UserForm1
11End Sub
◆標準モジュール
コメントやグラフなど未対応箇所あるが、必要に迫られていないので、追々対応する。
1'参考サイト
2'https://qiita.com/ctrlzr/items/e8c0ffab8fe029b25fb7
3
4Option Explicit
5
6Public oldWd As String ' 前回キーワード
7Public oldPl As Integer ' 前回検索場所
8Public spIdx As Integer ' 図形インデックス
9Public gFlg As Integer ' 発見フラグ
10
11Public Sub showForm()
12 With UserForm1
13 .Show vbModeless
14 .ComboBox1.AddItem "シート"
15 .ComboBox1.AddItem "ブック"
16 .TextBox1.Value = oldWd
17 .ComboBox1.ListIndex = oldPl
18 End With
19End Sub
20
21' wd: 検索キーワード, pl: 検索場所(0:シート、1:ブック)
22Public Sub searchShapeText(wd As String, pl As Integer)
23
24 Dim ret As Boolean
25 Dim st As Worksheet
26 Dim spArr() As Shape
27
28 If (Len(wd) = 0) Then
29 MsgBox "検索文字列を入力してください"
30 Exit Sub
31 End If
32
33 If wd <> oldWd Or pl <> oldPl Then
34 oldWd = wd
35 oldPl = pl
36 spIdx = 0
37 gFlg = False
38 End If
39
40 If pl = 0 Then ' シート
41 Call makeShapeArr(ActiveSheet.Shapes, spArr)
42 Else ' ブック
43 For Each st In ActiveWorkbook.Worksheets
44 Call makeShapeArr(st.Shapes, spArr)
45 Next
46 End If
47
48 ret = searchShapeString(spArr, wd)
49 If Not ret Then MsgBox "検索対象が見つかりません", vbExclamation, "図形内テキスト検索"
50End Sub
51
52' 検索対象の図形を配列に積み上げる
53' sps: 図形コレクション(ShapesまたはGroupItems), spArr: 図形配列
54Private Sub makeShapeArr(sps As Variant, spArr() As Shape)
55 Dim sp As Shape
56 Dim idx As Long
57 For Each sp In sps
58 If (sp.Type = msoGroup) Then
59 Call makeShapeArr(sp.GroupItems, spArr)
60 ElseIf (sp.Type = msoComment) Then
61 ElseIf (sp.Type = msoGraphic) Then
62 Else
63 If Not isArrayInit(spArr) Then
64 ReDim spArr(0)
65 Set spArr(0) = sp
66 Else
67 idx = UBound(spArr) + 1
68 ReDim Preserve spArr(idx)
69 Set spArr(idx) = sp
70 End If
71 End If
72 Next
73End Sub
74
75' 参考サイト: https://zukucode.com/2019/08/vba-array-init.html
76' True: 初期化済み、False:未初期化
77Private Function isArrayInit(arr As Variant) As Boolean
78On Error GoTo ERROR_
79 isArrayInit = IIf(UBound(arr) >= 0, True, False)
80 Exit Function
81ERROR_:
82 If Err.Number = 9 Then
83 isArrayInit = False
84 Else
85 '想定外エラー
86 End If
87End Function
88
89Private Function searchShapeString(spArr() As Shape, wd As String) As Boolean
90 Dim sp As Shape
91 Dim s As String
92 Dim pos As Long
93 Dim lFlg As Boolean
94
95 lFlg = False
96 Do While True
97 Set sp = spArr(spIdx)
98 If (sp.TextFrame2.HasText = msoTrue) Then
99 s = sp.TextFrame2.TextRange.Text
100 pos = InStr(s, wd)
101 ' 図形内に検索ワードが見つかった場合
102 If (pos > 0) Then
103 ActiveWorkbook.Worksheets(getParentSheet(sp.parent)).Activate
104 'sp.TopLeftCell.Select 'テキスト範囲選択を解除するため、カレントセルを選択する
105 sp.TextFrame2.TextRange.Characters(pos, Len(wd)).Select
106 On Error Resume Next
107 ActiveWindow.ScrollRow = sp.TopLeftCell.Row - 10
108 If Err.Number = 1004 Then
109 ActiveWindow.ScrollRow = sp.TopLeftCell.Row
110 End If
111 ActiveWindow.ScrollColumn = sp.TopLeftCell.Column -1
112 If Err.Number = 1004 Then
113 ActiveWindow.ScrollColumn = sp.TopLeftCell.Column
114 End If
115 On Error GoTo 0
116 lFlg = True
117 gFlg = True
118 End If
119 End If
120CONTINUE:
121 If spIdx = UBound(spArr) Then
122 If gFlg Then
123 spIdx = 0
124 If lFlg Then
125 searchShapeString = True
126 Exit Function
127 End If
128 Else
129 searchShapeString = False
130 Exit Function
131 End If
132 Else
133 spIdx = spIdx + 1
134 If lFlg Then
135 searchShapeString = True
136 Exit Function
137 End If
138 End If
139 Loop
140End Function
141
142' 図形が置かれているシートのシート番号を取得
143Private Function getParentSheet(parent As Variant) As Long
144 Dim ret As Long
145 If TypeName(parent) = "Worksheet" Then
146 ret = parent.Index
147 Else
148 ret = getParentSheet(parent.parent) ' グループ化されている場合
149 End If
150 getParentSheet = ret
151End Function