[[20131030060619]] 『2個のテキストボックスの値をドラッグ&ドロップ』(欲張り爺さん) ページの最後に飛ぶ

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

 

『2個のテキストボックスの値をドラッグ&ドロップで入替える』(欲張り爺さん)
ドラッグ&ドロップで入替え操作が出来ないかと思い、エクセルのヘルプ等で検索したのですが、DataObject,StartDrag,Effect等の初めて聞く(見る)単語が続出し、思うように理解できませんでした。
その使用例を見ても『Effect』の使い方に関しては特に?マークでした。更に例ではテキストボックスのコピペであり、複写先の情報等は皆無で値の入れ替え所ではありませんでした。Web上で検索しても見当たりませんでした。
実際にエクセルのフォーム上で『ドラッグ&ドロップで値の入替え』は可能でしょうか?

(環境)Windows8 Pro,Excel2010


TEXTBOXのプロパティにDrugBehaviorというのがあるので、
この値をfmDragBehavirEnabledに変更してみてください。
(みやほりん) 2013/10/30(水) 09:47

追記
単純に選択テキストをドラッグアンドドロップできるようになるだけなので、
入れ替えまではできません。
(みやほりん) 2013/10/30(水) 09:49

 みやほりんさんのDrugBehaviorをfmDragBehavirEnabledにした後で、こんな感じに入れて置くと出来るか・・・?
Private tmp As Object
'//マウスクリックしたときの処置
Private Sub TextBox1_MouseDown(ByVal Button As Integer, ByVal Shift As Integer, ByVal X As Single, ByVal Y As Single)
        With TextBox1
            .SetFocus
            .SelStart = 0
            .SelLength = Len(.Text)
        End With
    Set tmp = TextBox1
End Sub
Private Sub TextBox2_MouseDown(ByVal Button As Integer, ByVal Shift As Integer, ByVal X As Single, ByVal Y As Single)
        With TextBox2
            .SetFocus
            .SelStart = 0
            .SelLength = Len(.Text)
        End With
    Set tmp = TextBox2
End Sub
'//ドロップした時の処置
Private Sub TextBox1_BeforeDropOrPaste(ByVal Cancel As MSForms.ReturnBoolean, ByVal Action As MSForms.fmAction, ByVal Data As MSForms.DataObject, ByVal X As Single, ByVal Y As Single, ByVal Effect As MSForms.ReturnEffect, ByVal Shift As Integer)
    tmp.Value = TextBox1.Value
    TextBox1.Value = ""
End Sub
Private Sub TextBox2_BeforeDropOrPaste(ByVal Cancel As MSForms.ReturnBoolean, ByVal Action As MSForms.fmAction, ByVal Data As MSForms.DataObject, ByVal X As Single, ByVal Y As Single, ByVal Effect As MSForms.ReturnEffect, ByVal Shift As Integer)
    tmp.Value = TextBox2.Value
    TextBox2.Value = ""
End Sub

(稲葉) 2013/10/30(水) 10:04


早速のご返答ありがとうございます。丁度仕事から帰ってきて直ぐにこのサイトへ来たところでした。
これからどうなるのかをチャレンジしたいと思います。後ほど結果報告をいたします。
(欲張り爺さん) 2013/10/30(水) 18:16

みやほりんさん、稲葉さんへ

 大変有難うございます。キッチリと私の思い通りの動きになりました。
私の目的はフォーム内に15個のTextBoxを並べ、一旦夫々のTextBoxに書込む。
書込み後に、順番の入れ替えを簡単に出来る方法を探っていたのです。
これならば容易に操作できますね。
この方法の中や下の例も『Past』というメソッドが無いのですが不自然に感じます。
然し、そういう仕組みになっているんだと解釈しました。

もう一つこの件に絡み不明な事柄が有ります。
当初、エクセルのヘルプから『StartDrag』を検索した所、その使用例の中から
次の様なものが有りました。しかし、理解する事が出来ません。

Private Sub ListBox1_MouseMove(ByVal Button As _

     Integer, ByVal Shift As Integer, ByVal X As _
     Single, ByVal Y As Single)
Dim MyDataObject As DataObject
Dim Effect As Integer
    If Button = 1 Then
        Set MyDataObject = New DataObject
        MyDataObject.SetText ListBox1.Value
        Effect = MyDataObject.StartDrag
    End If
End Sub

上記の中の『Effect』の果たす役割が良く分かりません。
例の中では『Effect』を変数宣言しているだけの様に見え、なんの為なんでしょうか? 

 MyDataObject.StartDrag (0〜3) と記述しても同じ動作。殆ど理解不能です。
宜しければご教示をお願いします。

(欲張り爺さん) 2013/10/30(水) 19:10


みやほりんさん、稲葉さんへ

誠に申し訳ありません。よくよく考えてみれば複数のTextBoxを抱えている時にはどうなるんでしょうか?
最初のTextBoxは分かるにしても、Swap先が分かりません。この様な時はどうすれば良いのでしょうか?
MouseMoveイベントを使用するのではと考えますが、それを全く使った事が無く途方に暮れています。
よろしくお願いします。
(欲張り爺さん) 2013/10/30(水) 20:05


 私の頭ではこれが限界・・・
 マウスムーブとかたぶんいらないです。
 マウスクリックとドロップのイベントだけ拾えば何とかなります。
 追加するときは、
 '//=====textbox1=====
 '=====ここまで=====
 この間をコピーしてコントロールの名前を併せてください。

Private tmp As Object
'//=====textbox1=====
Private Sub TextBox1_MouseDown(ByVal Button As Integer, ByVal Shift As Integer, ByVal X As Single, ByVal Y As Single)

    Call MD(TextBox1)
End Sub
Private Sub TextBox1_BeforeDropOrPaste(ByVal Cancel As MSForms.ReturnBoolean, ByVal Action As MSForms.fmAction, ByVal Data As MSForms.DataObject, ByVal X As Single, ByVal Y As Single, ByVal Effect As MSForms.ReturnEffect, ByVal Shift As Integer)
    Call BD(TextBox1)
End Sub
'=====ここまで=====

'//textbox2
Private Sub TextBox2_MouseDown(ByVal Button As Integer, ByVal Shift As Integer, ByVal X As Single, ByVal Y As Single)

    Call MD(TextBox2)
End Sub
Private Sub TextBox2_BeforeDropOrPaste(ByVal Cancel As MSForms.ReturnBoolean, ByVal Action As MSForms.fmAction, ByVal Data As MSForms.DataObject, ByVal X As Single, ByVal Y As Single, ByVal Effect As MSForms.ReturnEffect, ByVal Shift As Integer)
    Call BD(TextBox2)
End Sub
'=====ここまで=====

'//textbox3
Private Sub TextBox3_MouseDown(ByVal Button As Integer, ByVal Shift As Integer, ByVal X As Single, ByVal Y As Single)

    Call MD(TextBox3)
End Sub
Private Sub TextBox3_BeforeDropOrPaste(ByVal Cancel As MSForms.ReturnBoolean, ByVal Action As MSForms.fmAction, ByVal Data As MSForms.DataObject, ByVal X As Single, ByVal Y As Single, ByVal Effect As MSForms.ReturnEffect, ByVal Shift As Integer)
    Call BD(TextBox3)
