三流君 ken3のmemo置き場

三流プログラマーのメモ書きです。主にVBAやWindowsの話題が多いです

挨拶・自己紹介:
失敗続きのAB型の変わり者 :三流プログラマー Ken3です
フリーのエンジニア・個人事業主です・・と書くと聞こえはイイが(それとなくカッコよく聞こえるが)、 現在は小さな案件の受注請負 と 短期派遣 で 日々つつましく?ほそぼそと暮らしてます。

よく検索されるキーワード: [質問回答XXXXさんへ] [CreateObject] [VBA] [JRA競馬オッズ]

MSAccess VBA WithEvents chk As CheckBox を使ってみた チェックボックスのイベントをクラスモジュールで処理する

要約:Accessフォームに動的に追加されたコントロールで共通のイベントコードを実行する方法を解説。Excel VBAのイベント処理を参考に、Accessチェックボックスに対して単体テストコードを作成し、クラスモジュールを用いてイベントを管理。動的フォーム作成と結合テストを通じて、チェックボックスのイベント操作を実演。

キーワード: #MSAccess #VBA #イベント処理 #チェックボックス #クラスモジュール #WithEvents #フォームイベント #コントロール

目次
00:00 0.やりたいこと:
01:18 1.似ている処理を紹介する
2.単体のテストコードを作成する
02:55 2.1 クラスモジュールを作成 名前はClass1と安易に付ける
06:09 2.2 テスト用の フォーム1 にコードを書く
08:00 2.3 イミディエイトの表示でコードの実行とタイミングを確認する
13:42 再度WithEventsのコードを軽く説明する
3.結合テスト Accessフォームでコントロールを動的追加後に単体テストコードを組み込む
15:46 3.1 メインフォームから動的フォームを作る
20:05 3.2 クラスモジュールを作成 名前はClassChkBoxと安易に付ける
22:16 3.3 フォームのForm_Current レコード移動時で、チェックボックス(のイベント)に細工する
3.4 タイミングが取れているか?チェックする
27:37 3.5 CheckBox Clickのイベントに固定のコードを書く おいおい
30:19 総合・結合テスト


0.やりたいこと:
https://youtu.be/7HKggrix5n4
Accessのフォームに作成した(動的追加した)
コントロールで共通のイベントコードを走らせたい、
そんな処理にチャレンジしてみます。

知恵袋の質問:
detail.chiebukuro.yahoo.co.jp

1.似ている処理を紹介する
Excel VBA グラフ選択時のイベント処理を探る クラスモジュールにWithEvents As Chartを書きイベント取得
解説動画:
https://www.youtube.com/watch?v=5Z6P4RldTsw&list=PL8vZhsyiiFht0NNHTC-4DdjsYls8KCcep
ソースコード:
ken3memo.hatenablog.com


2.上記を参考にして、単体のテストコードを作成する

ExcelのグラフとAccessチェックボックスが違うところ、
OnClick : "[Event Procedure]"が無いと、イベントが走らなかったり
(
ウォッチ式で不思議な文字列 String型を確認
: OnClick : "[Event Procedure]" : String : Form_フォーム1.Form_Current
)

とりあえず、固定の動かないフォームで単体テストする

2.1 クラスモジュールを作成 名前はClass1と安易に付ける
02:55 https://www.youtube.com/watch?v=7HKggrix5n4&t=175

Public WithEvents chk As CheckBox

Private Sub chk_Click()
    Debug.Print chk.Name & " チェックボックスのクリックイベント"
End Sub

Private Sub chk_Enter()
    Debug.Print chk.Name & "チェックボックスの_Enterイベント"
End Sub

2.2 テスト用の フォーム1 にコードを書く
06:19 https://www.youtube.com/watch?v=7HKggrix5n4&t=369

Private objChkBox(100) As New Class1  '100個のchkbox、違うな書き方が・・

Private Sub Form_Current()
    Debug.Print "Form_Current レコード移動時"
    'コントロールのセット
    Dim Con As Control
    Dim i As Long
    
    i = 0
    For Each Con In Me.Controls
        Debug.Print Con.Name
        If Con.Name <> "全協定" Then
            If TypeName(Con) = "CheckBox" And Right(Con.Name, 2) = "協定" Then
                i = i + 1
                Con.OnClick = "[Event Procedure]"  'イベントを発生させるおまじない※これないとダメ?
                Set objChkBox(i).chk = Con
                Debug.Print "set"
            End If
        End If
    Next
End Sub

Private Sub Form_Load()
    Debug.Print "Form_Load"
End Sub

Private Sub Form_Open(Cancel As Integer)
    Debug.Print "Form_Open"
End Sub

2.3 イミディエイトの表示でコードの実行とタイミングを確認する
08:00 https://www.youtube.com/watch?v=7HKggrix5n4&t=480

