Access (VBA)

Access VBAに関するフォーラムです。
  • 解決済みのトピックにはコメントできません。
このトピックは解決済みです。
質問

 
(Windows 10 Pro : Access 2016)
リストボックスのスクロールの同期
投稿日時: 21/03/25 16:55:50
投稿者: アロハ

お世話になります。
 
フォームに二つのリストボックスを配置しています。
データソースは同じテーブルを参照しています。
片方のリストボックスの垂直スクロールを動かしたときに、もう片方のリストボックスも同期して動作させたいのですが、いい方法はありますでしょうか。
 
ご指導の程、よろしくお願い致します。

回答
投稿日時: 21/03/26 14:39:44
投稿者: sk

引用:
フォームに二つのリストボックスを配置しています。

引用:
片方のリストボックスの垂直スクロールを動かしたときに、
もう片方のリストボックスも同期して動作させたいのですが、
いい方法はありますでしょうか。

Access のリストボックスでそれを実現する方法は
恐らくないと思います。
 
・Access.ListBox オブジェクトには、リストのスクロールを検知するイベントや
 垂直スクロールバーの位置を取得/設定できるプロパティが存在しない。
 
・GetScrollInfo や SetScrollInfo のような API も利用できない。
 (コントロールのハンドルを返すプロパティがないので)
 
引用:
データソースは同じテーブルを参照しています。

そもそもどういった理由からそのような処理を実現なさりたいと
思われたのでしょうか。

投稿日時: 21/03/28 16:09:52
投稿者: アロハ

sk様
 
コメントありがとうございます。
 
>そもそもどういった理由からそのような処理を実現なさりたいと
>思われたのでしょうか。
 
まず参照しているテーブルは、フィールド数が少し多めです。(50)
通常ならフィールド数が多かろうがそのまんま表示して何も気にしなかったのですが
今回は1〜25番目までのフィールドも大事だけど、26番目からは横スクロール無で
最初から画面に見えるようにする為の配慮が必要になった為です。
 
理由はこんな感じです。
 
ここはあきらめた方がいいでしょうか。。

回答
投稿日時: 21/03/29 08:37:53
投稿者: Suzu

引用:
今回は1〜25番目までのフィールドも大事だけど、26番目からは横スクロール無で
最初から画面に見えるようにする為の配慮が必要になった為です。

 
データシートビュー にして、「フィールドの固定」という方法がありますが
代用できませんでしょうか?
 
体裁をフォームっぽくという事であれば、そのフォームを非連結フォームのサブフォームとして配置してはどうでしょうか。

投稿日時: 21/03/29 10:57:13
投稿者: アロハ

sk様
  
コメントありがとうございます。
 
>データシートビュー にして、「フィールドの固定」という方法がありますが
>代用できませんでしょうか?
 
sk様がご指摘いただいたように、いろいろ調べていくうちに「データシートビュー」に
たどり着きましたが、「フィールドの固定」とはエクセルみないな〇〇列目までは固定で
その後の列は横スクロールみたいな感じですか?
 
ご指導の程、よろしくお願いします。

回答
投稿日時: 21/03/29 11:52:54
投稿者: sk

