2つのフォーム間でのユーザコントロールに対するアクセス への返答

投稿で使用できる特殊コードの説明。(別タブで開きます。)
本名は入力しないようにしましょう。
投稿した後で削除するときに使うパスワードです。返答があった後は削除できません。
返答する人が目安にします。相手が小学生か社会人かで返答の仕方も変わります。
最初の投稿が質問の場合、質問者が解決時にチェックしてください。(以降も追加書き込み・返信は可能です。)
※「過去ログ」について書くときはその過去ログのURLも書いてください。

以下の返答は逆順(新しい順)に並んでいます。

投稿者 neptune  (社会人) 投稿日時 2009/4/26 04:56:31
続き


'//////////////////////////////Class.vb////////////////////// 
Imports System.Collections.Generic

Public Class TextControls

    Private txtAry As List(Of TextControl)
    Public Event TextControls_UpDated(ByVal pText As TextBox)

    Public Sub New()
        txtAry = New List(Of TextControl)
    End Sub

    ''' <summary> 
    ''' Itemの追加 
    ''' </summary> 
    ''' <param name="pObj">TextBox</param> 
    ''' <returns>成功時:tru</returns> 
    ''' <remarks></remarks> 
    Public Function AddItem(ByVal pObj As TextBox) As Boolean
        Dim clsTxt As New TextControl
        Dim ret As Boolean = False
        Dim newCount As Integer

        Try
            If txtAry.Count = 0 Then
                newCount = 0
            Else
                newCount = txtAry.Count
            End If

            clsTxt.Item = pObj
            AddHandler clsTxt.Text_UpDated, AddressOf Text_UpDated
            txtAry.Add(clsTxt)
            ret = True
        Catch ex As Exception

        End Try

        Return ret
    End Function

    ''' <summary> 
    ''' 全てのTextBoxのTextをClearする 
    ''' </summary> 
    ''' <returns>成功時:true</returns> 
    ''' <remarks></remarks> 
    Public Function ClearAllText() As Boolean
        Dim ret As Boolean = False
        Dim iCount As Integer = txtAry.Count()

        Try
            For i = 0 To iCount - 1
                txtAry(i).Item.Clear()
            Next
            ret = True
        Catch ex As Exception

        End Try
        Return ret
    End Function

    Public ReadOnly Property Items(ByVal pIndex As IntegerAs System.Windows.Forms.TextBox
        Get
            Return txtAry(pIndex).Item
        End Get
    End Property

    'TextBoxで変更があった時のイベントを受け取る 
    Private Sub Text_UpDated(ByVal ptext As TextBox)
        RaiseEvent TextControls_UpDated(ptext)
        'MessageBox.Show(ptext.Name & "に変更がありました。") 
    End Sub

    '不要かも 
    Protected Overrides Sub Finalize()
        If IsArray(txtAry) Then
            txtAry.Clear()
        End If
        MyBase.Finalize()
    End Sub

End Class

'子クラス 
Public Class TextControl

    Private WithEvents m_Item As System.Windows.Forms.TextBox
    Private m_OldText As String
    Public Event Text_UpDated(ByVal pText As TextBox)


    'これはなくても良いと思う。 
    Protected Overrides Sub Finalize()
        m_Item = Nothing
        MyBase.Finalize()
    End Sub

    Public Property Item() As System.Windows.Forms.TextBox
        Get
            Return m_Item
        End Get
        Set(ByVal value As System.Windows.Forms.TextBox)
            m_Item = value
        End Set
    End Property

    'フォーカスを受け取った時のデータ保管 
    Private Sub m_Item_Enter(ByVal sender As TextBox, ByVal e As System.EventArgs) Handles m_Item.Enter
        m_OldText = sender.Text
    End Sub

    '変更後のデータを前のデータと比較、変更があれば Text_UpDated を発生させる 
    Private Sub m_Item_Validated(ByVal sender As TextBox, ByVal e As System.EventArgs) Handles m_Item.Validated
        If m_OldText.Length = 0 Then Exit Sub
        '全く同じでなければイベント発生 
        If String.Compare(sender.Text, m_OldText) <> 0 Then
            RaiseEvent Text_UpDated(sender)
        End If
    End Sub
End Class

投稿者 neptune  (社会人) 投稿日時 2009/4/26 04:54:12
今日思い出しがてら、vb2008用にコレクションの形式を持つコントロール管理クラス?の
自分用サンプルを書いてみましたので、UPしておきます。
ちなみに、構造そのものはVB6の頃と同じ考え方で作ってます。

なにか、おかしい点がありましたら、教えて下さい。

Formに
button 3個
Label  2個
TextBox 3個


'//////////////////////////////Form1.vb////////////////////// 
Public Class Form1
    Private m_TextCtrls As New TextControls

    Private Sub Form1_Disposed(ByVal sender As ObjectByVal e As System.EventArgs) Handles Me.Disposed
        m_TextCtrls = Nothing
    End Sub

    Private Sub Form1_Load(ByVal sender As ObjectByVal e As System.EventArgs) Handles Me.Load
        Me.Button1.Text = "閉じる"
        Me.Button2.Text = "全てのTextBoxをクリアする"
        Me.Button3.Text = "TextBox2のデータを取得してみる"
        Me.Label1.Text = "適当にTextBoxのTextを変更してみて下さい。"

        m_TextCtrls.AddItem(Me.TextBox1)
        m_TextCtrls.AddItem(Me.TextBox2)
        m_TextCtrls.AddItem(Me.TextBox3)

        AddHandler m_TextCtrls.TextControls_UpDated, AddressOf TextControls_UpDated_Handler
    End Sub

    Private Sub Button1_Click(ByVal sender As ObjectByVal e As System.EventArgs) Handles Button1.Click
        Me.Close()
    End Sub

    Private Sub Button2_Click(ByVal sender As ObjectByVal e As System.EventArgs) Handles Button2.Click
        m_TextCtrls.ClearAllText()
    End Sub

    Private Sub Button3_Click(ByVal sender As ObjectByVal e As System.EventArgs) Handles Button3.Click
        MessageBox.Show(m_TextCtrls.Items(1).Text)
    End Sub

    Private Sub TextControls_UpDated_Handler(ByVal pText As TextBox)
        Me.Label2.Text = pText.Name & " のデータが変更されました。"
    End Sub
End Class




投稿者 neptune  (社会人) 投稿日時 2009/4/26 04:35:52
魔界の仮面弁士さん

アドバイスありがとうございます。
>Private Sub mbtn_Click(ByVal btn As Button, ByVal e As EventArgs) Handles mbtn.Click
これ知りませんでした。これは便利ですねぇ。

ガベージ コレクタってのが出来たんで、これがどこまで面倒見てくれるんだろうとか
正直良く判らんです。

>親クラスの Controls に登録されたものは、親クラスによって管理されます。
>この場合、破棄のタイミングは親任せで大丈夫でしょう。しかしながら、
>親に登録されていない物に関しては、自分で責任を持つ必要があるかと。
ですが、ご紹介の「Finalize メソッドおよびデストラクタ」
のページとあわせて考えると、frameworkで用意されているクラス、名前空間などの
範囲且つアンマネージと呼ばれる物(COMとかAPIとかActive Xなど)を使用しないで
プログラムを作成すると
・建前では必要はないのかな?
と思っています。(本音では明示的に開放した方が安心感がある。)

なので、昨日UPしたサンプルプログラムに於いては必要はないのかなと思うんですが、
こういう事でよろしいんでしょうか?
気持ち的には多少のパフォーマンスは気にしないで、開放処理した方が安心ではあります。
投稿者 ふぐ次郎  (社会人) 投稿日時 2009/4/25 22:10:46
セットですよ。
<title>Ez安心アクセスサービスに加入しましょう</title>
とかさ。
投稿者 Kintonun  (社会人) 投稿日時 2009/4/25 13:25:43
新しい題目で投稿しようかと思いましたが、この中で、お教え頂いたことなので。
ご紹介頂いた、プロパティーの名前付けのガイドラインにて
(http://msdn.microsoft.com/ja-jp/library/cc433291.aspx)

   Public Property <b>BackColor</b> As Color
      ' Code for Get and Set accessors goes here.
   End Property

この中の表記方法で"<b>" "</b>"の記号は何を示しているのですか?
実際エディタにて打つと、<b>と</b>はセットになっているようですが、・・・
msdnでも、いろいろ、探したんですが、見つけえませんでした。

投稿者 葉月  (社会人) 投稿日時 2009/4/25 05:40:39
>>>”画像へのパス”にパスを設定しましたが、うまく、動作しません。
画像ファイルが格納されたフォルダーのパスを設定するのではなく、画像ファイルの絶対パスを設定してください。
例)C:\test.jpg
余白があったり、画像が大きいと全く表示されないように見えるかも知れません。
「画像を表示」するのがメインじゃないので、OS標準のペイントで色で塗りつぶした画像を用意するのがいいかも知れません。
投稿者 魔界の仮面弁士  (社会人) 投稿日時 2009/4/25 04:08:34
neptuneさんの投稿に対して追記返信。

> やはり、デストラクタやformのformcloseイベントとか、Disposedイベントで処理しなければ
> 駄目なんでしょうか?

まじめに考えると、これが結構ややこしいところで…。
http://msdn.microsoft.com/ja-jp/library/0s71x931.aspx


Finalize にもデメリットはありますので、使いどころを間違えると逆効果です。

ファイナライザを実装すると、メモリ回収までのサイクルが長期化するため、
結果的に、メモリ使用量の増加につながってしまう事もありえたりします。

http://msdn.microsoft.com/ja-jp/library/ms998547.aspx
》『必要でない限り Finalize を実装しない』
》ファイナライザを必要としていないクラスでファイナライザを実装すると、
》ファイナライザ スレッドとガベージ コレクタへの負荷が増加します。
》ファイナライゼーションが必要でない限り、ファイナライザやデストラクタは
》実装しないようにしてください。(以下略)
投稿者 (削除されました)  () 投稿日時 2009/4/25 04:04:36
(削除されました)
投稿者 チョコボ  (小学生) 投稿日時 2009/4/24 23:57:55
pc88さぁ、z80でしょ。
なかよくしてね。^^
投稿者 魔界の仮面弁士  (社会人) 投稿日時 2009/4/24 20:27:01
> 早々、msdnを調べたら、ジェネリック コレクションをまず、推奨しているようですね。
ArrayList だと、取り出す時に「Object型」になってしまいますので、
使う前に uctRect や TextBox 等への型変換が必要になってしまいます。

ジェネリック コレクションを使うと、uctRect 専用のコレクションを
簡単に作る事ができ、使う時に型変換が不要となります。


> 一寸、かじった言語が、Microsoft QuickBASIC Ver4.2の次がVB5だったもので。
QuickBASIC 4.2 の後は、最終版である 4.5 だったはずです。4.2 の前は 4.0b かな。

以下、私の把握している分の年表です。どうでも良い情報ですけれどね。
 1981年 … OA-BASIC (PASOPIA)、N88-BASIC (PC-8801)
 1985年 … QuickBASIC 1.0、ファミリーベーシックV3
 1988年 … QuickBASIC 4.5
 1991年 … VB1 英語版(Visual Basic 1.0)
 1992年 … VB1 DOS 英語版(Visual Basic 1.0 for MS-DOS)
 1992年 … VB2 英語版(Visual Basic 2.0)
 1993年 … VB2 日本語版
 1993年 … VB3 英語版(Visual Basic 3.0)
 1995年 … VB4 日本語版(Visual Basic 4.0 16bit版、Visual Basic 4.0 32bit版)
 1997年 … VB5 日本語版(Visual Basic 5.0 / Visual Studio 97)
 1998年 … VB6 日本語版(Visual Basic 6.0 / Visual Studio 6.0)
 2002年 … VB7 日本語版(Visual Basic.NET / Visual Studio.NET)
 2003年 … VB7.1 日本語版(Visual Basic.NET 2003 / Visual Studio.NET 2003)
 2005年 … VB8 日本語版(Visual Basic 2005 / Visual Studio 2005)
 2008年 … VB9 日本語版(Visual Basic 2008 / Visual Studio 2008)
 2010年?… VB10 日本語版[予定](Visual Basic 2010 / Visual Studio 2010)
投稿者 Kintonun  (社会人) 投稿日時 2009/4/24 12:57:34
魔界の仮面弁士 さま
いつも的確なご助言有難うございます。
> デザイン画面で作成したコントロールを配列化(正しくはコレクションにする?)方法は載ってないよう>です。
>配列やコレクションの使い方はわかりますよね。
>コントロールの配列であろうと、数値の配列であろうと、考え方は一緒ですよ。

ここが、多分、理解出来ていないのだろうと思います。いろいろと、読んでいるのですが。
記載されたプログラムを参考に、いろいろと、トライしようと思っています。道具として、使用できる
程度までは と思っています。道具を増やさないと、間違った道を遠回りしているようで。
的はずれな質問をすることがあるかもしれませんが、みなさん、宜しく。

> それらのコントロールをArrayListにて
>ArrayList でも良いですが、ジェネリック コレクション方が便利だと思います。

早々、msdnを調べたら、ジェネリック コレクションをまず、推奨しているようですね。
内容は理解できない状況ですが・・・ 

>そうなのですか? VB1 for Windows や VB1 for MS-DOS が出た当時は、
>画面デザインが楽になるのが売りだったと思っていたのですけれども。

VB1とかVB2とかがあったんですね。薄学ですみません。
一寸、かじった言語が、Microsoft QuickBASIC Ver4.2の次がVB5だったもので。VB5があるのですから、
VB1があっても当たり前ですが。これも薄い記憶ですが、VB5を見た時には本当に驚いた記憶があります。
VB1 for MS-DOSというものもあったんですね。





投稿者 魔界の仮面弁士  (社会人) 投稿日時 2009/4/24 12:18:57
》neptuneさん
> Private Sub mbtn_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles mbtn.Click
>  Dim btn As Button = DirectCast(sender, Button)

今回は 2008 なので、このように書くこともできそうですね。
Private Sub mbtn_Click(ByVal btn As Button, ByVal e As EventArgs) Handles mbtn.Click


> オブジェクト変数の開放を上記のサンプルでは行ってません。
親クラスの Controls に登録されたものは、親クラスによって管理されます。
この場合、破棄のタイミングは親任せで大丈夫でしょう。しかしながら、
親に登録されていない物に関しては、自分で責任を持つ必要があるかと。


》Kintonunさん
> VB5以前は、画面(フォーム)を作る事が、ソフトのかなりの手間であった。
> まず、図面上に設計した後、ドットの点をline文などで、書く必要があり、
> 何か追加した場合、変更するのが大変であった。

そうなのですか? VB1 for Windows や VB1 for MS-DOS が出た当時は、
画面デザインが楽になるのが売りだったと思っていたのですけれども。

まぁ、VB2 は "Visual Control Pack" が無いと苦労することにはなりますが、
少なくとも VB4 の画面デザインがそれほど大変だとは思いませんでしたので、
私は、「VB5以前は、画面作成が手間だった」とはあまり感じませんでした。


ただし画面設計は、むしろこれからの方が、逆の意味で大変になっていくかも知れません。
WPF の登場によって、表現できる内容が大きく広がってしまったので…。
投稿者 Kintonun  (社会人) 投稿日時 2009/4/24 11:53:37
魔界の仮面弁士さま
>しかしながら、今回のように
> frmB.uctRect0.shpLamp_BackColor = Color.Red
>あるいは
> For i=0 to frmB.panel1.Controls.Count-1
>のように、frmA が frmB のコントロールを直接操作してしまうと、フォーム間の結びつきが強くなりすぎ>てしまいます。
>frmB のコントロールを変更したりすると、frmB の修正後に frmA まで修正せねばならなくなってしまい
>ます。複数画面から frmB を利用していた場合は修正も大変です

改めて、考え直したら、言われる通りですね。ご指摘頂き、有難うございました。
誤った道に進むところでした。今回の課題に関しては色を変更するメソッドを同じフォーム内に
書くことが出来そうです。どうしても、今回のようなことを行う必要は発生しそうなので、
その時、これまでのご助言、参考にさせて頂きます。今後とも、宜しく、お願いします。
投稿者 魔界の仮面弁士  (社会人) 投稿日時 2009/4/24 11:44:33
> <旧バージョンとの互換性維持に関して>
> こういうものを使用するほうが良いのでしょうか?
使わないで済むなら、使わない方が良いでしょう。
旧バージョンの開発スタイルを使い続けたい場合には役に立ちますが、
多くの場合、この互換DLLを参照設定すらする必要はないと思います。


> 多分、VB2008も今後、変更されるでしょうし、
2010 もダウンロードできます。まだ、CTP 版ですけれどね。
https://connect.microsoft.com/VisualStudioJapan/content/content.aspx?ContentID=10212


> BASICの言語の変更は今後も続くのでしょうか?
かつて、「QuickBASIC の登場時」「VB1 の登場時」「VB.NET の登場時」には、それぞれ
大きな変化がありました。「.NET の次」が来た時には、また大きな変化があるでしょう。

また、VB.NET 系の中でも、バージョン毎に進化は続いていきます。
次のバージョンVB10(Visual Basic 2010)で予定されている機能については、
そのうちの幾つかが既に情報公開されています。

そして、今はまだ、詳しい内容について述べることは許されていませんが、
さらにその後の VB11 についても、幾つか検討されている言語面での新機能があります。


> コントロール配列化に関して、参考に頂いたホームページの内容もですが、msdnで調べた時にも
> 思ったのですが、コントロール配列をプログラムの中で、作成する方法は載っていますが、
旧VBのコントロール配列について言えば、デザイナで設定できるという利点はありますが、
必ずしも使いやすい物では無かったかと思います。たとえば、コントロール配列は
WithEvents と併用できないというデメリットを抱えていましたし、必ず、雛型として
最低 1 個のコントロールを、画面に用意しておかなければなりませんでした。

先に紹介したサイトに書かれている方法であれば、コレクションの仕様は
自分で自由に決定できるため、仕様面での制限を受けることはなくなります。あとは、
その機能を自力で作成していく時間と力量があるかどうかですけれどね。


> デザイン画面で作成したコントロールを配列化(正しくはコレクションにする?)方法は載ってないようです。
配列やコレクションの使い方はわかりますよね。
コントロールの配列であろうと、数値の配列であろうと、考え方は一緒ですよ。

TextBox のコントロールを配列で管理したいなら、
 Private TextBoxes() As TextBox
などという宣言をしておけば良いでしょうし、コレクションに格納したければ、たとえば
 Private TextBoxes As List(Of TextBox)
などと書けるでしょう。

こうして用意したコレクションには、デザイナで作成したコントロールを
 TextBoxes.Add( TextBox1 )
 TextBoxes.Add( TextBox2 )
と追加していく事もできますし、
 Dim txt As New TextBox()
 Controls.Add( txt )
 TextBoxes.Add( txt )
のように、デザイナを使わずに自作したコントロールを追加する事もできます。

また、デザイナで作成したコントロールを列挙したいのであれば、先にご自身が
書かれていたように、Controls から取り出すこともできますし、あるいは
先の例のように、拡張メソッド(あるいは LINQ)による抽出も可能かと。


> shapeが無くなり、直線を引くのにソフトを組まなければならない点にがっかりしました。
直線は、Shape コントロールではなく、Line コントロールですよ。

これらの廃止に関する御叱りは多かったようで、その後、「Visual Basic Power Pack」として、
LineShape コントロール、OvalShape コントロール、および RectangleShape コントロールが
追加されましたね。
http://msdn.microsoft.com/ja-jp/vbasic/ms789080.aspx
http://msdn.microsoft.com/en-us/vbasic/bb735936.aspx


> それらのコントロールをArrayListにて
ArrayList でも良いですが、ジェネリック コレクションの方が便利だと思います。


> Addすれば、コレクションとして扱えるのでしょうか?
使えます。そしてそれは、VB5 の頃であっても一緒ですよね。

VB5/VB6 であっても、
 Private col As Collection
に対して、
 Set col = New Collection
 col.Add Text1
 col.Add Text2
 col.Add Text3
のように登録して、非コントロール配列をコレクション管理することが可能です。
投稿者 Kintonun  (社会人) 投稿日時 2009/4/24 11:40:48
neptune さま
動作確認し、自分なりに理解しました。間違っているかも知れませんが、・・・
デザイン画面にて、貼り付けたコントロールを、改めて、クラス配列?(コレクション?)みたいに
定義し直して、そこをベースに処理する。(用語が間違っている?と思われますが、取りあえず、
何らかの表現をしないと、表現出来ないので)
参考になりました。

>#お願いですが、「50の手習い」ってのできればやめてもらえません^ ^;;
>#私も同じようなおっさんなんで、かなり抵抗あります。手習いには後10年ほど早いですよ。 

抵抗があったようでしたら、申し訳ありません。コンピュータとの付合いは長いのですが、・・
勉強したい気持ちはあったのですが、中々、普段の仕事で、手が出せなくて。
不景気な分もあり、ここ2ヶ月ぐらい、勉強を始めている状況です。
過去に、うわべのみ記憶した不充分記憶が、逆に邪魔をしている部分もあるように感じています。
専門用語にも苦労している状況です。用語を理解しないと、検索を出来ない。
いろいろありますが、ご教授頂き、ありがとうございます。今後とも、宜しく、お願いします。

投稿者 Kintonun  (社会人) 投稿日時 2009/4/24 10:46:04
葉月さま
> コントロール配列化のイメージが湧かないという解釈でよろしいでしょうか?
VB5以前は、画面(フォーム)を作る事が、ソフトのかなりの手間であった。まず、図面上に設計した後、ドットの点をline文などで、書く必要があり、何か追加した場合、変更するのが大変であった。
それがVB5からデザイン画面で部品をドラックすれば、画面が出来る事となった。これは私にとって
すごい、進歩であった。中身をみると、そのプログラムが自動的に組まれており、デザイン画面で勝手に
出来るか、直接、プログラムを書くかの違いであるが、ソフトを組む人たちにはすごい合理化であった
ように思っていました。従って、画面を描くのに、プログラムを直接組むのは時代と逆行している
ように思われる。(反対のご意見の方も多々おられると思いますが)
従って、画面の部品に関する位置、形状などのデータはデザイン画面で容易に設計出来、配列化
(コレクション?)には別途出来ないのか、と安易に思ったわけです。これはオブジェクト指向の
考えに反してる?かも知れませんが。イメージは大体は解っているのですが。配列のインデックス
を操作するだけで、同じグループの内容が変更、確認が出来たので、簡単でした。
コレクションは配列の機能強化版みたいなので、これを使いこなせば良いのですが。


>サンプルを動かすためには、"画像へのパス"を書き換える必要があります。
折角、プログラムを記載して頂きましたが、動かせるだけの、力がありませんでした。
>Using stream = New IO.FileStream("画像へのパス", IO.FileMode.Open, IO.FileAccess.Read)
の”画像へのパス”にパスを設定しましたが、うまく、動作しません。
動作させる力が足りませんが、コメントから判断すると、「画像データの入ったフォルダーをして、
その中から、その画像をピクチャボックスに読み込む」ということですか?もし、間違っていたら、
すみません。


投稿者 neptune  (社会人) 投稿日時 2009/4/24 07:37:33
お邪魔します。

葉月さんが既にサンプルUPされてますが、せっかく書いたのでUPしておきます。

コントロール配列ではないですが、ボタン処理用のクラスの一番簡単な奴書いてみました。
vb6時代と同じ考え方で書いてます。VB5はあまりやってないのですが、多分同じだったような???
FormにButtonを4つ配置、以下をコピペで動くと思います。


Public Class Form1
    Private clsButton() As CtrlButtons

    Private Sub Form1_Load(ByVal sender As ObjectByVal e As System.EventArgs) Handles Me.Load
        ReDim clsButton(2)
        For i As Integer = 0 To 2
            clsButton(i) = New CtrlButtons
        Next
        clsButton(0).uctButton = Me.Button1
        clsButton(1).uctButton = Me.Button2
        clsButton(2).uctButton = Me.Button3
        Me.Button4.Text = "ButtonのTextプロパティ変更を変更してみる"

    End Sub

    Private Sub Button4_Click(ByVal sender As System.ObjectByVal e As System.EventArgs) Handles Button4.Click

        Dim ret As Boolean = EditButtonText()
    End Sub


    'ButtonのTextプロパティ変更(戻り値手抜きしてます) 
    Public Function EditButtonText() As Boolean

        For i As Integer = 0 To clsButton.Count - 1
            clsButton(i).uctButton.Text = "Textプロパティ変更 その" & i.ToString()
        Next
        Return True
    End Function

    'ボタン処理用 
    Private Class CtrlButtons
        Private WithEvents mbtn As Button

        Public Property uctButton() As Button
            Get
                Return mbtn
            End Get
            Set(ByVal value As Button)
                mbtn = value
            End Set
        End Property

        Private Sub mbtn_Click(ByVal sender As ObjectByVal e As System.EventArgs) Handles mbtn.Click
            Const csMsg As String = "変更しました。"
            Const csFind As String = "変更"
            Dim btn As Button = DirectCast(sender, Button)

            If btn.Text.Contains(csFind) Then
                btn.Text = btn.Name
            Else
                btn.Text = btn.Name & " : " & csMsg
            End If
        End Sub
    End Class

End Class

CtrlButtonsですが、CtrlButtonとでも名前をつけ直し、CtrlButtonをコレクションItemとする
CtrlButtonsを新たに作れば、EditButtonTextなんかは、その中に持っていくと、
addメソッドや、removeメソッドなど必要な機能をを実装するとキチンとした、
コレクションが出来上がります。

皆さんへ>
ここで私も「質問」お願いします。
オブジェクト変数の開放を上記のサンプルでは行ってません。
やはり、デストラクタやformのformcloseイベントとか、Disposedイベントで処理しなければ
駄目なんでしょうか?するようには心掛けてますけど、本当に必要なのかどうかが知りたいです。


Kintonun  さん>
#お願いですが、「50の手習い」ってのできればやめてもらえません^ ^;;
#私も同じようなおっさんなんで、かなり抵抗あります。手習いには後10年ほど早いですよ。
投稿者 葉月  (社会人) 投稿日時 2009/4/24 06:20:37
ボリュームがありますので、わかる範囲で参加します。

>>>「frmA が frmB のコントロールを直接操作してしまう」
>>>方法で、プログラミングされているので、どうしても、そのスタンスになってしまいます。
 過去ログが参考になりそうです。
 http://rucio.groupsite.jp/commu/ThreadDetail.aspx?ThreadId=144

>>>コントロール配列をプログラムの中で、作成する方法は載っていますが、デザイン画面
>>>で作成したコントロールを配列化(正しくはコレクションにする?)方法は載ってないようです。
 コントロール配列化のイメージが湧かないという解釈でよろしいでしょうか?
 意図が把握しきれておりませんが、一応サンプルコードを掲載します。
 過去に投稿を予定して忘れていたものを、気持ち変更しました。できが悪い点は、ご了承ください。
 サンプルを動かすためには、"画像へのパス"を書き換える必要があります。

>サンプルコード
Imports System.IO

Public Class Form1

    ' スロットで使用するピクチャーボックス 
    Private picSlot(3) As System.Windows.Forms.PictureBox


    Private Sub Form1_Load(ByVal sender As System.ObjectByVal e As System.EventArgs) Handles MyBase.Load
        Me.MyInitializeComponent()
    End Sub


    '''<summary> 
    '''自作のイニシャライズコンポーネント 
    '''※ 自動生成されるイニシャライズコンポーネントも使います 
    '''</summary> 
    Private Sub MyInitializeComponent()
        ' ピクチャーボックスのXとY座標 
        Const INT_PB_X As Integer = 120
        Const INT_PB_Y As Integer = 30
        Const INT_START As Integer = 1

        Dim iPbMove As Integer = 0

        For i As Integer = 0 To 2
            picSlot(i) = New System.Windows.Forms.PictureBox()
            picSlot(i).Name = String.Concat("pictureBox", i)
            'picSlotを配置します。 
            picSlot(i).Location = New System.Drawing.Point((i + INT_START) * INT_PB_X + iPbMove, INT_PB_Y)

            Using stream = New IO.FileStream("画像へのパス", IO.FileMode.Open, IO.FileAccess.Read)
                ' 画像を読み込みます。 
                picSlot(i).Image = System.Drawing.Image.FromStream(stream)
            End Using

            ' クリックイベントを付加 
            AddHandler Me.picSlot(i).Click, New System.EventHandler(AddressOf picClick)
            iPbMove += 27
        Next i

        ' ピクチャーボックスをフォームに追加。 
        Me.Controls.AddRange(picSlot)
    End Sub


    ''' <summary> 
    ''' ピクチャーボックスがクリックされた時に起こるイベント 
    ''' </summary> 
    ''' <param name="sender">未使用</param> 
    ''' <param name="e">未使用</param> 
    Private Sub picClick(ByVal sender As System.ObjectByVal e As System.EventArgs)
        MessageBox.Show("ピクチャーボックスがクリックされました")
    End Sub