チェックボックスをクリックして、動作を確認する

こんな感じて、コントロールのイベントをクラスモジュールに書くことができます。


3.結合テスト Accessフォームでコントロールを動的追加後に単体テストコードを組み込む

知恵袋の質問:(※勝手に改行位置変更)
https://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q10299103690

>生成はF_メインのbtn_更新作業クリック時に行っています。

>各協定名チェックボックスは、更新作業時に協定名で対象を絞るためのものですが、
>協定は増減があり、また、使用状況も変更が多いため、動的に生成しています。

>全協定を一括選択するためにchk_全選択というチェックボックスも設置(これは固定)し、

>全協定のチェックボックスのON/OFFを切り替えるのですが、
>全協定をON(=各協定チェックボックスがON)にした後、
>各協定のチェックボックスを触ったときに、
>全協定チェックボックスをOFFにしたいのですが、うまく行きません。

>フォントサイズや色等は生成時に設定できたのですが、
>「クリック時:chk_全協定.Value=False」はどこにどう書けば設定できるか教えてください。
>=========================================
>■全協定
>■A協定 □B協定 □C協定
>□D協定 ■E協定
>=========================================
>解りづらいですが、↑のような状態になるのを避けるのが目的です。
>よろしくお願いいたします。

3.1 メインフォームから動的フォームを作る
15:46 https://www.youtube.com/watch?v=7HKggrix5n4&t=946

まぁ、いろいろやり方あるけど、
メインフォームから、
動的のサブ登録フォームを作成してみます

チェックボックスとラベルをCreateControlで作成する

名前 値 説明
acCheckBox 106 CheckBox コントロール
acLabel 100 Label コントロール

Private Sub btn_MAKETEST_Click()
    '登録フォームをデザインモードで開き、チェックボックスを作る
    
    'デザインモードで開く
    DoCmd.OpenForm "登録フォーム", acDesign
    
    'CreateControl の ヘルプからコードをコピーして作成。
    '名前    値  説明
    'acCheckBox  106 CheckBox コントロール
    'acLabel 100 Label コントロール
    
    Dim ctlCheckBox As CheckBox  'チェックボックスのコントロール
    Dim ctlLabel As Label        'ラベルのコントロール
    
    Dim intDataX As Integer, intDataY As Integer

    ' 新しいコントロールの位置を設定します。
    intDataX = 1000
    intDataY = 2000
    
    Dim n As Integer
    
    '先に chk_ lab_のコントロールを消す
    'コントロールの数を知るには Forms("フォーム名").Controls.Count
    Dim strNAME As String
    For n = Forms("登録フォーム").Controls.Count - 1 To 0 Step -1
        '消すには、 DeleteControl "フォーム名", "コントロール名"
        strNAME = Forms("登録フォーム").Controls(n).Name '対象のコントロール名
        '後ろ2文字が協定のコントロールを消す、ただし全協定は残す。
        If Right(strNAME, 2) = "協定" And Right(strNAME, 3) <> "全協定" Then
            'コントロールを消す
            DeleteControl "登録フォーム", strNAME
        End If
    Next
    
    'チェックボックスとラベルを付ける
    For n = 1 To Me.項目数  'メニューの項目数分テストで作成する
        'チェックボックスを、詳細セクションに作成します。
        Set ctlCheckBox = CreateControl("登録フォーム", acCheckBox, , "", "", _
            intDataX, intDataY)
    
        '上↑作成したテキストボックスに名前 chk_A協定 を付けたり
        ctlCheckBox.Name = "chk_" & Chr(Asc("A") + n - 1) & "協定"
        ctlCheckBox.DefaultValue = True  'デフォルトでON※非連結なのでテスト用
        
        'ラベルを作成します。↑の名前で関連付ける
        Set ctlLabel = CreateControl("登録フォーム", acLabel, , ctlCheckBox.Name, "", _
            intDataX + 250, intDataY, 900, 400)
        
        ctlLabel.Name = "lab_" & Chr(Asc("A") + n - 1) & "協定"
        ctlLabel.Caption = Chr(Asc("A") + n - 1) & "協定"
        
       'Y位置を増やす
        intDataY = intDataY + 500
        
        '5件でX位置の調整
        If (n Mod 5) = 0 Then
            intDataX = intDataX + 2000  '横移動
            intDataY = 2000  'Y位置を初期に縦位置を戻す
        End If
        
    Next

    MsgBox "動的にチェックボックスを作成終了"

    'フォームを閉じる
    DoCmd.Close acForm, "登録フォーム", acSaveYes  '保存して閉じる
    
End Sub

Private Sub 登録Fを開く_Click()
    DoCmd.OpenForm "登録フォーム", acNormal
