質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
VBA

VBAはオブジェクト指向プログラミング言語のひとつで、マクロを作成によりExcelなどのOffice業務を自動化することができます。

Q&A

解決済

1回答

2105閲覧

VBA(Access)におけるイベント実装を機能毎に分割する方法についてご相談です。

kanntyuu

総合スコア2

VBA

VBAはオブジェクト指向プログラミング言語のひとつで、マクロを作成によりExcelなどのOffice業務を自動化することができます。

0グッド

0クリップ

投稿2020/06/26 15:12

編集2020/06/26 15:15

前提・実現したいこと

言語:
VBA(Access2016)

実現したいこと:

  • 1 Access.TextBoxに対して共通のイベント処理を実装したい。
  • 2 機能毎に実装するクラスを分割したい。
    (テキストボックス毎に機能を付け外ししたい)

Access.TextBoxを複数のInterface実装クラスのメンバに持たせ、
その各実装クラスをInterface型の配列に格納すれば
一つのテキストボックスのイベントを同時に拾えるのではないかと考えて
以下のコードを作成してみたところ、
想定していたような動作をしてはいるのですが、
何か問題になりそうな箇所はありますでしょうか。

尚、下記のコードは以下のような想定で作成しました。
MyTextBoxクラスが基本機能を提供するクラス
NumberCheckTextBoxクラスが入力値が数値かどうかをチェックする機能を提供するクラス
RequiredTextBoxクラスが入力必須項目であるかどうかを判定し、画面上の挙動を変更するクラス

該当のソースコード

IControl クラス

VBA

1 2Public Sub TestSub() 3End Sub 4

IControl_MyTextBoxクラス

VBA

1Implements IControl 2 3Private WithEvents m_TextBox As Access.TextBox 4Public Sub IControl_TestSub() 5 Debug.Print "IControl_MyTextBox_TestSub!" 6End Sub 7Private Sub m_TextBox_Click() 8 Debug.Print "IControl_MyTextBox_OnClick!" 9End Sub 10Public Sub Initialize(value As Access.TextBox) 11 Set m_TextBox = value 12 m_TextBox.OnClick = "[EVENT PROCEDURE]" 13End Sub 14

IControl_NumberCheckTextBoxクラス

VBA

1Implements IControl 2 3Private WithEvents m_TextBox As Access.TextBox 4 5Public Sub IControl_TestSub() 6 Debug.Print "IControl_RequiredTextBox_TestSub!" 7End Sub 8 9Private Sub m_TextBox_Click() 10 Debug.Print "IControl_NumberCheckTextBox_OnClick!" 11End Sub 12 13Public Sub Initialize(value As Access.TextBox) 14 Set m_TextBox = value 15End Sub 16

IControl_RequiredTextBoxクラス

VBA

1Implements IControl 2 3Private WithEvents m_TextBox As Access.TextBox 4 5Public Sub IControl_TestSub() 6 Debug.Print "IControl_RequiredTextBox_TestSub!" 7End Sub 8 9Private Sub m_TextBox_Click() 10 Debug.Print "IControl_RequiredTextBox_OnClick!" 11End Sub 12 13Public Sub Initialize(value As Access.TextBox) 14 Set m_TextBox = value 15End Sub

テスト用フォーム (Me.txtはフォーム上に配置されたテキストボックスです)

VBA

1Private TestTextBox(2) As IControl 2 3Private Sub Form_Open(Cancel As Integer) 4 Dim myText As IControl_MyTextBox 5 Set myText = New IControl_MyTextBox 6 myText.Initialize Me.txt 7 8 Dim myRequired As IControl_RequiredTextBox 9 Set myRequired = New IControl_RequiredTextBox 10 myRequired.Initialize Me.txt 11 12 Dim myNumberCheck As IControl_NumberCheckTextBox 13 Set myNumberCheck = New IControl_NumberCheckTextBox 14 myNumberCheck.Initialize Me.txt 15 16 Set TestTextBox(0) = myText 17 Set TestTextBox(1) = myRequired 18 Set TestTextBox(2) = myNumberCheck 19End Sub 20 21

試したこと

上記のコードを実行し
フォーム上のテキストボックスをクリックすると
イミディエイトウィンドウに以下の文字列が出力されました。

VBA

1IControl_MyTextBox_OnClick! 2IControl_RequiredTextBox_OnClick! 3IControl_NumberCheckTextBox_OnClick!

補足情報(FW/ツールのバージョンなど)

言語:VBA(Access2016 32bit)

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

そういうことに関しては一度擬似からの脱却を読むことをオヌヌメ。

問題点としてはリンク内にもありますが「フォーム側にイベントを書けないこと」です。
クラス側にロジックのすべてを実装することになり「条件分岐」がしにくいので
結局「その画面専用クラス」になりやすいです。配列にWithEventsを書けない問題点は
上記リンクで改善方法が書いてあります。