End Class
投稿者 Kintonun  (社会人) 投稿日時 2009/4/23 17:26:04
刈谷勇さん
 わざわざ、ご挨拶有難うございます。
魔界の仮面弁士さん
 細かい説明、有難うございます。
 命名規約、規定書など参考になりました。
 プロパティー名にはっきりと「ハンガリー表記法は使用しないでください」とありますね。
 単純には名称を付ける時、文字数は長くても良いので、いろんな情報が入った方が良いように
 思っていました。文字が長くてもエディター中で勝手に出してくれるので。
 一般の変数名でそうなのかも知れませんが、外部に出る変数は確かに、ある程度、規則がないと、
 多人数での開発は出来ないんですね。
 改めて、この「初級講座」を読み直していたら、行いたいことを「プロパティー」で行うか、
 「メソッド」で行うかはどちらでも可能なことが記されていました。この辺りも含めた、
 統一が必要な点は実感しました。が、現実の課題を何とかしようと思ったら、・・・
 勉強することばかりで、その辺りも、読み直してみようと思います。ご指摘有難うございます。
 (今回、記載したプログラムの変数名は原本はもっと長く、添付するために、短くして記載しました)

>frmA が frmB のコントロールを直接操作してしまうと、フォーム間の結びつきが強くなりすぎてしまい>ます。
>frmB のコントロールを変更したりすると、frmB の修正後に frmA まで修正せねばならなくなってしまい>ます。複数画面から frmB を利用していた場合は修正も大変です。

