DOBON.NET DOBON.NETプログラミング掲示板過去ログ

buttonを配列に格納するには?

環境/言語:[Win2000 VB.NET 2002 .NER Framework(1.0)]
分類:[.NET]

fnです。こんにちは。
Form上にボタンがたくさんあるため、配列に定義して一括処理をしたいと考えています。
ボタンは、button1〜button20までForm1上にあり、配列変数allBtnに格納するため、
以下のようなコードを考えているのですが、
allBtn(i) = CType?
の行でどのように書けばいいのか分かりませんので、ご教授願います。

Dim allBtn() As System.Windows.Forms.Button
Private Sub Form1_Load(、、、)
Dim i As Integer
For i = 1 To 20
allBtn(i) = CType?
Next
end sub
■No3349に返信(fnさんの記事)
> fnです。こんにちは。
> Form上にボタンがたくさんあるため、配列に定義して一括処理をしたいと考えています。
> ボタンは、button1〜button20までForm1上にあり、配列変数allBtnに格納するため、
> 以下のようなコードを考えているのですが、
> allBtn(i) = CType?
> の行でどのように書けばいいのか分かりませんので、ご教授願います。
>
> Dim allBtn() As System.Windows.Forms.Button
> Private Sub Form1_Load(、、、)
> Dim i As Integer
> For i = 1 To 20
> allBtn(i) = CType?
> Next
> end sub
>

CTypeじゃなくて、普通にnewすればいいのではないですか?
fnです。こんにちは。
ご返答ありがとうございます。

> CTypeじゃなくて、普通にnewすればいいのではないですか?

new するということは、それぞれのボタンの位置や、場所もセットするんですよね?
すでに、Form1上にあるボタン20個をそれぞれ操作したかったので、
現在、Form1上にあるボタンを格納するためにはどうすればよいかお聞きしたいのです。
※CTypeは、私が安直に考えただけで、どんな方法でも、 allBtn配列変数に、
格納できればかまいません。
■No3351に返信(fnさんの記事)
> fnです。こんにちは。
> ご返答ありがとうございます。
>
>>CTypeじゃなくて、普通にnewすればいいのではないですか?
>
> new するということは、それぞれのボタンの位置や、場所もセットするんですよね?
> すでに、Form1上にあるボタン20個をそれぞれ操作したかったので、
> 現在、Form1上にあるボタンを格納するためにはどうすればよいかお聞きしたいのです。
> ※CTypeは、私が安直に考えただけで、どんな方法でも、 allBtn配列変数に、
> 格納できればかまいません。
>

こちらに書かれている方法では駄目なのでしょうか?

 ○コントロールの配列を作成する
 http://dobon.net/vb/dotnet/control/buttonarray.html
fnです。こんにちは。
ご返答ありがとうございます。

>  ○コントロールの配列を作成する
>  http://dobon.net/vb/dotnet/control/buttonarray.html

ですが、こちらは、のっぺらのForm1上に新規にボタンを作成し、
配列変数に格納しているものだと理解しています。

私がやりたいことは、すでにForm1上にあるボタンを配列変数に格納したいのです。

よろしくお願いします。
すでにボタンがフォーム上にある場合、すでにFormのControlsプロパティにそのボタンも含めたすべてのコントロールが格納されていることになります。
そこでそのControlsプロパティからButtonの型を持つコントロールだけを抽出してButton配列に格納するという方法はどうでしょうか。

'いくつのボタンがあるかわからないので動的にサイズを増やせるArrayListを一時的な格納先として用意します
Dim buttonTemp As New ArrayList

'Controlsプロパティにに格納されているコントロールを取り出し、Button型ならArrayListにいったん格納します
For Each ctrl As Control In Me.Controls()
If TypeOf (ctrl) Is Button Then
buttonTemp.Add(ctrl)
End If
Next

'ArrayListの内容をButton配列にします
allBtn = CType(buttonTemp.ToArray(GetType(Button)), Button())
fnです。こんにちは。ご回答ありがとうございます。

■No3356に返信(Codingslaveさんの記事)
> そこでそのControlsプロパティからButtonの型を持つコントロールだけを抽出して>Button配列に格納するという方法はどうでしょうか。
なのですが、こちらもうまくできません。

私の質問がまずくて申し訳ありません。
私が実際に行いたかったのは、
1)ボタンは60個登録されています。
2)ボタンの種類が3種類あり、各ボタン20個づつです。
3)ボタン名はボタンの種類から以下のように決めています。
入力ボタン⇒btnIn01〜btnIn20
出力ボタン⇒btnOut01〜btnOut20
実行ボタン⇒btnRun01〜btnRun20