End Sub
'=====ここまで=====

Private Sub BD(T As Object)

    tmp.Value = T.Value
    T.Value = ""
End Sub
Private Sub MD(T As Object)
    With T
        .SetFocus
        .SelStart = 0
        .SelLength = Len(.Text)
    End With
    Set tmp = T
End Sub
(稲葉) 2013/10/31(木) 08:58

稲葉さんへ
朝早くからご返答頂きありがとうございます。
ご指摘の様な方法は考えましたが、私の場合これが15個並ぶ事を思うと
大変だな〜の一語につきました。
然し、私の知らない世界をご教示して頂いた事には大変感謝しています。
実は昨日、Web上の検索ではエクセルには他の上位ソフトに有る様なDrag&Drop
は実装されていないとの記述がありました。
つまり、面倒ではありますがご教示して頂いた手法で取敢えずは構築する予定です。
同時に他の手法も考えて行きたいと思っています。
有難う御座いました。
(欲張り爺さん) 2013/10/31(木) 18:30

 クラスモジュールでコントロール配列を使う例です。

 クラスモジュールの二つ用意してください(Class1 Class2)。

 Class1のモジュール

 '===========================================================================
 Option Explicit
 Private txtcls As Collection
 Event mousedown(ByVal txt As MSForms.TextBox)
 Event dragorpast(ByVal txt As MSForms.TextBox)
 Private Sub Class_Initialize()
    Set txtcls = New Collection
 End Sub
 Sub add(txt As MSForms.TextBox)
    Dim cls As Class2
    Set cls = New Class2
    Set cls.txt = txt
    Set cls.parent = Me
    txtcls.add cls
 End Sub
 Sub mousedown(ByVal txt As MSForms.TextBox)
    RaiseEvent mousedown(txt)
 End Sub
 Sub dragorpast(ByVal txt As MSForms.TextBox)
    RaiseEvent dragorpast(txt)
 End Sub
 Private Sub Class_Terminate()
    Set txtcls = Nothing
 End Sub

 Class2のモジュール

 '=================================================================
 Option Explicit
 Public parent As Object
 Public WithEvents txt As MSForms.TextBox
 Private Sub txt_BeforeDropOrPaste(ByVal Cancel As MSForms.ReturnBoolean, ByVal Action As MSForms.fmAction, ByVal Data As MSForms.DataObject, ByVal X As Single, ByVal Y As Single, ByVal Effect As MSForms.ReturnEffect, ByVal Shift As Integer)
    parent.dragorpast txt
 End Sub

 Private Sub txt_MouseDown(ByVal Button As Integer, ByVal Shift As Integer, ByVal X As Single, ByVal Y As Single)
    parent.mousedown txt
 End Sub

 ユーザーフォームのモジュール

 Option Explicit
 Private WithEvents txtClass As Class1
 Private ctxt As MSForms.TextBox
 Private Sub txtClass_dragorpast(ByVal txt As MSForms.TextBox)
    ctxt.Value = txt.Value
    txt.Value = ""
 End Sub
 Private Sub txtClass_mousedown(ByVal txt As MSForms.TextBox)
        With txt
            .SetFocus
            .SelStart = 0
            .SelLength = Len(.Text)
        End With
    Set ctxt = txt
 End Sub
 Private Sub UserForm_Initialize()
    Dim g0 As Long
    Set txtClass = New Class1
    For g0 = 1 To 5 '←ここは、テキストボックスの数によって変更
        txtClass.add Controls("textbox" & g0)
    Next
 End Sub
 Private Sub UserForm_Terminate()
    Set txtClass = Nothing
 End Sub

 尚、各テキストボックスのプロパティDrugBehaviorをfmDragBehavirEnabledにすることは大前提です。

 コントロール配列を扱うときは、だいたいは 以下のサイトをご紹介しています。

http://www.h3.dion.ne.jp/~sakatsu/Breakthrough_P-Ctrl_Arrays.htm

 ここをよく読んでみることをお勧めします。

http://www.h3.dion.ne.jp/~sakatsu/Bpca_Common.htm

 試していませんが、↑からDLしたアドインを使えば、上記のクラスモジュールの部分は要り
 ません(インターフェースは違います)

 同じようなことができ、しかも他のいろんなコントロールに対しコントロール配列をサポートする
 アドインになっています。
 最初は、使用方法や概念の習得に苦労はすると思いますが、
 勉強すれば、次回からはこのような事象では、アドインを利用すれば
 同じようなコードを何回も書かなくても済むようになると思いますよ

 試してみてください

(ichinose) 2013/11/01(金) 05:39


 ichinoseさん
 いつも勉強になります。
 ご紹介頂いた、サイト
 §3まで読んで、§4から逃げてました!

 頑張って理解出来るようにします。

 欲張り爺さん(さん?)
 へたくそなやり方ですみませんでした。
(稲葉) 2013/11/01(金) 09:07

稲葉さん
へたくそな方法と言われますが私には貴重な資料となりました。
このDrag&Dropも知らなかった私だからです。
稲葉さんからご教示して頂いた今回の方法も、何故Swapしているのか分かりません。
理由は、Tmp=Text000 は有るのに Text000=Tmp が無いからです・・・。

Ichinoseさん
ご紹介のBPCAについては1年前ほど前に見てきました。然し、10章で挫折しました。
理由はIchinoseさんのクラスモジュールを見るのと同じ様に私にとって難解だったからです。
理解しようとしてk窓(083)も見ましたがやはり理解出来なかったのです。
昨日は自分なりに試行錯誤をしていてこれを見ていませんでした。済みません・・・