実は、「VB5」にて製作されたプログラムを「.NET」に変更しようとしている中で、自動変換を
しましたが、エラーばかりが出て、それを修正しようかとも思ったのですが、いろいろ、掲示板などを
読むと、初めから、作り直した方が良いようなので、現在、トライいている状況です。勿論、「原本」
は私の作品ではないのですが。その中で、「frmA が frmB のコントロールを直接操作してしまう」
方法で、プログラミングされているので、どうしても、そのスタンスになってしまいます。
今回のこの課題は本来はfrmBの中だけで済ませられる問題であり、そうすべきなのは解っていたのですが、
より大きなハードルがありそうだったので、・・・ 改めて、本来あるべき姿で検討してみようと
思います。

<旧バージョンとの互換性維持に関して>
compatibility.vb6が準備されているようですが、これまでのBASIC言語の流れから、観られて、
こういうものを使用するほうが良いのでしょうか?多分、VB2008も今後、変更されるでしょうし、
現状の課題も、N88-BASIC(N88Basicではなかったようでね。この辺、適当ですみません)から、随時
BASICが変わるたびに変更して、一部、GOTO文も残ったまま、その場、その場で、何とか見た目に
動作していれば、とのスタンスで変更されてきました。私はそのメンテナンス(一寸した変更を)
やっていたのですが、リストラではありませんが、一寸、時間が出来たので、トライしているのですが、
BASICの言語の変更は今後も続くのでしょうか?若い時、一寸かじった、C言語なども枝分かれはしている
ようですが、変更はかなりあっているのでしょうか?基礎が出来ている人にとっては大した仕様の
変更では無いのかも知れませんが、理解しているところと、理解していないところの判別が付かない
私のレベルでは中々頭の切換は大変です。

