Powerpoint VBAを使おう!

Powerpoint VBAやExcelのVBAで遊んでいます。Word VBAも始めました。

熱運動クラスモジュール化②速度実装の前に課題解決

①はこちら
chemiphys.hateblo.jp

ほんとにありがたい方々にアドバイスもらえています。他をどうこうする前にやらなきゃいけないことだったので,
たぶん解決できた気がするので,書きます。

imihitoさんのご指摘

Boxクラス内で使っているIsEmpty関数はVariant型専用関数なので、今回の場合だと意図した通りに動かないと思います。
対処として、判定方法を変えるのも手ですが、Drawメソッドの引数に渡すのはどうでしょうか?

わたしもここがごちゃごちゃしててだめだなぁと思ってて,どうしていいかわからなかったところ。

標準モジュール
    Dim B1 As Box
    Set B1 = New Box
    
    B1.pLeft = 80: B1.pTop = 100: B1.pRight = 150: B1.pBottom = 250
    Set B1.pSlide = TSlide
    B1.Draw
    B1.AddMolecile 5

Box.cls冒頭
Public Sub Draw()
    If IsEmpty(pSlide) Or IsEmpty(pTop) Or IsEmpty(pBottom) Or IsEmpty(pLeft) Or IsEmpty(pRight) Then Exit Sub
    
    Dim Box As Shape

たぶん改善できました。

標準モジュール
Sub test()
    Dim TSlide As Slide: Set TSlide = ActivePresentation.Slides(1)

    Dim B1 As Box
    Set B1 = New Box
    
    B1.Draw TSlide, 100, 250, 80, 150
    B1.AddMolecile 5
    Stop
End Sub
Box.cls冒頭
Public Sub Draw(objSlide As Slide, lngTop As Long, lngBottom As Long, lngLeft As Long, lngRight As Long)
    Set pSlide = objSlide
    pTop = lngTop
    pBottom = lngBottom
    pLeft = lngLeft
    pRight = lngRight
    
    Dim Box As Shape

引数が足りなければ勝手に怒ってくれますので,判定しなくてもよくなりました。

thomさんからのご指摘

あとで操作するには、シェイプもクラスに保持させると良いです。プロシージャ内のローカル変数だとプロシージャ実行後に消えてしまいますので。
具体的にはMoleculeクラスにShape型のインスタンス変数を持たせてシェイプを保持させます。
また、BoxクラスにCollection型のインスタンス変数(モジュールレベル変数)を持たせて複数のMoleculeを保持します。

ややこしい用語を使ってしまいました。
Dim shpEn As ShapeをAdd命令から外に出すという意味です。ついでにPublicにすると内部からも外部からもアクセスできて、Moleculeが生存している間はずっとシェイプを保持してくれます。

スコープのことは難しいですが,クラスモジュールと標準モジュールでやりとりしていくにはどうしてもきちんとしないといけないところ。この辺が弱くて今までやれてなかったわけで,乗り越えるべきところです。

Molcule.cls冒頭 shpEnをパブリックに出しました。Boxモジュールからは見える
Public shpEn As Shape
Public pSpeed As Long

Public Sub Add(半径 As Long)
    Set shpEn = pSlide.Shapes.AddShape(msoShapeOval, mLeft + 半径 + (mRight - mLeft - 2 * 半径) * Rnd(), mTop + 半径 + (mBottom - mTop - 2 * 半径) * Rnd(), 半径, 半径)

Box.cls冒頭  非固定長配列をどうやってPublicで宣言するの!?と少し悩んでいて,
もう一度thomさんのアドバイスを見てあぁ,配列はCollectionに放り込むのかと解釈。
Public pSpeed As Long
Public Molecules As Collection

'ここでコレクションを利用
Public Sub AddMolecile(粒数 As Long)
    Dim e() As Molecule
    ReDim e(粒数)
    Dim i As Long
    Set Molecules = New Collection
    
    For i = 1 To 粒数
        Set e(i) = New Molecule
        e(i).mLeft = pLeft
        e(i).mTop = pTop
        e(i).mRight = pRight
        e(i).mBottom = pBottom
        Set e(i).pSlide = pSlide
        e(i).Add 15
        Molecules.Add e(i)
    Next
    
End Sub

ローカルウィンドウを見てみた
f:id:chemiphys:20170115203850p:plain
B1というBoxがあって,その中にコレクションMolculesがあってその中に各粒のプロパティがある。
アクセスの仕方は

 Dim en1 As Molecule
    Set en1 = B1.Molecules(1)
    Debug.Print en1.mTop

For eachが使いやすい場面ですね。今はとりあえず一つの粒にアクセスしてみていますが,
ちゃんとプロパティに到達できる。

多数のフィールドを持つデータと格闘したときに,ソートキーを与えたくていろいろ試した経験が生きた。あれやってなかったらアドバイスの意味がつかめていない(;´▽`A``

コレクションの存在意義もすごいですね。可変長配列をぽんと上位モジュールにわたせるのかスゴイナ。

なんとか課題の解決はできたので,先に進めそう。

今はPublicでプロパティを扱ってるけど カプセル化するとき ユーザー定義型のをどう返すんだろうとか,こんどはまた次の?が出てきました。
x,y座標はいっぺんに計算したほうが楽ですし。でも,今は無視して進もう・・(ΦωΦ)今の敵はそいつじゃない。。