クラスのイベントが拾えないのですが

解決


クラス勉強中  2005-01-15 09:21:30  No: 87810

環境はWin2000,VB6です
現在クラスを勉強中です。
クラスをデータサーバとして使い,各フォームのデータの更新を通知できるように
ならないかと考えましたがForm側でイベントが拾えません。
Form1のボタンイベントでForm2側でText1.Text="ああああ"としたいのですが
以下のソースを参照ください。
(クラスを経由する必要がないのは理解しています。たくさんフォームがあって
  全てのフォームがアンロードする可能性があるとした場合に有効かと思ったのですが・・)

Module1.bas----------------------
Global clsa As Class1

Sub main()
  Set clsa = New Class1
  Form1.Show
  Form2.Show
End Sub
---------------------------------
class1.cls-----------------------
Dim strd As String
Public Event c(ByVal strf As String)

Public Sub b(ByVal strc As String)    
    RaiseEvent c(strc)
End Sub
----------------------------------
Form1------------------------------
Private Sub Command1_Click()
  clsa.b ("ああああ")
End Sub
-----------------------------------
Form2------------------------------
Private WithEvents clsa As Class1

Private Sub clsa_c(ByVal strf As String)
  Text1.Text = strf
End Sub
-----------------------------------

Form1のCommand1ボタンをクリックしてもForm2のclsa_c
のイベントが発生しません。
クラスの利点ばかりに目がいって、制限事項が分かって
いないようです。どなたかご指摘いただけないでしょうか?


mammal  2005-01-15 10:17:33  No: 87811

実行されるインスタンスが違います。
Form1で実行されたメソッドはGlobal宣言されたClass1インスタンスのものが実行されますから、これはWithEvents宣言されていませんから、イベントは発生しません。
このコードでは、WithEevents宣言されたインスタンスのメソッドは全く実行されません。なぜならForm2のプライベート宣言だから。

勉強されたと思いますが、インスタンスとはメモリに作られた『クラスのコピー』です。
このコードでは、有効範囲の異なるコピーが二つ作られていますが、Form1からアクセスできるコピーは、Global宣言したコピーだけです。だから、このコードでは、WithEvents宣言されたコピーは実行されていません。

てか、これでは、コンパイル時にエラーが出ませんか?
解決策は、Global宣言したコピーからイベントを拾ってください。それだけ。

駄長文スマソ。もっと上手い説明ができましたら、どなたかおながいします。


クラス勉強中  2005-01-15 22:12:12  No: 87812

mammal様
回答いただきありがとうございます。
内容は理解できるのですが・・・
>解決策は、Global宣言したコピーからイベントを拾ってください。それだけ。

を実現するのに力不足のようで・・

Form2の記述を以下のように変更してみました。
Set clsD = clsa
でGlobal宣言したクラスをForm2のclsDにコピー
しているつもりです。
・・・がやはりtext1に値が入りません。

Form2------------------------------
Option Explicit
Dim WithEvents clsD As Class1

Public Sub clsa_c(ByVal strf As String)
  Text1.Text = strf
End Sub

Private Sub Form_Load()
   Set clsD = clsa
End Sub

Private Sub Form_Unload(Cancel As Integer)
    Set clsD = Nothing
End Sub
-----------------------------------

>てか、これでは、コンパイル時にエラーが出ませんか?

私のところではエラーは出ずにEXEファイル作成されます^^;
(Form2にはテキストボックスを,Form1にはボタンを配置して
  スタートアップの設定をSub main()にしています。)


おかん  2005-01-15 22:12:25  No: 87813

標準モジュールに宣言したclsa As Class1への参照のセットが行われていないからではないのですか?

Form2のロード時に
Private Sub Form_Load()
 Set clsa = Module1.clsa
End Sub

として下さい。
ややこしいのでPrivate変数とグローバル変数の名前は変えたほうがいいかもしれませんね。


おかん  2005-01-15 22:17:34  No: 87814

Form1も同様にね


クラス勉強中  2005-01-15 23:45:08  No: 87815

おかん様
回答ありがとうございます。
分かりにくいソースで申しわけないです。コメントを反映してみました。
が,それでもForm2のclsa_cのイベント?が発生しません。
参照のセットは行われています。(Module.でglclsAが選択できます)
以下ソースです。
Module1.bas----------------------
Option Explicit
Global glclsA As Class1

Sub Main()
  Set glclsA = New Class1
  Form1.Show 0
  Form2.Show 0
End Sub

Sub Ending() '終了処理
  Set glclsA = Nothing 
End Sub
---------------------------------
class1.cls-----------------------
Dim strd As String
Public Event Evtest(ByVal strf As String)

Public Sub Testsub(ByVal strc As String)
    RaiseEvent Evtest(strc)
End Sub
----------------------------------
Form1------------------------------
Option Explicit

Private Sub Command1_Click()
  Module1.glclsA.Testsub ("ああああ")
End Sub

Private Sub Form_Unload(Cancel As Integer)  '終了処理
  Call Ending
  Unload Form2
End Sub
-----------------------------------
Form2------------------------------
Option Explicit
Dim WithEvents clsD As Class1

Private Sub clsD_Evtest(ByVal strf As String)
    Text1.Text = strf
End Sub

Private Sub Form_Load()
     Set clsD = Module1.glclsA
End Sub

Private Sub Form_Unload(Cancel As Integer)
    Set clsD = Nothing
End Sub
-----------------------------------


おかん  2005-01-16 00:03:48  No: 87816

だからForm1のロードイベントも同じようにって書いてるのに
MSDNライブラリでクラスの説明をもう一回よく読んでください。


おかん  2005-01-16 00:15:31  No: 87817

よく見たら、動きそうですけどね。
下記サンプルはテスト済みなのでこれと何がちがうか
考えてみてください。
同じ用に思いますが。

'----- Class1.cls
'RaiseEvent C[(arg1, arg2, ... , argn)]
Public Event C(ByVal D As String)

Public Sub B(ByVal D As String)
  RaiseEvent C(D)
End Sub

'----- Module1.bas
Sub Main()
  
  Set clsa = New Class1
  Form1.Show
  Form2.Show

End Sub

'----- Form1.frm
Private Sub Command1_Click()

  Module1.clsa.B "AAA"

End Sub

'----- Form2.frm
Private WithEvents clsb As Class1

Private Sub clsb_C(ByVal D As String)

  MsgBox D

End Sub

Private Sub Form_Load()

  Set clsb = clsa

End Sub


おかん  2005-01-16 00:18:17  No: 87818

'Module1.bas

Public clsa As Class1

が抜けてました


クラス勉強中  2005-01-16 00:46:41  No: 87819

おかん様のソースですがこちらで動作確認とれました。
こちらで再度自分のソース確認したところ・・・・動きました。
どこかで凡ミスしてたようです。
お手数おかけし申しわけないです。
大変参考になりありがとうございました。


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加