お絵かきロジックアナライザ開発記   その7

シートの新規作成機能がかなりイイ感じになってきたので、シート作成に関するユーザーインターフェイスを強化します。いつまでも[ツール]→[マクロ]→[マクロ]メニューで、マクロ実行ダイアログを開いているのも面倒ですし、何より実際に使うことを考えれば、マクロ実行アクションが直感的に解りやすいことが求められます。ここではメニューバーに[Nonogram]メニューを追加し、そこから[新規作成]コマンドを実行できるようにします。

メニューバーを操作する

ここで目指すのは[ファイル]とか[編集]とか並んでいるコマンドメニューの右端に[Nonogram]を追加し、それをクリックすると[新規作成]を選択することができて、その結果サイズ入力ダイアログが開くようにすることです。これも数式バー非表示処理などと同様に‘Nonogram.xls’ブックがアクティブなときにのみ[Nonogram]コマンドが現れるようにしたいので、ブックのアクティブ/非アクティブイベントからの処理プロシージャ呼出しとなります。

メニューの追加と削除

ExcelVBAでは、メニューバーやツールバー、右クリックメニューなど総てCommandBarオブジェクトとして扱われています。変更を加えようとしているのはCommandBarsコレクションの中でWorksheet Menu Barという名前を持つメニューバーです。これにAddメソッドで[Nonogram]コントロールを追加するという流れになります。NonoModuleに以下のプロシージャを追加して下さい。


Sub NonoMenuAdd()
' メニュー追加
  Dim MenuBar As CommandBar                       'メニューバーオブジェクト
  Set MenuBar = Application.CommandBars("Worksheet Menu Bar")
  If MenuBar.FindControl(Tag:="Nonogram") Is Nothing Then
    With MenuBar.Controls.Add(Type:=msoControlPopup)
      .Caption = "Nonogram(&N)"                   'メニュー追加
      .Tag = "Nonogram"
      With .Controls.Add                          'コマンド追加
        .Caption = "新規作成(&N)"
        .OnAction = "NonoModule.FieldSizeDialog"
        .FaceId = 18
      End With
    End With
  End If
  Set MenuBar = Nothing                           'オブジェクト変数開放
End Sub

オブジェクト変数MenuBarはメニューバーオブジェクトを示しています。この中にCaptionNonogram(&N)TagNonogramであるコントロールを追加し、更にその下に新規作成(&N)というCaptionFieldSizeDialogを呼出すコントロールを追加します。FaceIdというのはコマンドの左側に現れるアイコンで、どのようなモノがあるか調べてみるとなかなか楽しいですよ。そしてこのコントロール追加処理はTagNonogramであるコントロールが存在しない場合に限って実行されるようにしています。誤ってNonoMenuAddが複数回呼出された場合のホケンです。


Sub NonoMenuDel()
' メニュー削除
  Dim MenuBar As CommandBar                       'メニューバーオブジェクト
  Set MenuBar = Application.CommandBars("Worksheet Menu Bar")
  If Not MenuBar.FindControl(Tag:="Nonogram") Is Nothing Then
    MenuBar.Controls("Nonogram(&N)").Delete       'シートメニュー削除
  End If
  Set MenuBar = Nothing                           'オブジェクト変数開放
End Sub

メニューを削除する時も対象となるコントロールの存在を確認した上でNonogram(&N)コントロールを消去しているのですが、これはコントロールへのDeleteメソッドではなく、メニューバーに対するResetメソッドでも、同じようにNonogram(&N)コントロールは削除されます。Resetメソッドの実行なら、対象コントロールの存在を確認する必要は無くなりコードが簡単になりますが、もし他のプロジェクトなどによってメニューバーがカスタマイズされている場合に、それも削除されてしまいます。つまり「他のプロセスに迷惑をかけない」ためのひと手間ですね。

ブック切替時に自動で追加/削除

マクロ実行ダイアログでNonoMenuAddを実行すれば[Nonogram]メニュー追加、NonoMenuDelを実行すれば[Nonogram]メニューが削除されます。[Nonogram]メニューから[新規作成]をクリックするとサイズ設定ダイアログが開き、数値を設定すればロジックシートが作成されます。次はこれをマクロ実行ではなくブックアクティブ時に追加、非アクティブ時に削除するためのコード編集です。


Private Sub Workbook_Activate()
' ブックアクティブイベント
  NonoModule.SystemSheetDisable                   'システムシート非表示
  With Application                                'オプション情報取得
    FormulaBarSetting = .DisplayFormulaBar
    CellMoving = .MoveAfterReturn
    CellMoveDirection = .MoveAfterReturnDirection
  End With
  With Application                                'オプション情報設定
    .DisplayFormulaBar = False
    .MoveAfterReturn = False
  End With
  With ActiveWindow                               'シートオプション設定
    .DisplayHeadings = False
    .DisplayWorkbookTabs = False
  End With
  NonoModule.NonoMenuAdd                          'メニュー追加
End Sub