IchinoseさんのクラスモジュールではIndexに関する記述が無くても、フォームモジュールでは
呼出す事が出来るなんて素晴らしい事です。(それにすごく簡潔!)
訳も分からずクラスモジュールに『txt_BeforeDropOrPaste(ByVal Cancel As MSForms…』と
長々書込んで昨日からのエラーばかりのモジュールがエラーとならなくなっただけの状況でした。

恐縮ですが、終了時の処理はこれだけでいいのでしょうか?

 Private Sub UserForm_Terminate()
    Set txtClass = Nothing
 End Sub

 Class_Terminate()でCollectionの解放は不要なんでしょうか?
この辺もいつも分からず仕舞いで適当に片付けています・・・
本当にクラスモジュールも難解でしょうがないのです。とほほ・・・

通常のコレクションを使う事は出来ますが、クラスモジュールで扱う事が出来ません。
使う事が怖いのです。変数をウォッチウィンドに入れステップ実行しても『何で此処に』
と思う事ばかり、色々試せば試す程に収拾がつかなくなるのでそこへ立ちれないのです。

これからも挑戦したいと思います。又、説明する事は不得手なので結果については簡単に
報告したいと思っています。今後もよろしくお願いします。
(欲張り爺さん) 2013/11/02(土) 18:28


こんにちは。

上のほうで欲張り爺さんからご質問のあった件、
ListBox1_MouseMoveイベントの、ヘルプのサンプルコードの
Effect = MyDataObject.StartDrag の意味ですが、
これは右辺を実行するのが目的です。

そうすることで、データがマウスドラッグにくっついて
移動するようになります。移動していったデータが
BeforeDragOverイベントやBeforeDropOrPasteイベントの
「ByVal Data As MSForms.DataObject」この引数に入り、
ListBox2.AddItem Data.GetTextで取得されます。

0〜3の引数を与えても何も変わらないとのことですが
ドラッグ時のマウスポインタの形状が変わるようです。
引数により、ドロップできない場所では×マークだとか
コピーになる場所では+マークが出たり出なかったりします。
ヘルプの説明とは微妙に違うようですが、それは置くとして
ドラッグしたらどうなるか、目で見て分かるのは、
とくに自分以外のひとに使ってもらうときに有意義だと
思います。何も言わなくても分かる・使えるということです。

ヘルプによれば、StartDragメソッドの構文は、
fmDropEffect=Object.StartDrag([Effect as fmDropEffect])
なので、メソッドの返り値を変数に代入するのが「正式」
なのでしょう、たぶん。いまのわたしには分かりませんが、
もっともっと勉強すれば返り値の使い道を思いつくのかも
しれません。

(  佳 ) 2013/11/02(土) 19:28


お早うございます 

佳さんへ
DataObjectについての概念が今一の状態なので、ある程度は使える迄に調べたいと思います。
StartDrag も同じ様に理解不足で未だ質問できる状況ではありません。
有難うございました。

Ichinoseさんへ
Indexの件は私の早合点でした。(これは私の悪い性格でして・・・)やっぱり理解は?です。

 理解出来ない事への質問です。
 '=========================== Class1のモジュール =============================
 Option Explicit
 Private txtcls As Collection
 Event mousedown(ByVal txt As MSForms.TextBox)
 Event dragorpast(ByVal txt As MSForms.TextBox)
 Private Sub Class_Initialize()
    Set txtcls = New Collection
 End Sub
 Sub add(txt As MSForms.TextBox)
    Dim cls As Class2
    Set cls = New Class2
    Set cls.txt = txt           '← cls. の入力後の自動候補には上がって来ません
    Set cls.parent = Me         '  [Class2] の Public WithEvents txt As MSForms.TextBox か?
    txtcls.add cls              '← このコレクションはどの様に参照しているのか?
 End Sub

もう一点、コントロールの[txtClass]を[txtClass(i)]と扱う事が出来る様にするには
どうしたらいいのでしょうか? 全く分かりません。よろしくお願いします。

(欲張り爺さん) 2013/11/03(日) 06:39


こんにちは。

データオブジェクトはデータを入れておく箱のようなものです。
そう、変数のようなものです。

ややこしいのは、変数のこともデータオブジェクトと言い、
変数の型のこともデータオブジェクトと言うところです。
研究されるときは、とくに意識して切り分けてください。

(それさえなければFSOやRegExと大して変わりませんし
Set cls = New Class1とも大して変わりません。)

( 佳 ) 2013/11/03(日) 08:24


佳さん こんにちは。

このサイトで初めて質問したのは最近でした。皆さんのレスの速さには驚きました。
佳さんからのレスも本当に早く、皆さん夜は寝ないのかな〜と思うほどです。
(私は色々不明な点を探っていましたが、分からず酒を喰らって早々お寝んねでした)

私の実は、クラスモジュールの勉強を始めたの2年前ですが、殆ど進捗が無いのです。
FSOについても数か月前に知って自分の使える範囲で利用しているのが現状です。
趣味でのみ使っている為、性急さを求められ事は全然ありません。分からない ⇒ 中止
62歳の私にはAnsされる人達の頭の良さには Unbelievable
不明でも概念(想像)で分かる事と、全く不可能な事=クラスモジュール
これが私の印象です。             これからもよろしくお願いします。
(欲張り爺さん) 2013/11/03(日) 09:44


 こんにちは。

 欲張り爺さんの勉強熱心には、こちらのほうがいい影響をいただいています。
 VBAの勉強は、「しし脅し」みたいなものと思います。
 竹筒にすこしずつ水がたまっていき、でも何も起こらず、水がある一定量を
 超えたときはじめて 竹筒が回転して中の水が一気にあふれ出ます。 
 いまは、水をためている段階でしょう。

 >   Set cls.txt = txt           '← cls. の入力後の自動候補には上がって来ません
 Class2のコードを書くまでは、自動候補には上がって来ません。
 まだ書かれていないクラスにどんなプロパティがあるか、誰にも分かりませんよね。

 >   Set cls.parent = Me         '  [Class2] の Public WithEvents txt As MSForms.TextBox か?
 Class2のParentプロパティに自分自身を設定する。養子縁組みたいなものです。
 Class2がParentを呼んだときに、自分が反応するような仕組みを作りたいわけです。
 なので名前はParentでなくても何でも良いのです。

 >   txtcls.add cls              '← このコレクションはどの様に参照しているのか?
 Class1モジュールの冒頭にある「Private txtcls As Collection」ということでよろしいのでしょうか。
 見当はずれのコメントでしたらすみません。

 > もう一点、コントロールの[txtClass]を[txtClass(i)]と扱う事が出来る様にするには 
 実際に環境を作って、いろいろ試していたのですが
 ユーザーフォームを立ち上げるたび テキストボックスにデータを手入力するのが面倒で
 ユーザーフォームのコードを下記のように変更しました。...こんなので答えになるでしょうか。
 Private Sub UserForm_Initialize()
    Dim g0 As Long
    Set txtClass = New Class1
    For g0 = 1 To 5 '←ここは、テキストボックスの数によって変更
        Controls("textbox" & g0).Value = g0 & g0 & g0   '←★ここを追加
        txtClass.add Controls("textbox" & g0)
    Next
 End Sub

( 佳 ) 2013/11/03(日) 13:52


こんにちは。

 >   Set cls.parent = Me
 >   txtcls.add cls
については漠然としてですが理解出来ました。送信した後に確認したところ
自分の間違いに気付きました。

以下に就いては私の説明不足で済みません。
※もう一点、コントロールの[txtClass]を[txtClass(i)]と扱う事が出来る様にするには
 (1)各TextBoxにインデックスを付け、選択実行しているコントロールが分かる様にする。
 (2)任意のTextBoxをTextBox(i)として、TextBox(i)=xxxx で値やプロパティーの変更を可能にする
どの様にしたらいいのでしょうか?

PS:自分で適当に弄ってみましたが、エラー若しくは意図するものとは懸け離れ、用を足せませんでした。
アクセスは初級クラスですが若干知識が有り、こちらで作成すれば殆ど考えなくても実装されている機能だけで
出来るとは思います。然し、何故かエクセルの方が面白いのです。VBAの将来は無いと聞きますが…
皆さんはどの様に考えますか?

(欲張り爺さん) 2013/11/03(日) 16:33


こんにちは。

 Private txtcls As CollectionをPublieに変えて
 MsgBox txtClass.txtcls(3).txt.Value

 なんて美しくないこと(笑

 そもそもが、どのテキストボックスを操作しても関係なく
 同じひとつのコードで用を足そうという目的の仕組みなので、
 テキストボックスをインデックスで操作しようというのは
 そぐわないと思います。
 それ用のコードをまったく別に考えるほうがよろしいかと。

( 佳 ) 2013/11/03(日) 18:36


 ichinoseさんのコードをお借りして

 Class1に新たに読み取り専用のプロパティを作成します。

 Public Property Get Item(ByVal Index As Variant) As Class2
     Set Item = txtcls(Index) 'Indexよりコレクションの要素を取り出す
 End Property

 Class1のAddメソッドに少しだけ変更を加えます。

 Sub add(txt As MSForms.TextBox)
    Dim cls As Class2
    Set cls = New Class2
    Set cls.txt = txt
    Set cls.parent = Me
    txtcls.add cls, CStr(txt.Name) 'CollectionにAdd時にTexBoxの名前をKeyにして登録します。
 End Sub

 Keyを登録することで登録した順番でのアクセス、名前でのアクセスが可能になります。

 UserFormからの使用例

 インデックス指定
 MsgBox txtClass.Item(1).txt.Name

 名前指定
 MsgBox txtClass.Item("TextBox1").txt.Name

 これを日本語で説明すると
 txtClass(Class1)のメンバであるItemにインデックスを指定し、Collectionの要素(Class2型の参照)
 を返す。
 そのClass2のメンバであるtxt(Msforms.TextBox型)にアクセスする

 余談
 Accessの標準機能で作れる物をあえてExcel VBAでやってみる。
 (フォームウィザードを使えば一発で出来上がるのに)
 大好きですよ。その考え方。
 自前で処理しなきゃいけない事が沢山出てきますが
 それを乗り越える度に成長を実感できるはずです。
 62歳でその取り組む姿勢。頭が下がります。頑張って下さい。

(とおりすがり) 2013/11/03(日) 19:49


皆さん有難うございます。

取敢えず皆さんのコードを見た段階です。ほんの少しの変更で私の願望を叶える事が分かりました。
分かった事として、皆さんのコードを見ても理解出来ない事です。(利用は出来ます)
BPCAを見た時も、その形式や使用方法は分かれども『何でこうなるの?』ばかりでした。
皆さんに申し訳なく思っている事は、BPCAを使えば自分の目的は達成されます。然し、私としては
少しでもより多く理解したかったから質問しました。
自分の分からない事など星の数ほどあります故、今後もよろしくお願いします。
只、これから自分との戦いの作業に入りますので一時休憩します。

 本当に皆さん有難う御座いました。

(欲張り爺さん) 2013/11/03(日) 20:38


おはようございます。

本日目覚めると同時に、Class1にItemプロパティを作れば良いんだ!
と気づいたものの、とおりすがりさんからご解答がありました。

まだ起き抜けなので頭が回っていませんが、できれば
MsgBox txtClass.Item(1).Name という形に持っていけないものか、
と思っています。
さらに、できれば、Itemプロパティを規定のメンバーにして
MsgBox txtClass(1).Name というかたちに、、、できるものなのか?
ためしてみます。

おかげさまで本日の楽しみができました。
もしかしたら、向こう10年の楽しみになるのかもしれませんが。
ありがとうございました。

( 佳 ) 2013/11/04(月) 05:10


お早うございます。
早朝からの書込み有難うございます。

私も3時に起きて『とおりすがりさん』の回答を考えていました。
実際に私が必要としているのはItemプロパティとIndexプロパティ ←★★★
を同時に取得したいのです。昨日と同じくクラスモジュールの構図
も分からないまま試行しました。やっぱり出来ませんでした。

 Property Let Index(ByVal newIndex As Long)
   cIndex = newIndex
 End Property
などとしようとしましたが、これを何処へ入れるのか? 又、Indexの元となる連番を
何処から引っ張り出すのやら、更には Property Get をどう書くのかも・・・
私のクラスモジュールに関する知識はこの程度です。
私の様な者でも分かる様な参考書をご紹介願えればと思います。

(欲張り爺さん) 2013/11/04(月) 06:19


 欲張り爺さん さん

 TextBoxに何がしたいのか、どのタイミングで、どこのモジュールから実行したいかでクラス内の
 作り方が変わってくると思いますので、最終的にどういった使い方を
 想定されているのかご説明があると分かりやすいです。

 佳さんの
 >txtClass(1).Name というかたちに、、、できるものなのか?

 本日のお楽しみということで、書くのも気が引けるのですが

 これは、Class1のItemプロパティに

 Public Property Get Item(ByVal Index As Variant) As Class2
     Attribute Item.VB_UserMemId = 0 '既定のメンバーにする一文を追加する
     Set Item = txtcls(Index) 'Indexよりコレクションの要素を取り出す
 End Property

 Class2にもItemプロパティを作成して

 Public Property Get Item() As MsForms.TextBox
     Attribute Item.VB_UserMemId = 0 '既定のメンバーにする一文を追加する 
     Set Item = txt
 End Property

 このAttribute はこのままコンパイルするとエラーになります。
 Class1、Class2を一度エキスポート、解放、インポートしてコンパイルします。
 この操作で2つのクラスのItemが既定のメンバーになります
 VB6だとクラスウィザードで出来る行為ですが、VBAにはないのでこの方法で行います。

 両クラスのGet Itemプロパティが既定のメンバーになれば
 txtClass(1).Name は実現出来ます。

(とおりすがり) 2013/11/04(月) 08:25


こんにちは。

私の作成しているのは
[データシート]
1)カレンダー風の配送先リスト(横列=日付:縦列=行先)   ----11月5日 --|----11月6日 --|
  行先は毎日、30件程度。                       | xxxxxxxxxxxx | xxxxxxxxxxxxxxx |
  配達担当は3〜4名。
2)運転日報…各担当者ごとに印刷して渡す。
3)行先データリスト

