• ベストアンサー

リストボックスでの選択項目分削除について。

こんばんは。 リストボックスでのマルチセレクトで選択した項目を削除する 方法で悩んでいます。 (リストボックスで3項目選択したとして、この3項目を削除する方法) 解答は現在勉強している本に掲載されているのですが意味が分からず。 解答のコードの方にはリストを後ろから削除しているみたいなのですが、 前から削除しても大丈夫だと思いやってみましたが、エラーが出てしまいます。 解説には、先頭から削除するとその時点でリストのインデックス値がずれて しまう。と書いてあるのですが、後ろから削除しても一緒だと考えこんでいます。 解答コード ********************************************************** Private Sub Command2_Click() Dim i As Integer '選択状態(Selected=true)の項目だけ削除 For i = List1.ListCount - 1 To 0 Step -1 If List1.Selected(i) = True Then List1.RemoveItem i End If Next i End Sub ********************************************************* と言う解答コードを自分は、前から削除するように 自分なりのコード ********************************************************* Private Sub Command2_Click() Dim i As Integer For i = 0 To listcount-1 If List1.Selected(i) = True Then List1.RemoveItem i End If Next i End Sub ************************************************************* で作成してみましたが、やっぱりエラーが。 なぜ、前から削除するとエラーになってしまうのか、 もう少し具体的に教えてくれると助かります。 よろしくお願いします。m(__)m

質問者が選んだベストアンサー

  • ベストアンサー
  • hershe
  • ベストアンサー率55% (5/9)
回答No.5

こんにちわ。 コードの処理に沿って順番に説明しますね。 リストの内容はA~Eの5個あり、BとDを選択した状態だとします。 *リストの内容** 1|A 2|B ←選択 3|C 4|D ←選択 5|E ************** これを解答コードのように後ろから削除する場合、5から1まで繰り返し判定するわけですが、 1回目(5):Eは選択されていませんので何もしません。 2回目(4):Dが選択されているので削除します。 *リストの内容** 1|A 2|B ←選択 3|C 4|E ************** 3回目(3):Cは選択されていませんので何もしません。 4回目(2):Bが選択されているので削除します。 *リストの内容** 1|A 2|C 3|E ************** 5回目(1):Aは選択されていませんので何もしません。 結果、以下のようなリストになり正常に動作します。 *リストの内容** 1|A 2|C 3|E ************** 同じ様にmineral01さんのコードのように前から削除する場合、 1回目(1):Aは選択されていませんので何もしません。 2回目(2):Bが選択されているので削除します。 *リストの内容** 1|A 2|C 3|D ←選択 4|E ************** 3回目(3):Dが選択されているので削除します。 (この時点でインデックスがずれているためCの判定が飛ばされてしまいます。) *リストの内容** 1|A 2|C 3|E ************** 4回目(4):4番目の要素が無いためエラーになります。 この段階ではもうリストの内容が3つしかないために、4番目の内容を取得しようとするとインデックスエラーとなってしまいます。 どうしても前から削除したい場合は、以下のコードで大丈夫だと思います。 mineral01さんのコードに追記してみました。 ********************************************************* Private Sub Command2_Click() Dim i As Integer For i = 0 To List1.listcount - 1 If List1.Selected(i) = True Then List1.RemoveItem i i = i - 1 End If If i >= List1.ListCount - 1 Then Exit For End If Next i End Sub ************************************************************* 長文なってしまい、申し訳無いです。参考になれれば幸いです。

mineral01
質問者

お礼

hersheさん、とても理解しやすい説明ありがとうございます。 おかげさまで理解できました。 リストを前から、判定してしまうと、 インデックス値(iの値)がずれてしまったために 判定処理が飛ばされてしまうんですね。 リストに最後の値がないにもかかわらず、リストの内容を取得しようとして いるためにエラーが出ることがとても理解できました。 後ろから判定をすると全ての値を効率よく(インデックス値をずらすことなく)、 判定できるんですね。 また、前からの処理での削除方法ありがとうございます。 本当に勉強になりました。 iの値を引いてあげる点と、現時点でのインデックス値(iの値)を判定して あげる処理がポイントだと分かりました。 本当に、分かりやすい説明ありがとうございました。m(__)m

