FC2ブログ

スポンサーサイト 


上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

--/--/--

Category: スポンサー広告

TB: --  /  CM: --

top △

ListIndex の怪? 


リストボックス / コンボボックス に ListIndex があります。
値集合タイプを「テーブル/クエリ」にしていたとします。
また、リストボックスは、複数選択:しない とします。

この時、未選択時は ListIndex = -1 になっているようで、1つ選ぶと何番目が入るようです。
以下のテーブルを表示していた場合(表示順も同じとして)
F1F2F3F4
A1B1C1D1
A2B2C2D2
A3B3C3D3
A4B4C4D4

F1 = 'A1' の行部分をクリック選択すると、ListIndex = 0 となり、
F1 = 'A4' の行部分をクリック選択すると、ListIndex = 3 となるようです。
この時の値は、列見出しの有無に関係なく同じになるようです。

過去記事にもあったかと思いますが、列見出しの有無で気をつけなければいけない事が・・・
列見出し:あり では、
・ListCount は 5
・Column(0,0) は "F1" / Column(0,1) は "A1"
・ItemData(0) は "F1" / ItemData(1) は "A1"

列見出し:なし では、
・ListCount は 4
・Column(0,0) は "A1" / Column(0,1) は "A2"
・ItemData(0) は "A1" / ItemData(1) は "A2"

なので、単純に Column(0,ListIndex) っていう使い方はできませんね。
まぁ、Column(0,ListIndex - ColumnHeads) ってなことになるのでしょうか・・・
ColumnHeads は、列見出しのありなしを Boolean で持っているので、
列見出しあり(True = -1)を引いてあげれば、1 加算される事になりますよね・・・

※ 値集合タイプが「値リスト」だったらどうなるんだろ・・・ ???


本題になりますが・・・ (標題が適しているかは・・・???)

hatena さんに教えていただきました。
2003 以降のリストボックス / コンボボックス のプロパティに Recordset が存在する事を・・・
今まで知りませんでした・・・(勉強不足・・・ 否めないよね by ベロニカ)
フォームのように RecordsetClone は、ないみたい・・・ Clone 的な使い方が出来る・・・で OK ?????
2007 のヘルプ見ても・・・ フォームの Recordset についてしか書いてないし・・・・
いまひとつ不安が残るかな・・・・

列見出しの有無に関係なく、同じ値を持つ ListIndex ・・・・
ということは、Recordset 内の AbsolutePosition = ListIndex という考え方で良さそうですかね ???
この場合は、列見出しのありなしで細工する必要はなさそう・・・

では、これを踏まえて・・・見かけた質問をやってみる

F1F2F3F4
A1B1C1D1
A2B2C2D2
A3B3C3D3
A4B4C4D4
と、F1 = 'A2' を選んでおいてから、

「下ボタン」の処理で
F1F2F3F4
A1B1C1D1
A3B3C3D3
A2B2C2D2
A4B4C4D4
と表示を変え、

「上ボタン」の処理で
F1F2F3F4
A2B2C2D2
A1B1C1D1
A3B3C3D3
A4B4C4D4
と表示を変更する・・・

表示順を変更するので、大元のテーブルにフィールド「順」を追加します。
F1F2F3F4
1A1B1C1D1
2A2B2C2D2
3A3B3C3D3
4A4B4C4D4

確認用のフォーム「F1」は、

kEnt180

で、私が回答したもの(変更あり)を、上側のリストボックスで、
教えていただいた Recordset を使うものを、下側のリストボックスでやってみる。
また、リストボックスを「コントロールの種類の変更」でコンボボックスに変えただけの「F2」「F3」

kEnt180_1  kEnt180_2

での動作を確認してみる。
Recordset を使ったフォーム下側のものは、2000 では動きません・・・
 
まず、テーブル「T1」を作成します。
anF1F2F3F4
11A1B1C1D1
22A2B2C2D2
33A3B3C3D3
44A4B4C4D4

an:オートナンバ ・・・ これは愛嬌で
順:長整数 ・・・ 1 ~ の連番で(以降のVBA記述では、重複しない番号であれば・・・としていますが)
F1:重複しないテキスト ・・・ リストボックスの値にしたいので
F2 ~ F4:適当なテキスト