[ユーザーフォーム] Modeless
 日付(Label)、担当者(ComboBox);各1個
 CheckBox:15個 ・・・TextBox と対
 TextBox :15個  
 その他、今回に関連しないコントール

(操作)
シート画面を好む入力者を考慮して、Modelessのユーザーフォームとシートを行き来する。
配送先リストの行先を選択してCheckBoxを押す。
結果、担当者ごとに割振った背景色をシートに。TextBoxへその行先を表示。
選択済みの行先で実行した場合、メッセージを出す。
※ここまでは完了済み。又、行先の変更等についても処理済み。

【問題発生】
担当者の行先の順番を変える事が多々有り、TextBox の入替が必要になったのです。
同時に、CheckBox の値変更も必要なのです。
つまり、TextBox の入替の時点で CheckBox も変更する必要があるのです。
然し、入替えすら分からなかったのです。
故に、Indexも同時に知りたいのです。

別の方法(リストを2個使っての順番替え等)も考えたのですが、利用者から見た場合
面倒臭さが目に浮かび中止しました。

こんな説明でご理解できるでしょうか。

(欲張り爺さん) 2013/11/04(月) 13:06


 >同時に、CheckBox の値変更も必要なのです。 
 >つまり、TextBox の入替の時点で CheckBox も変更する必要があるのです。 

 テキストボックスのオブジェクト名をTextBox1〜TextBox15、対応するチェックボックスは、
 CheckBox1〜CheckBox15と命名すれば、そんなに難しいことではないです。

 Class1、Class2は、前回投稿したとおりです。

 ユーザーフォームのモジュールだけ
 Option Explicit
 Private WithEvents txtClass As Class1
 Private ctxt As MSForms.TextBox
 Private cchk As MSForms.CheckBox
 Private Sub txtClass_dragorpast(ByVal txt As MSForms.TextBox)
    Dim wk1 As Variant
    Dim wk2 As Variant
    ctxt.Value = txt.Value
    txt.Value = ""
    wk1 = cchk.Value
    wk2 = cchk.Caption
    With Controls(Replace(txt.Name, "TextBox", "CheckBox"))
       cchk.Value = .Value
       .Value = wk1
       cchk.Caption = .Caption
       .Caption = wk2
    End With
 End Sub
 Private Sub txtClass_mousedown(ByVal txt As MSForms.TextBox)
        With txt
            .SetFocus
            .SelStart = 0
            .SelLength = Len(.Text)
        End With
    Set ctxt = txt
    Set cchk = Controls(Replace(txt.Name, "TextBox", "CheckBox"))
 End Sub
 Private Sub UserForm_Initialize()
    Dim g0 As Long
    Set txtClass = New Class1

    For g0 = 1 To 15
        txtClass.add Controls("textbox" & g0)
        Controls("textbox" & g0).Value = String(10, Chr(&H41 + g0))
    Next

 End Sub
 Private Sub UserForm_Terminate()
    Set txtClass = Nothing
 End Sub

 とすればよいのでは?

 オブジェクト名をうまく合わせれば Controlsプロパティを使えばどうにかなります。

 こういうことがちょっと考えれば、解決できるように コントロール配列という方法を
