【Excel VBA入門】チェックボックスの判定とマクロの連動

入門編最終回になります。今回はチェックボックスのON/OFFを判定して、それぞれに処理を連動させるマクロを作成します。チェックボックスとはダイアログ等で見るアレの事です。

コレの事です。

普通のボタンと違ってONとOFFの状態が判るのが利点です。制御はそんなに難しくありません。最後まで読んでチェックボックスを実装しましょう。

目次

覚える用語

For Each~Nextステートメント

いわゆる「ループ処理」です。記述した内容を繰り返し処理してくれる命令文です。

If Thenステートメント

エクセルのIF関数と同じような処理です。条件式のTrue、Falseを判定し、分岐処理します。

準備

今回はエクセルの名前の定義を利用するので適当な範囲を定義して下さい。本記事では別記事のカレンダーをサンプルにしています。

数式タブの名前の定義をクリックするとダイアログが現れます。

名前を付け、参照範囲を設定して下さい。サンプルは月曜としています。

サンプルはカレンダーの月曜部分を月曜と定義していますが、皆さんがテストする分には適当な範囲で構いません。

ただし、今回はループ処理を使用するので範囲がある程度あった方がマクロの動きが分かりやすいと思います。

チェックボックスでON/OFFを判定し、書式変更を連動させる

仕様

  • チェックボックスオンで定義した範囲全てを「赤字」「太字」「下罫線(赤)」に変更する
  • チェックボックスオフで元の書式に戻す

チェックボックスの作成

チェックボックスにはフォームコントロールActiveXコントロールの2種類がありますが、違いについての詳細はここでは紹介しません。マクロを割り当てるにはActiveXコントロールを使用します

フォームコントロールでもボタンだけはマクロの実行を割り当てる事はできます。ボタン以外はセルの値を変化させる事しかできません。

開発タブの挿入アイコンをクリックします。

ActiveXコントロールチェックボックスをクリックします。

適当な場所でドラッグするとチェックボックスが現れます。

デザインモードアイコン→チェックボックスを右クリックプロパティと進み、現れたプロパティウィンドウCaption欄を付けたい名前に変更します。

これでチェックボックスの見た目は完成です。先述のフォームコントロールとの違いですが、ActiveXコントロールプロパティで見た目の変更ができます。

色を付けたいとか書式を変更したいのであればプロパティを適当にいじって遊んでみて下さい。

サンプル入手

チェックボックスで実行する処理を作成します。名前の定義を利用しているので「VBA 複数範囲 名前の定義」で検索しました。このサイトのサンプルを頂戴します。

名前が月曜で定義されている場合は、Range(“月曜”)で参照できそうです。何やら見慣れぬ記述もありますがとりあえず動かしてみます。

Module1(標準モジュール)

Sub テスト1()
    Dim rng As Range

    For Each rng In Range("月曜")
        MsgBox rng.Value
    Next rng

End Sub

定義した範囲が次々とダイアログで表示されます。For Each ~ Nextステートメントの処理によるものです。

For Each ~ Nextステートメント

構文

さっそくOfficeリファレンスを覗いてみます。

For Each…Next ステートメントを使用する

For Each…Next ステートメントは、コレクション内の オブジェクトごと、または 配列内の要素ごとに、ステートメントのブロックを繰り返します。 ループを実行するたびに、Visual Basic によって変数が自動的に設定されます。

https://docs.microsoft.com/ja-jp/office/vba/language/concepts/getting-started/using-for-eachnext-statements

相変わらず難読です。マーカーで色付けされている部分をサンプルに当てはめるとそれぞれ

コレクション内のオブジェクトごと、または配列内の要素ごと

Range(“月曜”)

ステートメントのブロック

MsgBox rng.Value

変数

rng

となります。逆にサンプルへ説明文をあてはめるとこうなります。

Sub テスト1()
    Dim 変数 As Range

    For Each 変数 In コレクション内のオブジェクト
        ステートメントのブロック(2行以上あってもOK)
    Next 変数

