【Excel VBA入門】チェックボックスの値を取得、ON/OFF判定とマクロの連動

アイキャッチ

CheckBox1.ValueCheckBoxオブジェクトValueプロパティを取得します。ONならTrue、OFFならFalseを返します。

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

チェックボックスの画像。クリックすると枠内にレ点が入ります。

コレの事です。

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

目次

覚える用語

For Each~Nextステートメント

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

If Thenステートメント

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

準備

今回はエクセルの名前の定義を利用するので適当な範囲を定義して下さい。本記事では年間カレンダーをサンプルにしていますが、サンプルは何でも構いません。皆さんがチェックボックスを実装したいファイルを利用して、適宜読み替えてください。

名前の定義設定ダイアログの画像。詳細は以下。

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

名前を定義する様子。詳細は以下。

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

サンプルはカレンダーの月曜部分を月曜と定義していますが、皆さんがテストする分には適当な範囲で構いません。ただし、今回はループ処理を使用するので範囲がある程度あった方がマクロの動きが分かりやすいと思います。

チェックボックスの値を取得、ON/OFFを判定して書式変更を連動させる

チェックボックスに連動する処理の内容

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

チェックボックスの作成

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

フォームコントロールでもボタンだけはマクロの実行を割り当てる事ができます。ボタン以外はセルの値を変化させる事しかできません。VBAの処理を連動させるにはActvieXコントロールを使用しましょう。

コントロール挿入方法の説明画像。詳細は以下。

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

ActiveXコントロールのチェックボックスを選択する様子。詳細は以下。

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

チェックボックスを設置した様子。詳細は以下。

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

チェックボックスのプロパティを設定する様子。詳細は以下。

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

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

色を付けたい等、書式を変更したいのであればプロパティを適当にさわってください。

ユーザーフォーム内に作成したチェックボックスも同じCheckBoxオブジェクトです。同様に操作できます。

名前の定義でオブジェクトを参照するサンプル

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

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

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 rngで5行目のFor Eachに戻る

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

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

処理
処理2、処理3を実行する

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

End Sub

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

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

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

サンプルを編集する

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

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 描画を止める」で検索しました。

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モジュールを覗いてみます。

SheetモジュールでCheckBoxオブジェクトを選択する様子。詳細は以下。

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

  • チェックボックスON→Sub 月曜日書式変更オン()を実行
  • チェックボックスOFF→Sub 月曜日書式変更オフ()を実行

これらをClickイベントで実行するようにします。

「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 

CheckBox1.ValueCheckBoxオブジェクトValueプロパティを取得しています。ONならTrue、OFFならFalseを返します。

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

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が入ってくると混乱に輪をかけます。

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

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

チェックボックスの値を取得、ON/OFFを判定してマクロと連動させるコード

今回の出来高です。

Private Sub CheckBox1_Click()
    If CheckBox1.Value Then
        Call 月曜日書式変更オン
    Else
        Call 月曜日書式変更オフ
    End If
    ActiveCell.Activate
End Sub
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

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

チェックボックスの判定をする上で、2つのステートメント(For Each NextステートメントIf Thenステートメント)について触れてきました。

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

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

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

よかったらシェアしてね!
  • URLをコピーしました!
目次