Excel VBA質問箱 IV

当質問箱は、有志のボランティア精神のおかげで成り立っています。
問題が解決したら、必ずお礼をしましょうね。
本サイトの基本方針をまとめました。こちら をご一読ください。

投稿種別の選択が必要です。ご注意ください。
迷惑投稿防止のため、URLの入力を制限しています。ご了承ください。


2944 / 13644 ツリー ←次へ | 前へ→

【65124】リストボックスでの履歴表示について のだめ 10/4/17(土) 23:21 質問[未読]
【65126】Re:リストボックスでの履歴表示について kanabun 10/4/18(日) 9:54 発言[未読]
【65134】Re:リストボックスでの履歴表示について kanabun 10/4/18(日) 15:03 発言[未読]
【65142】Re:リストボックスでの履歴表示について のだめ 10/4/18(日) 23:08 発言[未読]
【65143】Re:リストボックスでの履歴表示について kanabun 10/4/19(月) 1:56 発言[未読]
【65150】Re:リストボックスでの履歴表示について のだめ 10/4/19(月) 21:24 お礼[未読]

【65124】リストボックスでの履歴表示について
質問  のだめ  - 10/4/17(土) 23:21 -

引用なし
パスワード
   はじめまして。
最近VBAをはじめたのですがあるところで詰まりました。
どなたかご教授ください。。

リストボックスが二つあります。rirekiとSBとします。
rirekiにはSBで選択されたものが重複を許さず追加されていき、
重複が起きた場合は一旦削除して一番上に再び追加します。
また、rireki自身も選択可能で選択すると必然と重複が起きますので
一旦消して一番上に再び追加してます。
この両方の操作でsheet1のあるセルに選択したvalueを入れています。

rowsourceとしてsheet2のある列をそれぞれ使っています。
以下はコードなのですが詰まっているところは
rireki自身を選択したときにセルにうまく選択したものが入らず
ずれが生じ、また、2重に内容もrirekiに登録されてしまします。

よろしくお願いします。

以下useform1に記述
Private Sub rireki_Click()
  Dim i As Long, flag As Boolean
  If 行 >= 5 Then
    Cells(行, 10) = rireki.Value
  End If
  i = 10
  For i = 1 To 10
  If rireki.Value = Worksheets("sheet2").Cells(i + 2, 12).Value Then
    flag = True
    Exit For
  End If
  Next i
  Do While i > 1
    Worksheets("sheet2").Cells(i + 2, 12).Value = Worksheets("sheet2").Cells(i + 1, 12).Value
    i = i - 1
  Loop
  Worksheets("sheet2").Cells(3, 12).Value = rireki.Value
  UserForm1.Hide
End Sub

Private Sub SB_Click()
  Dim i As Long, flag As Boolean
  If 行 >= 5 Then
    Cells(行, 10) = SB.Value
  End If
  i = 10
  For i = 1 To 10
  If SB.Value = Worksheets("sheet2").Cells(i + 2, 12).Value Then
    flag = True
    Exit For
  End If
  Next i
  If flag Then
    Do While i > 1
      Worksheets("sheet2").Cells(i + 2, 12).Value = Worksheets("sheet2").Cells(i + 1, 12).Value
      i = i - 1
    Loop
    Worksheets("sheet2").Cells(3, 12).Value = SB.Value
  End If
  If Not flag Then
    i = 10
    Do While i > 1
      Worksheets("sheet2").Cells(i + 2, 12).Value = Worksheets("sheet2").Cells(i + 1, 12).Value
      i = i - 1
    Loop
    Worksheets("sheet2").Cells(3, 12).Value = SB.Value
  End If
  UserForm1.Hide
End Sub

Private Sub userform_deactive()
  Unload Me
End Sub

