Visual Basic 中学校 掲示板 投稿内容
タグのない投稿を抽出 統計 RSS

Visual Basic 中学校 > 投稿一覧 >

配列とコントロールの繰り返しについて 解決済み

タグの編集...

投稿者   (学生)   投稿日時 2022/5/12 15:29:24
何度も質問申し訳ございません。

二次元配列(i,j)というものを宣言し、フォーム上にテキストボックスが表の様に並んでいるものとします。

そしてこのテキストボックスの名前は、i,

TextBox0_0 TextBox0_1 ~TextBox0_3 TextBox1_0 TextBox1_1 ~

の様に、配列の添え字とTextBoxの後ろの数字が一致しています。

ここで疑問なのですが、Forを使って二次元配列にセットするプログラムを調べたところ、

For i As Integer = 0 To 4
For j As Integer = 0 To 4

配列名(i,  j) = i + j  

Next
Next
 
の様に、二重でループをするという方法があるのは知っていますが、(例では足し算とさせていただきました)、上記の様にテキストボックスの数字をFor を使ってループし、代入することはできないのでしょうか?


今までは、

配列名(0,0) = TextBox0_0.Text 

のようにすべて入力して代入をしていたので、もっといい方法がないかと思い質問させていただきました。
お手数ですがご回答よろしくお願いいたします。



投稿者 魔界の仮面弁士   (社会人)   投稿日時 2022/5/12 15:37:36
> 上記の様にテキストボックスの数字をFor を使ってループし、代入することはできないのでしょうか?
そのための手段(コントロールの名前を使ってアクセスする方法)は、
今週月曜日にお伝えしたばかりですよね???
http://rucio.cloudapp.net/ThreadDetail.aspx?ThreadId=30726


> フォーム上にテキストボックスが表の様に並んでいるものとします。
ちなみに、TableLayoutPanel って使ってますか?
行・列に揃えてコントロールを配置する時に便利な代物です。

基本的には 1 つのセルにつき一つのコントールしか配置できないのですが、
複数セルにまたがるように配置することもできます。

列番号と行番号を指定して、コントロールにアクセスすることや、
TableLayoutPanel1.GetControlFromPosition(2, 3).Text = "あいうえお"
その逆に、コントロールがどの位置にあるかを確認することもできます。
Dim pos = TableLayoutPanel1.GetCellPosition(TextBox1)
MsgBox(pos.Column & "," & pos.Row)

投稿者   (学生)   投稿日時 2022/5/12 16:10:52
二つ数字があるので、もう一度質問してしまいました、申し訳ございません。
もう一度そちらを見てやってみたいと思います。

今まさにTableLayoutPanelというものにテキストボックスを配置しているので、魔界の仮面弁士さんが仰っているコントロールへのアクセス方法が使えると思うのでやってみたいと思います。

投稿者   (学生)   投稿日時 2022/5/13 10:38:53
連投申し訳ございません。

自分でやっては見たのですが力不足でできませんでした、、

お気を煩わせてしまうかもしれませんがご回答のほどよろしくお願いいたします。

投稿者 魔界の仮面弁士   (社会人)   投稿日時 2022/5/13 13:31:35
'案1:TableLayoutPanel 上にあるすべてのテキストボックスに同じ値を入れたい 
Dim s As String = "example1"
For Each txt In TableLayoutPanel1.Controls.OfType(Of TextBox)()
    txt.Text = s
    'txt.Text = txt.Name 
Next



'案2:TableLayoutPanel のインデックスを使って代入したい(コントロールの名前は考慮しない) 
Dim s As String = "example2"
For x = 0 To 3
    For y = 0 To 1
        Dim txt = TryCast(TableLayoutPanel1.GetControlFromPosition(x, y), TextBox)
        If txt IsNot Nothing Then
            txt.Text = s
        End If
    Next
Next



'案3:TableLayoutPanel に載せてある TextBoxY_X のみを対象にしたい 
Dim s As String = "example3"
For Each txt In TableLayoutPanel1.Controls.OfType(Of TextBox)()
    If txt.Name Like "TextBox#_#" Then
        txt.Text = s
    End If
Next



'案4:配置場所が TableLayoutPanel であるかどうかを問わず、TextBoxY_X という名を対象にしたい 
Dim s As String = "example4"
For x = 0 To 3
    For y = 0 To 1
        Dim textBoxName = $"TextBox{y}_{x}"
        Me.Controls.Find(textBoxName, True)(0).Text = s
    Next
Next


※VB2005 以下のバージョンを対象とする場合は、上記それぞれ、もう少し手直しが必要です。

※案4 の『Dim textBoxName = $"TextBox{y}_{x}"』は VB2015 以降向けの構文です。
 VB2008~2013 の場合には、『Dim textBoxName = String.Format("TextBox{1}_{0}", x, y)』
 もしくは『Dim textBoxName = "TextBox" & CStr(y) & "_" & CStr(x)』のようにしてください。

投稿者 魔界の仮面弁士   (社会人)   投稿日時 2022/5/13 13:43:48
なお、月曜日に回答した