>コントロール配列化した場合、Text1 は TextBox 型ではなく、このコレクション型に変化します。

コントロール配列化に関して、参考に頂いたホームページの内容もですが、msdnで調べた時にも
思ったのですが、コントロール配列をプログラムの中で、作成する方法は載っていますが、デザイン画面
で作成したコントロールを配列化(正しくはコレクションにする?)方法は載ってないようです。
私のイメージでのVBはフォーム画面をデザイン画面にて設計できる事であるように思っており、VB2003
にて、shapeが無くなり、直線を引くのにソフトを組まなければならない点にがっかりしました。
本題に戻って、コントロールをフォームに貼り付けた後、それらのコントロールをArrayListにて
Addすれば、コレクションとして扱えるのでしょうか?

余裕もあまり無いのですが、「初級講座」を読み直してみたいと思います。
(技術的内容以外も一寸述べましたが、この点、ご勘弁下さい)
ネットの調子が悪く、早々の返事を頂いたのに遅くなり、申し訳ありませんでした。
投稿者 刈谷勇  (社会人) 投稿日時 2009/4/22 20:39:13
魔界の仮面弁士さん、ご指摘ありがとうございます。
また、Kintonunさん、間違った回答をしてしまって申し訳ありません。
投稿者 魔界の仮面弁士  (社会人) 投稿日時 2009/4/22 19:32:24
元質問者とは、別の投稿者名に変わってしまっていますよ。

