ListViewで選択されている項目番号を取得するには

解決


ペン吉  2003-11-20 08:11:02  No: 110067

VB.NetでListViewを使いたいのですが、実行したときに選択されている項目(行)の番号を取得したいのですが、わかりません。
ListBox(VB6の)にはIndexというプロパティがあったと思うのですが、そのように選択されている番号は簡単に取得できないのでしょうか?


特攻隊長まるるう  2003-11-20 21:20:05  No: 110068

ListView1.SelectedItems(i).Index

で i を0から順にカウントすれば取れると思うよ。…というか VB6.0 で作ったプログラムがあれば .Net で開けば変換してくれます。それを参考にするのも手です。


ペン吉  2003-11-21 04:16:47  No: 110069

助言ありがとうございます。VB6で使っていたのはListBoxでした。VB.Netへの変換後は【ListBox.SelectedIndex】となっていました。

教えていただいた通りに試してみましたが、どうもうまくいきません。【.SelectedItems(i)】の【i】がなんだかわかりません。ヘルプで見ると項目のインデックスとしかでていないのですが・・・。
下記の記述で実行すると一回目のリストのクリック時は番号を取得できるのですが、連続で違う行を選択すると【引数が有効な値の範囲内にありません】となり終了してしまいます。

  Private Sub Listview_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Listview.SelectedIndexChanged
        Dim SelectNo As Integer
        SelectNo = Listview.SelectedItems(0).Index
        TextBox1.Text = SelectNo
    End Sub


ペン吉  2003-11-21 04:27:47  No: 110070

あっ、すいません。「使っていたのはListBoxでした」というのはVB6のときのコントロールです。VB.Netでは【ListView】を使用しています。


特攻隊長まるるう  2003-11-21 09:55:34  No: 110071

SelectedIndexChanged は選択行が変更されると毎回走ります。
人間には選択行を1行目から2行目に変えたように見えても
プログラム側から見ると
・1行目を選択
・SelectedIndexChanged
・1行目を選択解除(選択行なし)
・SelectedIndexChanged←上記のプログラムではここでエラー
・2行目を選択
・SelectedIndexChanged
という処理になります。ちゃんとデバッグすれば分かりますよ?。
せっかく Index をヘルプで調べたんならもう一歩! Listview が
どんなオブジェクトを格納してそのプロパティには何がどんな形で
あるか…そこまで調べられればすぐに理解できますよ。
明日、時間があれば上手くいくソース載せます。それまで頑張ってみて?


ペン吉  2003-11-21 21:51:57  No: 110072

イベントハンドラを【Handles Listview.Click】にしたら取得することができました。なぜ。【.SelectedItems(i)】のインデックスを0にしないといけないのかがいまだにわかっていないので、もう少し勉強します。
ありがとうございました。


特攻隊長まるるう  2003-11-22 02:24:57  No: 110073

