Excel VBA質問箱 IV

当質問箱は、有志のボランティア精神のおかげで成り立っています。
問題が解決したら、必ずお礼をしましょうね。
本サイトの基本方針をまとめました。こちら をご一読ください。

投稿種別の選択が必要です。ご注意ください。
迷惑投稿防止のため、URLの入力を制限しています。ご了承ください。


5048 / 13644 ツリー ←次へ | 前へ→

【52863】クラスによるコントロールの配列処理 ハナ 07/12/7(金) 9:33 質問[未読]
【52867】Re:クラスによるコントロールの配列処理 ichinose 07/12/7(金) 11:34 発言[未読]
【52870】Re:クラスによるコントロールの配列処理 ハナ 07/12/7(金) 12:00 発言[未読]
【52871】Re:クラスによるコントロールの配列処理 ハナ 07/12/7(金) 12:34 お礼[未読]
【52888】Re:クラスによるコントロールの配列処理 ichinose 07/12/7(金) 22:36 発言[未読]

【52863】クラスによるコントロールの配列処理
質問  ハナ  - 07/12/7(金) 9:33 -

引用なし
パスワード
   いつも参考にさせていただいてます。
UserForm上に配置したTextBoxを配列として扱う処理を
MOUGの「スキルアップ講座」を参考にして、以下のように作成しました
動作および内容は
UserForm1上のTextBoxをダブルクリックするとそのTextBoxに文字”OK”が入る
というイメージです。
 
標準モジュール
Sub test()
UserForm1.Show
End Sub

で、UserForm1を表示。

UserForm1
*TextBox1〜3を配置
コレクション インスタンス生成

Option Explicit
Option Base 1
Dim myClass1(3) As New Class1
Private Sub UserForm_Initialize()
   Dim myTextBox As New Collection
   Dim i As Integer
   With myTextBox
      .Add Item:=TextBox1
      .Add Item:=TextBox2
      .Add Item:=TextBox3
   End With
   For i = 1 To 3
      Set myClass1(i) = New Class1
      With myClass1(i)
         .Txt = myTextBox(i)
         .Index = i
      End With
   Next
End Sub

クラスモジュール「Class1」でTextBoxダブルクリック時の
メソッド記述(イベントプロシジャー)
標準モジュールに記述の *** Syori_FromTextBox をCall ***

Option Explicit

Private WithEvents myTxt As MSForms.TextBox
Private t_intIndex As Integer

Public Property Get Cmd() As MSForms.TextBox
   Set Txt = myTxt
End Property

Public Property Let Txt(ByVal txtNewValue As MSForms.TextBox)
   Set myTxt = txtNewValue
End Property

Public Property Get Index() As Integer
   Index = t_intIndex
End Property

Public Property Let Index(ByVal intNewValue As Integer)
   t_intIndex = intNewValue
End Property


Private Sub myTxt_DblClick(ByVal Cancel As MSForms.ReturnBoolean)
Dim temps As Object
  Set temps = Me.Txt(t_intIndex)
  Call Syori_FromTextBox(temps)
End Sub
************************************************************
標準モジュール
Public Sub Syori_FromTextBox(objTextBox As MSForms.TextBox)
  objTextBox.Text = "OK"
End Sub

この流れの中で、実際にUserForm1上のTextBoxをクリックするとクラスモジュールで
エラーになるのですが、回避方法が発見できません。
エラー修正のアドバイス、方法のご教授をお願いできませんでしょうか。
どうぞよろしくお願いします。

【52867】Re:クラスによるコントロールの配列処理
発言  ichinose  - 07/12/7(金) 11:34 -

引用なし
パスワード
   ▼ハナ さん:
こんにちは。
現状の記述は、非常にわかりやすくて、すぐ再現できました。
お手本ですね!!

