[[20230503082502]] 『複数コントロールのオブジェクト配列変数をクラス』(山川海湖) ページの最後に飛ぶ

[ 初めての方へ | 一覧(最新更新順) | 全文検索 | 過去ログ ]

 

『複数コントロールのオブジェクト配列変数をクラスで定義するには?』(山川海湖)

お世話になります。
例えば、定数をクラスで定義する場合、以下の様にすれば良いことは知り得ました。


Private Const c_c1Cmb As Integer = 4

Public Property Get c1Cmb() As Integer

    c1Cmb = c_c1Cmb
End Property

これと同様に、変数もクラスで定義させたいのですが、その変数というのが、
オブジェクトの配列変数をクラスで定義させて、ピリオドの後に入力候補として
その変数を表示させられるようにしたいと考えています。

まず、そこまでいかないのですが、例えば、以下の様にすれば
オブジェクト配列変数を作成できそうに思っています。
(デバッグのコンパイルではエラーは出ていません)


Dim uf1Cmb(1 To c_c1Cmb) As ComboBox
Dim iCount As Integer

Function SetCtrlVar(isSet As Boolean)
'//isSet=True:変数set
'//isSet=False:変数解放(Set 〜 = Nothing)

    Call SetObjVarCtrl(isSet, UserForm1, uf1Cmb, "ComboBox", 1, c1Cmb)
End Function

Sub SetObjVarCtrl(isSet As Boolean, ByRef UF As UserForm, _

    ByRef objVar As Variant, strCtrl As String, _
    iStart As Integer, iEnd As Integer)
    Select Case isSet
        Case True
            For iCount = iStart To iEnd Step 1
                Set objVar(iCount) = UF.Controls(strCtrl & iCount)
            Next iCount
        Case False
            For iCount = iStart To iEnd Step 1
                Set objVar(iCount) = Nothing '解放
            Next iCount
    End Select
End Sub


Public objVar As New clsCtrlObjVar
Call objVar.SetCtrlVar(True) '変数Set

Call objVar.SetCtrlVar(False) '変数解放(Set 〜 = Nothing)


そこで次に、クラスから変数単位で、(ピリオドの後の)入力候補にできるように設定したいのですが、
例えば、ComboBoxが4個あるとして、1個ずつをPropertyのLetとGetに書けば良いのでしょうか?
或いは、配列として一気に書くことは可能でしょうか?
また或いは、1個ずつPropertyを作成するにしても、オブジェクト配列変数として設定できるのでしょうか?

可能なのかどうかすら、よくわかっておりませんが、
お分かりになる方がいらっしゃいましたら、ご教授頂けましたら誠にありがたいです。
お手数で誠に恐縮ですが、どうぞよろしくお願いいたします。

< 使用 Excel:Microsoft365、使用 OS:Windows10 >


プレビューで確認しようとしたつもりで投稿されてしまっておりましたが、
最初の2つが、「clsSetCtrlVar」というクラスに記載してあり、
最後の1つが、標準モジュールに記載してあります。
(点線4個の後ろのコメント書きが投稿に反映されず、見えにくくなってしまいました。)


(↓ここから、「clsSetCtrlVar」というクラスに記載↓)
Private Const c_c1Cmb As Integer = 4

Public Property Get c1Cmb() As Integer

    c1Cmb = c_c1Cmb
End Property
(↑ここまで、「clsSetCtrlVar」というクラスに記載↑)


(↓ここから、「clsSetCtrlVar」というクラスに記載↓)
Dim uf1Cmb(1 To c_c1Cmb) As ComboBox
Dim iCount As Integer

Function SetCtrlVar(isSet As Boolean)
'//isSet=True:変数set
'//isSet=False:変数解放(Set 〜 = Nothing)

    Call SetObjVarCtrl(isSet, UserForm1, uf1Cmb, "ComboBox", 1, c1Cmb)
End Function