そこで、私がお聞きしたかったのは、
配列変数にボタンを登録する際、ボタン名から行いたかったのです。
1)allBtnIn(20)←btnIn01〜btnIn20 を順番に格納
2)allBtnOut(20)←btnOut01〜btnOut20 を順番に格納
3)allBtnRun(20)←btnRun01〜btnRun20 を順番に格納
する方法です。

ですので、最初の質問にあったような、
>allBtn(i) = CType?
で格納するのではないかと質問しました。

あまり掲示板を使用したことがなく、皆さんに私の質問の意図が伝わりにくくてすみません。

ボタン名からボタン配列変数に格納するにはどうすればいいのか教えてください。
2004/03/29(Mon) 15:40:59 編集(投稿者)

> ボタン名からボタン配列変数に格納するにはどうすればいいのか教えてください。

FormのControls コレクションに入っている以外にはまとまったボタンの情報はありません。
Controls コレクションを列挙し、ボタンの名前を見ながら配列に格納していくにも、
コントロールの列挙される順番はfnさんの期待される通りになるわけではないので、
単に配列に入れようとすると自分で期待する順番に入るように工夫する必要があります。

私の考る方法としては2つあります。
1.地道に配列に入れる。
現行の希望する通りの使用方法になります。
その代わり、初期設定だけは泥臭い感じになります。

  allBtnIn = New Button(){btnIn01, btnIn02, ・・・, btnIn20}

のようにあらかじめ配列に代入しておくだけです。

2.Hashtableを使う。
Hashtableに入れる方法は、
初期設定は、Codingslaveさんのソースコードのようなやり方でできます。
使用方法としてはコントロール名でボタンのオブジェクトを取得できるので、
btnInの付くものだけを処理、btnOutの付くものだけを処理・・・等、
希望されていることは一通りできます。しかし、Hashtableそのものをそのまま使う場合、
毎回毎回、Hashtableから取出した値をButton型にキャストする必要があり面倒です。
(プロパティ化してしまうとキャスト部分をラップできてすっきりします。)

' ボタン保存用のプライベート変数
Private buttonTable As New Hashtable

' allBtnIn配列の代わり
Private ReadOnly Property allBtnIn(ByVal index As Integer) As Button
Get
Return DirectCast(buttonTable("btnIn" & index.ToString("00")), Button)
End Get
End Property

' allBtnOut配列の代わり
Private ReadOnly Property allBtnOut(ByVal index As Integer) As Button
Get
Return DirectCast(buttonTable("btnOut" & index.ToString("00")), Button)
End Get
End Property

' allBtnRun配列の代わり
Private ReadOnly Property allBtnRun(ByVal index As Integer) As Button
Get
Return DirectCast(buttonTable("allBtnRun" & index.ToString("00")), Button)
End Get
End Property


' FormのLoadイベントに記述
For Each ctrl As Control In Me.Controls()
If TypeOf (ctrl) Is Button Then
buttonTable.Add(ctrl.Name, ctrl)
End If
Next
■No3355に返信(fnさんの記事)
> fnです。こんにちは。
> ご返答ありがとうございます。
>
>> ○コントロールの配列を作成する
>> http://dobon.net/vb/dotnet/control/buttonarray.html
>
> ですが、こちらは、のっぺらのForm1上に新規にボタンを作成し、
> 配列変数に格納しているものだと理解しています。
>
> 私がやりたいことは、すでにForm1上にあるボタンを配列変数に格納したいのです。
>
> よろしくお願いします。

そのリンクの下半分あたりに、予めデザインされたボタンを配列として扱う方法が書いてあるのですが、これとはまた違うのでしょうか?
変数名を識別の基準に使用するのであればControl.Nameプロパティが利用できます。VS.netのIDEにフォームのデザインをさせているのであればこのプロパティには変数名と同じ文字列が入っています(ただし、これはあくまでもVS.netの開発環境が行っている処理なので必ず変数名が入るという保証はありません)。

If ctrl.Name = "btnIn01" Then

といった具合にいちいち比較していく方法もありますが、この場合だとこれを60個も書かなければならないつまらない精神的苦痛をともなう単純作業になるので正規表現で識別し、IComparerインターフェイスで並び替える方法を提案します。

'一時的に各ボタンを格納し、並び替えに利用するArrayList
Dim btnAllInTemp As New ArrayList
Dim btnAllOutTemp As New ArrayList
Dim btnAllRunTemp As New ArrayList

'変数名を識別するために使用します
Dim regexIn As New Regex("btnIn[0-9]+")
Dim regexOut As New Regex("btnOut[0-9]+")
Dim regexRun As New Regex("btnRun[0-9]+")