問題点ではないですがもう一つやり方があって
フォームのVBAのPrivate Functionなどはコントロールから直接Callできる
ということです。そこまで大仰なことをしないでもいいかもしれません。
ただ「基本機能を提供し、さらに入力必須項目を」というような「重ね掛け」は
うまくやらないとできないかもしれません。

イメージ説明
こうして
イメージ説明
こう。

直接関係ないですがそこまでやるんなら

IConstructorクラス作って

vba

1Public Function Init(ByVal Args As Variant) As Boolean 2 3End Function

標準モジュールにfunction書いて

vba

1Public Function Init(ClassObject As IConstructor, ParamArray Args() As Variant) As IConstructor 2 Call ClassObject.Init(Args) 3 Set Init = ClassObject 4End Function

クラスでIConstructorをImplementsして

vba

1Implements IControl 2Implements IConstructor 3 4Private WithEvents m_TextBox As Access.TextBox 5 6' Initiarizeの代わり 7Private Function IConstructor_Init(ByVal Args As Variant) As Boolean 8 Set m_TextBox = Args(0) 9 m_TextBox.OnClick = "[EVENT PROCEDURE]" 10End Function 11 12Public Sub IControl_TestSub() 13 Debug.Print "IControl_MyTextBox_TestSub!" 14End Sub 15 16Private Sub m_TextBox_Click() 17 Debug.Print "IControl_MyTextBox_OnClick!" 18End Sub 19

フォーム側

vba

1Private TestTextBox(2) As IControl 2 3Private Sub Form_Open(Cancel As Integer) 4' Dim myText As IControl_MyTextBox 5' Set myText = New IControl_MyTextBox 6' myText.Initialize Me.txt 7 8 ' 上3行が1行に!初期化の引数も初期化ロジックもクラス側に書けるしかっこいい、それだけ 9 Set TestTextBox(0) = Init(New IControl_MyTextBox, Me.txt) 10 11' Dim myRequired As IControl_RequiredTextBox 12' Set myRequired = New IControl_RequiredTextBox 13' myRequired.Initialize Me.txt 14' 15' Dim myNumberCheck As IControl_NumberCheckTextBox 16' Set myNumberCheck = New IControl_NumberCheckTextBox 17' myNumberCheck.Initialize Me.txt 18' 19' Set TestTextBox(0) = myText 20' Set TestTextBox(1) = myRequired 21' Set TestTextBox(2) = myNumberCheck 22End Sub

VBAはオブジェクトの破棄に参照カウント制を使っているといわれています。
相互参照がされると永続的に破棄されない状態になる場合もあるので

vba

1Set obj = Nothing

はしっかり意識したほうがメモリリークしないでいい…かも。

投稿2020/06/27 03:55

編集2020/06/27 07:40
sousuke

総合スコア3830

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

kanntyuu

2020/06/27 07:07

回答ありがとうございます。 確かにフォーム側にイベント記述がなくなってしまうのは問題かも知れません。 別の人がメンテする際混乱しそうですしね...。 紹介頂いた[疑似からの脱却]をざっと読んでみましたが、 こちらで紹介されている手法であれば、 クラス数の爆発も避けられそうな気がしますので、 もう少ししっかり読み込んでみます。 2つ目の方法についても 単純な処理であれば利用できそうなので 参考にさせて頂きます。 回答ありがとうございました。
sousuke

2020/06/27 07:31

質問者さんはvbaは初心者っぽいのですが考え方が完全に他の言語のそれな気がしますね~ 擬似からの脱却を使う時点で別の人のメンテはほぼ諦めたほうがいいかもしれません… VBAで作ってあるから!って言われてこのコード見せられたら沈黙しそう笑 私が使っているコンストラクタのメソッドも提示しておきますね。ナカーマ
kanntyuu

2020/06/27 13:54

なるほど...。 コンストラクタ自体ををInterfaceとしてしまうのは思い付きませんでした。 毎回インスタンスの初期化をするだけで3行も書かないといけないのは 見栄え上もあまり綺麗ではないなぁと思いながら 何か方法が無いのかと悩んでおりましたので非常に勉強になりました。 また、オブジェクト破棄のタイミングを参照カウント制で判断しているのであれば 終了処理のNothingを意識したほうが良いですね...。 つい忘れがちなので気を付けたいと思います。 VBAにおけるクラスモジュールを使用する実装例というのは Web上でもあまり見かけない上、 私自身、周囲にこういった質問が出来る人がおりませんので 本当に助かりました。 ありがとうございます。 また何か分からないことがありましたら 質問させて頂ければ幸いです。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問