Sub SetObjVarCtrl(isSet As Boolean, ByRef UF As UserForm, _

    ByRef objVar As Variant, strCtrl As String, _
    iStart As Integer, iEnd As Integer)
    Select Case isSet
        Case True
            For iCount = iStart To iEnd Step 1
                Set objVar(iCount) = UF.Controls(strCtrl & iCount)
            Next iCount
        Case False
            For iCount = iStart To iEnd Step 1
                Set objVar(iCount) = Nothing '解放
            Next iCount
    End Select
End Sub
(↑ここまで、「clsSetCtrlVar」というクラスに記載↑)


(↓ここから、標準モジュールに記載↓)
Public objVar As New clsCtrlObjVar
Call objVar.SetCtrlVar(True) '変数Set

Call objVar.SetCtrlVar(False) '変数解放(Set 〜 = Nothing)
(↑ここまで、標準モジュールに記載↑)


(山川海湖) 2023/05/03(水) 08:35:30


「AddinBox/擬似からの脱却」
http://addinbox.sakura.ne.jp/Breakthrough_P-Ctrl_Arrays.htm

頭から最後まで読み込めば、
イベント処理を含めて、
コントロール配列を構築できます。

楽したいならば、
「汎用クラス/clsBpca」を使い、
「§11 サンプルコード」を参考にすれば、
色々と出来ます。

〉 As New clsCtrlObjVar
変数宣言時に New はしない方が良いですね。
Set objVar = Nothing
としても変数のメモリが解放されません。
新たに初期化された objVar が再作成されるだけです。

変数宣言後に New で初期化します。
Public objVar As clsCtrlObjVar
Set objVar = New clsCtrlObjVar

(AddinBox_角田) 2023/05/03(水) 09:28:43


〉としても変数のメモリが解放されません。

― 訂正 ―
とすると、変数のメモリが解放されると同時に
新たに初期化された objVar が再作成されるだけです。

(AddinBox_角田) 2023/05/03(水) 10:15:52


 >(↓ここから、「clsSetCtrlVar」というクラスに記載↓)
 >Dim uf1Cmb(1 To c_c1Cmb) As ComboBox

   (↓ここから、「clsCtrlObjVar」というクラスに記載↓) ですよね?
         ~~~~~~~~~~~~~~

 >例えば、以下の様にすれば
 >オブジェクト配列変数を作成できそうに思っています。
 >(デバッグのコンパイルではエラーは出ていません)

 コンパイルでエラーが出るけどなぁ。。

 >Dim uf1Cmb(1 To c_c1Cmb) As ComboBox
          ~~~↑~~~
          変数が定義されていません。

 >例えば、ComboBoxが4個あるとして、1個ずつをPropertyのLetとGetに書けば良いのでしょうか?
 >或いは、配列として一気に書くことは可能でしょうか?

 言っている事がよく分からないですが、配列なんですから、
 通常はIndexだけ変えて処理するんじゃないですか?
 (つまり1個のみ。じゃなければ配列にする意味がない。)

(半平太) 2023/05/03(水) 12:28:23


AddinBox_角田さん、半平太さん、
ご教授頂けまして誠にありがとうございます。

まずは、
AddinBox_角田さん、
変数宣言時に New はしない方が良いのですね。
Nothingとしても変数のメモリが解放されると同時に
新たに初期化された objVar が再作成されるだけなのは、
重要な基本を知る意味でも、今回大変貴重なご教授になりました。

また、VBAでは元々VBの様な「コントロール配列」機能は無いのですね。

なお、現在、リンク先などを勉強させていただいております。
(どの辺を見れば、ピンポイント良さそうでしょうか?)

あと、新たな疑問になりますが、先ほどのクラスでの定数定義におきまして、
「Property Get c1Cmb」の中で「c1Cmb = c_c1Cmb」と書きましたが、
このような定数が複数あるとして、「Property Get」自体を関数化のようにして
引数のように、「c1Cmb」や「c_c1Cmb」を送り込んで、
PropertyのGet(やLet)自体を関数化(カプセル化)できたりしますでしょうか?

