tagCANDY CGI VBレスキュー(花ちゃん)の Visual Basic 6.0用 掲示板 [ツリー表示へ]   [Home]
一括表示(VB6.0)
タイトルVBA コントロールに付加したイベントが働かない
記事No16184
投稿日: 2015/09/15(Tue) 19:52
投稿者わごなる
お世話になります。

Office2013 VBAで動的にコンボボックスを作成し、イベントを割り付けることが目的です。

Workbook_Openにおけるコンボボックスの項目Add回路ではChangeなりClickイベントが発生していますが、
それ以降コンボボックスをどのように操作してもイベントが発生しません。
問題点がわかる方いらっしゃいましたらご教授頂きたいです。

現コードは下記の通りです。


※Workbook_Open内の関数でCmbMakeをCall

Sub CmbMake()

    Dim cmbPos As Range
    Dim m_objOLE_C As Object
    Dim objcmb As ComboBox

    'コンボボックスの位置を指定
    Set cmbPos = Range(A3)

    'コンボボックスを作成
    Set m_objOLE_C = ActiveSheet.OLEObjects.Add(ClassType:="Forms.ComboBox.1", _
       Link:=False, DisplayAsIcon:=False, Left:=cmbPos.Left, _
       Top:=cmbPos.Top, Width:=cmbPos.Width, height:=cmbPos.height)
    
    Set objcmb = ActiveSheet.OLEObjects(m_objOLE_C.Name).Object
    objcmb.Locked = False

    Set NewObj = New clsObjectIvent
    Set NewObj.CMB = objcmb

    With objcmb
        'プロパティ変更
       .AddItem "選択肢1", 0
       .AddItem "選択肢2", 1
       .BackStyle = fmBackStyleOpaque
       .BackColor = RGB(200, 250, 250)
        .Style = fmStyleDropDownList
       .ListIndex = 0
    End With
                
End Sub


−−−−−−−−−−−−−−−−−−−−−−−−−−
※クラスモジュール「clsObjectIvent」に下記コード
Option Explicit
Public WithEvents cmbBox As MSForms.ComboBox

Public Property Set CMB(InstComboBox As MSForms.ComboBox)
  Set cmbBox = InstComboBox
End Property

Public Property Get CMB() As MSForms.ComboBox

End Property
'確認用にイベント複数定義
Private Sub cmbBox_Change()
     MsgBox "cmbBox_Change"
End Sub
Private Sub cmbBox_Click()
     MsgBox "cmbbox_Click"
End Sub
Private Sub cmbBox_LostFocus()
     MsgBox "cmbbox_LostFocus"
End Sub

Private Sub cmbBox_AfterUpdate()
     MsgBox "cmbbox_AfterUpdate"
End Sub

[ツリー表示へ]
タイトルRe: VBA コントロールに付加したイベントが働かない
記事No16185
投稿日: 2015/09/15(Tue) 22:09
投稿者魔界の仮面弁士
> それ以降コンボボックスをどのように操作してもイベントが発生しません。

変数が有効期間外になったか、コードの実行が終了したなどの理由で、
生成しておいたクラスのインスタンスが解放されているのではないでしょうか?

試しに、クラスモジュールに

Private Sub Class_Initialize()
    Debug.Print "→生成:"; Hex(ObjPtr(Me)), Format(Now, "yyyy/MM/dd HH:mm:ss") & Format(Timer - Fix(Timer), ".0000000")
End Sub

Private Sub Class_Terminate()
    Debug.Print "←解放:"; Hex(ObjPtr(Me)), Format(Now, "yyyy/MM/dd HH:mm:ss") & Format(Timer - Fix(Timer), ".0000000")
End Sub

という行を追加し、イミディエイトの内容を確認してみて下さい。
オブジェクトが解放されているようであれば、それが「イベントが発生しない(ようにみえる)」原因かと思います。