> この件ですが、別のフォームからアクセスするために、色の設定をプロパティーにて
> Public宣言して、外からアクセス出来るようにしたのですが、この点が、推奨できない
> との事でしょうか?
いえ、今回指摘したカプセル化の件は、uctRect を貼った「frmB クラス」に対するものです。
作成した「uctRect クラス」の設計については、概ね問題無いと思いますよ。

細かく言えば、プロパティ名が一般的な命名規約に沿っていないとか、
http://msdn.microsoft.com/ja-jp/library/cc433291.aspx
http://msdn.microsoft.com/ja-jp/library/ms229002.aspx
デザイナのための「規定値」の設定が不足しているとか、
http://msdn.microsoft.com/ja-jp/library/53b8022e.aspx
変更通知イベントが実装されていないといった点はありますけれどね。
http://msdn.microsoft.com/ja-jp/library/ms229016.aspx


> VB5にて、コントロール配列があり、2008にてコントロール配列への対応記事が載っていますが、
もしかして、VB5 の利用経験がおありなのでしょうか?

VB5 のコントロール配列は、名前に反して配列ではなく、コレクションの一種です。

普通は、Text1, Text2 で TextBox として管理されているコントロールが、
Text1(0), Text1(1) とインデックスで管理できるようになるという物ですね。

