VBAクラスの作り方:独自Rangeっぽいものを作ってみた
クラスの作成は、標準モジュールで作成していた時とは様相が違い戸惑う部分も多いと思います、
それは、初めてVBAに取り組んだ時の戸惑いと同じかもしれません。
細かい文法や機能は、少し慣れてから改めて学んでも遅くはありません。
それらを極力クラスに委ねようということです。
マクロVBAが遅いのは、多くの場合Rangeオブジェクトの操作に関係しています。
これを避けるためには表範囲を配列に入れて処理するといった方法がありますが、
これをクラスにカプセル化しようということです。
クラス化することで入力支援が使えることも利点になります。
ただし、
今回のクラスは即実用で使う為ではなく、あくまでクラスの作り方のサンプルとして作成しています。
従って、どういう機能をどうやって実装するかという部分を中心にVBAコードを読んでください。
その為のVBAクラスのサンプルとして作成しています。
また学習素材の意味として、意図的にいろいろなテクニックを使っている部分もあります。
そいったテクニックも込みでサンプルとして使ってください。
これらを使っていますので、もしこれらが分からない場合はクラスの前にそちらを先に学んでください。
特に実務でVBAを使い業務の自動化を目指すのなら、クラスよりもこれらの方がはるかに重要です。
以下、いきなりクラスの全VBAコードを提示します。
クラス モジュールを挿入して、コピペで貼り付けてください。
クラス作成後は、後の標準モジュールで動作を確認しつつクラス内のVBAコードを読んでみてください。
>クラスの全VBAコード
>後の標準モジュールでの使い方では、
clsRange
このクラス名になっています。
独自Rangeオブジェクトっぽいものということで、この名称にしました。
Option Explicit
'==================================================
' 公開変数等
'==================================================
Public Enum ErrValue 'このクラス専用の列挙の意味でここに
Through 'そのまま返す
ToBlank '""を返す
ToEmpty 'Emptyを返す
ToNull 'Nullを返す
End Enum
'==================================================
' 非公開変数
'==================================================
Private Ws As Worksheet '対象ワークシート
Private pHeadRow As Long '見出し行
Private pDataRow As Long 'データ開始行
Private pDataCol As Long 'データ開始列
Private pArray As Variant 'データ格納2次元配列(1~)
Private pErrCells As Integer 'エラー値の場合の値
'==================================================
' 公開プロパティ
'==================================================
'対象シート
Public Property Get Worksheet() As Worksheet
Set Worksheet = Ws
End Property
Public Property Set Worksheet(ByVal argWs As Worksheet)
Set Ws = argWs
End Property
'表の見出し行:名前定義がされている行
Public Property Get HeadRow() As Long
HeadRow = pHeadRow
End Property
Public Property Let HeadRow(ByVal HeadRow As Long)
pHeadRow = HeadRow
End Property
'表のデータ開始行
Public Property Get DataRow() As Long
DataRow = pDataRow
End Property
Public Property Let DataRow(ByVal DataRow As Long)
pDataRow = DataRow
End Property
'表のデータ開始列
Public Property Get DataCol() As Long
DataCol = pDataCol
End Property
Public Property Let DataCol(ByVal DataCol As Long)
pDataCol = DataCol
End Property
'データ行数:ReadOnly Property
Public Property Get RowsCount() As Long
If IsArray(pArray) Then
RowsCount = UBound(pArray, 1)
End If
End Property
'データ列数:ReadOnly Property
Public Property Get ColumnsCount() As Long
If IsArray(pArray) Then
ColumnsCount = UBound(pArray, 2)
End If
End Property
'クラス独自のCells
Public Property Get Cells(ByVal Row As Long, ByVal col As Long) As Variant
Cells = pArray(Row, col)
If IsError(Cells) Then
Select Case pErrCells
Case ErrValue.Through
'そのまま
Case ErrValue.ToBlank
Cells = ""
Case ErrValue.ToEmpty
Cells = Empty
Case ErrValue.ToNull
Cells = Null
End Select
End If
End Property
Public Property Let Cells(ByVal Row As Long, ByVal col As Long, ByVal Value As Variant)
pArray(Row, col) = Value
End Property
'エラー値の場合にCellsが戻す値を指定:ReadOnly Property
Public Property Let ErrCells(ByVal arg As ErrValue)
pErrCells = arg
End Property
'クラス独自のColumn:WriteOnly Property
Public Property Let Column(ByVal col As Long, ByVal Value As Variant)
Dim i As Long
For i = 1 To RowsCount
pArray(i, col) = Value
Next
End Property
'==================================================
' 公開メソッド
'==================================================
'指定されたワークシートの表全体を2次元配列に入れる
Public Sub StoreValues(Optional ByVal TargetSheet As Worksheet)
Dim myRange1 As Range, myrange2 As Range
Set myRange1 = Ws.Cells(pDataRow, pDataCol)
Set myrange2 = myRange1.CurrentRegion
Set myrange2 = myrange2.Item(myrange2.Count)
'行・列が途切れている場合は警告
If myrange2.Column _
< Ws.Cells(pDataRow, Ws.Columns.Count).End(xlToLeft).Column Then
If MsgBox("表内に空白列があります。" & vbLf & vbLf & _
"処理を中断してよろしいですか?", vbYesNo, "確認") _
= vbYes Then
End
Else
If MsgBox("表内に空白列があるので、" & vbLf & vbLf & _
"エラーとなる可能性があります。" & vbLf & vbLf & _
"処理を続行してよろしいですか?", vbYesNo, "確認") _
= vbYes Then
End
End If
End If
End If
pArray = Ws.Range(myRange1, myrange2)
End Sub
'データ格納用の2次元配列から指定範囲をシートに戻す
'オプションの指定状況により範囲を変更
Public Sub PutArray(Optional ByVal Row1 As Long = 0, Optional ByVal Col1 As Long = 0, _
Optional ByVal Row2 As Long = 0, Optional ByVal Col2 As Long = 0)
'引数全て省略:全データ→配列全体を出力し抜ける
If Row1 = 0 And Col1 = 0 And _
Row2 = 0 And Col2 = 0 Then
Ws.Cells(DataRow, DataCol) _
.Resize(RowsCount, ColumnsCount) _
= pArray
Exit Sub
End If
Select Case True
Case Row1 <> 0 And Col1 <> 0 And Row2 <> 0 And Col2 <> 0
'全て指定:指定行列範囲
'処理なし
Case Row1 <> 0 And Col1 <> 0 And Row2 = 0 And Col2 = 0
'Row1とCol1のみ:指定セル
Row2 = Row1
Col2 = Col1
Case Row1 <> 0 And Col1 = 0 And Row2 = 0 And Col2 = 0
'Row1のみ:指定行のみ
Row2 = Row1
Col1 = 1
Col2 = ColumnsCount
Case Row1 <> 0 And Col1 = 0 And Row2 <> 0 And Col2 = 0
'Row1とRow2のみ:指定行範囲
Col1 = 1
Col2 = ColumnsCount
Case Row1 = 0 And Col1 <> 0 And Row2 = 0 And Col2 = 0
'Col1のみ:指定列のみ
Col2 = Col1
Row1 = 1
Row2 = RowsCount
Case Row1 = 0 And Col1 <> 0 And Row2 = 0 And Col2 <> 0
'Col1とCol2のみ:指定列範囲
Row1 = 1
Row2 = RowsCount
Case Else
MsgBox "PutRangeの引数不正"
Exit Sub
End Select
'始点行・列~終点行・列範囲を配列からシートへ
'配列の指定範囲を別配列へ
Dim myArray()
Dim i1 As Long, i2 As Long
ReDim myArray(1 To Row2 - Row1 + 1, 1 To Col2 - Col1 + 1)
For i1 = 1 To Row2 - Row1 + 1
For i2 = 1 To Col2 - Col1 + 1
myArray(i1, i2) = pArray(i1 + Row1 - 1, i2 + Col1 - 1)
Next
Next
'出力先のセル範囲を求める
Dim myRange1 As Range, myrange2 As Range
Set myRange1 = Ws.Cells(DataRow + Row1 - 1, DataCol + Col1 - 1)
Set myrange2 = Ws.Cells(DataRow + Row2 - 1, DataCol + Col2 - 1)
'シートへ出力
Ws.Range(myRange1, myrange2) = myArray
End Sub
'データ格納用の2次元配列から指定範囲をシートに戻す
'列1,比較演算子1,値1,列2,比較演算子2,値2・・・
'全てAnd条件です。Orが必要な場合は別途作成
Public Function FilterArray(ParamArray ParamFilter()) As Variant
'引数未指定は配列全体を返し抜ける
If UBound(ParamFilter) < 0 Then
FilterArray = pArray
Exit Function
End If
'該当行をコレクションに入れる:要素数が不定なのでコレクション
Dim i1 As Long, i2 As Long, ix As Long
Dim myCollection As New Collection
Dim varTemp As Variant
Dim myArray()
ReDim myArray(1 To ColumnsCount)
For i1 = 1 To RowsCount
'関数IsTargtで欽定
If IsTargt(i1, ParamFilter()) Then
For i2 = 1 To ColumnsCount
myArray(i2) = Cells(i1, i2)
Next
myCollection.Add myArray
ix = ix + 1
End If
Next
If myCollection.Count = 0 Then
Exit Function
End If
'コレクションを2次元配列にする
ReDim myArray(1 To myCollection.Count, 1 To ColumnsCount)
i1 = 1
For Each varTemp In myCollection
For i2 = 1 To ColumnsCount
myArray(i1, i2) = varTemp(i2)
Next
i1 = i1 + 1
Next
FilterArray = myArray
Exit Function
End Function
'Vlookup機能
'検索値(String),検索列(Long),取得列(Long)
'検索値はVariant同士の比較を避けるために型を指定している
Public Function Vlookup(ByVal What As String, _
ByVal ColSearch As Long, _
ByVal ColReturn As Long) As Variant
Dim i As Long
For i = 1 To RowsCount
If Cells(i, ColSearch) = What Then
Vlookup = Cells(i, ColReturn)
Exit Function
End If
Next
End Function
'==================================================
' 非公開メソッド
'==================================================
'列1,比較演算子1,値1,列2,比較演算子2,値2・・・
Private Function IsTargt(ByVal i1 As Long, ParamArray AryFilter()) As Boolean
Dim i2 As Long
IsTargt = True
'ParamArrayを配列で受け取ると(0,要素数)の2次元配列
For i2 = 0 To UBound(AryFilter(0)) Step 3
'比較演算子
Select Case UCase(AryFilter(0)(i2 + 1))
Case "="
If Not Cells(i1, AryFilter(0)(i2)) = AryFilter(0)(i2 + 2) Then
IsTargt = False
End If
Case ">"
If Not Cells(i1, AryFilter(0)(i2)) > AryFilter(0)(i2 + 2) Then
IsTargt = False
End If
Case "<"
If Not Cells(i1, AryFilter(0)(i2)) < AryFilter(0)(i2 + 2) Then
IsTargt = False
End If
Case ">="
If Not Cells(i1, AryFilter(0)(i2)) >= AryFilter(0)(i2 + 2) Then
IsTargt = False
End If
Case "<="
If Not Cells(i1, AryFilter(0)(i2)) <= AryFilter(0)(i2 + 2) Then
IsTargt = False
End If
Case "<>"
If Not Cells(i1, AryFilter(0)(i2)) <> AryFilter(0)(i2 + 2) Then
IsTargt = False
End If
Case "LIKE"
If Not Cells(i1, AryFilter(0)(i2)) Like AryFilter(0)(i2 + 2) Then
IsTargt = False
End If
Case Else
IsTargt = False
End Select
Next
End Function
'==================================================
' クラスのメソッド
'==================================================
'クラス初期処理
Private Sub Class_Initialize()
HeadRow = 1
DataRow = 2
DataCol = 1
pErrCells = ErrValue.Through
End Sub
以下、コメントおよびプロシージャーを抜き出したものです。
全体の構成を見る時の参考にしてください。
' 公開プロパティ
'==================================================
Public Property Get Worksheet() As Worksheet
Public Property Set Worksheet(ByVal argWs As Worksheet)
Public Property Get HeadRow() As Long
Public Property Let HeadRow(ByVal HeadRow As Long)
Public Property Get DataRow() As Long
Public Property Let DataRow(ByVal DataRow As Long)
Public Property Get DataCol() As Long
Public Property Let DataCol(ByVal DataCol As Long)
Public Property Get RowsCount() As Long
Public Property Get ColumnsCount() As Long
Public Property Get Cells(ByVal Row As Long, ByVal col As Long) As Variant
Public Property Let Cells(ByVal Row As Long, ByVal col As Long, ByVal Value As Variant)
Public Property Let ErrCells(ByVal arg As ErrValue)
Public Property Let Column(ByVal col As Long, ByVal Value As Variant)
' 公開メソッド
'==================================================
Public Sub StoreValues(Optional ByVal TargetSheet As Worksheet)
'オプションの指定状況により範囲を変更
Public Sub PutArray(Optional ByVal Row1 As Long = 0, Optional ByVal Col1 As Long = 0, _
Optional ByVal Row2 As Long = 0, Optional ByVal Col2 As Long = 0)
'列1,比較演算子1,値1,列2,比較演算子2,値2・・・
'全てAnd条件です。Orが必要な場合は別途作成
Public Function FilterArray(ParamArray ParamFilter()) As Variant
'検索値(String),検索列(Long),取得列(Long)
'検索値はVariant同士の比較を避けるために型を指定している
Public Function Vlookup(ByVal What As String, _
ByVal ColSearch As Long, _
ByVal ColReturn As Long) As Variant
' 非公開メソッド
'==================================================
Private Function IsTargt(ByVal i1 As Long, ParamArray AryFilter()) As Boolean
' クラスのメソッド
'==================================================
Private Sub Class_Initialize()
>サンプルとして使うブックの構成
>顧客マスタ
売上データ
この2シートになります。
氏名
氏名(カナ)
性別
生年月日
年齢
郵便番号
都道府県
電話番号
備考
フィールド
顧客ID
売上日
金額
氏名
都道府県
この2シートについては、
前回までにやった、列名のクラスを作成します。
VBAクラスの作り方:列名のプロパティを自動作成する
作成されるクラスは
clsC売上データ
データは適当に入れてください。
ネット上には、無料のテストデータ作成ツールがいろいろありますので活用してください。
標準モジュールでの使い方
Option Explicit
'clsRangeの使い方サンプル
Sub ClassTestMain()
Dim clsMst As New clsRange
Dim colMst As New clsC顧客マスタ
Dim clsDat As New clsRange
Dim colDat As New clsC売上データ
Dim Ws As Worksheet
'顧客マスタClassの初期設定
With clsMst
Set .Worksheet = ThisWorkbook.Worksheets("顧客マスタ")
Set colMst.Worksheet = .Worksheet
.HeadRow = 1 '列タイトル行
.DataRow = 2 'データ開始行
.DataCol = 1 'データ開始列
.ErrCells = ToNull 'エラー値処理
Call .StoreValues 'データ全体を配列へ格納
End With
'売上データClassの初期設定
With clsDat
Set .Worksheet = ThisWorkbook.Worksheets("売上データ")
Set colDat.Worksheet = .Worksheet
.HeadRow = 1 '列タイトル行
.DataRow = 2 'データ開始行
.DataCol = 1 'データ開始列
.ErrCells = ToEmpty 'エラー値処理
Call .StoreValues 'データ全体を配列へ格納
End With
Call 顧客マスタ更新(clsMst, colMst)
Call 売上データ更新(clsDat, colDat, clsMst, colMst)
'解放
Set clsMst = Nothing
Set colMst = Nothing
Set clsDat = Nothing
Set colDat = Nothing
End Sub
Private Sub 顧客マスタ更新(ByVal clsMst As clsRange, ByVal colMst As clsC顧客マスタ)
Dim i As Long
'シートの内容を更新する場合
With clsMst
'クラスのCellsを使った読み書き
.Cells(3, colMst.氏名_カナ) = StrConv(.Cells(3, colMst.氏名_カナ), vbHiragana)
.Cells(4, colMst.氏名_カナ) = Application.GetPhonetic(.Cells(4, colMst.氏名))
.Cells(5, colMst.氏名_カナ) = Application.GetPhonetic(.Cells(5, colMst.氏名))
.Cells(5, colMst.備考) = "引っ越し:" & .Cells(5, colMst.都道府県)
.Cells(5, colMst.都道府県) = "千葉県"
'全行処理
For i = 1 To .RowsCount
.Cells(i, colMst.年齢) = Age(.Cells(i, colMst.生年月日), Date)
Next
'シートへの書き出し
'名前付き引数:[Row1:=開始行][,Col1:=開始列][,Row2:=終了行][,Col2:=終了列]
Call .PutArray(Row1:=3, Col1:=colMst.氏名_カナ, Row2:=4, Col2:=colMst.氏名_カナ)
Call .PutArray(Row1:=5)
Call .PutArray(Col1:=colMst.年齢)
End With
'Filterを指定して配列を受け取り別シートへ出力する場合
Dim Ws As Worksheet
Dim myArray As Variant
With clsMst
myArray = .FilterArray(colMst.性別, "=", "女", _
colMst.年齢, "<", 30, _
colMst.電話番号, "Like", "080*")
Set Ws = Worksheets.Add(After:=Worksheets(Sheets.Count))
On Error Resume Next
Application.DisplayAlerts = False
Worksheets("Filter出力").Delete '2度実行対応
Application.DisplayAlerts = True
On Error GoTo 0
Ws.Name = "Filter出力"
.Worksheet.Rows(.HeadRow).Copy Destination:=Ws.Rows(1)
If IsArray(myArray) Then
Ws.Cells(2, 1).Resize(UBound(myArray, 1), UBound(myArray, 2)) = myArray
End If
End With
End Sub
Private Sub 売上データ更新(ByVal clsDat As clsRange, ByVal colDat As clsC売上データ, _
ByVal clsMst As clsRange, ByVal colMst As clsC顧客マスタ)
Dim i As Long
Dim strSearch As String
'顧客マスタの情報を取得し更新する
With clsDat
For i = 1 To .RowsCount
strSearch = .Cells(i, colDat.顧客ID)
'検索値(String),検索列(Long),取得列(Long)
.Cells(i, colDat.氏名) = clsMst.Vlookup(strSearch, colMst.顧客ID, colMst.氏名)
.Cells(i, colDat.都道府県) = clsMst.Vlookup(strSearch, colMst.顧客ID, colMst.都道府県)
Next
Call .PutArray(Col1:=colDat.氏名)
Call .PutArray(Col1:=colDat.都道府県)
End With
End Sub
'年齢算出
Public Function Age(FromDate As Variant, ToDate As Variant) As Integer
Dim intAge As Integer
intAge = Year(ToDate) - Year(FromDate)
If Format(ToDate, "mmdd") < Format(FromDate, "mmdd") Then
intAge = intAge - 1
End If
Age = intAge
End Function
ClassTestMainが起動のプロシージャーです。
ここでやっていることは他愛のないことなので、VBA内のコメントを参考にしてください。
一番下の年齢算出については、おまけみたいなものになりますので参考までに。
Dim clsDat As New clsRange
つまり、同じ型のオブジェクトが複数作れるのが良いところです。
VBAのクラスとは(Class,Property)
Dim colMst As New clsC顧客マスタ
Dim colDat As New clsC売上データ
clsRangeの中に入れられれば使いやすいのですが、
クラスの型が違いますし、何より列名入力支援の為なので統一することができません。
入力支援は実際にタイピングして確認
クラス名称にプリフィックスを付けておくと、ここでまとまって表示されます。
・・・
Public Property Let ErrCells(ByVal arg As ErrValue)
これで実現されています。
列挙体はPublicにする必要があります。
クラス内のプロパティ等のプロシーシャーの型として使うことで、
それを外部で指定する場合に列挙体のメンバーが候補表示されるようになります。
列挙体はプロジェクト内でユニークでなければなりません。
列挙体はモジュール名で修飾することはできません。
つまり、
クラスのインスタンスを経由して直接列挙体そのものを参照することもできません。
従って clsMst.ErrValue このような参照はできないということです。
このクラス専用なのでクラス内にパッケージしたほうが再利用しやすくなるということです。
エラーが出たときはF8で確認
プロパティCellsの中でエラー値判定して、返す値("",Empty,Null)を制御しています。
ではエラーを出してみましょう。
データ3行目(シートでは4行目)の「氏名(カナ)」のセルをエラー値にします。
=NA() や =1/0 等々
そして、ClassTestMainを実行すると、
.ErrCells = ToEmptyを生かすと、
このCells内で値を変更している動きが理解できるはずです。
ClassTestMainを実行すると、
「型が一致しません」となりますので、「デバッグ」
そこで、F8で進めると、
なんか不便ですよね、エラー箇所で止まってくれない、、、
これで、クラス内で停止するようになります。
ただし、クラス内でOn Errorが指定されればスルーします。
全モジュールにおいて、On Errorに関係なくエラー停止させることができます。
最後に
もう少し手を加えれば、実用としても十分耐えうるものにできるはずです。
列挙体、配列、コレクション、Optional、ParamArray、そしてProperty
これらが使われていますが、これに、
構造体や、WithEventsキーワード、RaiseEventステートメント
これらが使えるようになれば、もう文法的には学ぶものはほとんどありません。
(ステートメントやプロパティの細部については別として)
VBAでオブジェクト指向の多態性(ポリモーフィズム)を実現する手段と言えます。
スーパークラス(親クラス)には、プロパティ・メソッド等の「枠」「型」のみ定義し、
Implementsステートメントを実装した子クラスで実際の動作を決定するものです。
こんな感じの説明でしょうか、、、これでわかるはずもありません。
インターフェースの説明で良くある「ワンワン」「ニャンニャン」的なものでは、、、
単にサンプルVBAコードを提示しても、あーそうなのか、ということが分かるだけで、
実際の使い道を実感できないと思います。
大規模かつ堅牢なシステムを作るような時でもなければ良さを実感できるものではないと思います。
実装の大変さを上回る利点を実感できないだろうということです。
逆に言えば、VBAでそういうシステムを今後作ろうと考えているのなら是非習得してください。
最初に書いた通り、クラスを使うには慣れが必要です。
どうしてもクラスはVBAコードが多くなりがちで、VBA記述が大変になることが多いものです。
だからと言って、VBAコードを短くしたいだけの理由で、
変数をやたらに公開するようなカプセル化できていないようなクラスでは本末転倒になります。
クラスはしっかり使えれば、その大変さを補ってあまりある恩恵があります。
同じテーマ「VBAクラス入門」の記事
クラスを使った全ブック(他ブック)のイベント補足
VBAクラスの作り方:列名の入力支援と列移動対応
VBAクラスの作り方:列名のプロパティを自動作成する
VBAクラスの作り方:独自Rangeっぽいものを作ってみた
クラスとイベントとマルチプロセス並列処理
クラスとCallByNameとポリモーフィズム(多態性)
オートフィルターを退避回復するVBAクラス
オートフィルター退避回復クラスを複数シート対応させるVBAクラス
コレクション(Collection)の並べ替え(Sort)に対応するクラス
VBAクラスのAttributeについて(既定メンバーとFor Each)
VBAクラスのAttributeについて(既定メンバーとFor Each)
新着記事NEW ・・・新着記事一覧を見る
TRIMRANGE関数(セル範囲をトリム:端の空白セルを除外)|エクセル入門(2024-08-30)
正規表現関数(REGEXTEST,REGEXREPLACE,REGEXEXTRACT)|エクセル入門(2024-07-02)
エクセルが起動しない、Excelが立ち上がらない|エクセル雑感(2024-04-11)
ブール型(Boolean)のis変数・フラグについて|VBA技術解説(2024-04-05)
テキストの内容によって図形を削除する|VBA技術解説(2024-04-02)
ExcelマクロVBA入門目次|エクセルの神髄(2024-03-20)
VBA10大躓きポイント(初心者が躓きやすいポイント)|VBA技術解説(2024-03-05)
テンキーのスクリーンキーボード作成|ユーザーフォーム入門(2024-02-26)
無効な前方参照か、コンパイルされていない種類への参照です。|エクセル雑感(2024-02-17)
初級脱出10問パック|VBA練習問題(2024-01-24)
アクセスランキング ・・・ ランキング一覧を見る
1.最終行の取得(End,Rows.Count)|VBA入門
2.セルのコピー&値の貼り付け(PasteSpecial)|VBA入門
3.変数宣言のDimとデータ型|VBA入門
4.繰り返し処理(For Next)|VBA入門
5.RangeとCellsの使い方|VBA入門
6.ブックを閉じる・保存(Close,Save,SaveAs)|VBA入門
7.セルのクリア(Clear,ClearContents)|VBA入門
8.メッセージボックス(MsgBox関数)|VBA入門
9.条件分岐(Select Case)|VBA入門
10.マクロとは?VBAとは?VBAでできること|VBA入門
このサイトがお役に立ちましたら「シェア」「Bookmark」をお願いいたします。
記述には細心の注意をしたつもりですが、
間違いやご指摘がありましたら、「お問い合わせ」からお知らせいただけると幸いです。
掲載のVBAコードは動作を保証するものではなく、あくまでVBA学習のサンプルとして掲載しています。
掲載のVBAコードは自己責任でご使用ください。万一データ破損等の損害が発生しても責任は負いません。