http://www.h3.dion.ne.jp/~sakatsu/Breakthrough_P-Ctrl_Arrays.htm 

 説明しているのです。

 それから、 
 >Class_Terminate()でCollectionの解放は不要なんでしょうか?

 Set txtClass = Nothing 'これが実行された時にClass1の

 Private Sub Class_Terminate()
    Set txtcls = Nothing
 End Sub

 このイベントが実行されます。

 もっとも、私がコードを提示したのは、コントロール配列のアルゴリズムの一例を
 提示しただけで実際の運用は、提示したURLからDLしたアドインを使って、配列コントロールを
 構築することをお勧めします。

 もちろん、同じ機能を持ったものを作る というなら、話は別ですが、結構大変ですからねえ。

 >理由はIchinoseさんのクラスモジュールを見るのと同じ様に私にとって難解だったからです。 

 私がリンク先で言う疑似コントロール配列を見たのは、15年ぐらい前、モーグの元代表の方が
 載せた日経ソフトウエアの記事です。

 当初は、私もよくわからなかったことを覚えています。

 自分のわからないことを相手にわかるように記述することは、よい勉強になりますよ。

(ichinose) 2013/11/04(月) 14:24


 欲張り爺さん さん
 少しだけ場所貸してください。
 私もクラスの勉強したいので・・・

 ichinoseさんの紹介頂いた「疑似からの脱却」を全て読みました。
 セクション通りに構築したところ、無事動かすことができたのですが・・・
 上で紹介頂いたコードと何か違う!!と思い、参考にしながら簡素化を進めていたのですが、
 イベントが発生しなくなりました。

 半日くらい悩んでどうしても答えが出ませんでした。
 せっかくの機会でしたので、是非なぜイベント起きないのか教えていただきたく、ずうずうしく
 場所をお借りした次第です。

 '//クラス「clsOP」
Option Explicit
Private OP_Val As Collection
Public Event click(ByVal index As Integer)
Private Sub Class_Initialize()
    Set OP_Val = New Collection
End Sub
Sub Add(Ev_OP As MSForms.OptionButton, Index As Integer)
    Dim cls As clsOP_Sub
    Set cls = New clsOP_Sub
    Set cls.Ev_OP = Ev_OP
    Set cls.Parent = Me
    cls.index = Index '★インデックス番号で条件分岐させているので、番号が欲しい
    OP_Val.Add Ev_OP
End Sub
Sub click(ByVal index As Integer)
    RaiseEvent click(index)
End Sub
Private Sub Class_Terminate()
   Set OP_Val = Nothing
End Sub

 '//サブクラス「clsOP_Sub」
Option Explicit
Public WithEvents Ev_OP As MSForms.OptionButton
Public Parent As Object
Public index As Integer
Private Sub Ev_OP_Click()
    Parent.click (index)
End Sub

 '//ユーザーフォーム
Private WithEvents cOP As clsOP
Private Sub UserForm_Initialize()
    Dim i As Integer
    Set cOP = New clsOP
    With cOP
        For i = 1 To 10
            .Add Controls("OP" & i), i
        Next i
    End With
End Sub
Private Sub cOP_Click(ByVal index As Integer)'★ブレークポイント置いても反応なし!
    Call 検索(index)
End Sub
Private Sub UserForm_Terminate()
    Set cOP = Nothing
End Sub
(稲葉) 2013/11/04(月) 16:32

 >Sub Add(Ev_OP As MSForms.OptionButton, Index As Integer)
 >   Dim cls As clsOP_Sub
 >   Set cls = New clsOP_Sub
 >   Set cls.Ev_OP = Ev_OP
 >   Set cls.Parent = Me
 >   cls.index = Index '★インデックス番号で条件分岐させているので、番号が欲しい
    OP_Val.Add cls   'これにしないと clsOP_Subのイベントは発生しませんねえ 
 >End Sub

(ichinose) 2013/11/04(月) 17:10


 おぅ・・・
 コレクションにクラスを入れずに、そのままコントロールだけ突っ込んでいたんですね・・・
 ありがとうございました。
 (半日悩んでこの体たらく)
(稲葉) 2013/11/04(月) 17:19

こんばんは。

皆さん有難うございます。
本当に良く分からないクラスモジュールですが、教示して頂いた事を
自分の中に取り入れさせて頂き、完成させたいです。いや、完成させます。
これからも時々顔を出させていただきます。よろしくお願いします。