或いは、やはり、定数(や変数)のGet(やLet)は、
個数分だけ1個ずつ設定が必要となるのでしょうか?
(例えば、c1Cmb、c1Lbl、c1Btn、c2Cmb、c2Chk、c2Btn、、、
 など、それぞれごとにPropertyの記述が別々に必要でしょうか?
 引数で送り込んで関数化みたい一括処理で定義はできないでしょうか?)

半平太さん、
>変数が定義されていません。

紛らわしい書き方となってしまい申し訳ございませんでしたが、
一番最初の質問時に、「clsSetCtrlVar」というクラスへの記述を
2か所に分けて(それらの間に日本語の補足を挿入して)
書いてしまいましたので、上側に書いた方で定義していたつもりでした。
これでしたら、変数が定義されていないエラーは出ないですかね?

>配列なんですから、通常はIndexだけ変えて処理

なるほどです。現在、書き方を検索・確認中ではありますが、
Propertyの記述も、そのようにIndexを分ければ良いのかもしれないですね。
参考にさせていただきます。

角田さん、半平太さん、ご教授いただけまして誠にありがとうございます。
まだ、書き方などを確認中ではありますが、参考にさせていただきます。
(山川海湖) 2023/05/03(水) 15:33:31


あと、今頃気が付いたのですが、解放するべきなのは、
クラスオブジェクトとしての「Set objVar = New clsCtrlObjVar」であって、
クラスの中に書いた各オブジェクト変数は解放する必要が無いのですかね。

もし、そうでしたら、引数にisSetを設定して場合分けした処理は
意味のない処理になるのでしょうか?

(山川海湖) 2023/05/03(水) 16:02:16


更に、今考えていますのは、標準モジュールの最初に
(Newな)クラスオブジェクトをSetしておいて、
ピリオドの後の入力候補の呼び出しとして使用したいのですが、
その場合、どのタイミングで、Newクラスオブジェクト(クローン?)を
解放させれば良さそうでしょうか?

或いは、各プロシージャ(処理)の中で、いちいち使う時に
NewをSetさせて、その各プロシージャ(処理)の最後に解放させる
というのを繰り返すしか無いのでしょうか?
(山川海湖) 2023/05/03(水) 16:38:11


今、最初にご指摘いただきました通り、
「Public objVar As New clsCtrlObjVar」の書き方を止めようとして
「Public objVar As clsCtrlObjVar:Set objVar = New clsCtrlObjVar」
などと、標準モジュールの最初の方に記述しましたら、コンパイルエラーとして
「Set」の記述が「プロシージャの外では無効です」と警告されてしまいました。

やはり、プロシージャの中で、毎回、NewとNothingのSetを繰り返すしか
無さそうみたいですね。それならば、これを関数化しておいて
isSet(True or False)の引数渡しで毎回、それぞれをSetさせれば良いのかもですが。
(山川海湖) 2023/05/03(水) 16:56:49


 >上側に書いた方で定義していたつもりでした。
 >これでしたら、変数が定義されていないエラーは出ないですかね?

 よく分からないですが、clsCtrlObjVar に全部書いてみましたら、
 コンパイルエラーは出なくなりました。

 ところで、(私にとって)意味不明な個所が幾つかありますよ。

 >    Call SetObjVarCtrl(isSet, UserForm1, uf1Cmb, "ComboBox", 1, c1Cmb)
 なぜ自分で持っているc_c1Cmb を直接使わないで、わざわざc1Cmbを使うんですか?
 そもそも引数で渡す必要すらないんじゃないですか?

 uf1Cmbの配列の型はComboBoxですよね?
 それを何故、こんな変数に渡すんですか? 
        ↓
  ByRef objVar As Variant

 しかもその名前は標準モジュールで持っているオブジェクトと同名ですよ。私は頭がおかしくなります。
 またこれも引数で渡す必要すらないんじゃないですか?(自分が保持している変数なんですから)

 つまり、こんな書き方になるんじゃないですか?(絶対とは言いませんが・・)

 Private Const c_c1Cmb As Integer = 4
 Private uf1Cmb(1 To c_c1Cmb) As ComboBox
 Private iCount As Integer

 'Public Property Get c1Cmb() As Integer
 '    c1Cmb = c_c1Cmb
 'End Property

 Function SetCtrlVar(isSet As Boolean)
 '//isSet=True:変数set
 '//isSet=False:変数解放(Set 〜 = Nothing)
     Call SetObjVarCtrl(isSet, "ComboBox", 1)
 End Function

 Sub SetObjVarCtrl(isSet As Boolean, strCtrl As String, iStart As Integer)
     Select Case isSet
         Case True
             For iCount = iStart To c_c1Cmb Step 1
                 Set uf1Cmb(iCount) = UserForm1.Controls(strCtrl & iCount)
             Next iCount
         Case False
             For iCount = iStart To c_c1Cmb Step 1
                 Set uf1Cmb(iCount) = Nothing '解放
             Next iCount
     End Select
 End Sub