コントロール配列化した場合、Text1 は TextBox 型ではなく、このコレクション型に変化します。
Text1.Count で同名のコントロールを取得でき、イベント通知も個々の Text1(0) に対して受けるのでは無く、
コレクションである Text1 にて一括管理されるようになります(引数 Index で区別する)。

このコントロール配列は、旧バージョンとの互換性維持を目的として、
http://msdn.microsoft.com/ja-jp/library/microsoft.visualbasic.compatibility.vb6.textboxarray.aspx
などといった管理クラスが、それぞれのコントロールごとに用意されています。

しかし今回の場合、ここまで大げさな物を用意せずとも、
http://dobon.net/vb/dotnet/control/buttonarray.html
http://homepage1.nifty.com/rucio/main/shokyu/jugyou20.htm
などの方式で十分かと思います。


> プロジェクト毎に「カプセル化」?しなさいとのことですね。
はい。そしてカプセル化は、プロジェクト毎のみならず、クラス毎に対しても必要です。
(VB2008 に限らず、VB6、VB4、VBA、VBScript であっても同様です)

frmA をアプリケーション本体とした場合、そこから frmB のコントロールを操作したいというのは
比較的良くある話だと思います。たとえば、データ自体が frmA で管理されていて、それを
frmB たとえば「進捗表示画面」や「オプション設定画面」などに表示させる場合などには、
frmA から frmB のコントロールに、データを渡す必要があるでしょう。