以下worksheetに記述
Private Sub Worksheet_BeforeDoubleClick(ByVal Target As Range, Cancel As Boolean)
  If Target.Column = 10 And Target.Row >= 5 Then
    Cancel = True
    行 = Target.Row
    列 = Target.Column
    UserForm1.rireki.RowSource = ""
    UserForm1.rireki.RowSource = "sheet2!l3:l12"
    
    UserForm1.SB.RowSource = ""
    UserForm1.SB.RowSource = "sheet2!j3:j50"
    UserForm1.SG.RowSource = ""
    UserForm1.SG.RowSource = "sheet2!k3:k50"
    
    UserForm1.Show
  End If
End Sub

以下module1
Option Explicit
Public 行 As Variant
Public 列 As Variant
Sub auto_open()
  Load UserForm1
End Sub

【65126】Re:リストボックスでの履歴表示について
発言  kanabun  - 10/4/18(日) 9:54 -

引用なし
パスワード
   ▼のだめ さん:
こんにちは。

コードをトレースしようとしても、
変数に Explicit でないものがあるようです。

>リストボックスが二つあります。rirekiとSBとします。

そうすると、以下の SG とは何ですか?
>    UserForm1.SG.RowSource = ""
>    UserForm1.SG.RowSource = "sheet2!k3:k50"

また、
>  If 行 >= 5 Then
>    Cells(行, 10) = rireki.Value
>  End If
この Cellsの親シートの指定がありません。(2カ所)
どのシートのCells(すべてのセルの集合)のことですか?


> 以下worksheetに記述

どのワークシートですか? Sheet1?


【65134】Re:リストボックスでの履歴表示について
発言  kanabun  - 10/4/18(日) 15:03 -

引用なし
パスワード
   午前中にいちど投稿しましたが、
リストボックスrirekiの更新に不具合があったので、一度削除して
再掲します。

リストボックス rireki の項目数は リストボックスSBで新しい
アイテムが追加されるたびに、元データ範囲の行数は増えていく
ということですね

深く検証してませんが、こんなのでいちど試してみてください。
リスト(のRowSource)にあるか検索は WorksheetFunction.Matchを
Applicationオブジェクトのメソッドとして利用しています。


'----------------------- Sheet1 モジュールに記述
Private Sub Worksheet_BeforeDoubleClick( _
    ByVal Target As Range, Cancel As Boolean)
  If Target.Column <> 10 Then Exit Sub
  If Target.Row >= 5 Then
    Cancel = True
    行 = Target.Row
    列 = Target.Column
    UserForm1.Show '0
  End If
End Sub

'------------------------ Useform1に記述
Option Explicit

Private WS2 As Worksheet

Private Sub UserForm_Initialize()
  Dim r As Range
  Set WS2 = Worksheets("Sheet2")
  Set r = WS2.[J3]
  Set r = WS2.Range(r, r.End(xlDown))
  SB.RowSource = r.Address(External:=True)
  SB.ColumnHeads = True
   
End Sub

Private Sub UserForm_Activate()
  Dim r As Range
  Set r = WS2.[L3]
  Set r = WS2.Range(r, r.End(xlDown))
  rireki.RowSource = ""
  rireki.RowSource = r.Address(External:=True)
  rireki.ColumnHeads = True

End Sub

Private Sub SB_Click()
  'ダブルクリックされたセルに選択アイテムを代入する
  ActiveCell.Value = SB.Value
  
  Dim m As Variant
  Dim r As Range
  Set r = WS2.Range("L3")
  Set r = Excel.Range(r, r.End(xlDown)) 'L列リストにあるか
  m = Application.Match(SB.Value, r, 0)
  If IsNumeric(m) Then
    'すでにあれば、そのセルを一番上[L3] に移動
    If m > 1 Then
      r.Item(m).Cut
      r.Item(1).Insert shift:=xlDown
    End If
  Else
    'ないときは L列の一番上に挿入
    Application.CutCopyMode = False
    r.Item(1).Insert shift:=xlDown
    r.Item(0).Value = SB.Value
    'RowSourceを更新
    rireki.RowSource = _
      r.Item(0).Resize(r.Count + 1).Address(External:=True)
  End If
  
  Me.Hide