(半平太) 2023/05/03(水) 17:51:24


半平太さん、ごもっともなご指摘ありがとうございます。
外していまして遅くなりすみませんでした。

この記述方法を目指す理由や経緯は、最初の投稿時にも書きましたが、
「変数をクラスで定義し、ピリオドの後に入力候補として表示させたい」
と考えています。その為には、クラスでPropertyを定義しておき
標準モジュールなどで呼び出すと、複製クラス名のピリオドの後に入力候補として
変数などが選択できるような構造を作ろうとしている背景があります。

実際に、先ほどの定数も、例えば、標準モジュール(のどこかのsub内)で
「Public cls As clsCtrlObjVar:Set cls = New clsCtrlObjVar」などと記述しておくと
標準モジュール側からは、「cls.」と記述するだけで、そのピリオドの後に
入力候補として、先ほどの定数の「c1Cmb」や他に記述済みの関数名やsub処理名が
ぶら下がって選択肢として表示されていますので、変数でも記述が成功すれば、
今回目指している構造にできるのではないかと考えております。

ただ、今は正直、中途半端な状態でして、実は今回の質問前から既に、
拡張性などを追及したく思い、なるべくクラス内に記述しておき、後で
標準モジュールなどで関数や変数やら呼び出して使いたいと思っていましたが、
今のclsCtrlObjVarクラスモジュール内で記述しても、外からの呼び出しで無い為か
入力候補の自動表示の恩恵を受けられていません。

ですので、まずは、定数からPropertyを作成してみたところなのですが、
その(clsCtrlObjVarクラスモジュール内の)記述をそのまま投稿してしまいましたので
例えば、定数c_c1Cmbで済むのに、わざわざ、、、のご指摘はごもっともと思います。

なお、引数のUFやc1Cmbも、拡張性も考慮したり、実際に
他のUserform2以降や、他の定数でも使えるような関数化を図りたいために
わざわざ外からの引数を受ける形にしております。説明不足ですみませんでした。
今、私がclsCtrlObjVarクラスモジュール内に記述している関数やsub処理は、
この後、標準モジュールか、別のクラスモジュールに移動させて、
他の未記述の処理も含めて、ピリオドの後に入力候補を表示させられる環境の中で
記述を進めていきたいと考えております。
(今はその為に、オブジェクト配列変数を同様に記述させたくて悩んでおります。)

また、ComboBoxの配列を引数「ByRef objVar As Variant」で渡すのも
クラスモジュールで設定したいつもりのオブジェクト配列変数を、
標準モジュールなどからクラス変数を呼び出す時に、参照渡しでこのように
記述しないとコンパイルエラーが出るのではないかと私は認識しているつもりだからです。
もしかしたら 不要 又は 誤り なのかもしれないのですが。

