[Excel]VBAでチェックボックスを利用する

エクセル

今回はチェックボックスに書式変更できる機能を実装します。チェックボックスとはエクセルの書式設定ダイアログ等で見るアレの事です。

チェックボックス見本

コレの事です。

普通のボタンと違ってオンとオフの状態が判るのが利点です。チェックを入れたら書式変更、外したら書式を戻す、という仕様にします。

準備

今回はエクセルの「名前の定義」を利用するので適当な範囲を定義して下さい。

名前の定義ダイアログ

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

名前の定義を設定する

名前を付け、参照範囲を設定して下さい。

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

チェックボックスで書式を変更する

仕様

  • チェックボックス「オン」でカレンダーの月曜日全てを「赤字」「太字」「下罫線(赤)」に変更する
  • チェックボックス「オフ」で元の書式に戻す

チェックボックスの作成

チェックボックスには「フォームコントロール」と「ActiveXコントロール」の2種類がありますが、違いについて興味のある方は以下のサイトを読んで下さい。

フォームの場合、ボタンはマクロの実行ができますが、ボタン以外(チェックボックスも含まれます)はマクロの実行ができないので今回はActiveXコントロールを使用します。「なんで?」なんて事考えてたら手が止まるので考えないように。

ActiveXコントロール挿入

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

チェックボックス選択

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

チェックボックス出現

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

ActiveXプロパティウィンドウ

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

これでチェックボックスの見た目は完成です。先述のフォームコントロールとの違いですが、ActiveXコントロールはプロパティで見た目の変更ができます。色を付けたいとか書式を変更したいのであればプロパティを適当にいじって遊んでみて下さい。

For Each ~ Nextステートメント

では、コードを書いていきますサンプルを拾ってきます。なかなかヒットしませんでしたが、以下のワードで目的のコードに辿り着けました。

チェックボックスで書式変更

Sub monday_set()
    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 monday_cancel()
    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

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

マクロ実行失敗

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

すごい、すごいですよFor Each ~ Nextステートメント。これは便利ですね。このステートメントの中に書かれたコードを繰り返し実行してくれる訳です(繰り返す回数は今回の場合、「月曜」で定義された範囲全て)。先ほどのサイトにFor ~ Next(Eachがない)ステートメントのサンプルもありましたが、今回のケースはFor Each ~ Nextでよさそうです。しかしFor ~ Nextも今後お世話になりそうな予感なので、 「For~ は2種類ある」 と頭の片隅に置いておきましょう。

このサンプルを拾ってきた直後はFor Each rng In Range(“月曜”)の部分が何をやっているのかよくわかりませんでした。別のコードを書き進めていく内になんとなく理解していった感じです。繰り返す事で理解できるケースもあるので、わからなくても「動けばいい」の精神でいきましょう。

Dim rng As Rangeですが、ズバリ「変数」です。この「変数」もFor文同様に理解せずにVBAをいじりまわしていましたが、最近ちょっと理解できてきた感じです。調べてもよくわからなかった事が使っているうちになんとなく理解できるその2ですね。合言葉は「動けば(ry

If ~ Thenステートメント

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

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

1番目は「セルが空白でなかったらコードを実行する」でなんとかなりそうな予感。2番目は…ググればなんとかなるさ(毎度適当)。

こんなワードでヒットさせてくれるGoogleは素敵です。

もし〜ならの書き方が 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

続いて2番目ですが、なかなかヒットしません。やっとの思いで辿り着いたこのワードでヒットしました。

このサイトではこの「Application.ScreenUpdatingを勘違いして乱用しても早くならないよ」と教えてくれていますが、今回のケースは使ってもいいよね?間違ってないよね?(独り言)

空白無視、描画ストップ


Sub monday_set()
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 'If ~ Thenが1行で記述できる場合は省略可能
    Next rng
Application.ScreenUpdating = True ’画面描画
End Sub

Sub monday_cancel()
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を使わないようにしましょう(教え)。

Application.ScreenUpdating = Trueを忘れると、描画が止まったままになります。必ず同一プロシージャ内でTrueを設定しましょう。

チェックボックスでマクロを実行する

私も少し慣れてきたのでここからは自力でできそうです。subプロシージャを実行するのにイベントを使用します。当然、チェックボックスをトリガーにしますが、とりあえずWorksheetイベントプロシージャを覗いてみます。

CheckBox Clickイベント

プロシージャ内にちゃんと「CheckBox1」オブジェクトがありました。「Click」イベントも用意されています。

ここに呼び出すsubプロシージャを書いてやれば解決、とはいきませんでした。チェックボックスのオンオフ判定の仕方がわかりません。結局ググります(全然自力でできなかった)。

Private Sub CheckBox1_Click()

If CheckBox1 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 monday_set 'マクロ「monday_set」を実行する
    Else 'trueでない場合=falseの場合
        Call monday_cancel 'マクロ「monday_cancel」を実行する
    End If
    ActiveCell.Activate 'セルをアクティブにする
End Sub

省略しすぎてもわかりにくいので、わかるように書きました。始めたばかりの自分にはこれくらい書かないと理解できません。

7行目の「セルをアクティブにする」はマクロ実行後、チェックボックスにフォーカスが残っているのが嫌で追加しました(作業性向上)。また、Call ~ですが、以前の記事でマクロ実行はOnActionを使用しました。何が違うか調べてみました。

  • Call…Callステートメント
  • OnAction…OnActionプロパティ

プロパティはオブジェクトの情報を取得・設定する、Callはステートメントだから命令文、うーん、わかりません(投げやり)。ただ、オブジェクト.プロパティとかオブジェクト.メソッドみたいな感じでコードを書けば動くのはわかってきたかも。とりあえずエラーが出たらググって直してを繰り返していけばステートメントもプロパティもその内理解できると信じています。

完成

今回の出来高です。

Worksheetイベントプロシージャ

Private Sub CheckBox1_Click()
    If CheckBox1.Value = True Then
        Call monday_set
    Else
        Call monday_cancel
    End If
    ActiveCell.Activate
End Sub
subプロシージャ(標準モジュール内)

Sub monday_set()
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 monday_cancel()
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

チェックボックスのオンオフでマクロが実行できるコードが完成しました。これも以前紹介した「右クリックメニュー」同様、subプロシージャを書き換えれば色々な機能が実装できるので今後も重宝しそうです。

これで「万年カレンダー」に実装した機能の骨組みは全て紹介できました。初めて本格的にVBAに取り組み、何とか動く機能を実装する事ができましたが、やっと初心者の仲間入りといった所でしょうか。次回は「差し込み印刷」に挑戦したいと思います。実務で役立つ機能に仕上げていきたいと思うので、出来上がった際には是非ダウンロードしてみて下さい。

では、最後までご高覧いただきありがとうございました。

タイトルとURLをコピーしました