さて、
>いつも参考にさせていただいてます。
>UserForm上に配置したTextBoxを配列として扱う処理を
>MOUGの「スキルアップ講座」を参考にして、以下のように作成しました
>動作および内容は
>UserForm1上のTextBoxをダブルクリックするとそのTextBoxに文字”OK”が入る
>というイメージです。
> 
>標準モジュール
>Sub test()
>UserForm1.Show
>End Sub
>
>で、UserForm1を表示。
>
>UserForm1
>*TextBox1〜3を配置
>コレクション インスタンス生成
>
>Option Explicit
>Option Base 1
Dim myClass1(3) As Class1
>Private Sub UserForm_Initialize()
'>   Dim myTextBox As New Collection
>   Dim i As Integer
'>   With myTextBox
'>      .Add Item:=TextBox1
'>      .Add Item:=TextBox2
'>      .Add Item:=TextBox3
'>   End With
'このコレクション殆ど要りません
>   For i = 1 To 3
>      Set myClass1(i) = New Class1
>      With myClass1(i)
         .Txt = Controls("textbox" & i)
>         .Index = i
>      End With
>   Next
>End Sub
>
>クラスモジュール「Class1」でTextBoxダブルクリック時の
>メソッド記述(イベントプロシジャー)
>標準モジュールに記述の *** Syori_FromTextBox をCall ***
>
>Option Explicit
>
>Private WithEvents myTxt As MSForms.TextBox
>Private t_intIndex As Integer
>
>Public Property Get Cmd() As MSForms.TextBox
>   Set Txt = myTxt
>End Property
>
>Public Property Let Txt(ByVal txtNewValue As MSForms.TextBox)
>   Set myTxt = txtNewValue
>End Property
>
>Public Property Get Index() As Integer
>   Index = t_intIndex
>End Property
>
>Public Property Let Index(ByVal intNewValue As Integer)
>   t_intIndex = intNewValue
>End Property
>
>
>Private Sub myTxt_DblClick(ByVal Cancel As MSForms.ReturnBoolean)
  myTxt.Text = "ok"
'ここで「OK」の設定を行う
>End Sub

'以下の標準モジュールは要りません

>************************************************************
>標準モジュール
>Public Sub Syori_FromTextBox(objTextBox As MSForms.TextBox)
>  objTextBox.Text = "OK"
>End Sub


として試してください。
このコードは、本来はまだ問題点があります(モジュール間の結合度が強すぎる)
が、クラスモジュールを理解する
段階なら、上記でよいです。

【52870】Re:クラスによるコントロールの配列処理
発言  ハナ  - 07/12/7(金) 12:00 -

引用なし
パスワード
   ▼ichinose さん:
早速の返信ありがとうございます。
コードを細かく見直していただいて、ほんとうに助かります。
ところで、ご教授いただいたメソッドの部分なんですが

>>Private Sub myTxt_DblClick(ByVal Cancel As MSForms.ReturnBoolean)
>  myTxt.Text = "ok"
>'ここで「OK」の設定を行う
>>End Sub
>
>'以下の標準モジュールは要りません
>
>>************************************************************
>>標準モジュール
>>Public Sub Syori_FromTextBox(objTextBox As MSForms.TextBox)
>>  objTextBox.Text = "OK"
>>End Sub
>
>
>として試してください。
例が悪くてもうしわけなかったのですが、実際にやりたい動作は
TextBoxにOKをだすのではなくて、もう少し複雑な処理(別フォームのカレンダーを表示して、そこから選んだ日付をこのTextBoxにフォーマットして表示する)
なんです。つまり、メソッドでCALLをしたい部分です。
その部分がどうも上手くいきませんので、できましたら再度ご教授ねがえませんでしょうか。
どうぞ、よろしくお願いします。

【52871】Re:クラスによるコントロールの配列処理
お礼  ハナ  - 07/12/7(金) 12:34 -

引用なし
パスワード
   ▼ichinose さん:
ichinoseさんのアドバイスを参考に以下でやってみました
上手くいきました。
Private Sub myTxt_DblClick(ByVal Cancel As MSForms.ReturnBoolean)
  Call Syori_FromTextBox(Txt)