End Sub

処理の流れ

用語と2行目は現時点では無視して下さい。その内覚えます。今回は処理の流れだけ把握しましょう。処理の流れは次の通りです。説明用に月曜の範囲をセルA1,B1,C1とします。

Sub テスト1()
'セル"A1","B1","C1"が「月曜」で[名前の定義]されている
    Dim rng As Range

    For Each rng In Range("月曜")
        MsgBox rng.Value
    Next rng

End Sub
処理
コレクション内のオブジェクトを変数に代入する

5行目 /ループ1回目 …月曜で定義した範囲の先頭A1セルをrngに代入する

処理
ステートメントを実行する

6行目…MsgBox関数を実行する=A1セルに入力された値が表示される

処理
For Eachの行に戻る

7行目…Next rngFor Eachに戻る

処理
コレクション内の次のオブジェクトを変数に代入する

5行目/ループ2回目…B1セルをrngに代入する

処理
STEP2、STEP3を実行する

コレクション内のオブジェクトが無くなるまでこの流れを繰り返します

For Each ~ NextステートメントForNextに挟まれている処理を繰り返す訳です。オブジェクトの数だけ繰り返します。これから嫌というほどこのステートメントを使うことになります。今回は記述方法や付帯する用語は無視して、処理の流れをつかみましょう。

マクロに取り組んだのは、こういったエクセル関数や標準機能では実現できない処理をやりたかったからです。それを実感させてくれるステートメントです。

1行目のDim rng As Rangeですが、変数です。VBAを理解する上で非常に重要なポイントになりますが、今回は潔く無視しましょう。

サンプルを編集する

前回記事で作成した書式変更コードをそのままサンプルに入れ込みました。キャンセルするコードも一緒に作成しました。

Module1(標準モジュール)

Sub 月曜日書式変更オン()
    Dim rng As Range '変数宣言
    For Each rng In Range("月曜") '「月曜」で定義された範囲を取得
            With rng.Borders(xlEdgeBottom) '書式変更_下罫線
                .color = vbRed
                .Weight = xlMedium
            End With
            With rng.Font '書式変更_太赤字
                .color = vbRed
                .Bold = True
            End With
    Next rng '書式変更を取得した範囲まで繰り返す
End Sub

Sub 月曜日書式変更オフ()
    Dim rng As Range '変数宣言
    For Each rng In Range("月曜") '「月曜」で定義された範囲を取得
            rng.Borders(xlEdgeBottom).LineStyle = xlLineStyleNone '罫線を消す
            With rng.Font '書式_黒色、太字キャンセル
                .color = vbBlack
                .Bold = False
            End With
        Next rng '書式変更を取得した範囲まで繰り返す
End Sub

マクロ月曜日書式変更ONを実行すると、月曜で定義した範囲が全て、書式変更されました。月曜日書式変更OFFを実行すると元の書式に戻りました。

