ユーザーフォームとワークシートの不一致を解消する

昨日は、シート上でのオートシェイプ選択結果と、ユーザーフォームのリストボックス項目を介してのオートシェイプ選択結果を、等しくユーザーフォームのリストボックスに反映させてみました。
infoment.hatenablog.com

今日は、今のところ唯一残った「不一致」部分の解消に挑戦です。
f:id:Infoment:20180926222556p:plain

今日やりたいこと

リストボックス内の項目が一つ以上選択状態の場合であって、うっかりセルを選択すると、以下の不一致が発生します。

  • シート上では、全てのオートシェイプが選択解除される
  • リストボックス上では、依然として選択が保持されている

f:id:Infoment:20180926224537p:plain

そこで、以下手順による問題解決を図りました。

  1. シートが選択されたことを検知する
  2. ユーザーフォームが表示されている場合だけ、リストボックスの項目選択状態を解除する。

必要なこと

  1. ユーザーフォームの表示状態を確認する
  2. シートのイベントで、オートシェイプの全解除を検知する
  3. リストボックスの選択状態を解除する
  4. ユーザーフォームを閉じる際の処理を追加する

1.ユーザーフォームの表示状態を確認する

昨日は、以下の方法でユーザーフォームが非表示であることを確認していました。

    If EditChartForm.Visible = False Then
        EditChartForm.Show vbModeless
    End If

しかし実は、

If EditChartForm.Visible = False Then

の部分で、ユーザーフォームが表示されてしまいます。この場合は「都度再表示しない」ことが目的であったため、問題ありませんでした。しかし今回は、表示されている場合を検知したいので、上記では不適切です。このまま利用すると、シートのどこかを選択するたびに、ユーザーフォームが表示されてしまいます。

  • 表示されています
     ⇒ では、もう表示しなくていいです。
     ⇒ 表示されていてOK
  • 表示されていません
     ⇒ では、何もしないでください。
     ⇒ 表示されるとNG(「何か」をされてしまうため)

そこで今回は、Public変数でフラグを立てることにしました。様々な記事で「NG方法」として紹介されていた記憶があるのですが、今回はこれ以上の手段を思いつけませんでした。

【標準モジュール】
Option Explicit
Public EditChartFlag As Boolean
  • 表示中 ⇒ True
  • 非表示 ⇒ False
【クラスモジュール】(EditChartClass)

次いで、クラスの初期化部分を変更します。ここで、ユーザーフォームを表示させたうえで、フラグを True に切り替えています。

Private Sub Class_Initialize()
    If EditChartFlag = False Then
        EditChartForm.Show vbModeless
        EditChartFlag = True
    End If
End Sub

2.シートのイベントで、オートシェイプの全解除を検知する

シート上の操作でオートシェイプが全解除されるのは、いずれかのセルを選択したときです。従って今回は、シートモジュールのSelectionChangeイベントを利用します。

フローチャートを作成するシートのシートモジュール】

先ほどのフラグを利用することで、ユーザーフォームが表示されている時だけ以下を行います。

Private Sub Worksheet_SelectionChange(ByVal Target As Range)
    If EditChartFlag = True Then
  ' リストボックスの選択を解除する処理
    End If
End Sub

3.リストボックスの選択状態を解除する

上記の「リストボックスの選択を解除する処理」は、今回以下の手順で行います。

  1. リストボックスの内容を一旦クリア
  2. 改めてリストをセット
フローチャートを作成するシートのシートモジュール】

先ほどのフラグを利用することで、ユーザーフォームが表示されている時だけ以下を行います。

Private Sub Worksheet_SelectionChange(ByVal Target As Range)
    If EditChartFlag = True Then
        Dim EChC As EditChartClass
        Set EChC = New EditChartClass
        EditChartForm.ListBox1.Clear
        EditChartForm.ListBox1.List = EChC.ShapeList
    End If
End Sub

折角なので、昨日作成したクラスモジュールの「リストボックス用のリスト」を流用しました。

4.ユーザーフォームを閉じる際の処理を追加する

ユーザーフォームを閉じる方法は、現時点で以下の二つです。

  1. 「終了」ボタンを押す
  2. 「×」ボタンを押す

そこでそれぞれに、フラグを False にする処理を追加します。

【ユーザーフォームのモジュール】(EditChartForm)

「終了」ボタン

Private Sub EndButton_Click()
    EditChartFlag = False
    Unload Me
End Sub

「×」ボタン

Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
    If CloseMode = 0 Then
        EditChartFlag = False
    End If
End Sub

結果

シート選択によるオートシェイプの全解除が、ユーザーフォームのリストボックスに反映されるようになりました。
f:id:Infoment:20180926233521p:plain

(静止画像で結果が分かりにくいのは、相変わらずです)。

次回に続きます。

参考まで。