'一応書いたので参考にしてもらえれば嬉しいです。

    ' ポイント1:文頭に Option Explicit On 宣言をしファイル内のすべての変数を明示的に宣言するクセをつけましょう。
    ' ポイント2:キャストしなくても .NET が適当に変換してくれますが、変数は明示的にキャストするクセをつけましょう。
    ' ポイント3:プロパティ名にも意味があります。ListView は Item を加えて ListView.Items(i).Text を表示します。
    '         ListView.Items の最後に複数形の s がついてるのは ListView.Items が Item を複数抱え込んだコレクション
    '         だからです。ListView.SelectedItems も同じで選択行を全て抱え込んだコレクションです。デバッグ時に内容を
    '         知りたい場合はウォッチ式を追加し、ツリーを展開してください。
    Private Sub ListView_SelectedIndexChanged(ByVal sender As System.Object, _
                                              ByVal e As System.EventArgs) _
                                              Handles ListView.SelectedIndexChanged
        Dim SelectNoTxt As String
        Dim i As Integer

        With Me.ListView
            ' ListView に Item(項目) が1つもない場合処理しない。
            If .Items.Count = 0 Then Exit Sub
            ' ListView で SelectedItem(選択された項目) が1つもない場合
            ' (1行も選択されていない場合)選択行についての処理を飛ばします。
            With .SelectedItems
                If .Count <> 0 Then
                    For i = 0 To .Count - 1
                        ' カウントが0始まりか1始まりか?そして終了条件は極めて重要です。
                        ' 配列などを扱う時や、エクセルのセル選択など…つねに意識しましょう。
                        '''SelectNoTxt = SelectNoTxt & CStr(Me.ListView.SelectedItems(i).Index + 1) & ", "
                        ' 上のように書けますが、With を使ってますので下のように書き直します。
                        ' SelectedItems も Item のコレクションなので以下のように書けます。
                        SelectNoTxt = SelectNoTxt & CStr(.Item(i).Index + 1) & ", "
                    Next i
                End If
            End With

            ' この時点で SelectNoTxt の長さが0の場合、行は選択されていません。
            ' If 文の条件は SelectNoTxt = "" としても同じです。
            ' SelectNoTxt の明示的な初期化(SelectNoTxt = "")は行っていませんが、SelectNoTxt の
            ' スコープは関数内のみ有効なので、関数を抜けると破棄されます。(再び関数が呼ばれた時に
            ' "" で初期化されます)
            If Len(SelectNoTxt) = 0 Then
                ' 行が選択されていない状態は、ユーザが ListView の微妙な位置を選択した場合や、
                ' Esc キーを押下した時(今回は ListView_KeyPress イベントで意図的に定義)に起こります。
                SelectNoTxt = "行は選択されていません。"
            Else
                SelectNoTxt = SelectNoTxt & "行を選択しましたね?(‾ー‾)。"
            End If

            ' TextBox1 に表示
            TextBox1.Text = SelectNoTxt
        End With
    End Sub

    Private Sub Form1_Load(ByVal sender As System.Object, _
                           ByVal e As System.EventArgs) _
                           Handles MyBase.Load
        ' 初期化処理
        InitForm()
    End Sub

    ' 初期化処理
    Private Sub InitForm()
        ' i,j,m,n などは通常、カウンタとして使われます。
        ' 何の説明もなくても使用されている場所を見てカウンタなら
        ' Dim i, j, m, n As Integer と宣言しましょう。
        Dim i As Integer

        ' ListView のプロパティを設定([デザイン]画面で設定しても同じです)
        With Me.ListView
            .Columns.Clear()        ' カラムの初期化
            .Items.Clear()          ' Item の初期化
            .Columns.Add("名称", .Width - 5, HorizontalAlignment.Left) ' カラムの設定
            .HeaderStyle = ColumnHeaderStyle.Nonclickable ' カラムはボタン状でない表示
            .MultiSelect = True     ' 複数行選択可(Ctrl[or Shift]キーを押したまま選択)
            .View = View.Details    ' 詳細表示
            For i = 1 To 7          ' テスト表示用 Item 追加
                .Items.Add("Test" & CStr(i))
            Next i
        End With

        ' ちょっとした初期化のテクニック(関数内で引数を利用してないのでエラーは起こらない)
        ListView_SelectedIndexChanged(Nothing, Nothing)
    End Sub

    Private Sub ListView_KeyPress(ByVal sender As Object, _
                                  ByVal e As System.Windows.Forms.KeyPressEventArgs) _
                                  Handles ListView.KeyPress
        Dim i As Integer
        'Debug.WriteLine(CStr(Asc(e.KeyChar)))  ' キーの文字コードを簡単に出力する方法
        With Me.ListView
            Select Case e.KeyChar
                Case Chr(27) ' Esc キー押下で全ての行の選択解除
                    With Me.ListView
                        If .SelectedItems.Count = 0 Then Exit Sub
                        ' 何でカウンタを逆に回してるかは自分で色々変更して検証してください。
                        For i = .SelectedItems.Count - 1 To 0 Step -1
                            .Items(.SelectedItems(i).Index).Selected = False
                        Next i
                    End With
                Case Else
            End Select
        End With
    End Sub


カナ  2004-07-27 23:16:56  No: 110074

ListBoxで同じようなことは出来ないのでしょうか?


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加