(マクロ実行のショートカットはAlt+F8

おおよそ狙った動きにはなりましたが、一部想定外の部分があるので修正していきます。

  • 日付が入っていない空白部分も下罫線が変更される
  • 1セルずつ変更される様子が描画される(見た目が遅そうで嫌)

If~Thenステートメント

日付が入っていない空白部分の対策は、「空白ではない場合処理をしない」で何とかなりそうです。「VBA セルが空白でなかったら」で検索します。

もし〜ならの書き方が If 条件式 Thenなので

If Range(“A1”).Value <> “” Then

https://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q10146188485

Ifはエクセル関数にあるので何となく判りますね。ちなみにこのIf~Thenステートメント、1行で記述できる場合はEnd Ifは省略できます。

Application.ScreenUpdating

1セルずつ変更される様子を描画しないように、「VBA 描画を止める」で検索しました。

Application.ScreenUpdatingプロパティで画面の更新を止められるようです。Officeリファレンスも覗いてみましょう。

マクロの速度を向上させるため、画面を更新しないようにします。 この場合、マクロの処理過程は見ることができませんが、実行速度が速くなります。マクロが終了した後は、ScreenUpdating プロパティの値を True に戻してください。

https://docs.microsoft.com/ja-jp/office/vba/api/excel.application.screenupdating
Application.ScreenUpdating = True '画面を更新をする
Application.ScreenUpdating = False '画面を更新をしない

先ほどのサイトではこの「Application.ScreenUpdatingを勘違いして乱用しても早くならない」と教えてくれています。

ネットで色々なサンプルを見てきて思ったのですが、おまじないとしてApplication.ScreenUpdatingを書いてる人がたくさんいます。中には「問答無用の呪文」みたいな紹介をしているところもあったりします。「乱用しても早くならない」はそういう人達へのメッセージでしょう、きっと。

If Thenステートメントといっしょにサンプルへ記述します。

Sub 月曜日書式変更オン()
Dim rng As Range
Application.ScreenUpdating = False '画面の更新を止める
    For Each rng In Range("月曜")
        If rng.Value <> "" Then 'もし定義した範囲が空白でなかったら
            With rng.Borders(xlEdgeBottom)
                .color = vbRed
                .Weight = xlMedium
            End With
            With rng.Font
                .color = vbRed
                .Bold = True
            End With
        End If
    Next rng
Application.ScreenUpdating = True '画面の更新をする
End Sub

Sub 月曜日書式変更オフ()
Dim rng As Range
Application.ScreenUpdating = False
    For Each rng In Range("月曜")
        rng.Borders(xlEdgeBottom).LineStyle = xlLineStyleNone
        With rng.Font
            .color = vbBlack
            .Bold = False
        End With
    Next rng
Application.ScreenUpdating = True
End Sub

空白セルは罫線が引かれなくなり、1セルずつ処理される様子も映らなくなりました。

Application.ScreenUpdating = Trueがなくても、プロシージャ終了時に自動でTrueにしてくれます。が、必ず同一プロシージャ内でTrueを設定しましょう(厳密には描画を止める必要がなくなった時点)。「変えたら戻す」のクセを付けておいたほうが吉です。

チェックボックスの判定とマクロの連動

作成したマクロを実行するのにイベントが使えそうです。当然、チェックボックスをトリガーにしますが、前々回の記事の流れでとりあえずSheetモジュールを覗いてみます。

モジュール内にちゃんとCheckBox1がありました。Clickイベントも用意されています。

ここに呼び出すSubプロシージャを書いてやれば解決、とはいきませんでした。チェックボックスのON/OFF判定の仕方がわかりません。結局、「VBA チェックボックス Subプロシージャ実行」でググります。

Private Sub CheckBox1_Click()
    If CheckBox1.Value Then
        'Trueのときの処理または、Call 処理1
    Else
        'Falseのときの処理または、Call 処理2
    End If
End Sub 
https://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q1197144376 

何となくわかるんですけど、これって省略されてね?って事でもうちょっと調べてみると別の書き方がありました。

Private Sub CheckBox1_Click()
    If CheckBox1.Value = True Then 'チェックボックスがオンの時
        Call 月曜日書式変更オン 'マクロ "月曜日書式変更ON" を実行する
    Else 'trueでない場合=falseの場合
        Call 月曜日書式変更オフ 'マクロ "月曜日書式変更OFF" を実行する
    End If
    ActiveCell.Activate 'セルをアクティブにする
End Sub

省略しすぎてもわかりにくいので、わかるように書きました。こっちの方がわかりやすい、と思った人は私と同じ勘違いをしているかも知れません。以下重要です。

最初のネットサンプルの記述が正解です。勘違いサンプルも間違いではないですが冗長ですIf Thenステートメントの構文をみてみましょう。

構文

    If 条件式(True or False) Then
        'Trueのときの処理
    Else
        'Falseのときの処理
    End If

私の勘違いの原因は恐らくエクセルのIF関数です。

エクセル関数の場合、「条件式」が「論理式」になることが多いので、「A = B」や「A < B」のように何らかの比較演算子を使います。その習慣でCheckBox1.Value Thenに違和感を覚え、CheckBox1.Value = True Thenと記述してしまいました。

CheckBox1.Valueはチェックが入っていればTrue、なければFalseを返します(要は条件式に比較演算子が入らない)。勘違いサンプルにあてはめるとそれぞれTrue = True、またはFalse = Trueと記述している事になります。

「冗長でも間違いではないからいい、分かりやすい方がいい」と意固地になる方はそれでも構いませんが、今後VBAを続けていくとこの条件式の中にNotを入れるケースに出会うと思います。冗長記述に慣れている状態で、このNotが入ってくると混乱に輪をかけます。

条件式が返す値がTrue or Falseの場合は= True(False)と記述しないことをおすすめします。

Private Sub CheckBox1_Click()
    If CheckBox1.Value Then 'チェックボックスがオンの時
        Call 月曜日書式変更オン 'マクロ "月曜日書式変更ON" を実行する
    Else 'チェックボックスがオフの時
        Call 月曜日書式変更オフ 'マクロ "月曜日書式変更OFF" を実行する
    End If
End Sub

また、Call~ですが、以前の記事でマクロ実行はOnActionを使用しました。何が違うのでしょうか。

  • CallCallステートメント
  • OnActionOnActionプロパティ

プロパティオブジェクトの情報を取得・設定する、Callステートメントだから命令文、うーん、まだ難しいですね。

ただ、オブジェクト.プロパティみたいな感じでコードを書けばマクロが動くのはなんとなく身についてきたのではないでしょうか?とりあえずエラーが出たらググって直してを繰り返していけばオブジェクトプロパティもその内理解できます。今はわからなくても全く問題ありません。「動けばいい」んです。

完成

今回の出来高です。

Sheet1(シートモジュール)

Private Sub CheckBox1_Click()
    If CheckBox1.Value Then
        Call 月曜日書式変更オン
    Else
        Call 月曜日書式変更オフ
    End If
    ActiveCell.Activate
End Sub

Module1(標準モジュール)

Sub 月曜日書式変更オン()
Dim rng As Range
Application.ScreenUpdating = False
    For Each rng In Range("月曜")
        If rng.Value <> "" Then
            With rng.Borders(xlEdgeBottom)
                .color = vbRed
                .Weight = xlMedium
            End With
            With rng.Font
                .color = vbRed
                .Bold = True
            End With
        End If
    Next rng
Application.ScreenUpdating = True
End Sub

Sub 月曜日書式変更オフ()
Dim rng As Range
Application.ScreenUpdating = False
    For Each rng In Range("月曜")
        rng.Borders(xlEdgeBottom).LineStyle = xlLineStyleNone
        With rng.Font
            .color = vbBlack
            .Bold = False
        End With
    Next rng
Application.ScreenUpdating = True
End Sub

チェックボックスのオンオフでマクロが実行できるコードが完成しました。

前回前々回と今回で入門編として3つのマクロを作成してきました。その中で3つのステートメントWithステートメントFor Each NextステートメントIf Thenステートメント)について触れてきました。

これらのステートメントを何となく知っていれば、今後Web上で出会うサンプルもある程度読めると思います。難しい用語は抜きにして、まずはたくさんのサンプルに触れ、動かして、編集するといった作業を積み重ねましょう。各ステートメントの記述方法(文法)は何回も書けば覚えられます。忘れたらまたググればいいだけの話です。

VBA入門で重要なのは、簡単な処理でもいいので「動くマクロを作成すること」です(私見)。知識だけではマクロは動きません。

サンプルにある程度触れた後(=VBAにある程度慣れた後)で以下の2記事を読めばより理解が深まると思います。

よかったらブックマークとシェアをお願いします。最後までご高覧いただきありがとうございました。

よかったらシェアしてください
URLをコピーする
URLをコピーしました!
目次へ
トップへ
目次
閉じる