(欲張り爺さん) 2013/11/04(月) 18:46


 >Class_Terminate()でCollectionの解放は不要なんでしょうか?

 Set txtClass = Nothing 'これが実行された時にClass1の

 Private Sub Class_Terminate()
    Set txtcls = Nothing
 End Sub

 このイベントが実行されます。

 -----------------------------------------------------------------
 このパターンはClass2がParentととしてClass1を参照しているので
 Class1のTerminateは呼ばれません。クラス同士が循環参照を起こしています。

 クラスモジュールのTerminateが呼ばれるのは = Nothingとした時ではなく
 どのオブジェクトからも参照されなくなった時です(参照カウントが0)

 解放されていないのを確認するにはClass1,Class2のTerminateにDebug.PrintやMsgBoxを入れます。

 UserformのTerminateで Set txtcls = Nothing としても
 Class1とClass2のTerminateが呼ばれなく解放されていない事が確認出来ます。

 擬似からの脱却の筆者角田さんは、その回避にClearメソッドを用意されています。

 Class1
 Public Sub Clear()
     Dim tmp As Class2
     For Each tmp in txtcls
         tmp.Claer
         Set tmp = Nothing
     Next

     Set txtcls = Nothing
 End Sub

 Private Sub Class_Terminate()
    Debug.Print "Class1_Terminate"
 End Sub

 Class2
 Public Sub Clear()
     Set parent = Nothing
     Set txt = Nothing
 End Sub

 Private Sub Class_Terminate()
    Debug.Print "Class2_Terminate"
 End Sub

 UserForm
 Private Sub UserForm_Terminate()
    txtClass.Claer 'Nothingの前に必ずClearメソッドを呼びます
    Set txtClass = Nothing
 End Sub

 Class1のClearメソッドを呼びCollectionの要素Class2のClearメソッドを呼びます。
 Class2のparent(Class1)をNothingとする事で循環参照を断ち切ります。

 これで全てのクラスのTerminateが実行されます。
(とおりすがり) 2013/11/04(月) 19:02

 >このパターンはClass2がParentととしてClass1を参照しているので
 Class1のTerminateは呼ばれません。クラス同士が循環参照を起こしています。

 本当ですねえ

 では、Class1に

 Sub clear()
    Set txtcls = Nothing
 End Sub

 というメソッドを追加してもらって、

 Private Sub Class_Terminate()
 は、削除

 ユーザーフォームに

 Private Sub UserForm_Terminate()
    txtClass.clear
    Set txtClass = Nothing
 End Sub

 これでよいでしょうか?

 ご指摘ありがとうございます

(ichinose) 2013/11/04(月) 19:20


 ある程度、方向性は決まっているようなので、余計は事かも知れませんが、
 一つだけ。
 D&Dで入れ替え作業を行いたいとの事ですが、ユーザー側としては
 「左クリック」での操作は、テキストの一部選択などの通常操作が
 できなくなる副作用がありますね。 私なら、「右クリック」での操作が
 ユーザーに優しいのではないかと思います。
(Abyss) 2013/11/04(月) 19:49

本当に沢山の人達から助言を頂き感謝しています。

たった今、ichinose さんからのスクリプトを自分のブックで実行し終えた所です。
只々、感心するばかり唖然としていました。それを終えてここに来てみれば更に
沢山の書込みがありビックリでした。その内容の理解は出来ていませんが・・・

Abyssさん
ご指摘は何処かでも見た事が有りますが、基本的にはTextBoxには入力をさせない
を前提に考えています。本来はラベルで扱いたいのですがカレントラインに背景色
をつけ、分かり易くするのに私のレベルでは複雑さを増幅させるだけでした。
皆さんのアドバイスで作成中のブックの全ての難点を解消する事が出来ました。

最後に、今回質問しました『各コントロールのIndexを取得する方法』をご指導下さい。

 Sub add(txt As MSForms.TextBox)
    Dim cls As Class2
    Set cls = New Class2
    Set cls.txt = txt
    Set cls.parent = Me
    txtcls.add cls
 End Sub
の中でどの様にすれば良いのでしょうか?
クラスモジュールを知る上で拘っています。この事が解らないと眠れません。
あつかましくて申しあげません。何卒宜しくお願いします。

(欲張り爺さん) 2013/11/04(月) 20:40


 >各コントロールのIndexを取得する方法

 クラスモジュールって、オブジェクトの設計図を記述する箇所で、
 そのオブジェクトって、データとアルゴリズムを隠蔽化したもの
 なんて言われますよね!!

 その隠蔽化されたデータやアルゴリズムは、メソッドとプロパティという手続き
 (インターフェース)で外部とやり取りされます。

 書式としては、

 メソッドが、 Sub xxxx(・・・) 又は、 Function xxxx(・・・) As zzzz

 プロパティは、

 Property Get aaa()
 Property Let aaa(m)
 Property Set aaa(s)

 今回私は、Public変数を使いましたが、本来は、上記の手続きの方がよいですねえ!!

 いずれにせよ、クラスに隠蔽しているデータやアルゴリズムをこの様な手続きを通して、
 きっちりしたデータのやりとりをしないと使いづらいオブジェクトになってしまいます。

 私たちが何気に使っている WorksheetやRangeオブジェクトって、こういう手続きが
 しっかりしていますよね!!

 同じように

 >各コントロールのIndexを取得する方法

 なら、まず、この手続きをしっかり決めなければなりません。

 例えば プロパティ名を Indexとした場合、

 どのコントロールのIndexが取得したいのか?
 その時の入力パラメータは何なのか?

 又、このIndexというプロパティを取得して どのような使い方をしたいのか?

 等の仕様書を記述してみてください。

(ichinose) 2013/11/05(火) 09:13


 こんにちは。

 Itemプロパティの件、月曜日のお楽しみのはずが 火曜日職場でのお楽しみに
 なってしまいました。

 ● ichinoseさんのオリジナルのコードに以下を追加
 Class1で
 Property Get Item(ByVal n as Long)as msforms.TexBox
     Set Item = txtcls.Item(n).txt
 End Property

 Itemを既定のプロパティにするのはこのサイトを参考に
 http://www.excellenceweb.net/vba/class/default_member.html

 Userform1で動作確認
 Private Sub CommandButton1_Click()
     MsgBox txtClass(3).text
     txtClass(1).text = "ddd"
 End Sub

 ●欲張り爺さん、参考になる書籍を教えろ とのことでしたが
 上記サイトは、結構いいと思います。
  ・コンパクトで
  ・でも必要なことははずしてなくて
  ・上記のようなマニアックなことも書いてあります
 書籍なら、わたしにとって影響が大きかったのは
 大村あつしさんの「簡単プログラミングエクセルVBA 応用編」です。
 要するにクラスとはどういうことか、ひとことでずばっと書いてあり、
 大掴みな説明が合う人には響くと思います。
 (細かいことはほとんど書いてありません。ま、入門書ですから。)

 ●Indexについては ichinose さんからあるようですので
 勉強させていただきます。

( 佳 ) 2013/11/05(火) 19:23


こんばんは。 ( です ます 調では無いのであしからず)

>このIndexというプロパティを取得して どのような使い方をしたいのか?
今回の様にClass1,Class2 の2つのクラスを持った場合のIndexプロパティー設定の方法を知りたい。
使い方:今現在は特に無くて、只、今回の時の設定と取出し方法を知りたいだけ。

私のPC履歴:
経験20年強。仕事では不使用で趣味のみ。初めての[Basic]何の事やらさっぱりだった。
何冊か本を買い求め辿り着いたのは、非常に簡単な[住所録]だった。何度か読み直し『分かった』
という時が比較的早く訪れた。
今のエクセルでは、シート・ThisWorkBook・標準モジュール・フォームモジュールの何処に書くのが
ベストかをある程度理解できるようになった。
昨年クラスモジュールと初対面。Web上で本当の初歩を見て3ヶ月程の間は只見ているだけ。
意を決してアクセスのテーブル・クエリーを取込んで試行。見た目はクラスモジュールを使っている。
概ね、私なりの考えのアクセスに準ずる動作をしてくれた。
然し、これは標準モジュールで出来るもんじゃないかな?と思い私からクラスは途絶えた。