半平太さん、色々とご協力いただけまして誠にありがとうございます。
よろしければ引き続き、どうぞよろしくお願いいたします。
(これから調べ直しですので、まだ解決できておりませんでして、すみません。)
(山川海湖) 2023/05/03(水) 22:50:27


 >「Public cls As clsCtrlObjVar:Set cls = New clsCtrlObjVar」などと記述しておくと
 >標準モジュール側からは、「cls.」と記述するだけで、そのピリオドの後に
 >入力候補として、先ほどの定数の「c1Cmb」や他に記述済みの関数名やsub処理名が
 >ぶら下がって選択肢として表示されていますので、変数でも記述が成功すれば、
 >今回目指している構造にできるのではないかと考えております。

 ちょっと理解できないのですが、
 単純に変数をPublic属性で定義すればいいんじゃないですか?

 但し配列変数は不可なので、PropertyプロシージャとかFunctionプロシージャを使うしかないようです。
 また、返って来たオブジェクト変数(配列)は、一旦同じデータ型の配列に入れてからじゃないと
 イメージ通りに使えないようです。
 いずれにしても、Variantに型を変えたらインテリセンスが出なくなるのは当然だと思います。

 >ただ、今は正直、中途半端な状態でして、実は今回の質問前から既に、
 >拡張性などを追及したく思い、なるべくクラス内に記述しておき、後で
 >標準モジュールなどで関数や変数やら呼び出して使いたいと思っていましたが、
 >今のclsCtrlObjVarクラスモジュール内で記述しても、外からの呼び出しで無い為か
 >入力候補の自動表示の恩恵を受けられていません。

 簡単なサンプルを提示願えませんか?
 どのステートメントを書く途中でインテリセンスが出て来ないのか分かる様にお願いします。

 >なお、引数のUFやc1Cmbも、拡張性も考慮したり、実際に
 >他のUserform2以降や、他の定数でも使えるような関数化を図りたいために
 >わざわざ外からの引数を受ける形にしております。説明不足ですみませんでした。

 了解です。

(半平太) 2023/05/04(木) 11:10:27


半平太さん、色々とありがとうございます。
私からのレスが大変遅くなってしまいまして申し訳ございませんでした。
5/4(木)は早朝から外出し、一日全く対応できませんでした。
5/5(金)は、クラスについて、引き続き調べ続けていました。
色々と勉強にはなっておりますが、以下の通り、上手くできないかもしれないです。

>簡単なサンプルを提示願えませんか?
>どのステートメントを書く途中でインテリセンスが出て来ないのか分かる様にお願いします。

恐らくですが、自分自身の(クラスや)モジュールの変数だから、
インテリセンスが出てこないのだと思われます。
私がこれまで書きました様に、標準モジュールからでも、
「Public cls As clsCtrlObjVar:Set cls = New clsCtrlObjVar」のように書けば
クラス(clsCtrlObjVar)で作成した定数や関数やsub処理が「cls.」で
選択肢に呼び出せていますので、単に、同一箇所だからだと思われます。
私が今回やりたかった事は、例えば、オブジェクト配列変数「 uf1Cmb 」などを
「 cls.uf1Cmb(i) 」のように呼び出せればと思っていましたが、
もしかしますと、これは無理なのかもしれません。

>単純に変数をPublic属性で定義すればいいんじゃないですか?
>但し配列変数は不可なので、Propertyプロシージャとか
>Functionプロシージャを使うしかないようです。
>また、返って来たオブジェクト変数(配列)は、一旦同じデータ型の配列に
>入れてからじゃないとイメージ通りに使えないようです。
>いずれにしても、Variantに型を変えたらインテリセンスが出なくなるのは
>当然だと思います。

例えば、以下のようにクラスに書いても、その下のようなエラーが出てしまいます。


Dim v_uf1Cmb As ComboBox

Public Property Let uf1Cmb(index As Integer) As ComboBox

    uf1Cmb(index) = v_uf1Cmb
End Property

↑このように記述しても、既に赤色エラーが出ていて、コンパイルエラーとして、
「定数、固定長文字列、配列、ユーザー定義型および Declare ステートメントは、
 オブジェクト モジュールのパブリック メンバーとしては使用できません。」
のエラーが消えません。