End Sub

Private Sub rireki_Click()
  Dim m As Long
  If rireki.ListIndex > -1 Then
    'ダブルクリックされたセルに選択アイテムを代入する
    ActiveCell.Value = rireki.Value
    m = rireki.ListIndex + 1
    
    If m > 1 Then
      Dim r As Range
      Set r = WS2.Range("L3")
      Set r = Excel.Range(r, r.End(xlDown)) 'L列リスト
      'そのセルを一番上[L3] に移動
      r.Item(m).Cut
      r.Item(1).Insert shift:=xlDown
    End If
    Me.Hide
  End If
End Sub

【65142】Re:リストボックスでの履歴表示について
発言  のだめ  - 10/4/18(日) 23:08 -

引用なし
パスワード
   すばやい解答と親切な解説ありがとうございます。
一つ目のSGは実はSBと似たリストボックスがあるのですが
簡単の為省きましたが、消し忘れてしまいました。

コード例の知らない関数など勉強になりました!

しかし何故?という部分が勉強も兼ねて知りたいので
rirekiの不具合というのを教えていただければ嬉しいです。

rireki_clickの
cells(行,12) = rireki.value
がおかしいのですが
(activecell.value = rireki.valueでもおかしい)
何故か一つ前の選択セル値が代入され
選択したものが二つ新たに重複して追加されます。

この原因を究明したいのでお力を貸していただければ幸いです。

rirekiは最大で10個登録し、11個目は削除するシステムです。

【65143】Re:リストボックスでの履歴表示について
発言  kanabun  - 10/4/19(月) 1:56 -

引用なし
パスワード
   ▼のだめ さん:
>しかし何故?という部分が勉強も兼ねて知りたいので
>rirekiの不具合というのを教えていただければ嬉しいです。
>
>rireki_clickの
>cells(行,12) = rireki.value
>がおかしいのですが
>(activecell.value = rireki.valueでもおかしい)
>何故か一つ前の選択セル値が代入され
>選択したものが二つ新たに重複して追加されます。
>
>この原因を究明したいのでお力を貸していただければ幸いです。


それは Step実行してみれば分かります。
新規Bookを作成し、その「Sheet2」の[L3]以降に
以下のようなSourceList があったとします。
L3  Jan
L4  Feb
L5  Mar
L6  Apr
L7  May
L8  Jun
L9  Jul
L10 Aug
L11 Sep
L12 Oct

UserFormから値を選んで代入するシートは このリストのあるSheet2 ではないので
このままではデバッグしにくいので、Sheet1の [L3]以降に Sheet2のL列を
参照する数式を埋め込みます。
L3: =Sheet2!L3
のように。

また、Sub rireki_Click() 内のコードを 以下のように簡単化します。
変更点
(1)Public変数 「行」を使わず、アクティブセルへの代入とする。(ダブル
  クリックされたセルが J列の5行目以降という判定は ダブルクリックさ
  れたシートのほうですでにやっているので )
(2)リストボックス rirekiの何行目がClickされたかは 一行づつシートの
  RowSourceを調べなくても、ListBox の何行目がClickされたか
  すなわち rireki.ListIndex から分かる。これを ClickRow とする。
(3)ClickRowから2行目まで セルをひとつづつ下方へシフトするのは
  For 〜 Next Loop のほうが速いし読みやすい。

これでも、同じ不具合が発生します。