End Sub

その他、関連動画を紹介:
かなり、古い動画ですが少しヘルプを見ながら解説をしています。
テスト ウ. Access フォームにコントロールを動的に追加 QA110318
https://youtu.be/qLKQ9UISxnQ?t=212
↑、こちらも、時間のある時に2倍速で笑ってみてください。
ken3memo.hatenablog.com


3.2 クラスモジュールを作成 名前はClassChkBoxと安易に付ける
20:05 https://www.youtube.com/watch?v=7HKggrix5n4&t=1205

Public WithEvents chk As CheckBox  'これで、イベントを取得する

Private Sub chk_Click()
    Debug.Print chk.Name & " チェックボックスのクリックイベント"
End Sub

Private Sub chk_Enter()
    Debug.Print chk.Name & "チェックボックスの_Enterイベント"
End Sub

3.3 フォームのForm_Current レコード移動時で、チェックボックス(のイベント)に細工する

22:16 https://www.youtube.com/watch?v=7HKggrix5n4&t=1336

Open,LOAD,後に処理を入れたかったので
(※loadに入れてもいいかも?)

Form_Current レコード移動時のタイミングで、コードを実行します。

'クラスモジュールに付けた名前↓ClassChkBoxを使用する
Private objChkBox(100) As New ClassChkBox  '100個のchkbox、違うな書き方が・・

Private Sub Form_Current()  '非連結のテストなのにね・・
    Debug.Print "Form_Current レコード移動時"
    'コントロールのセット
    Dim Con As Control
    Dim i As Long
    
    i = 0
    For Each Con In Me.Controls
        Debug.Print Con.Name
        If Con.Name <> "chk_全協定" Then
            If TypeName(Con) = "CheckBox" And Right(Con.Name, 2) = "協定" Then
                i = i + 1
                Con.OnClick = "[Event Procedure]"  'イベントを発生させるおまじない※これないとダメ?
                Set objChkBox(i).chk = Con
                Debug.Print "set"
            End If
        End If
    Next
End Sub

Private Sub Form_Load() 'おまけ、タイミング確認用、いつもどれが先か忘れるのは初老?
    Debug.Print "Form_Load"
End Sub

Private Sub Form_Open(Cancel As Integer) 'おまけ、タイミング確認用、いつもどれが先か忘れるのは初老?
    Debug.Print "Form_Open"
End Sub

3.4 タイミングが取れているか?チェックする


3.5 CheckBox Clickのイベントに固定のコードを書く おいおい

27:37 https://www.youtube.com/watch?v=7HKggrix5n4&t=1657

クラスモジュールに、固定のForm操作コードを書く

>「クリック時:chk_全協定.Value=False」はどこにどう書けば設定できるか教えてください。

Forms![登録フォーム]![chk_全協定].Value=False
をクラスモジュールへ

Option Compare Database
Option Explicit

Public WithEvents chk As CheckBox  'これで、イベントを取得する

Private Sub chk_Click()
    Debug.Print chk.Name & " チェックボックスのクリックイベント"
    Forms![登録フォーム]![chk_全協定].Value = False
    
End Sub

コードの動作を確認する
30:19 https://www.youtube.com/watch?v=7HKggrix5n4&t=1819

4.おわりの挨拶

こんな感じて、
チェックボックス(※他のコントロールも)
のイベントをクラスモジュールにかけるので、
使ってみてください。

再生リストの紹介: WithEvents VBA マクロ イベント処理
https://www.youtube.com/playlist?list=PL8vZhsyiiFht0NNHTC-4DdjsYls8KCcep
↑似た処理があるので、お時間のある時に動画を見て笑って(ツッコんで下さい)

Ken3 ホームページ 目次

分類:HPを大きく分けると4つの柱(分類)です。

  1. [VBA・マクロ プログラミング]の解説
    当店の人気はVBA系のCreateObject("XXXXXX.application")で他のアプリケーションを操作するサンプルが人気です
  2. [プログラマーの愚痴]では、あまり見せたくない三流プログラマーの内面かな。
    三流君を踏み台にする
  3. [古いクラシック ASP(Active Server Pages)]の解説。
  4. [元コンビニ店長時代の話]が弟に巻き込まれ、失敗した脱サラ、畑違い?の仕事で失敗。
主に上記4つの分類でHP作成やメルマガの発行を行ってます。
※更新頻度が落ちていて情報の鮮度が悪いです。



本当に三流なんです(笑):たまにスゴイですねなんて言われることもありますが、
真実は→ [三流君の真実は...] ←を初めに見てくださるとわかると思います。
(からくりは、成功例↑しか載せてなくて ヒドイ失敗例はお蔵入り迷宮入りが多かったりします)