私が調べてみたサンプルコードでも、例えば、PropertyでItemプロパティを設定して
「(コントロール変数名).Item(Index)」みたいな書き方をしていましたが、
私がやりたいことは、「uf1Cmb(i)」のような形でコーディングを楽したいことですので、
確かに、クラス化はできたとしても、今回の私には余りありがたくないのです。
繰り返しになりますが、私がやりたかったことは、「 cls.uf1Cmb(i) 」のような記述
ですので、もしかしたら、(VBAでは?)無理なのかもしれないと思いました。

いずれは、クラス化の恩恵を感じるかもしれませんが、今回、私が作ろうとした
内容であれば、クラス化してオブジェクト配列変数が扱いにくくなるよりも、
上述のような、subやfunctionでの簡略化の方が使い勝手が良さそうに感じてしまいました。

もちろん、現時点では、コンパイルエラーが出ていないというだけですから、
実際に記述を進めていって、この記述方法で問題なく動作できるかは
現時点では未確認なのですが、少なくとも、今回の私の望みは、クラス化では
実現できないのかなと思ってしまいました。(記述がかえって面倒になりそうでして)
(山川海湖) 2023/05/06(土) 02:21:17


私が今回やりたかったことは、入力手間を省いたり、短い変数名で見やすく
したかったことになります。例えば、クラスのクローンをclsとしたのは、
3文字+ピリオドで、入力候補が自動で選べたら、「見やすくて、入力手間も減る」
と思い、今回の質問をさせていただきました。

しかし、調べてみますと、VBAの仕様なのかもですが、
オブジェクト配列変数の場合は、そう簡単にできなさそうに思えました。

少なくとも、クラスクローン名.変数名.Item(i)のような記述では、
かえって、入力手間がかかる上に、煩雑で読みにくそうですので、
なんだか手間をかけて本末転倒なことをしているように思えました。

クラスの勉強にはなっています(まだ完ぺきではないです)が、
今回私が作成しようとしている内容においては、微妙な気がしてきました。
(山川海湖) 2023/05/06(土) 02:33:45


> Dim v_uf1Cmb As ComboBox
> Public Property Let uf1Cmb(index As Integer) As ComboBox
>  uf1Cmb(index) = v_uf1Cmb
> End Property

書き方、使い方 共に間違えてる。エラーになるのは当たり前です。
Let と Get をごちゃ混ぜにしている。

――― クラスモジュール Class1 ―――
Private クラス変数1(10) As String
Private クラス変数2 As Long

Public Property Let プロパティ1(ByVal Index As Integer, ByVal データ As String)
'※ 複数の引数を指定する場合、最後の引数がこのプロパティの属性であり、
'  対になるGetと同じ属性とする
  クラス変数1(Index) = データ
End Property

Public Property Get プロパティ1(ByVal Index As Integer) As String
  プロパティ1 = クラス変数1(Index)
End Property

Public Property Let プロパティ2(ByVal データ As Long)
'※ 引数が1つの場合、その引数がこのプロパティの属性であり、
'  対になるGetと同じ属性とする
  クラス変数2 = データ
End Property

Public Property Get プロパティ2() As Long
  プロパティ2 = クラス変数2
End Property
―――――――――
Sub xxxx()
 Dim クラス As Class1
 Set クラス = New Class1

 クラス.プロパティ1(2) = "文字列"
 クラス.プロパティ2 = 123456

 MsgBox クラス.プロパティ1(2)
 MsgBox クラス.プロパティ2
End Sub
 
 
 
 
 
インテリセンスが使いたいだけならば、構造体(Type 宣言)でも可能。
Private Type abc
 aaaa As Integer
 bbbb(1 To 3) As String
End Type

Sub xxx()
 Dim yyy As abc
 yyy.aaaa = 1
 yyy.bbbb(2) = "XYZ"
 MsgBox yyy.aaaa & vbCrLf & yyy.bbbb(2)
End Sub

