リストからコネクタを除外する

昨日は、オートシェイプの位置関係を、コネクタの種類と接続位置に反映してみました。

infoment.hatenablog.com

今日は、接続済みのコネクタをリストから除外することに挑戦です。

今日やりたいこと

今までは、シート上に接点・処理・分岐の3つのオートシェイプのみ存在する前提で、様々な処理を行ってきました。しかし、コネクタが存在する状態でオートシェイプのリストを作成しようとすると、現時点ではエラーが発生します。

f:id:Infoment:20180919062659p:plain

恐らく、コネクタが持っていない情報(=テキスト)を取り出して表示させようとしたのが原因と思われます。

そこで、リスト作成の時点でコネクタを処理の対象から除外することにしました。手順は、以下の通りです。

  1. リスト作成時に、対象となるオートシェイプの種類を確認
  2. 配列のサイズを変更

必要なこと

  1. オートシェイプの種類の確認方法
  2. 二次元配列の一次元サイズを変更する方法

いくつか方法があると思います。今回紹介する方法は、その中の一つです。

1.オートシェイプの種類の確認方法

コネクタだけを除外したい場合、直ぐに思いつく方法は二つありました。
① オートシェイプの名前で判別
現時点で登場するコネクタの名前は、以下の二つです。

  1. Straight Arrow Connector
  2. Elbow Connector

いずれの場合も、名前に「Connector」が含まれています。そこでLike演算子を用いて、名前にConnectorを含むものを除外します。こんな感じです。

If Shape.Name Like "*Connector*" Then

② Connectorプロパティで判別
オートシェイプがConnectorであればTrueを返し、それ以外の場合はFalseを返してくれます。従って、こんな感じで確認します。

If Shape.Connector = msoTrue Then

これは省略して、このようにも書けます。

If Shape.Connector Then

①は直感的に分かり易く、②はコードがすっきりします。今回は、②を採用することにします。

2.二次元配列の一次元サイズを変更する方法

リストボックスのリスト用データとして準備した配列は、そのサイズを、シート上のオートシェイプの数で決めていました。

Dim ListBoxSeq As Variant
ReDim ListBoxSeq(1 To ActiveSheet.Shapes.Count, 1 To 3)

この中にはコネクタも含まれるため、これを除外した場合、リストの末尾に空っぽの項目が追加されてしまいます。
f:id:Infoment:20180919065600p:plain

現時点ではこの項目を選択すると、存在しないオートシェイプを選択しようとしてエラーが発生します。
f:id:Infoment:20180919065658p:plain

配列のサイズを整えて、余分な空白が出ないようにしたいのですが、今回調整したい次元はRedimで変更できません。
thom.hateblo.jp

そこで、一次元のサイズを変更する関数を作成してみました。

【クラスモジュール】(SequenceClass)
'[用 途]
'   二次元配列について、一次元のサイズを変更する

'[引 数]
'   seq As Variant 元の配列
'   update_size As Long 変更後の一次元のサイズ
'   preserve_flag As Boolean 値保持を選択(初期値はTrue)

'[戻り値]
'   一次元のサイズを変更した配列

Public Function SpecialRedim(seq As Variant, _
                             update_size As Long, _
                             Optional preserve_flag As Boolean = True) As Variant

    Dim tempSeq As Variant
    ReDim tempSeq(LBound(seq) To update_size, LBound(seq, 2) To UBound(seq, 2))
        Select Case preserve_flag
            Case False
            Case True
                Dim i As Long, j As Long
                    For i = LBound(seq) To UBound(tempSeq)
                        For j = LBound(seq, 2) To UBound(seq, 2)
                            tempSeq(i, j) = seq(i, j)
                        Next
                        If i = UBound(seq) Then
                            Exit For
                        End If
                    Next
        End Select

        SpecialRedim = tempSeq

End Function

変更後のサイズで新たな配列を作成し、そこに値を移すだけの関数です。

これを、先ほどのコネクタ判別の仕掛けと併せてリスト作成に反映します。

【ユーザーフォームのモジュール】
Private Sub UserForm_Initialize()

    Dim Shape As Shape
    Dim ListBoxSeq As Variant
    ReDim ListBoxSeq(1 To ActiveSheet.Shapes.Count, 1 To 3)
    Dim i As Long
        i = 1
        For Each Shape In ActiveSheet.Shapes
            If Shape.Connector = msoFalse Then  ' ← 今回追加した箇所
                ListBoxSeq(i, 1) = Shape.TextFrame2.TextRange.Characters.Text
                ListBoxSeq(i, 2) = Shape.ID
                ListBoxSeq(i, 3) = 0
                i = i + 1                       ' ← 今回追加した箇所
            End If
        Next

' ------------↓↓今回追加した箇所↓↓------------
    Dim SQC As SequenceClass
    Set SQC = New SequenceClass
        ListBoxSeq = SQC.SpecialRedim(ListBoxSeq, i - 1)
' ------------↑↑今回追加した箇所↑↑------------
        ListBox1.List = ListBoxSeq

    Dim ComboBoxSeq(1 To 3, 1 To 2)
        ComboBoxSeq(1, 1) = "接点": ComboBoxSeq(1, 2) = msoShapeFlowchartTerminator
        ComboBoxSeq(2, 1) = "処理": ComboBoxSeq(2, 2) = msoShapeFlowchartProcess
        ComboBoxSeq(3, 1) = "分岐": ComboBoxSeq(3, 2) = msoShapeFlowchartDecision

        With ComboBox1
            .ColumnCount = 2
            .TextColumn = 1
            .BoundColumn = 2
            .List = ComboBoxSeq
        End With
                    
End Sub

結果

シート上にコネクタがあっても、それを除外したリストが作成されるようになりました。
f:id:Infoment:20180919072651p:plain

次回に続きます。

参考まで。