プログラミング

プログラミングに関するフォーラムです。VBAは除きます。
  • 掲示板への投稿には会員登録(無料)が必要です。会員登録がまだの方はこちら
  • 掲示板ご利用上のお願い」に反するご記入はご遠慮ください。
  • Q&A掲示板の使い方はこちらをご覧ください
トピックに返信
質問

 
(指定なし : 指定なし)
VB.NET Visual Studio 2022についての質問
投稿日時: 22/05/20 15:35:18
投稿者: masawa
メールを送信

 VB.NETの初心者です。
 
 Public Class Form1
   For j As Integer = 7 To 16
        Dim cnt As Control() = Me.Controls.Find($"ListBox{j}", True)
        Dim lsb As ListBox = cnt(0)
        Dim d As Long = lsb.Items.Count
 
        lsb.Items.Clear()
 
     Next
 End Class
 
 以上は正常に動きました。
--------------------------------------------------------------------------------------------------- 
 Public Class Form1
  Private Sub ComboBox1_SelectedIndexChanged(sender As Object, e As EventArgs) Handles ComboBox1.SelectedIndexChanged
   
  Call YkClear()
 
   End Sub
    
   Sub YkClear()
     For j As Integer = 7 To 16
        Dim cnt As Control() = Me.Controls.Find($"ListBox{j}", True)
        Dim lsb As ListBox = cnt(0)
        Dim d As Long = lsb.Items.Count
 
        lsb.Items.Clear()
     Next
   End Sub
 End Class
 
 だと正常に動きません。
 ListBox7 〜 ListBox16は、TabControl1の中のTabControl3に配置してあります。
 『Message=インデックスが配列の境界外です。』というメッセージです。
 因みに、For j As Integer = 1 To 6 とやるとうまく動きます。
 ListBox1 〜 ListBox6は、TabControl1の中のTabControl2に配置してあります。
 よろしくお願い致します。

回答
投稿日時: 22/05/20 22:32:19
投稿者: MMYS

希望の動作がされいなとのことですが、その前に、前回のサンプルコードはどこまで、理解されましたか。特に、Controls.Find を理解しましょう。たとえば、第2パラメータに、なぜ True を指定なのかなど。
 