しかしながら、今回のように
> frmB.uctRect0.shpLamp_BackColor = Color.Red
あるいは
> For i=0 to frmB.panel1.Controls.Count-1
のように、frmA が frmB のコントロールを直接操作してしまうと、フォーム間の結びつきが強くなりすぎてしまいます。
frmB のコントロールを変更したりすると、frmB の修正後に frmA まで修正せねばならなくなってしまいます。複数画面から frmB を利用していた場合は修正も大変です。

そこで、依存性排除のために、カプセル化という作業が必要になります。

カプセル化されたフォームの実装例を、たとえば「InputBox」などに見る事ができます。
これは TextBox や Button が配置されたフォームを表示する機能ですが、呼び出し側が、それらのコントロールを
 frmInputBox.TextBox1.Text = "新しい値"
などと直接触るような設計にはなっていませんし、逆に InputBox 側がメインフォームを直接操作することもありません。


> N88Basicにて
正確には、大文字のみで N88-BASIC と記述します。そもそも BASIC という言語名自体が、
  Beginner's
   All-purpose
    Symbolic
     Instruction
      Code
の略という事もあり、当時の BASIC 系言語の正式名称は、基本的にすべて大文字表記です。
小文字の混じる表記法が使われだしたのは、比較的後発の製品ですね。
("Visual Basic"、"ActiveBasic"、"REALbasic" 等)

# 私が小学生の頃は、OA-BASIC を使っていました。どうでも良い事ですが。


>> frmB の操作は frmB 自身に任せ、frmA は frmB に対して、背景色の
>> 「変更依頼」をメソッドあるいはイベントを通じて投げた方がよろしいかと。
> イベントで行う場合、「frmBにて70個の色データ領域(配列)を持っていて、そのデータのchange
> イベントで自分自身の色を変更する。一方、frmAは色データを変更する。」といった感じですか?
70個の色データを管理する役割が、frmA にあるのか frmB にあるのかそれ以外にあるのかは、
そのアプリの仕様に依存するところなので、私には判断ができません。しかし、その change イベントと
いうのが、データの変更を知らせるための独自イベントであるならば、たとえば frmB を
 Private WithEvents manager As データ管理クラス
 Private Sub manager_change(…) Handles manager.change
  Me.Shapes(e.Index).shpLamp_BackColor = e.Color
 End Sub