引用:
まず参照しているテーブルは、フィールド数が少し多めです。(50
通常ならフィールド数が多かろうがそのまんま表示して何も気にしなかったのですが

いやそこは気にされた方がよいでしょう。
 
まず、そのフォームやリストボックスの利用目的を踏まえた上で、
リストボックスのリストに表示すべきフィールドを絞り込むことを
(場合によってはテーブルの正規化も)検討される方が先だと思います。
 
引用:
今回は1〜25番目までのフィールドも大事だけど、26番目からは横スクロール無で
最初から画面に見えるようにする為の配慮が必要になった為です。

26 〜 50 番目のフィールドがそれぞれどのようなものなのであるのか
(どんな意味を持った、どんなデータが格納されているのか)が不明ですが、
25 個ものフィールドを「横スクロールなし」のリストとして表示させる
というのは、視認性の観点においては逆効果なのではないでしょうか。
( Excel のワークシートでだって、25 個もの列の表示を
固定させるなんてことは滅多に行なわれないはず)
 
引用:
sk様がご指摘いただいたように、いろいろ調べていくうちに
「データシートビュー」にたどり着きましたが、

それは私ではなく Suzu さんの回答。
 
引用:
「フィールドの固定」とはエクセルみないな〇〇列目までは固定で
その後の列は横スクロールみたいな感じですか?

概ねそういうこと。
(リストボックスではなく、データシートフォームの機能の 1 つ)

投稿日時: 21/03/29 18:22:39
投稿者: アロハ

sk様
 
コメントありがとうございます。
 

引用:
いやそこは気にされた方がよいでしょう。
  
まず、そのフォームやリストボックスの利用目的を踏まえた上で、
リストボックスのリストに表示すべきフィールドを絞り込むことを
(場合によってはテーブルの正規化も)検討される方が先だと思います。

 
十分に絞りこんでこのザマなので困っている次第でございます。
 
引用:
26 〜 50 番目のフィールドがそれぞれどのようなものなのであるのか
(どんな意味を持った、どんなデータが格納されているのか)が不明ですが、

 
ある機械のパラメータとだけ説明させて下さい。
 
引用:
25 個ものフィールドを「横スクロールなし」のリストとして表示させる
というのは、視認性の観点においては逆効果なのではないでしょうか。
( Excel のワークシートでだって、25 個もの列の表示を
固定させるなんてことは滅多に行なわれないはず)

 
最初のフィールド(ID)は見る人全員にわかる必要があります。
しかし2〜25番目までは見る人(部門)によって必要性にムラがあります。
したがって、全体で考えたときに25個になってしまった次第です。
次に26番目からいくつかは、カテゴリが変わり、見る人(部門)に共通な内容で
ある為、見せる必要がありました。
 
引用:
それは私ではなく Suzu さんの回答。

 
記載を間違えてしまい、大変申し訳ありませんでした。
改めて、Suzu様コメントありがとうございました。
 
引用:
概ねそういうこと。
(リストボックスではなく、データシートフォームの機能の 1 つ)

 
結果的に2つのサブフォームを配置して、左側のサブフォームにデータシートビューで1〜25番目までを表示。
その際、1番目の列は固定。
右側のサブフォームには26番目からデータシートビューで表示するようにしました。
さらに、hatena様が公開しておられた垂直スクロールの連動も参考にさせていただき思うように
なったのですが、クリックしたときに、左右両方の同じレコードをアクティブにして、各フィールドの
値を取得したいのですが、データシートビューではどうするのかわかりません。
 
何卒ご指導の程、よろしくお願いします。

投稿日時: 21/03/30 10:37:46
投稿者: アロハ

お世話になります。
 

引用:
クリックしたときに、左右両方の同じレコードをアクティブにして、各フィールドの
値を取得したいのですが、データシートビューではどうするのかわかりません。

 
各フィールドの値は、非連結フォームのサブフォームの中の各コントロールのクリックイベントで
現在選択しているレコードの値を取得できました。
 
問題は左右のサブフォームの同じIDのレコードをどうやって選択させるかです。
 
どちらかのクリックされたレコードのIDを取得して、そのIDの行を選択させるコードがわかりません。
 
何卒、ご指導の程よろしくお願いします。

回答
投稿日時: 21/03/30 11:55:27
投稿者: hatena
投稿者のウェブサイトに移動

アロハ さんの引用:
最初のフィールド(ID)は見る人全員にわかる必要があります。
しかし2〜25番目までは見る人(部門)によって必要性にムラがあります。
したがって、全体で考えたときに25個になってしまった次第です。
次に26番目からいくつかは、カテゴリが変わり、見る人(部門)に共通な内容で
ある為、見せる必要がありました。

 
具体的にどのようなUIなのか、いまいち把握できてませんが、
リストボックスでするなら、VBAで列幅を変更して、表示する列を設定すればどうでしょうか。
 
リストボックスの上にコマンドボタンを2つ並べて、それぞれのキャプションを「◀」「▶」としておいて、そのクリック時イベントで列表示を変更することで、疑似的にスクロールしているように見せるということです。(もう少し凝るなら、ActiveXのスクロールバーコントロールを使うとよりリアルになるでしょう。)
 
 
 

回答
投稿日時: 21/03/30 13:23:45
投稿者: hatena
投稿者のウェブサイトに移動

上記の回答のサンプルを作成してみました。
 
とりあえず下記の仕様としました。
列数は18列
1列目と10列目以降を固定
2列目から9列目のうち2列分を表示して、スクロールする。
 
リストボックスを配置して下記のように設定します。
名前 ListBox1
値集合ソース テーブル名(クエリ名)
列数 18
 
その上にコマンドボタンを2つ並べて配置して名前を cmdLeft、cmdRight とする。
 
フォームのモジュールに下記のようにコードを記述。
 

'各列の幅
Const conRowWidth = "2cm;2cm;2cm;2cm;2cm;2cm;2cm;2cm;2cm;2cm;2cm;2cm;2cm;2cm;2cm;2cm;2cm;2cm"
Const LeftFixCol = 1 '1列目まで固定
Const RightFixCol = 10 '10列目以降固定
Const ScrlColCnt = 2 'スクロールする列数 2

Private curCol As Long 'スクロール列の表示されている列位置


Private Sub Form_Load()
    curCol = LeftFixCol
    setColumnWidths
End Sub
Private Sub cmdLeft_Click()
    If curCol <= 1 Then Exit Sub
    curCol = curCol - 1
    setColumnWidths
End Sub

Private Sub cmdRight_Click()
    If curCol >= 10 - 2 Then Exit Sub
    curCol = curCol + 1
    setColumnWidths
End Sub

Public Sub setColumnWidths()
    Dim RWs As Variant
    RWs = Split(conRowWidth, ";")
    
    Dim i As Long
    For i = LeftFixCol To curCol - 1
        RWs(i) = "0cm"
    Next
    For i = curCol + ScrlColCnt To RightFixCol - 1
        RWs(i) = "0cm"
    Next

    Me.ListBox1.ColumnWidths = Join(RWs, ";")
End Sub

回答
投稿日時: 21/03/30 14:02:42
投稿者: sk

引用:
結果的に2つのサブフォームを配置して、左側のサブフォームに
データシートビューで1〜25番目までを表示。
その際、1番目の列は固定。
右側のサブフォームには26番目からデータシートビューで
表示するようにしました。

引用:
クリックしたときに、左右両方の同じレコードをアクティブにして、
各フィールドの値を取得したい

「 2 つのサブフォームのレコードソースは同じテーブルであり、
その全てのレコードを同一の並べ替え順によって表示させている」
という前提である場合は、例えば次のような例が挙げられます。
 
(メインフォームのフォームモジュール)
----------------------------------------------------------------
Option Compare Database
Option Explicit
 
Private WithEvents frmSubform1 As Access.Form
Private WithEvents frmSubform2 As Access.Form
 
Private Sub Form_Load()
 
    Set frmSubform1 = Me![サブフォーム1].Form
    frmSubform1.OnCurrent = "[イベント プロシージャ]"
    Set frmSubform2 = Me![サブフォーム2].Form
    frmSubform2.OnCurrent = "[イベント プロシージャ]"
 
End Sub
 
Private Sub frmSubform1_Current()
 
    SyncRecord Me![サブフォーム1], Me![サブフォーム2]
 
End Sub
 
Private Sub frmSubform2_Current()
 
    SyncRecord Me![サブフォーム2], Me![サブフォーム1]
     
End Sub
 
Private Sub SyncRecord(SubForm1 As Access.SubForm, SubForm2 As Access.SubForm)
 
    If SubForm1.Form.CurrentRecord = SubForm2.Form.CurrentRecord Then
        Exit Sub
    End If
     
    If SubForm1.Form.NewRecord Then
        SubForm2.SetFocus
        DoCmd.GoToRecord , , acNewRec
        SubForm1.SetFocus
    Else
        SubForm2.Form.Recordset.AbsolutePosition = SubForm1.Form.Recordset.AbsolutePosition
    End If
 
End Sub
----------------------------------------------------------------
([サブフォーム1],[サブフォーム2]はサブフォームコントロールの名前)
 
それぞれのサブフォームに表示されているレコードの件数や
並べ替え順、各行の主キーの値が一致していないケースには
適してません。
 
引用:
ある機械のパラメータとだけ説明させて下さい。

引用:
最初のフィールド(ID)は見る人全員にわかる必要があります
しかし2〜25番目までは見る人(部門)によって必要性にムラがあります。
したがって、全体で考えたときに25個になってしまった次第です。
次に26番目からいくつかは、カテゴリが変わり、見る人(部門)に
共通な内容である為、見せる必要がありました。

そういう場合は 1 番目と 26 〜 50 番目のフィールドを
「全員に共通して見せたいフィールド」として
まとめてしまった方がよいのではないでしょうか。
(データシートビューにして列固定、なんて
面倒くさいことをする必要もない)
 
リストボックスなりデータシートなりに表示する
フィールドの並び順を、テーブルで定義されている通りの
順番に合わせる必要はないと思います。

投稿日時: 21/03/30 19:22:28
投稿者: アロハ

hatena様
 
コメントありがとうございます。
 

引用:
(もう少し凝るなら、ActiveXのスクロールバーコントロールを使うとよりリアルになるでしょう。)

ActiveXのスクロールバーコントロールを使用したことがないので、いろいろ調べてみましたが、あまり情報が出ていなく、左側、右側クリックイベントとかあるのでしょうか。
それができれば、本来のリストボックス1つ案で解決できそうなので。
ActiveXのスクロールバーコントロールもご指導いただけないでしょうか。
 
sk様
 
コメントありがとうございます。
 
sk様のおかげで、データシートビューで思うように出来ました。がっつり作り込んだ感満載です。
ただ、hatena様より本来やりたかったリストボックスでのやり方が浮上してきた以上、両方作ってみたいと思います。
使用者にはデータシートビューがいいか、リストボックスがいいか判断してもらおうと思います。
 
引用:
リストボックスなりデータシートなりに表示する
フィールドの並び順を、テーブルで定義されている通りの
順番に合わせる必要はないと思います。

ぶっちゃけ自分もそう思います。こんなにフィールド数が多くてナンセンスなのは十分承知の上です。
しかし、使用者は順番も種類もこれでいいと言うので、せめて共通部分だけは見せておこうかと配慮
してみた次第です。

回答
投稿日時: 21/03/30 20:26:25
投稿者: hatena
投稿者のウェブサイトに移動

フォームのデザインビューで、コントロールを選択するボックスの右のドロップダウンボタンをクリックして、[ActiveXコントロール]をクリックする。
リストが表示されるので、そこから「Microsoft Forms 2.0 ScrollBar」を選択して[OK]をクリック。
フォーム上にスクロールバーが配置されるので、マウスで適切なサイズに変更する。
名前を「LBScrollBar」に変更。
 
フォームのモジュールは下記のように記述します。
 

'各列の幅
Const conRowWidth = "2cm;2cm;2cm;2cm;2cm;2cm;2cm;2cm;2cm;2cm;2cm;2cm;2cm;2cm;2cm;2cm;2cm;2cm"
Const LeftFixCol = 1 '1列目まで固定
Const RightFixCol = 10 '10列目以降固定
Const ScrlColCnt = 2 'スクロールする列数 2

Private Sub Form_Load()
    With Me.LBScrollBar
        .Min = LeftFixCol
        .Max = RightFixCol - ScrlColCnt
        .Value = .Min
        setColumnWidths .Value
    End With
End Sub

Private Sub ScrollBar4_Change()
    setColumnWidths Me.LBScrollBar.Value
End Sub

Public Sub setColumnWidths(curCol As Long)
    Dim RWs As Variant
    RWs = Split(conRowWidth, ";")
    
    Dim i As Long
    For i = LeftFixCol To curCol - 1
        RWs(i) = "0cm"
    Next
    For i = curCol + ScrlColCnt To RightFixCol - 1
        RWs(i) = "0cm"
    Next

    Me.ListBox1.ColumnWidths = Join(RWs, ";")
End Sub

 
仕様は前回と同じです。
列数は18列
1列目と10列目以降を固定
2列目から9列目のうち2列分を表示して、スクロールする。
 
コードの先頭の Const宣言部分で列幅や固定列などをそちらの仕様に合わせて変更してください。

投稿日時: 21/03/31 11:42:37
投稿者: アロハ

hatena様
 
コメントありがとうございます。
 
リストボックスで作ることができました。
更にActiveXのスクロールバーコントロールの使い方までご指導いただき大変勉強になりました。
お忙しいところご指導いただき本当にありがとうございました。
 
sk様
 
データシートビューの使い方について大変勉強になりました。
お忙しいところご指導いただき本当にありがとうございました。