私の現在:
クラスのアルゴリズムが未だに分からない。メソッド・プロパティ・コレクションが結ばれない。
何時までも点でしかなく線になってくれない。何か手掛かりが無いかと『ウォッチウィンドー』
を覗くも『ピピッ』と来ない。全く[住所録]と大違いで進捗が無い。
こんな事をこの場所で言う事ではないと思うが…

どうも済みません。愚痴っぽくて…。只、クラスへの手掛かりが欲しいのです。
※佳さんの書込み前から書いていたものですからちょっと時間間隔が狂っています。
この後、『大村あつしさん』の本を調べてみます。
(欲張り爺さん) 2013/11/05(火) 20:12


 話の流れに大きく反しますが、Classを利用するメリットの一つとして、
Userformコントロール個々のイベントを一括管理し、
今後のメンテに置いて、やりやすくする目的がありますね。

 そう言った流れで考えると、Class側はコントロールのイベントを受け入れ、
その何かをUserformに教えればクラスとしての役割は果たしてる。

 後半の質問にもありますが、Indexを取得し、またそれをクラス側で料理し
UserFormに伝えるのは複雑さを増して、あり得るエラー探しを難しくする
恐れいがあります。

 製作者の設計にも依りますが、今回の場合だとCheckBoxとTextBoxが一つの組で、
必ずもう一つの組と向き合う形ですよね。だとしたら、Indexそのものより
ダイレクトにObjectを相手にした方が楽だと思います。
 (考え方にもよりますが。)

 以下は、前半の質問にもありました StartDragメソッドを利用してのサンプルです。
ご参考になれば幸いです。

 '----(UserFormモジュール)UserForm1----

 ' UserForm上、5個のTextBox、5個のCheckBoxを対象に。

 Private mCol As Collection

 Private Sub UserForm_Initialize()
    Dim i As Long
    Dim Tx As MSForms.TextBox
    Dim cc As Class1
    Dim vTextBoxes, vCheckBoxes, e

    ' 初期化の方法はお好みに。下記はその一つ
    ' 配列並び順でマッチング

    vTextBoxes = VBA.Array(TextBox1, _
                    TextBox2, _
                    TextBox3, _
                    TextBox4, _
                    TextBox5)

    vCheckBoxes = VBA.Array(CheckBox1, _
                    CheckBox2, _
                    CheckBox3, _
                    CheckBox4, _
                    CheckBox5)

    Set mCol = New Collection

    For Each e In vTextBoxes
        Set cc = New Class1
        cc.Init Me, e, vCheckBoxes(i)
        mCol.Add cc
        i = i + 1
        ' サンプルデータ
        e.Text = Format$(i, "テストデータ 0")
    Next

 End Sub

 Private Sub UserForm_Terminate()
    Dim i As Long
    For i = 1 To mCol.Count
        mCol.Remove 1
    Next
 End Sub

 Friend Sub Swap(ByVal ClsFrom As Class1, _
                    ByVal ClsTo As Class1)

    Dim sText As String, bFlg As Boolean

    With ClsFrom

        ' TextBox文字列交換
        sText = ClsTo.TBox.Text
        ClsTo.TBox.Text = .TBox.Text
        .TBox.Text = sText

        ' CheckBox値交換
        bFlg = ClsTo.CBox
        ClsTo.CBox = .CBox
        .CBox = bFlg

    End With

 End Sub

 '----(クラスモジュール) Class1----
 Private Declare Sub MoveMemory Lib "Kernel32" Alias "RtlMoveMemory" _
    (Destination As Any, _
     Source As Any, _
     Optional ByVal Length As Long = 4)

 Private mpFrm As Long
 Private WithEvents mTx As MSForms.TextBox
 Private mCx As MSForms.CheckBox
 Const flg = "Member"

 Friend Sub Init(ByVal Frm As UserForm1, _
                ByVal Tx As MSForms.TextBox, _
                ByVal Cx As MSForms.CheckBox)
    mpFrm = ObjPtr(Frm)
    Set mTx = Tx
    Tx.Tag = flg
    Set mCx = Cx
    mTx.DragBehavior = fmDragBehaviorDisabled
 End Sub

 ' 排除したいTextBoxがあれば
 Friend Sub Exclude(ByVal Tx As MSForms.TextBox)
    Tx.Tag = vbNullString
 End Sub

 Friend Property Get TBox() As MSForms.TextBox
    Set TBox = mTx
 End Property

 Friend Property Get CBox() As MSForms.CheckBox
    Set CBox = mCx
 End Property

 Private Sub mTx_MouseDown(ByVal Button As Integer, _
                        ByVal Shift As Integer, _
                        ByVal X As Single, ByVal Y As Single)
    Dim fClr As Long, bClr As Long

    ' 左クリックのみ受け入れる。
    If (Button And vbKeyLButton) = 0 Then Exit Sub
    If LenB(mTx.Tag) = 0 Then Exit Sub

    With mTx
        fClr = .ForeColor: bClr = .BackColor
        .ForeColor = vbYellow
        .BackColor = vbRed
        With New DataObject
            .SetText CStr(ObjPtr(Me))
            .StartDrag
        End With
        .ForeColor = fClr: .BackColor = bClr
    End With

 End Sub

 Private Sub mTx_BeforeDragOver(ByVal Cancel As MSForms.ReturnBoolean, _
                        ByVal Data As MSForms.DataObject, _
                        ByVal X As Single, ByVal Y As Single, _
                        ByVal DragState As MSForms.fmDragState, _
                        ByVal Effect As MSForms.ReturnEffect, _
                        ByVal Shift As Integer)

    Effect = fmDropEffectNone
    If LenB(mTx.Tag) = 0 Then Exit Sub

    If ObjPtr(Me) = CLng(Data.GetText) Then
        If DragState = fmDragStateEnter Then mTx.SetFocus
        Exit Sub
    End If

    Effect = fmDropEffectMove

    With mTx
        Select Case DragState
        Case fmDragStateEnter
            .SelStart = 0: .SelLength = Len(.Text)
            .SetFocus
        Case fmDragStateLeave
            .SelStart = Len(.Text)
        End Select
    End With
    Cancel = True

 End Sub

 Private Sub mTx_BeforeDropOrPaste(ByVal Cancel As ReturnBoolean, _
                        ByVal Action As fmAction, _
                        ByVal Data As MSForms.DataObject, _
                        ByVal X As Single, ByVal Y As Single, _
                        ByVal Effect As ReturnEffect, _
                        ByVal Shift As Integer)

    Dim Cls As Class1, ClsTmp As Class1
    Dim fm As UserForm1, fmTmp As UserForm1
    Dim lZero As Long

    If Action <> fmActionDragDrop Then Exit Sub

    MoveMemory fmTmp, mpFrm
    Set fm = fmTmp
    MoveMemory fmTmp, lZero

    MoveMemory ClsTmp, CLng(Data.GetText)
    Set Cls = ClsTmp
    MoveMemory ClsTmp, lZero

    fm.Swap Cls, Me
    Cancel = True

 End Sub