Private Sub Workbook_Deactivate()
' ブック非アクティブイベント
  With Application                                'オプション情報復元
    .DisplayFormulaBar = FormulaBarSetting
    .MoveAfterReturn = CellMoving
    .MoveAfterReturnDirection = CellMoveDirection
  End With
  NonoModule.NonoMenuDel                          'メニュー削除
End Sub

NonoMenuAddNonoMenuDelをイベントプロシージャから呼出すことにより、自動的に[Nonogram]メニューの追加と削除が行われるようになりました。今後メニューバーに対してコマンドの追加があれば、NonoMenuAddプロシージャにコードを足していくようにします。

マクロ実行の抑制

これまで[ツール]→[マクロ]→[マクロ]コマンドで、マクロ実行ダイアログを開いてはマクロを実行してきましたが、実用の際には上記のようなメニューバーやツールバーに実行コードを記述するとか、シート上にコントロールを配置して、そのクリックイベントプロシージャから実行を開始するなどの方法が採られると思います。そうするとマクロ実行ダイアログに実行可能マクロ名が表示され、だれでも自由に任意のプロシージャを起動できてしまう点が「いただけない状況」になってきます。つまりマクロ実行ダイアログには何も表示されず、コード記述者の意図しないプロシージャ実行がされないようにしたくなりますよね。

ここからはマクロ名リストに表示されない方法について考えていきます。

マクロ名のリスト化条件

お気付きとは思いますが[マクロ]ダイアログにマクロ名が表示されるのは標準モジュール内のSubプロシージャだけで、FunctionプロシージャやPropertyプロシージャは実行の対象になりません。このように実行可能マクロのリストにマクロ名が表示されるには、それなりの条件があります。例えば次のようにSubプロシージャをPrivate化すると、リストから外されます。


Private Sub NonoMenuAdd()
' メニュー追加
  Dim MenuBar As CommandBar                       'メニューバーオブジェクト
  Set MenuBar = Application.CommandBars("Worksheet Menu Bar")
  If MenuBar.FindControl(Tag:="Nonogram") Is Nothing Then
    ....

ただしPrivate宣言されたプロシージャはモジュール内でローカルとなってしまい、他のモジュールから利用することができなくなってしまいます。上記NonoMenuAddプロシージャの場合、ThisWorkbook内のブックアクティブイベントから呼出すのでこのテは使えません。

引数を要するプロシージャもリストから外れます。[マクロ]ダイアログから引数を渡す機能がないので、引数を伴う呼出しができないワケです。今回はこの方法で実行可能リストにプロシージャを表示させないようにします。

引数といってもダミー的なものであり、実際に引数がないと実行できない形にする必要はありません。また呼出側もムリに不要な引数を併記するのはつまらないので、Optionalキーワードを使って「省略可能引数」とします。


Sub NonoMenuAdd(Optional ByVal CallSwitch As Boolean)
' メニュー追加
  Dim MenuBar As CommandBar                       'メニューバーオブジェクト
  Set MenuBar = Application.CommandBars("Worksheet Menu Bar")
  If MenuBar.FindControl(Tag:="Nonogram") Is Nothing Then
    ....

これでCallSwitchというダミーの引数を設定できました。NonoMenuAddプロシージャはマクロ実行ダイアログには表示されなくなり、またNonoMenuAddを呼出す部分は今のままで問題ありません。

それではNonoModule内の総てのプロシージャに引数追記を行っておきましょう。


Sub NonoMenuDel(Optional ByVal CallSwitch As Boolean)
' メニュー削除
  Dim MenuBar As CommandBar                       'メニューバーオブジェクト
  Set MenuBar = Application.CommandBars("Worksheet Menu Bar")
  If Not MenuBar.FindControl(Tag:="Nonogram") Is Nothing Then
    ....

Sub SystemSheetDisable(Optional ByVal CallSwitch As Boolean)
' システムシート非表示
  NonoWorksheet.Activate                          'ロジックシートアクティブ
  SystemWorksheet.Visible = xlSheetVeryHidden     'システムシート非表示
End Sub

Sub SystemSheetEnable(Optional ByVal CallSwitch As Boolean)
' システムシート表示
  With SystemWorksheet                            'システムシート表示
    .Visible = xlSheetVisible
    .Activate
  End With
End Sub

Sub FieldSizeDialog(Optional ByVal CallSwitch As Boolean)
' フィールドサイズ設定ダイアログ
  NonoModule.SystemSheetDisable                   'システムシート非表示
  With ActiveWindow                               'シートオプション設定
    .DisplayHeadings = False
    ....

Sub NewLogicSheet(Optional ByVal CallSwitch As Boolean)
' 新規ロジックシート作成
  Dim FieldX As Integer                           'フィールドサイズ
  Dim FieldY As Integer
  Dim HintX As Integer                            'ヒントサイズ
    ....

これで[マクロ]ダイアログから実行できるプロシージャはなくなりました。つまりユーザーが勝手に任意のマクロを実行するコトがなくなり、制作者の意図したアクションを取らない限りVBAコードは実行されないようになったワケです。今後プロテクトなどを組合わせれば、使用者にはマクロ名などを殆ど不可視とすることも可能です。

← 前へ   → 次へ ▲ ページトップ