(AddinBox_角田) 2023/05/06(土) 07:19:46


  >Functionプロシージャを使うしかないようです。
  >また、返って来たオブジェクト変数(配列)は、一旦同じデータ型の配列に
  >入れてからじゃないとイメージ通りに使えないようです。
  ここが、実に不可思議なのですけど、
  インテリセンスが効いているのにコンパイルエラーになるんですよ。
  理由が分かる人が居たら私も教えて欲しい。

  あと、既述の通り、Variantにしたらインテリセンスが効かなくなるので、
  これはマズいです。またネーミングもおかしい。
   ↓
  ByRef objVar As Variant

  なので、下のコードでは ByRef objCmb() As ComboBox としています。 
  インテリセンスが効かない箇所は無かったです。

  ’---clsCtrlObjVar クラス---------

  Private Const c_c1Cmb As Integer = 4
  Dim uf1Cmb(1 To c_c1Cmb) As ComboBox
  Dim iCount As Integer

  Property Get c1Cmb() As Integer
      c1Cmb = c_c1Cmb
  End Property

  Function SetCtrlVar(isSet As Boolean)
  '//isSet=True:変数set
  '//isSet=False:変数解放(Set 〜 = Nothing)
      Call SetObjVarCtrl(isSet, UserForm1, uf1Cmb, "ComboBox", 1, c1Cmb)
  End Function

  Sub SetObjVarCtrl(isSet As Boolean, ByRef UF As UserForm, _
      ByRef objCmb() As ComboBox, strCtrl As String, _
      iStart As Integer, iEnd As Integer)

      Select Case isSet
          Case True
              For iCount = iStart To iEnd Step 1
                  Set objCmb(iCount) = UF.Controls(strCtrl & iCount)
                  objCmb(iCount).Value = "TEST" & iCount '識別用の仮データ
              Next iCount

          Case False
              For iCount = iStart To iEnd Step 1
                  Set objCmb(iCount) = Nothing '解放
              Next iCount
      End Select

  End Sub

  Property Get PufCbxAry() As ComboBox()
      PufCbxAry = uf1Cmb
  End Property

  ’---標準モジュール---------

  Public objVar As clsCtrlObjVar

  Sub test()
      Dim objVar As New clsCtrlObjVar
      Dim cmbAry() As ComboBox

      Call objVar.SetCtrlVar(True) '変数Set

  '    Debug.Print objVar.PufCbxAry(1).Value      'インテリセンスは効くが、コンパイルエラー(※)になる。
  '                                               '※引数の数が一致していません。
  '                                               ' または不正なプロパティを指定しています。

      cmbAry = objVar.PufCbxAry                   '已むを得ず、一旦ComboBox型の配列に入れる
      Debug.Print cmbAry(1).Value, cmbAry(4).Value

      Call objVar.SetCtrlVar(False) '変数解放(Set 〜 = Nothing)
  End Sub

(半平太) 2023/05/06(土) 09:40:43


AddinBox_角田さん、ご指摘・ご教授ありがとうございます。
確かに、まだ私の中で、LetとGetの理解が微妙かもしれません。

ところで、今回ご提示頂きました事例は、String型とLong型ですが、
オブジェクト配列変数でも同様にできますでしょうか?
先日、ご提示頂きましたリンク先を見ていますと、
オブジェクト配列変数自体はItemプロパティを使ったり、クラスを2重にしなければ
使いまわしができなさそうにも見受けられますが、いかがでしょうか?

今更ながら、インテリセンスはプロパティかメソッドの位置づけのようですので、
確かに、(参照型?配列変数)オブジェクト自体を取得するのは少し違うのかも
しれないですし、リンク先では、Itemプロパティに本体をSetさせているようにも
見受けられました。

凡例の方?では、VBと同じ仕様として、Itemの書き方を消せると見受けましたが、
サンプルコードを見ていても、今の私では、どの部分でそれが可能となっているのか、
よく分かりませんでした。
(山川海湖) 2023/05/06(土) 13:26:09


半平太さん、ご指摘・ご教授ありがとうございます。

コンパイルエラーの内容は、オブジェクト配列変数だからでは
ないのでしょうか?私がVariantを使おうとしたのは、
オブジェクト配列変数ではコンパイルエラーになったからだったような
気がしていますが、色々やっていてよく分からなくなっております。