'IComparerを実装したクラス。並び替えのために使用します
'Buttonを直接並び替えることのできる既存のIComparerはないため、独自に実装する必要があります。
Dim buttonComparer As New ControlComparer

For Each ctrl As Control In Me.Controls()
'ボタンかどうかを識別
If TypeOf (ctrl) Is Button Then
'ボタンの名前を識別
If regexIn.IsMatch(ctrl.Name) Then
btnAllInTemp.Add(ctrl)
ElseIf regexOut.IsMatch(ctrl.Name) Then
btnAllOutTemp.Add(ctrl)
ElseIf regexRun.IsMatch(ctrl.Name) Then
btnAllRunTemp.Add(ctrl)
End If
End If
Next

'各リストの内容を並び替えます
btnAllInTemp.Sort(buttonComparer)
btnAllOutTemp.Sort(buttonComparer)
btnAllRunTemp.Sort(buttonComparer)

'各リストからButton配列を取り出します
Me.btnAllIn = CType(btnAllInTemp.ToArray(GetType(Button)), Button())
Me.btnAllOut = CType(btnAllOutTemp.ToArray(GetType(Button)), Button())
Me.btnAllRun = CType(btnAllRunTemp.ToArray(GetType(Button)), Button())

以下はControlComparerクラス(IComparerの実装)です。
フォームと同じファイルでもかまいませんが、別のファイルを新規作成してそこに書くことをおすすめします。
Public Class ControlComparer
Implements IComparer

Public Function Compare(ByVal x As Object, ByVal y As Object) As Integer Implements System.Collections.IComparer.Compare
Dim buttonX As Button = CType(x, Button)
Dim buttonY As Button = CType(y, Button)

'文字列を比較してその結果を返します
Return String.Compare(buttonX.Name, buttonY.Name)
End Function
End Class
どらごらです。横槍失礼します。

■No3357に返信(fnさんの記事)
> 1)allBtnIn(20)←btnIn01〜btnIn20 を順番に格納
> 2)allBtnOut(20)←btnOut01〜btnOut20 を順番に格納
> 3)allBtnRun(20)←btnRun01〜btnRun20 を順番に格納

        Dim I As Integer
        Dim allBtnIn As New ArrayList
        Dim allBtnOut As New ArrayList
        Dim allBtnRun As New ArrayList

        For Each ctrl As Control In Me.Controls()
            If TypeOf (ctrl) Is Button Then
                Select Case Mid(CType(ctrl, Button).Name, 4, 1)
                    Case "I" 'In
                        allBtnIn.Add(ctrl)
                    Case "O" 'Out
                        allBtnOut.Add(ctrl)
                    Case "R" 'Run
                        allBtnRun.Add(ctrl)
                End Select
            End If
        Next

ってことではないですか? もしかして。。。
fnです。こんばんは。たくさんのご回答ありがとうございます。

■No3360に返信(琴さんの記事)
> そのリンクの下半分あたりに、予めデザインされたボタンを配列として扱う方法が書いてあるのですが、これとはまた違うのでしょうか?
確かに、この方法でも可能なのですが、60個もの代入文を書くのが面倒だったので、
forループ文で簡単に記述できないものかと質問しました。

■No3362に返信(どらごらさんの返事)
>For Each ctrl As Control In Me.Controls()
の部分でサーチされるctrlが必ずしも btnIn??のインデックスと異なるため、
この方法では実現できませんでした。
(ボタンの作成を順番に行わず、行き当たりばったりで作成したため、
 順番がバラバラになったものと思われます。)

■No3361に返信(Codingslaveさんに返事)
■No3359に返信(よねKEN さんに返事)
ArrayList,Regex,ControlComparer,Hashtable等、
VB.NETを始めて1ヶ月の私が、初めて出会った単語なので、
ただいま教えていただいたソースとにらめっこしています。
実装出来次第、こちらの掲示板に報告させていただき、
解決済みとさせていただきます。

※独り言ですが、みなさんはボタンの多いGUIはどのようにして作ってらっしゃるのでしょうか?
この質問は、3種類*20ヶでしたが、今度は、8種類*50ヶのボタンを実装しようとしています。
このようにボタンの多いGUIをつくる私が変わり者?なのでしょうか?
fnです。こんにちは。
無事に実装できました。
みなさん、ご回答ありがとうございました。
また、何かありましたらよろしくお願いします。
解決済み!
■No3376に返信(fnさんの記事)
> fnです。こんにちは。
> 無事に実装できました。

最終的にどの方法(あるいは別の方法?)で実装されたのでしょう?
解決したら、どのように解決したかフィードバックして下さいね。

DOBON.NET | プログラミング道 | プログラミング掲示板