フォームをデザインから作っていきます。
リストボックス「lst1」を作成
・値集合タイプ ・・・ 「テーブル/クエリ」
・値集合ソース ・・・ SELECT F1, F2, F3, F4, 順 FROM T1 ORDER BY 順;
・列数 ・・・ 5
・列幅 ・・・ 1.5cm;1.5cm;1.5cm;1.5cm;0cm ・・・ 「順」は表示しない様に
・連結列 ・・・ 1 ・・・ F1の値になるように
・列見出し ・・・ はい
上ボタン用コマンドボタン「btn1」
下ボタン用コマンドボタン「btn2」
その時の「lst1」の ListIndex 表示用ラベル「lab1」
 ・・・ この表示は、ラベル上でマウスカーソルが動いたら・・・ のタイミングで

ここまでを上段に配置して、全てを選択して下段にコピーし、
リストボックス「lst2」で、列見出し:なし に変更
上ボタン用コマンドボタン「btn3」
下ボタン用コマンドボタン「btn4」
その時の「lst2」の ListIndex 表示用ラベル「lab2」

配置して、表示してみると

kEnt180

となります。
で、各ボタンをクリックした際の処理を記述していきます。
以下(上段用)は、回答したものに修正を入れて、「順」が連番でなくても動くように・・・
Private Sub fncBtnCom(iSel As Long, iNum As Long)
  Dim rs As DAO.Recordset
  Dim rsC As DAO.Recordset
  Dim bExit As Boolean
  Dim sSql As String

  sSql = "SELECT * FROM T1 ORDER BY 順;"
  Set rs = CurrentDb.OpenRecordset(sSql)
  bExit = False
  Select Case iSel
    Case 0
      If (iNum = rs("順")) Then bExit = True
    Case 1
      rs.MoveLast
      If (iNum = rs("順")) Then bExit = True
  End Select
  If (Not bExit) Then
    Set rsC = rs.Clone
    rs.FindFirst "順=" & iNum
    rsC.Bookmark = rs.Bookmark
    Select Case iSel
      Case 0: rsC.MovePrevious
      Case 1: rsC.MoveNext
    End Select
    rs.Edit
    rs("順") = rsC("順")
    rs.Update
    rsC.Edit
    rsC("順") = iNum
    rsC.Update
    rsC.Close
    Set rsC = Nothing
  End If
  rs.Close
  Set rs = Nothing
End Sub

Private Sub btn1_Click()
  If (IsNull(Me.lst1)) Then Exit Sub
  Call fncBtnCom(0, Me.lst1.Column(4))
  Me.lst1.Requery
  Me.lst2.Requery
End Sub

Private Sub btn2_Click()
  If (IsNull(Me.lst1)) Then Exit Sub
  Call fncBtnCom(1, Me.lst1.Column(4))
  Me.lst1.Requery
  Me.lst2.Requery
End Sub

 
※ 回答時のものは、フォーム内記述にコメントで残しています。

まぁ、これはこれで動きますね・・・
リストボックスがクリックされた状態か・・・ この判別には結構迷いますね
今回は操作だけのものなので、IsNull(Me.lst1) で判別してましたが、
VBA で何か値を設定した後で選択されているか・・・ 
これ、非表示にしておいてリストにあるか・・・ あったら付属するもの何個か入手したい
ってな時に良くやります。
1つだけ入手したい時には DLookup(・・・) 使えば、ある・ないとか判別できますが・・・
例えば、この「社員ID」があったら、「部署」・「TEL」・「・・・」を得たい場合、
そう変動がないものは、フォームが起動された時に、非表示のリスト / コンボで抽出しておいて、
それに「社員ID」を代入してみて・・・ 一致するものがあったら Column(1) なり Column(2) で・・・
この時、一致するものがなかった場合、単に IsNull(リスト) ではできなかったような ???
IsNull(リスト.Column(0)) としていたような気がします。
まぁ、ListIndex < 0 の方が良いんでしょうか・・・ ???


リストボックスの Recordset を使う方法で以下記述してみた
Private Sub btn3_Click()
  Dim i As Long, j As Long

  If (IsNull(Me.lst2)) Then Exit Sub
  With Me.lst2.Recordset
    .AbsolutePosition = Me.lst2.ListIndex
    i = .Fields("順")
    .MovePrevious
    If (.BOF) Then Exit Sub
    j = .Fields("順")
    .Edit
    .Fields("順") = i
    .Update
    .MoveNext
    .Edit
    .Fields("順") = j
    .Update
  End With
  Me.lst1.Requery
  Me.lst2.Requery
End Sub