Excel VBA はあまり使わないので、さほど詳しくは無いのですが、
CmbMake の中で「Stop ステートメント」を記述してみたところ、
OLEObjects.Add の「実行前」には Stop できるものの、
OLEObjects.Add の「実行後」に Stop を書いた場合には、処理が中断するのではなく
『中断モードでは入力できません』というエラーメッセージと共に、
コードの実行が打ち切られてしまう(VBA の実行が停止させられる)現象を確認しました。


ここからは私の想像ですが、OLEObjects.Add が実行されたことによって、
「CmbMake の実行が完了した後」で、Sheet1 上に「Sheet1.ComboBox1」なメンバーが追加されますが、
そのために、VBA 的には再コンパイル相当の処理が必要な事態となり、一連のコードが終了した
タイミング(すなわち、Workbook_Open の処理が完了した直後)に、
VBA コードが終了(あるいはリセット)されたのではないか…と予想しています。


実際、「自ブック上に OLEObjects.Add する」という現状のコードに少し手を加えて、
「他のブック上に  OLEObjects.Add する」動作に書き換えてみたところ、その場合は
クラスが解放されることなく、イベントを受け取り続けられることを確認しています。


---- 以下、本題とは無関係の突っ込み ----


> Set cmbPos = Range(A3)
A3 という変数ですか?
"A3" という文字列ではなく?

それと、ComboBox の生成コードに合わせるため、上記は「Range」ではなく、
「ActiveSheet.Range」にした方が適切かと思います。



> Set objcmb = ActiveSheet.OLEObjects(m_objOLE_C.Name).Object
「Set objcmb = m_objOLE_C.Object」で良いのでは。


> Set NewObj = New clsObjectIvent
変数 NewObj はどこで宣言されていますか?


> ※クラスモジュール「clsObjectIvent」に下記コード
clsObjectEvent ではなく?

[ツリー表示へ]
タイトルRe^2: VBA コントロールに付加したイベントが働かない
記事No16186
投稿日: 2015/09/16(Wed) 09:54
投稿者わごなる
魔界の仮面弁士様、御回答頂きありがとうございます。
前回この掲示板に相談させて頂いた際にも御回答頂き、大変助かりました。

早速ですが、試しました。
→生成:13064DC0             2015/09/16 09:35:38.1015625
←解放:13064DC0             2015/09/16 09:35:42.0820313
仰るとおり、すぐに解放されてしまっていることが確認できました。

実はこの問題にぶつかる前に、グローバル定義の配列変数が
本件と同様のタイミングで初期化されてしまうことがありました。
魔界の仮面弁士様の推察通りだとすると、それについても合点がいきます。
初期化されてしまうきっかけはOLEObjectの挿入でした。
ユーザーコントロールの挿入では発生しませんでした。

現時点では解決策は見つけられていませんが、
今起きている現象がわかっただけでも大きな収穫です。
ありがとうございました。
もし何か打開策あればご教授頂けますでしょうか。


> > Set cmbPos = Range(A3)
> A3 という変数ですか?
> "A3" という文字列ではなく?
本来このA3のところには変数を割り当てておりましたが、
本投稿に際し、適当な定数に置き換えたつもりでした。
その場合、正しくは"A3"です。

> それと、ComboBox の生成コードに合わせるため、上記は「Range」ではなく、
> 「ActiveSheet.Range」にした方が適切かと思います。
> > Set objcmb = ActiveSheet.OLEObjects(m_objOLE_C.Name).Object
> 「Set objcmb = m_objOLE_C.Object」で良いのでは。
> > ※クラスモジュール「clsObjectIvent」に下記コード
> clsObjectEvent ではなく?
ありがとうございます。
修正後、動作確認できました。

> > Set NewObj = New clsObjectIvent
> 変数 NewObj はどこで宣言されていますか?
標準モジュールで定義しております。
Public NewObj As clsObjectEvent

[ツリー表示へ]