(Abyss) 2013/11/06(水) 01:52

 >これは標準モジュールで出来るもんじゃないかな?と思い私からクラスは途絶えた。
 標準モジュールのコードをクラスモジュールにそのまま移行しても使えるようなコードにしておけるようなら、
 そのモジュールの強度は強く、結合度が弱いモジュールになり、よいと思いますけどねえ!!
 私が角田さんのサイトをよくリンクするのは、そんな意味合いもあってご紹介しています。

 クラスモジュールにコードをおいて、オブジェクト化することのメリット・・・。

 1 モジュールの強度を強くし、結合度を弱くすることを考えるようになる

 2 必要なとき、必要な間だけインタンスを作成し、運用して不要になったら開放することができる

 3 複製を簡単に作成できるので、これにより、アルゴリズムが簡単になる場合が多い。

 4 イベントを使用できたり、提供出来たりすることができる。

 ざっと考えて思いついたのこんなところですが、他にもあるかもしれません。

 私がクラスモジュール化するものは、殆ど再利用可能なものです。
 もっと言えば、再利用しやすいようにインターフェースを考えると、
 クラス化しようという結論になってしまいます

 今回のリンクした角田さんのコントロール配列のクラスだって、ユーザーフォーム
 全般で使用可能ですよね!!

 >Indexプロパティー設定の方法を知りたい。

 一例です。

 このIndexは、Class1に登録するメソッド ADDで テキストボックス共に指定する任意の数字だとします。

 class1のモジュール
 '==========================================================================
 Option Explicit
 Private txtcls As Collection
 Event mousedown(ByVal index As Long)
 Event dragorpast(ByVal index As Long)
 Private Sub Class_Initialize()
    Set txtcls = New Collection
 End Sub
 Sub add(txt As MSForms.TextBox, index As Long)
    Dim cls As Class2
    Set cls = New Class2
    Set cls.txt = txt
    Set cls.parent = Me
    cls.index = index
    txtcls.add cls, CStr(index)
 End Sub
 Sub mousedown(ByVal indexd As Long)
    RaiseEvent mousedown(indexd)
 End Sub
 Sub dragorpast(ByVal index As Long)
    RaiseEvent dragorpast(index)
 End Sub
 Property Get txt(ByVal index As Long) As MSForms.TextBox
    Set txt = txtcls(CStr(index)).txt
 End Property
 Sub clear()
    Set txtcls = Nothing
 End Sub

 class2

 '=========================================
 Option Explicit
 Public parent As Object
 Public index As Long
 Public WithEvents txt As MSForms.TextBox
 Private Sub txt_BeforeDropOrPaste(ByVal Cancel As MSForms.ReturnBoolean, ByVal Action As MSForms.fmAction, ByVal Data As MSForms.DataObject, ByVal X As Single, ByVal Y As Single, ByVal Effect As MSForms.ReturnEffect, ByVal Shift As Integer)
    parent.dragorpast index
 End Sub
 Private Sub txt_MouseDown(ByVal Button As Integer, ByVal Shift As Integer, ByVal X As Single, ByVal Y As Single)
    parent.mousedown index
 End Sub

 ユーザフォーム

 '==========================================================================
 Option Explicit
 Private WithEvents txtClass As Class1
 Private ctxt As MSForms.TextBox
 Private cchk As MSForms.CheckBox
 Private Sub txtClass_dragorpast(ByVal index As Long)
    Dim wk1 As Variant
    Dim wk2 As Variant
    With txtClass
       ctxt.Value = .txt(index).Value
       .txt(index).Value = ""
       wk1 = cchk.Value
       wk2 = cchk.Caption
       With Controls(Replace(.txt(index).Name, "TextBox", "CheckBox"))
          cchk.Value = .Value
          .Value = wk1
          cchk.Caption = .Caption
          .Caption = wk2
       End With
    End With
 End Sub
 Private Sub txtClass_mousedown(ByVal index As Long)
    With txtClass
        With .txt(index)
           .SetFocus
           .SelStart = 0
           .SelLength = Len(.Text)
        End With
        Set ctxt = .txt(index)
        Set cchk = Controls(Replace(.txt(index).Name, "TextBox", "CheckBox"))
    End With
 End Sub
 Private Sub UserForm_Initialize()
    Dim g0 As Long
    Set txtClass = New Class1

    For g0 = 1 To 5
        txtClass.add Controls("textbox" & g0), g0
        Controls("textbox" & g0).Value = String(10, Chr(&H41 + g0))
    Next

 End Sub
 Private Sub UserForm_Terminate()
   txtClass.clear
   Set txtClass = Nothing
 End Sub

(ichinose) 2013/11/06(水) 07:16


お早うございます。 たった今拝見させて頂いたところです。

Abyssさん

 APIのMoveMemory が入ってきて私には意味が解りません。今日の帰宅後勉強します。

ichinoseさん

 ただ言葉で伝えただけの私の『住所録』ですが、これが有る程度モジュールの強度は強く、
結合度が弱いモジュールとなっていたのでしょうか?
実の所、レコード移動に関してはスピンボタンを利用していました。その時にスピンにレコード位置情報を
持たせ、そのイベントプロシージャーでこの情報を引数にしていました。その時に『結合性が有り、クラスの隠蔽性が損なわれているんのではないか!。これは本来のクラスではない』思ったのです。
済みません。これから仕事に行きます。帰宅後に皆さんのスクリプトを見て考えます。

Abyssさん、ichinoseさん お付合い有難うございました。
 
(欲張り爺さん) 2013/11/06(水) 07:59


やっぱりクラスモジュールは難しいですね・・・

昨日から教示された内容を見て来ましたが、さらっと流して見た時とじっくり見た時では
全く違っていました。私のレベルではクラスの鍵を解くという前の話になってしまいました。

 Option Explicit
 Private WithEvents txtClass As Class1
 Private ctxt As MSForms.TextBox
 Private cchk As MSForms.CheckBox
 Private Sub txtClass_dragorpast(ByVal txt As MSForms.TextBox)
    Dim wk1 As Variant
    Dim wk2 As Variant
    ctxt.Value = txt.Value
    txt.Value = ""
    wk1 = cchk.Value
    wk2 = cchk.Caption
    With Controls(Replace(txt.Name, "TextBox", "CheckBox"))
       cchk.Value = .Value
       .Value = wk1
       cchk.Caption = .Caption
       .Caption = wk2
    End With
 End Sub

夫々の値代入から理解に苦しんでいます。取敢えずこの部分を私なりに理解する時間が必要になりました。
頑張って克服したいと思います。(本当に大変ですね・・・ でも、年のせいにしたくはありません!)

(欲張り爺さん) 2013/11/07(木) 23:30


コメント返信:

[ 一覧(最新更新順) ]


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