Private Sub rireki_Click()
  Dim ClickRow As Long
  Debug.Print rireki.Value; rireki.ListIndex
  ActiveCell.Value = rireki.Value '<-- ●この行にブレークポイント
  
  ClickRow = rireki.ListIndex + 1 'リストの元データ範囲内の行Index
  Dim i As Long
  Dim r As Range
  Set r = WS2.Range("L3").Resize(10)
  For i = ClickRow To 2 Step -1
    'ひとつ上のセル値をCopy
    r.Item(i).Value = r.Item(i - 1).Value '▲セルの値を変更
  Next
  r.Item(1).Value = rireki.Value
  
  'Me.Hide
End Sub

最初の行↓
  Debug.Print rireki.Value; rireki.ListIndex
に、ブレークポイントを置いて、
シートSheet1 のJ列でダブルクリックして、rirekiリストの 「Apr」を
Clickしてみます。
rireki リストから 4つめの「Apr」を選ぶと、
ダブルクリックしたセルに「Apr」を代入して、
プログラムの実行は一時停止します。
これ以降は [F8]キーで 一行づつStep実行していきます。
そうすると
>    'ひとつ上のセル値をCopy
>    r.Item(i).Value = r.Item(i - 1).Value '▲セルの値を変更
のところで、L列が
RowSource範囲の
1行目  Jan
2:   Feb
3:   Mar
4:   Mar  <------ 上のデータがCopyされる
5:   May
6:   Jun
   ・・・
のように、4行目の値が変わった途端、プログラムの実行は

> Private Sub rireki_Click()
に戻っていることが分かります。
これは RowSourceのリンク先のシートのセルの値が変わったので、
また新たなClickイベントが発生したということです。

ブレークポイントでStopしたとき
2回目のときの rireki.Value は「Mar」になっています。
プログラムでそうしたからです。
>  r.Item(i).Value = r.Item(i - 1).Value '▲セルの値を変更

2回目の時のFor〜Next Loop による セル値のシフトは
2行目までうまく行きます。これはListIndexが3 で、その
ListIndexに対応するセルの値に今度は変更が無く
「Mar」のままだからです。
で、プロシージャ最後の
RowSource範囲の1行目にrireki.Valueを代入して
>  r.Item(1).Value = rireki.Value
一旦終了するかのように見えます。
1: Mar
2: Jan
3: Feb
4: Mar
5: May
・・・

ところが、不思議なことに、Hideした後にも
3度目のイベントが発生して、プログラムの実行は
プロシージャの振り出しに戻って実行が続きます。
これはどうしてかというと、(たぶん) 「Mar」という
リスト項目があるListIndex が 3から 0(先頭)へ
移動したためです。2回目の時は ListIndex=3 の内容が
変化したため Click Event が発生しましたが、こんどは
ListIndexが変化したため またもや Eventが発生したと
いうことです。

ActiveCellにまた「Mar」を書き込み(ただし、ListIndex=0
つまり リストの先頭行の値を、です)、For〜Nextの
Nextを実行し、、、、
結局、ほんとに終わるまで、イミディエイト・ウィンドウを
みると、
Apr 3
Mar 3
Mar 0
Mar 0
Mar 0
Mar 0
Mar 0
Mar 0
Mar 0
Mar 3
Mar 3
Jan 0
Jan 0
Jan 0

回ものイベント処理を実行していることが分かります。

のだめ さんもそちらのデータで 上に書いたDebugを
実際にやって 確かめてみてください。
RowSourceを使うと 元シート更新されるとき、思わぬ
副作用がある、ということが、お分かりになると思います。

【65150】Re:リストボックスでの履歴表示について
お礼  のだめ  - 10/4/19(月) 21:24 -

引用なし
パスワード
   > Private Sub rireki_Click()
に戻っていることが分かります。
これは RowSourceのリンク先のシートのセルの値が変わったので、
また新たなClickイベントが発生したということです。

ここが引っかかっていましたがすっきりしたような感じがします。
おかげさまで思い通りのシステムとなりました。

本当にありがとうございました!!

2944 / 13644 ツリー ←次へ | 前へ→
ページ:  ┃  記事番号:
2610219
(SS)C-BOARD v3.8 is Free