などと記述するイメージにできるかと思います。
データ管理クラスとは frmA で良いのか、引数 e の実装をどうするのかといった
細かい点は、実装したい元仕様によりますので、ケースバイケースですけれども。
投稿者 2つのフォーム間でのユーザコントロールに対するアクセス  (社会人) 投稿日時 2009/4/22 10:19:01
魔界の仮面弁士さん
一寸、的が間違っていたら、訂正願います。
>frmB の操作は frmB 自身に任せ、frmA は frmB に対して、背景色の
「変更依頼」をメソッドあるいはイベントを通じて投げた方がよろしいかと

この件ですが、別のフォームからアクセスするために、色の設定をプロパティーにて
Public宣言して、外からアクセス出来るようにしたのですが、この点が、推奨できない
との事でしょうか?
投稿者 2つのフォーム間でのユーザコントロールに対するアクセス  (社会人) 投稿日時 2009/4/22 07:45:48
魔界の仮面弁士さん
いろいろとご指摘ありがとうございます。
>frmB の操作は frmB 自身に任せ、frmA は frmB に対して、背景色の
「変更依頼」をメソッドあるいはイベントを通じて投げた方がよろしいかと

ご意見を聞いて、解ったんですが、プロジェクト毎に「カプセル化」?しなさい
とのことですね。中々、この考え方が、活用できない状況です。N88Basicにて
全て、グローバルな変数として扱っていた考えが先立ってしまい。
イベントで行う場合、「frmBにて70個の色データ領域(配列)を持っていて、そのデータのchange
イベントで自分自身の色を変更する。一方、frmAは色データを変更する。」といった感じですか?

>70個のコントロールに関して
VB5にて、コントロール配列があり、2008にてコントロール配列への対応記事が載っていますが、
いろいろと、読むと、コントロール配列は必要ない。との方向性。この際、別な方法でと思い、
進めていますが、コレクションの使い方が中々、ぴんとこない状況で。勉強してみます。
投稿者 魔界の仮面弁士  (社会人) 投稿日時 2009/4/22 06:42:11
■刈谷勇さん
> Modifiersをpublic等に設定するのではダメですか?
もともとが Friend ですから、特に修正の必要は無いと思います。

実際、
>> frmB.uctRect0.shpLamp_BackColor = Color.Red
>> にて、frmAからfrmBの色を変更できた。
とありますので、既に Modifiers ≠ Private になっているようです。


■Kintonunさん
> frmAからfrmBに配置したユーザコントロールのプロパティーを変更したい。
frmA が、frmB のコントロールを直接操作するのは避けた方が無難です。
後から frmC が追加された場合や、frmB のコントロールを変更した場合、
その修正が frmA に波及してしまうからです。

frmB の操作は frmB 自身に任せ、frmA は frmB に対して、背景色の
「変更依頼」をメソッドあるいはイベントを通じて投げた方がよろしいかと。


> この結果から、70個、この文を並べると何とかなりますが、ループを使って、一括で処理出来ないのでしょうか?
70 個のコントロールを、最初からコレクションや配列で管理しておくと良いでしょう。
そうすればコントロール名ではなく、数値で処理できるようになります。

> いろいろ参考にして、コントロール名まではアクセス出来ているようですが、
全部に同じ色を設定するのであれば、たとえばこう書けます。

For Each uct In frmB.Panel1.Controls.OfType(Of uctRect)
    uct.shpLamp_BackColor = Color.Red
Next
投稿者 刈谷勇  (社会人) 投稿日時 2009/4/22 03:05:48
ちょっと良く把握していないのですが、Modifiersをpublic等に設定するのではダメですか?
投稿者 Kintonun  (社会人) 投稿日時 2009/4/22 00:31:37
前略。言語はMicrosoft Visual Basic 2008 Express Editionです。
行いたいことの概略は以下の通りです。
frmAからfrmBに配置したユーザコントロールのプロパティーを変更したい。
msdnなど見ながら、以下のユーザコントローラを作りました。テストし、何とかfrmBのPanl1内に
貼り付けることが出来ました。
・ユーザコントロール名:uctRectにてプロパティーを作成
  (ユーザコントロール用フォーム?にShapコントロールを貼り付けた)
   Public class uctRect
       Public Property shpLamp_BackColor() As Drawing.Color
           Get
               Return (shpLamp.BackColor)
           End Get
            Set(ByVal value As Drawing.Color)
              shpLamp.BackColor = value
           End Set
       End Property
   end Class
・別のプロジェクトにて、frmBのpanel1にuctRect0~uctRect69(70個)を貼り付けた。
・同ソリューション内にてfrmAにてfrmBにアクセスを行う。
   frmA内ソフト
   frmB.uctRect0.shpLamp_BackColor = Color.Red
 にて、frmAからfrmBの色を変更できた。
 この結果から、70個、この文を並べると何とかなりますが、ループを使って、一括で処理出来ない
のでしょうか?いろいろ参考にして、コントロール名まではアクセス出来ているようですが、プロパティー
へのアクセスが分かりません。ご助言頂けませんでしょうか?以下、検討したソフトを記載します。
  For i=0 to frmB.panel1.Controls.Count-1
       if frmB.panel1.Controls.Item(i).Name Like "uctRect*" then

          この中でshpLamp_BackColor プロパティーに書き込みたい

       End if
    Next
最後に、専門用語が間違っていましたら、訂正願います。現在、50の手習いで勉強中です。