ご提示のコードでは、「Call objVar.SetCtrlVar(True) '変数Set」の行で
「オブジェクトは、このプロパティまたはメソッドをサポートしていません」
みたいなコンパイルエラーが出ませんか?
私の貼り付け方が良くないのかもしれませんが。
(山川海湖) 2023/05/06(土) 13:27:18


更に、クラスを分けて整理して使おうかと思いまして、
例えば、上述の「定数扱い部分」だけを、
clsConstモジュールに移動させて、(とりあえず)「Dim c As New clsConst」と書いて、
「Dim uf1Cmb(1 To c.c1Cmb) As ComboBox」を使おうとしても、
「c.」の後ろの「c1Cmb」の箇所で、「定数式が必要です。」のコンパイルエラーが出ます。

インテリセンスは取れますが、Propertyでは定数っぽく書いているだけのようで
今回の私の想定した使い方はできなさそうに思えました。
ちなみに、NewはDimと分けてSetの場所で使うべきと思っていますが、
とりあえず、簡単な動作確認のつもりで試してみただけになります。

私自身が別のサイトのテクニックを真似たつもりで、Propertyで定数も
インテリセンスを取れると思っていましたが、Dimでの定数箇所には
この書き方では対応できないのかもしれないですね。
(山川海湖) 2023/05/06(土) 13:29:11


半平太さん、失礼いたしました。今のところ、エラーは出ませんでした。
イミディエイトウィンドウに、TEST1とTEST4だけ表示されました。
先ほどは、objCmb()の部分をobjVarのままになっていました。

ただ、この書き方ですと、ComboBoxにしか対応できないですね。
私がVarで書いていたときは、他のコントロールについても
関数として使うために、そうしていましたので、他のコントロールで
まとめて使用できなくなってしまいました、、、
(山川海湖) 2023/05/06(土) 13:40:16


 山川海湖さんのやっている事がどんなものなのかを想像しながら
 進めるのはしんどいので、申し訳ないですが私はここまでとします。 m(__)m

(半平太) 2023/05/06(土) 15:46:06


Item プロパティの既定プロパティ化の
方法は §10 の中程に紹介してます。
 
 
 
イベント処理が必要無ければ、
オブジェクト変数の配列化には
クラスを2重にする必要はありません。
そもそも、クラス自体不要です。
オブジェクトをそのまま配列定義すれば
良いだけです(§2、§3)。
(AddinBox_角田) 2023/05/06(土) 19:21:49

半平太さん、色々とご教授・ご指摘いただけまして誠にありがとうございました。
私の勉強不足を痛感しております。引き続き勉強を進めてまいります。
私の説明や考察・構想の至りません箇所が多くて、お手数をお掛けいたしました。

半平太さん、ご教授やご指摘、ご協力いただけましてどうもありがとうございました。
(山川海湖) 2023/05/07(日) 04:00:58


AddinBox_角田さん、色々とご教授・ご指摘いただけまして誠にありがとうございます。
2重クラスはイベント処理と配列処理の組み合わせに必要なのですかね。

私にとりましては、インテリセンスからオブジェクト配列変数も選択できれば、
入力が楽そうに思えたのですが、その為には、プロパティかメソッドのように、
それだけの個数を準備しなければならなさそうですかね。
クラスを使えば一気に処理できるのかと私は勘違いしていたかもしれません。

恐らくですが、同じような構造体を幾つも扱う時などには、一度、設計図を作成しておき
それを複製して使えば、定義とか設定が楽なのかもしれないのかなと思います。
私がクラスを使いこなすには、もう少し時間を掛けて勉強を続ける必要がありそうです。

AddinBox_角田さん、ご教授やご指摘、ご協力いただけましてどうもありがとうございました。
(山川海湖) 2023/05/07(日) 04:04:51


ご教授ありがとうございます。
typeでもインテリセンスが使えそうですので、
これで進めてみようかなと思いました。
(山川海湖) 2023/05/07(日) 05:47:00

コメント返信:

[ 一覧(最新更新順) ]


YukiWiki 1.6.7 Copyright (C) 2000,2001 by Hiroshi Yuki. Modified by kazu.