その他の回答 (4)

  • BlueRay
  • ベストアンサー率45% (204/453)
回答No.4

BlueRayです。少しばかり追加解説です。 ダルマA 順|○| 1|A| 2|B| 3|C| 4|D| 5|E| リストの順番は、下から1,2,3,4,5です。 そして、ダルマが一番最後を表しています。

  • BlueRay
  • ベストアンサー率45% (204/453)
回答No.3

ダルマ落しで表現しますね。○をダルマでと思ってください(^^; ダルマA  ダルマB 順|○|  順|○| 1|A|  5|A| 2|B|  4|B| 3|C|  3|C| 4|D|  2|D| 5|E|  1|E| 解答コードがダルマAで、mineral01さんのコードがダルマBです。 順と書いてある通りに崩していきます。 では、参考までに1番目を崩してみましょう。 ダルマA  ダルマB 順     順 1|○|  5|○| 2|B|  4|A| 3|C|  3|B| 4|D|  2|C| 5|E|  1|D| 次に2番目を崩してみましょう。 ダルマA  ダルマB 順     順 1     5 2|○|  4|○| 3|C|  3|A| 4|D|  2|B| 5|E|  1|D| 以下5番目まで崩して、ダルマを一番下に落とすことが出来るのはどちらですか。 明らかにダルマAですね。ダルマBは4回目で何も出来ないですね。 連続項目削除は、この様に最後までダルマを落とせる様にしなくてはいけないんです。 わかりにくかったら、補足してください。ではでは。

mineral01
質問者

お礼

説明ありがとうございます。 皆様の説明で、理解するとことができました。 かなり悩んでいたので、本当に助かりました。 ありがとうございます。

  • maruru01
  • ベストアンサー率51% (1179/2272)
回答No.2

こんにちは。maruru01です。 リストを1つ削除すると、その度にそれより後ろ(Indexが大きいもの)のIndexが変更(1つずつ繰り上がる)されてしまうからです。 前(Indexの小さい方)から削除すると、後ろの削除対象のリストのIndexが変更(1つ繰り上がる)されるので、選択したものと別のものを削除したり、エラーになったりします。 後ろ(Indexの大きい方)から削除すれば、その後ろのIndexが変更されても構わないわけです。(削除対象が前(Indexが小さい方)にしかないので。) では。

mineral01
質問者

お礼

後ろから削除することによって、削除対象が小さい方にしかないので、 全て効率よく(index値をずれなくして)削除できるんですね。 また、後ろからだと比較したインデックスが変更されても大丈夫と言うことが 分かりました。 説明、本当にありがとうございました。m(__)m

  • imogasi
  • ベストアンサー率27% (4737/17068)
回答No.1

下記の「繰り上がりがあるときの」ロジックを考えてみられては。 下記(2)の下からの繰り上がりを考えに入れてないのでは。(下記でdeleteとかA(i)としているのは仮想の表現で、リストの場合RemoveItemです。セルの削除等の場合も念頭に入れているため) 5つアイテムがあったとして、 (1)後ろ(下と言いますか)から、3つ削除するときは、 上から5番目削除、次に上から4番目削除、次に上から3番目削除・・となります。iは5,4,3・・・です。 for i=5 to 3 step -1 a(i).delete next i (2)先(上と言いますか)から、3つ削除する時は、 まず上から1番目削除、「下から繰り上がってくるので」、2番が1番に繰り上がってくるので、次も1番を削除すればよい。次も同じ。 for i=1 to 3 a(1).delete next i

mineral01
質問者

お礼

説明ありがとうございました。 プログラミングの奥の深さを新ためて実感しました。 まだまだ、勉強不足です。 本当にありがとうございました。m(__)m

関連するQ&A

  • リストボックスから削除、「いいえ」でも削除される

    Windows7 Excel2007でマクロ作成中の初心者です。 リストボックスから、シート(顧客名)を選んで削除するマクロです。 削除がうまくいくのですが、「いいえボタン」を押しても シートが削除されてしまいます。どう修正したらよろしいでしょうか。 Private Sub 顧客削除_Click() Dim i As Integer Dim btn Dim name As String With 顧客リスト For i = 0 To .ListCount - 1 If .Selected(i) Then name = .list(i) '選択されたリストを変数に格納 btn = MsgBox("本当に、 " & name & " さんを削除していいですか?", _ vbYesNo, "削除の確認") End If Next i Application.DisplayAlerts = False Worksheets(Mid(.list(.ListIndex - 0), InStr(.list(.ListIndex - 0), " ") + 1)).Delete Application.DisplayAlerts = True '顧客リスト.RemoveItem (顧客リスト.ListIndex) '顧客リスト.ListIndex = -1 リストボックスの項目削除 Worksheets(1).Activate End With If btn = vbYesNo Then Exit Sub End If ActiveWorkbook.Save End Sub ----------------------------------------------- Sub リストボックスの項目削除() Dim i As Integer For i = 顧客リスト.ListCount - 1 To 0 Step -1 If 顧客リスト.Selected(i) Then 顧客リスト.RemoveItem (i) Exit For End If Next i End Sub

  • リストボックスからシート削除のマクロを合体したい

    Windows7 Excel2007でマクロ作成中の初心者です。 やりたいことは、リストボックスからシートを選択し、そのシートを削除する。 削除したら、リストボックスの中の、シート選択状態を解除し、その項目だけを 削除することです。 以下のコードで出来たのですが、これを統合して一個のコードにしたいです。 どうしたらよろしいでしょうか。 Private Sub 顧客削除_Click() Dim i As Integer Dim btn Dim name As String With 顧客リスト For i = 0 To .ListCount - 1 If .Selected(i) Then name = .list(i) '選択されたリストを変数に格納 btn = MsgBox("本当に、 " & name & " さんを削除していいですか?", _ vbYesNo, "削除の確認") If btn = vbYes Then Application.DisplayAlerts = False Worksheets(Mid(.list(.ListIndex - 0), InStr(.list(.ListIndex - 0), " ") + 1)).Delete Application.DisplayAlerts = True リストボックスの項目削除 End If End If Next i Worksheets(1).Activate End With ActiveWorkbook.Save Application.ScreenUpdating = True End Sub ----------------------------- Sub リストボックスの項目削除() Dim i As Integer For i = 顧客リスト.ListCount - 1 To 0 Step -1 If 顧客リスト.Selected(i) Then 顧客リスト.RemoveItem (i) Exit For End If Next i End Sub

  • リストボックスから選択したシートを削除したい

    Excel2007でマクロ作成の初心者です。 リストボックスの選択項目のワークシートを削除したいのですが、 「インデックスが有効範囲にありません。」のエラーが発生し、 先に進めません。どうしたらよろしいでしょうか? ’--------------------- Private Sub 顧客削除_Click() Application.ScreenUpdating = False Unload Me Unload DS請求フォーム Dim i As Integer With 顧客リスト For i = 0 To .ListCount - 1 If .Selected(i) Then ' Worksheets(.list(.ListIndex)).Delete Worksheets(Split(.list(.ListIndex - 0), " ")(1)).Activate '←ここでエラー発生 ActiveSheet.Delete End If Next i End With MsgBox "選択の顧客を削除しました。" End Sub ’------------------------- Private Sub UserForm_Initialize() Workbooks("請求.xls").Activate Dim i As Integer Const EXCEPT_NAME = "経理●一覧●基本●" For i = 1 To Worksheets.Count If InStr(EXCEPT_NAME, Worksheets(i).Name & "●") = 0 Then 顧客リスト.AddItem i & " " & Worksheets(i).Name End If Next i End Sub ’----------------------

  • リスト間のアイテム移動について - VBAで

    http://okwave.jp/qa/q4903870.html を読んで、No.2の回答にあるようなコードをExcel2000のVBAで組みたいと思いました。VBではitemdataというプロパティがありましたがVBAではなかったようで、かわりにListプロパティなどを使ってみましたが、うまくいきません。アドバイスをお願いできますでしょうか? VBでの元のコードは以下のとおりです。 Private Sub Form_Load() With List1   .AddItem "FreeBSD"   .AddItem "Linux"   .AddItem "Macintosh"   .AddItem "MS-DOS"   .AddItem "Slaris"   .AddItem "Windows 95"   .AddItem "Windows CE"   .AddItem "Windows NT"   for n = 0 to .ListCount-1     .ItemData(n) = n   next End With としておきます リストの移動時に Private Sub Command1_Click()   dim m as Integer   m = 0   For i = List1.ListCount - 1 to 0 step - 1     If List1.Selected(i) = True Then       if list2.ListCount > 0 then         for m = 0 to List2.ListCount-1           ' ここで ItemData比較する           if list2.itemData(m) > list1.ItemData(i) then             exit for           end if         next       end if       ' 挿入位置が mに求められている       list2.additem List1.List(i), m       list2.ItemData(m) = List1.ItemData(i)       List1.RemoveItem i     End If   next End Sub

  • リストボックスに表示後、選択したシートを削除する

    初歩的な質問で恐縮ですが、ご教示ください。 リストボックスにすべてのシート名を表示させ、選択したシートのみ削除するマクロを作成したいのですが、エラーメッセージ「オブジェクトが必要」と表示されエラーとなります。どのように変更したらよいのでしょうか?  Private Sub CommandButton1_Click() 'Selectedプロパティを使って、選択されているかどうかを判断して、選択されていたらメッセージボックスにその内容を表示します。 'このメッセージボックスを表示される全シートのうち、選択したシートのみ、削除処理する。 Dim i As Integer With ListBox1 For i = 0 To .ListCount - 1 If .Selected(i) Then MsgBox .List(i) End If Next i End With ' 選択シート削除 '「はい」「いいえ」のアイコンを表示する Btn = MsgBox("選択されたシートが全て消去されます。元にもどりません いいですか?", vbYesNo + vbQuestion, "確認") '「いいえ」の場合は終了します。 If Btn = vbNo Then Exit Sub End If 'リストのうち、選択したシートだけ削除する 'オブジェクトが必要? Workbook.Sheet.[(List(i))].Delete End Sub

  • リスト間のアイテム移動について

    現在独学でhttp://www4.plala.or.jp/tamo/vb/vb99.htmlの問題の10番を解いてるのですが、どうしてもうまくいきません。 左のリストボックスから右のリストボックスへの1つ1つのアイテム移動はできたのですが、アイテムを複数同時に選択すると違うアイテムが移動したりすべてのアイテムが移動してしまいます。 今のコードは Private Sub Command1_Click() For i = List1.ListCount To 1 Step -1 If List1.Selected(i - 1) = True Then List2.AddItem List1.Text List1.RemoveItem List1.ListIndex End If Next End Sub Private Sub Form_Load() With List1 .AddItem "FreeBSD" .AddItem "Linux" .AddItem "Macintosh" .AddItem "MS-DOS" .AddItem "Slaris" .AddItem "Windows 95" .AddItem "Windows CE" .AddItem "Windows NT" End With End Sub このように指定しています。 解決法がありましたら教えてください。

  • リストボックスからシート選んで削除したい

    Excel2007でマクロ作成中の初心者です。 以下のマクロを実行すると、最終行でコンパイルエラーがでて 「参照が不正または不完全です」と表示され削除ができません。 どうしたら、削除できるでしょうか。 Private Sub 顧客削除_Click() Dim i As Integer Dim btn Dim name As String With 顧客リスト For i = 0 To .ListCount - 1 If .Selected(i) Then name = .list(i) '選択されたリストを変数に格納 btn = MsgBox("本当に、" & name & "さんを削除していいですか?", _ vbYesNo + vbQuestion, "削除の確認をする") End If Next i End With If btn = vbNo Then Exit Sub End If 'Worksheets(Mid(.list(.ListIndex - 0), InStr(.list(.ListIndex - 0), " ") + 1)).Delete 'ActiveWorkbook.Sheet.[(List(i))].Delete 'ActiveWorkbook.Sheets(name).Delete Worksheets(Split(.list(.ListIndex - 0), " ")(1)).Delete ' End Sub

  • VB6.0 リストボックス

    VB6.0で3つのリストボックスに関連性を持たせたいと思っています。 Private Sub lstBox_Click() Dim intLstIndex As Integer intLstIndex = lstA.ListIndex If (lstA.Selected(intLstIndex)) Then lstB.Selected(intLstIndex) = True lstC.Selected(intLstIndex) = True Else lstB.Selected(intLstIndex) = False lstC.Selected(intLstIndex) = False End If End Sub 以上のように、どれか一つのリストボックスがクリックされたら他のリストボックスの同じ行がtrueになるようにしています。 しかしこれでは件数が増えた場合、選択された行が揃わなくなる場合があり非常に見栄えが悪くなります。 リストボックスでなくともかまわないのですが、このように三つの項目に関連性をもたせることはできませんでしょうか。

  • リストボックスから項目を選択してセルに入力したいのです

    EXcel2003でマクロ作成中です。エクセルシートのN列を右クリックすると、ユーザーォームが現れ、その中のリストボックスから項目を選択すると選択文字が白色に反転します。 ユーザーホームの下方に設置した「入力する」ボタンをクリックする、アクティブセルにテキスト文字列が挿入されます。 Option Explicit Private Sub CommandButton1_Click() With ListBox1 If .ListIndex = -1 Then MsgBox "項目を選択してくだい" Else ActiveCell.Value = ListBox1.list(ListBox1.ListIndex) End If End With Unload UserForm1 End Sub --------------------------- Private Sub CommandButton2_Click() Unload UserForm1 End Sub ------------------------------ これと同じものをB列につくりました。エクセルシートのB列を右クリックすると、リストボックスが表示されますが、その中の項目を選択しようとすると、一瞬にしてユーザーフォーム自体が消えてしまい項目を 選択できません。 Private Sub CommandButton1_Click() With ListBox2 If .ListIndex = -1 Then MsgBox "項目を選択してくだい" Else ActiveCell.Value = ListBox2.list(ListBox2.ListIndex) End If End With Unload UserForm2 End Sub ----------------------------- Private Sub CommandButton2_Click() Unload UserForm2 End Sub ------------------------------------------ まったく同じものを作って内容だけかえたのですが、できません。 どうしてでしょうか?ご教授おねがいします。

  • リストボックスからの入力をテキストに貼付

    下記コードではリストボックあ行選択しテキスト1~6に入力後、クリアボタンで消去したあと、か行選択しテキストに入力したら7~貼付けになるクリアボタンで消去後、改めてテキスト1~入力するコードがありますか。どなたか解る方よろしくお願いします。 Private Sub 実行_Click() Static cnt As Integer Dim i As Integer If Listbox.ListIndex = -1 Then Exit Sub For i = 0 To Listbox.ListCount - 1 If Listbox.Selected(i) Then cnt = cnt + 1 If cnt > 10 Then cnt = 1 Me.Controls("TextBox" & cnt).Text = Listbox.List(i) End If Next End Sub Private Sub クリア_Click() Dim tbCont As Control With Me.MultiPage1 For Each tbCont In .Pages(.Value).Controls If TypeName(tbCont) = "TextBox" Then tbCont.Value = Null End If Next tbCont End With End Sub