19
47

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

[VBA]クラスを定義する(ちょっと応用)

Last updated at Posted at 2017-12-16

VBAでのクラス定義の基礎はこちらhttps://qiita.com/Kamo123/items/a4c7749fa30d8f68df28

##デフォルトプロパティを設定する
デフォルトプロパティとは、RangeオブジェクトのValueプロパティなど、プロパティを省略すると取得されるやつです。

自作クラスに設定してみます。

元のクラスとして、以下のPersonクラスを考えます。

Person(クラスモジュール)
Option Explicit

' プロパティ
Private Name As String

' メソッド
Public Sub SayHello()
    MsgBox "Hello, I'm " & Name & "!"
End Sub

' プロパティプロシージャ
Property Get MyName() As String
    MyName = Name
End Property

Property Let MyName(namae As String)
    If namae = "" Then
        ' 氏名がブランクならエラー
        Err.Raise 10000, , "名前がブランクです"
    End If

    Name = namae
End Property

まず、このPersonクラスをエクスポートします。(プロジェクト エクスプローラからドラッグ&ドロップでできます。)

次に、エクスポートした.clsファイルをテキストエディタで開いて、デフォルトにしたいプロパティの先頭行にAttribute Value.VB_UserMemId = 0と入れます。

clsファイル
Property Get MyName() As String
    Attribute Value.VB_UserMemId = 0
    MyName = Name
End Property

これでインポートしなおしますと、見た目は変化はありませんが、たしかにデフォルトプロパティに設定されています。

標準モジュール
Sub test1()
    Dim p As Person
    Set p = New Person
    p = "taro"
    Debug.Print p   ' => "taro"
End Sub

##For Eachで回せるようにする

セルをたくさん入れて管理できるクラスを考えます。

CellManager(クラスモジュール)
Option Explicit

Public Cells As Collection

Private Sub Class_Initialize()
    Set Cells = New Collection
End Sub

Public Sub Add(newCell As Range)
    Cells.Add newCell
End Sub

Public Function Item(Index As Long) As Range
    Set Item = Cells(Index)
End Function

Public Function NewEnum() As stdole.IUnknown
    Set NewEnum = Cells.[_NewEnum]
End Function

NewEnumというのを定義するのが肝です。
このように、For Eachで回したいものをCollectionに入れておき、自作クラスのNewEnumの中でCollection_NewEnumを呼び出します。

このクラスモジュールをエクスポートしてテキストエディタで開きます。

clsファイル
Public Function NewEnum() As stdole.IUnknown
Attribute NewEnum.VB_UserMemId = -4   ' この行を追加した
    Set NewEnum = CellCollection.[_NewEnum]
End Function

こんな感じでAttribute NewEnum.VB_UserMemId = -4を追加します。
保存後、インポートするとFor Eachで使えるようになります。

標準モジュール
Sub test1()
    Dim cm As New CellManager
    Dim c As Range
        
    Range("A1").Value = "A"
    Range("A2").Value = "B"
    cm.Add Range("A1")
    cm.Add Range("A2")
        
    For Each c In cm
        Debug.Print c.Value
    Next
End Sub
出力
A
B

なぜか変数cがVariant型でなくてもコンパイルエラーになりませんが、チェックできていないだけのようです。(追記:この部分、誤解していました。コメント欄を参照ください)

IntellisenseでNewEnumが見えてしまうのが気持ち悪いですが、VBAではどうしようもないです。

##参考サイト
日本語情報でVBAの深いところまで解説しているサイトが少ない中、大変貴重な情報源です。
http://thom.hateblo.jp/entry/2015/02/16/003000
http://d.hatena.ne.jp/miau/20110203/1296706824

19
47
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
19
47

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?