> Dim n As Integer
> Dim txtName As String = "TextBox" & CStr(n)
> Dim txtBox As TextBox = DirectCast(Me.Controls.Find(txtName, True)(0), TextBox)
> txtBox.BackColor = Color.Red

にあたるのが上記の案4です。

『Dim textBoxName As String = "TextBox" & CStr(n)』の部分が、数値が 2 つになって
『Dim textBoxName As String = "TextBox" & CStr(y) & "_" & CStr(x)』に変わっただけで、
あとは「Me.Controls.Find(textBoxName, True)(0)」でアクセスできるという点は変わりません。


なお、案4 の名前での全探索は、あまり多用しないようが望ましいです。
何度も使う場合には、前回も回答しましたように Form1_Load で Controls.Find を呼び出して、
その検索した結果を、適当なフィールド変数(たとえば Private Tables(2, 1) As TextBox など)に
キャッシュしておき、その他の処理(たとえば Button1_Click)ではその変数を
ループ処理のために用いた方が好ましいです。

投稿者 魔界の仮面弁士   (社会人)   投稿日時 2022/5/13 17:52:46
>> コントロール数が多い場合は、初回のみ Controls.Find で探索し、
>> それをキャッシュすると良いですね。
蛇足とは思いますが、二次元配列にキャッシュしてみる例。

TextBox0_0 TextBox0_1 TextBox0_2 TextBox0_3
TextBox1_0 TextBox1_1 TextBox1_2 TextBox1_3
の 8 つのテキストボックスが貼ってある想定です。


Private 二次元配列(0 To 1, 0 To 3) As TextBox
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    'Controls.Find で探したテキストボックスを、二次元配列にキャッシュしておく 
    For i = 0 To 1
        For j = 0 To 3
            Dim controlName As String = $"TextBox{i}_{j}"
            二次元配列(i, j) = DirectCast(Me.Controls.Find(controlName, True)(0), TextBox)
        Next
    Next
End Sub

'その後は二次元配列を使って、テキストボックスをループ処理できる 
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    For i = 0 To 1
        For j = 0 To 3
            二次元配列(i, j).Text = $"{i}-{j}"
        Next
    Next
End Sub
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
    For Each txt In 二次元配列
        txt.Text = ""
    Next
End Sub


投稿者   (学生)   投稿日時 2022/5/16 10:24:58
ご回答ありがとうございます、初心者なのでたくさんのことを記述していただき大変うれしく思います。
まだプログラムは完成していませんが参考にして進めたいと思います。

初心者の質問で誠に申し訳ないのですが、

 Dim controlName As String = $"TextBox{i}_{j}"

のように書かれている、$の部分、記号は何を表しているのでしょうか?
変数を定義するときに昔は使っていたという記述をWebサイトで見ましたが、気になったので聞いてみました。

投稿者 魔界の仮面弁士   (社会人)   投稿日時 2022/5/16 11:29:21
「$」という記号キーワードは、Google などでも検索しにくいので厄介ですよね…。

> Dim controlName As String = $"TextBox{i}_{j}"
> のように書かれている、$の部分、記号は何を表しているのでしょうか?
> 変数を定義するときに昔は使っていたという記述をWebサイトで見ましたが、気になったので聞いてみました。

変数定義に使う「$」と、今回使っている「$」は、実は全く別のものなのです。

$"TextBox{i}_{j}" のように、先頭に $ を付与した記述は、
専門用語で 『文字列補間機能』や『補完文字列』などと呼ばれます。
また、その中の { } で囲まれた部分のことは『挿入文字列』と呼ばれます。
これは VB では 2015 から(C# では 2013 から)追加された、比較的「新しい文法」です。

下記の説明を読んでみてください。

VB → http://rucio.o.oo7.jp/VBNyumon/BEGIN6.htm
C# → https://www.umayadia.com/CSNyumon/BEGIN6.htm

一方、昔使われていたという変数定義の方は、
 Dim controlName As String
という記述を
 Dim controlName$
と書けるという物であり、こちらは『型文字』もしくは『型宣言文字』と呼ばれます。
(VB.NET では型文字、VBA でも型宣言文字と呼ばれることが多いです)

文字列型以外にも、幾つかの数値型に対しても型文字(型宣言文字)が用意されています。
今見ているサイト(VB中学校)でも紹介されていますね。
https://www.umayadia.com/VBStandard2/Standard03.htm
https://www.umayadia.com/Note/Note049VBDataType.htm

ただし、数値型の型文字(型宣言文字)は今でもしばしば使われることがありますが、
文字列型のための $ の型宣言文字は、今ではあまり使われていません。

一方、文字列補間機能の方の $ は便利なので、今ではよく使われるようになってきましたが、
比較的新しい文法なので、古い書籍などには記載されていないことが多いです。


投稿者   (学生)   投稿日時 2022/5/16 13:55:59
文字列補完機能を使う合図なんですね!

中々出てこず、URLの方も過去に読んではいたのですが、忘れておりました、、

しっかりメモとして残しておきたいと思います、回答ありがとうございました。