End Sub
何を考えていたのだか・・・・ 恥ずかしいです(汗
おかげさまで、食事ができます。ありがとうございました。

>>************************************************************
>>標準モジュール
>>Public Sub Syori_FromTextBox(objTextBox As MSForms.TextBox)
>>  objTextBox.Text = "OK"
>>End Sub


>このコードは、本来はまだ問題点があります(モジュール間の結合度が強すぎる)
同じプロジェクト内で別のUserFormでコマンドボタンコントロールを配列化していますが、そのEvent処理を別のクラスモジュールでやらせてます。
そのへんを統合することができる・・の問題でしょうか。
とにかく、今回の回答で大変たすかりました。本当にありがとうございました。

【52888】Re:クラスによるコントロールの配列処理
発言  ichinose  - 07/12/7(金) 22:36 -

引用なし
パスワード
   ▼ハナ さん:
こんばんは。
>>このコードは、本来はまだ問題点があります(モジュール間の結合度が強すぎる)
>同じプロジェクト内で別のUserFormでコマンドボタンコントロールを配列化していますが、そのEvent処理を別のクラスモジュールでやらせてます。
>そのへんを統合することができる・・の問題でしょうか。

Userformのコントロールのイベントプロシジャーをクラスモジュール内に記述することが
このクラスモジュールとUserformの結合度(関わり度合い)を強くしているということです。
結合度が強いとそのまま再利用すことが困難になります。
クラスの中の記述されているコントロールのイベントプロシジャーは、特定のUserform内にあるコントロールに関するコードが入っているのですから、特定のUserformとの関わりが強すぎるのです。
Userformが変わるたびにクラスのコードも変えなければなりません。

クラスって、オブジェクトの設計図ですよね?
ExcelのWorkbookやWorksheetというオブジェクトの中のコードを毎回変更しなければ使えなかったら、VBAでは使えませんよね?

本来は、クラスモジュール内に記述しているTextboxのイベントプロシジャーは、
Userform内に記述されるべきなのです。

これを可能にしたアドインを角田さんが紹介しています。
www.h3.dion.ne.jp/~sakatsu/Breakthrough_P-Ctrl_Arrays.htm
(擬似からの脱却)

これが「本来はまだ問題点があります」と申し上げた理由なのです。
が、汎用的にコントロール配列を実現するためのオブジェクトの作成は、結構大変ですから
これは取りあえずは、現行コードで良しとしましょう!!
又は、上記URLにあるアドインを利用してください。


>Private Sub myTxt_DblClick(ByVal Cancel As MSForms.ReturnBoolean)
>  Call Syori_FromTextBox(Txt)
>End Sub
>
>>>************************************************************
>>>標準モジュール
>>>Public Sub Syori_FromTextBox(objTextBox As MSForms.TextBox)
>>>  objTextBox.Text = "OK"
>>>End Sub

クラスとユーザーフォームとの結合度の強さを上記のように認めたとしても、更にこの標準モジュールでユーザーフォームのコントロールに関わるコードを記述するのは私は、疑問に感じます。

クラス、Userform、標準の各モジュールの結合度が強くなってしまいます。
仕様書に記述する場合には、「このクラスの利用に当たっては、標準モジュールに以下のプロシジャーの記述が必須となります。」なんていう但し書きが必要になってしまいます。
一般的なオブジェクトにはないですよね!!

クラスとユーザーフォームとの結合度の強さを上記のように認めた場合、標準モジュールのプロシジャーは、クラス内に記述するか、Userform内に記述してクラスから呼び出すかのどちらかだと思いますよ!! 時間があったら、検討してしてみてください。

クラスモジュールに

Private Sub myTxt_DblClick(ByVal Cancel As MSForms.ReturnBoolean)
  myTxt.Parent.Syori_FromTextBox myTxt
End Sub

Userform1のモジュールに

>>Public Sub Syori_FromTextBox(objTextBox As MSForms.TextBox)
>>  objTextBox.Text = "OK"
>>End Sub

5048 / 13644 ツリー ←次へ | 前へ→
ページ:  ┃  記事番号:
2610219
(SS)C-BOARD v3.8 is Free