Windowsフォーム上のコントロールを検索するには?[2.0のみ、C#、VB]
https://atmarkit.itmedia.co.jp/fdotnet/dotnettips/479ctrlfind/ctrlfind.html
 
フォームに配置されているコントロールを名前で探す
https://dobon.net/vb/dotnet/control/findcontrolbyname.html
 
 
それから、フォームにコントロールを配置ですが、配置後のコントロールの階層構造を把握されてますか。特に今回は、コンテナ(TabControl)を配置したのですよね。
配置したコントロールの階層構造の把握には、VisualStadioの次の機能を使いましょう。
 
 
  メニュー・バーから[表示]→[その他のウィンドウ]→[ドキュメント アウトライン]
 
 
「ドキュメント アウトライン」でフォーム配置したコントロールを確認してみましょう。Controls.Findは検索して見つかれば、そのコントロール(今回の例ならListbox)を返しますが、存在しなかった(見つからない場合)、戻り値は何でしょう。その場合、Indexって存在するのでしょうか。
なお、ドキュメントアウトラインの詳細は下記を参照願います。
 
Visual Studio 2005でコントロールの選択/移動を簡単に行うには?[VS 2005のみ]
https://atmarkit.itmedia.co.jp/fdotnet/dotnettips/612docoutline/docoutline.html
 
 
ちなみに、masawa さんが 提示されたコードを、こちらで動作させましたが、問題なく動作します。
 

投稿日時: 22/05/21 16:37:49
投稿者: masawa
メールを送信

MMYS様
本当にありがとうございます。
False or True の意味もあまり理解していませんでした。
フォーム上のすべてのコントロールから検索するということですね。
教えて頂いたドキュメントアウトラインで確かめたら以下のような階層構造でした。
 
TabControl1 TabControl
  TabPage1 TabPage
 
  TabPage2 TabPage
  TabControl2 TabControl
      TaPage5 TabPage
      TaPage6 TabPage
      TaPage7 TabPage
      TaPage8 TabPage
      TaPage9 TabPage
      TaPage10 TabPage
 
  TabPage3 TabPage
    TabControl3 TabControl
      TaPage11 TabPage
            .
            .
      TaPage20 TabPage
 
  TabPage4 TabPage
    TabControl4 TabControl
      TaPage21 TabPage
            .
            .
      TaPage30 TabPage
以上のような階層構造でした。
実は、VBAで作ったプログラムをVB.NETに置き換えています。
VB.NETが全く分からず苦労しています。
戻り値がどこを見ればいいのかもわかりません。
cntが{Length=0}というときにエラーになります。
Vidual studio2022の操作もおぼろげです。
すみません。
よろしくお願いします。

回答
投稿日時: 22/05/22 11:53:55
投稿者: MMYS

masawa さんの引用:

フォーム上のすべてのコントロールから検索するということですね。

少々、意味が異なります。コントロールの配置はフォームに直接配置とコンテナを配置して、そのコンテナ内へのコントロール配置があります。
コントロールは、親の下に配置されます。フォームに配置すれば親はフォームになります。コンテナ内に配置すれば親はそのコンテナになります。たとえば
Me.Controls.Find("TextBox1", False)
とした場合、Meを指定してるので検索対象はフォームとなり、フォーム直下の"TextBox1"は検索されますが、コンテナ内に配置した場合、見つかりません。
 
下記のリンク先の中ほどの
 2.Controlsプロパティ
読んでください。特に画像2の説明とコンテナを理解しましょう。
 
第20回 コントロールをまとめる方法
http://rucio.o.oo7.jp/main/dotnet/shokyu/standard20.htm
 
なお、今回、masawaさんはTabControlを配置されてますが、TabControlはコンテナです。
 
 
masawa さんの引用:

戻り値がどこを見ればいいのかもわかりません。
cntが{Length=0}というときにエラーになります。

VBAは理解できますよね。VBAで、次のコードを実行するには ユーザーフォームにTextbox1 を配置しなければ、エラーになることは、理解している思います。
 
VBA
    Dim c As Control
    Set c = Me.Controls("Textbox1")

では、VB.Net ではどうでしょうか。Findとは英語で「探す」という意味です。
  Me.Controls.Find(
つまり、探して、見つかったコントロールの数だけ、配列で返します。しかし、探す以上、見つからない場合も考えられます。見つからない場合、0個の配列を返します。VB.Netでは、配列の数は、Lingthプロパティで分かります。cntが{Length=0}って配列は0個って意味です。
 
つまりVBAではコントロールは前もって配置が必要は、理解してますよね。
今回、VB.Netのコードも同じで、配置されているはずのコントロールを探します。しかし、そんな名前のコントロールは配置されてないと、返している。それを無視して、実行しているのだから、当然エラーです。
 
ちなみに
https://dobon.net/vb/dotnet/control/findcontrolbyname.html
で下記コードはLengthプロパティで配列の数を確認してエラー回避してます。
 
Dim cs As Control() = Me.Controls.Find("TextBox1", True)
If cs.Length > 0 Then
    CType(cs(0), TextBox).Text += "*"
End If
 
 
masawa さんの引用:

教えて頂いたドキュメントアウトラインで確かめたら以下のような階層構造でした。

肝心の ListBox が見当たりません。配置しなければ当然、エラーです。
ですから、ドキュメントアウトラインで配置されていることをご確認してください。という意味なのですが。
 
 
 
どのように配置が希望か存じませんが、
・ComboBox1 を配置
・TabControl1 を配置後、
 ・Page1に ListBox1 〜 ListBox6 を配置
 ・Page2に ListBox7 〜 ListBox16 を配置
であれば、ドキュメントアウトラインは下記のようになります。
 
 
Form1
  TabControl1
    TabPage1
      ListBox1
      ListBox2
      ListBox3
      ListBox4
      ListBox5
      ListBox6
    TabPage2
      ListBox7
      ListBox8
      ListBox9
      ListBox10
      ListBox11
      ListBox12
      ListBox13
      ListBox14
      ListBox15
      ListBox16
  ComboBox1
 

投稿日時: 22/05/22 22:59:11
投稿者: masawa
メールを送信

MMYS様
こんばんは。
勉強不足で申し訳ありません。
ListBoxを書くのを忘れていました。
詳しくは以下のようになります。
 
Form1 Form
  ComboBox1 ComboBox
  TabControl1 TabControl
    TabPage1 TabPage
  
    TabPage2 TabPage
   TabControl2 TabControl
        TaPage5 TabPage
          ListBox1 ListBox
        TaPage6 TabPage
          ListBox2 ListBox
        TaPage7 TabPage
          ListBox3 ListBox
        TaPage8 TabPage
          ListBox4 ListBox
        TaPage9 TabPage
          ListBox5 ListBox
        TaPage10 TabPage
          ListBox6 ListBox
  
    TabPage3 TabPage
      TabControl3 TabControl
        TaPage11 TabPage
          ListBox7 ListBox
                .
                .
        TaPage20 TabPage
          ListBox16 ListBox
  
    TabPage4 TabPage
      TabControl4 TabControl
        TaPage21 TabPage
          ListBox17 ListBox
                .
                .
        TaPage30 TabPage
          ListBox26 ListBox
 
以上のような階層構造です。
すべてのListBoxの中をクリアーしたいと思っています。
教えて頂いたコードでまだ理解できていないのが
Dim lsb As ListBox = cnt(0) です。
cnt(0)が良くわかりません。
よろしくお願いします。

回答
投稿日時: 22/05/23 09:17:41
投稿者: MMYS

masawa さんの引用:

教えて頂いたコードでまだ理解できていないのが
Dim lsb As ListBox = cnt(0) です。
cnt(0)が良くわかりません。

配列変数は理解されてますか。VBAでも配列変数はありますが。
 
まず、下記のコードは理解出来ますか。
    Private Sub Test()
        Dim cnt(3) As String
        cnt(0) = "あ"
        cnt(1) = "い"
        cnt(2) = "う"
        cnt(3) = "え"
        MsgBox(cnt(0))
    End Sub

この単純なコードなので問題ないと思いますが。
では次のコードは理解出来ますか。
 
    Private Sub Test()
        Dim cnt As String()
        cnt = testFind()
        MsgBox(cnt(0))
    End Sub

    Private Function testFind() As String()
        Dim result(3) As String
        result(0) = "あ"
        result(1) = "い"
        result(2) = "う"
        result(3) = "え"
        Return result
    End Function

最初のコードとの違いは、「プロシージャに変更。結果を配列で返す」です。呼び出し元で、配列変数で受け取り、あとは結果を表示です。
 
    Private Sub Test()
        Dim cnt As String()
        cnt = testFind()
        MsgBox(cnt(0))
    End Sub

    Private Function testFind() As String()
        Dim result As String()
        result = {"あ", "い", "う", "え"}
        Return result
    End Function

VBAには無い記述で、VB.Netの構文が含まれますが、すぐに理解できると思います。前のコードと基本同じです。
 
では次のコードはどうでしょう。
    Private Sub Test()
        Dim cnt As String()
        cnt = testFind()
        MsgBox(cnt(0))
    End Sub

    Private Function testFind() As String()
        Dim result As String()
        result = {}
        Return result
    End Function

戻り値は配列ですか、0個の配列を返します。ところが実行すると
'インデックスが配列の境界外です。'
とエラーとなります。当然です。配列変数 cnt(0) は存在しないのですから。
 
重要なので、もう一度。
    Private Sub Test()
        Dim cnt(3) As String
        cnt(0) = "あ"
        cnt(1) = "い"
        cnt(2) = "う"
        cnt(3) = "え"
        MsgBox(cnt(10))
    End Sub

このコードもエラー。'インデックスが配列の境界外です。'のエラー
インデックスに10を指定ですが、10番は存在しません。とエラーメッセージ。
 
さて、話を戻して
    Private Sub Test()
        Dim cnt As String()
        cnt = testFind()
        MsgBox(cnt.Length)
    End Sub

    Private Function testFind() As String()
        Dim result As String()
        result = {}
        Return result
    End Function

こんどは、配列の数を表示するように変更。変更箇所は
 MsgBox(cnt.Length)
です。結果は 0 と表示されます。配列の数は0です。つまり、配列は存在しないってことです。
 
では、配列変数の数のチェックを追加
    Private Sub Test()
        Dim cnt As String()
        cnt = testFind()
        If cnt.Length > 0 Then
            MsgBox(cnt(0))
        End If
    End Sub

    Private Function testFind() As String()
        Dim result As String()
        result = {}
        Return result
    End Function

上記コードは、配列の数をチェックしてから、配列変数 cnt(0) の値を表示するように変更。これでエラーは発生しません。
 
    Private Sub Test()
        Dim cnt As String()
        cnt = testFind()
        If cnt.Length > 0 Then
            MsgBox(cnt(0))
        End If
    End Sub

    Private Function testFind() As String()
        Dim result As String()
        result = {"あ"}
        Return result
    End Function

さて、上記のコードは、どんな動きをしますか。testFindはどんな値を返し、受け取った側はどんな動きをするでしょう。
ご自身で考えましょう。
 
 
以上の説明で cnt(0) は理解出来ましたか。
何度も申し上げますが、Findメゾットは結果を配列で返します。見つかれば 配列変数 cnt(0) は有効ですが、見つからない場合、配列変数 cnt(0) は無効です。存在しない配列の指定は、'インデックスが配列の境界外です。'とエラーです。
 
 
また、前回
https://dobon.net/vb/dotnet/control/findcontrolbyname.html
 
Dim cs As Control() = Me.Controls.Find("TextBox1", True)
If cs.Length > 0 Then
    CType(cs(0), TextBox).Text += "*"
End If
 
で上記コードを例題あげましたが、今回のサンプルと、ほぼ同じって、理解出来ましたか。
 

投稿日時: 22/05/23 17:04:15
投稿者: masawa
メールを送信

MMYS様
有難うございました。
cnt(0)は、配列でした。VBAでは理解していたつもりでしたが・・・
 
それから、エラーで止まった件ですが、どうも階層構造か名前に問題があったと思われます。
一からフォームを作り直したら問題なく動きました。
取り敢えずこの問題は解決しました。
 
有難うございました。
また問題が出てくると思います。
申し訳ありませんがその時はまたご教授下さい。
本当にありがとうございました。

投稿日時: 22/07/06 17:43:45
投稿者: masawa
メールを送信

VB.NETの初心者です。
 
また新たな問題です。
同一のListView内で左ボタンを押したまま上下に移動した時(ドラッグ)、一緒にフォーカスも移動できませんか?
どなたかご存じであれば教えて頂きたいのですが。
 
よろしくお願い致します。

トピックに返信