Private Sub btn4_Click()
  Dim i As Long, j As Long

  If (IsNull(Me.lst2)) Then Exit Sub
  With Me.lst2.Recordset
    .AbsolutePosition = Me.lst2.ListIndex
    i = .Fields("順")
    .MoveNext
    If (.EOF) Then Exit Sub
    j = .Fields("順")
    .Edit
    .Fields("順") = i
    .Update
    .MovePrevious
    .Edit
    .Fields("順") = j
    .Update
  End With
  Me.lst1.Requery
  Me.lst2.Requery
End Sub

 
リストボックスをクリックすると、ListIndex が変わり・・・
Recordset の AbsolutePosition と ListIndex が連動しているような感じにも見えるけど・・・
でも
    .AbsolutePosition = Me.lst2.ListIndex
しないとエラーが出てくるし・・・ Clone 的な使い方なのかなぁ
また、逆操作(Recordset で MoveNext / MovePrevious)すると ListIndex はどうなる ???
変わらないみたいだけど・・・
チョッと不安なので、移動して値を更新してから、元に戻って値を更新・・・ としてみた。
(と言ってるけど、移動した後で Exit しているので・・・ なんだかなぁ)

各リストボックスの ListIndex を表示するラベル用に記述したのは以下
Private Sub lab1_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)
  Me.lab1.Caption = Me.lst1.ListIndex
End Sub

Private Sub lab2_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)
  Me.lab2.Caption = Me.lst2.ListIndex
End Sub

 
ソコソコ動きますね・・・
ということで、このフォーム「F1」を「F2」「F3」名でコピーします。
フォーム「F2」では、上側リストボックスを「コントロールの種類の変更」でコンボボックスに変更
フォーム「F3」では、下側リストボックスを「コントロールの種類の変更」でコンボボックスに変更
VBA の記述はそのままです。

kEnt180_1  kEnt180_2

フォーム「F3」を 2003 で動かして(2003 の mdb を 2007 で動かしても)下側を操作すると
・実行時エラー '3001': 引数が無効です
が、
    .AbsolutePosition = Me.lst2.ListIndex
部分で発生する時があります。
でも、デバッグでそのまま「横▲マーク」クリック実行で、継続できます。
その後、操作を続けてもエラーが起きる事はありません。
この動きは何なんだろう・・・ 私の環境だけなのかなぁ・・・ ???
コンボボックスはチョッと違うのかなぁ・・・ ???

※ 2000 では、各フォームの表示はできますが、下側の動作確認はできません。
 (メソッドがないとかのエラーになります)


VBA の記述とかは、あれですね・・・
1度記述してから、眺めていると・・・ あっ、こういう記述が・方法が良かったかな・・・
と思う事、多いです。

こっちの方が良かったのかなぁ・・・ っていうのが以下(サンプル内にはありません)
Private Sub fncBtnCom(iMove As Long, iNum As Long)
  Dim rs As DAO.Recordset
  Dim rsC As DAO.Recordset
  Dim sSql As String

  sSql = "SELECT * FROM T1 ORDER BY 順;"
  Set rs = CurrentDb.OpenRecordset(sSql)
  Set rsC = rs.Clone
  rs.FindFirst "順=" & iNum
  rsC.Bookmark = rs.Bookmark
  rsC.Move iMove
  If ((Not rsC.BOF) And (Not rsC.EOF)) Then
    rs.Edit
    rs("順") = rsC("順")
    rs.Update
    rsC.Edit
    rsC("順") = iNum
    rsC.Update
  End If
  rsC.Close
  Set rsC = Nothing
  rs.Close
  Set rs = Nothing
End Sub

Private Sub btn1_Click()
  If (Me.lst1.ListIndex < 0) Then Exit Sub
  Call fncBtnCom(-1, Me.lst1.Column(4))
  Me.lst1.Requery
  Me.lst2.Requery
End Sub

Private Sub btn2_Click()
  If (Me.lst1.ListIndex < 0) Then Exit Sub
  Call fncBtnCom(1, Me.lst1.Column(4))
  Me.lst1.Requery
  Me.lst2.Requery
End Sub

 

サンプルは以下
 バージョン 20002003 (2002)2007
 ファイル kEnt180_2000.zipkEnt180_2003.zipkEnt180_2007.zip
 サイズ 18,86425,11227,325
※ ファイルは zip 形式
※ 2007 以外は、2007 保存時に変換 & 各バージョンで動作確認 & 最適化

※ 2000 では、各フォーム下側の動作確認はできません
関連記事

2013/09/28

Category: やってみる

TB: --  /  CM: 0

top △

この記事に対するコメント

top △

コメントの投稿

Secret

top △


上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。