2

複数選択リストボックス (VB6) で垂直スクロールバーを許可する必要がありますが、コントロールが無効になっているとスクロールできません。

これを可能にする API があると思いますが、私のお気に入りのVB6 サイト (MVPS VB.NET)には方法がありません。

無効になっているふりをして、クリックを無視しました...しかし、VB6コードでそれを行うのは本当に醜いです...したがって、これが解決策である場合、クリックを無視するAPIが必要です。

ご協力いただきありがとうございます。

4

5 に答える 5

4

クラスの背後にある危険な詳細をすべて隠す、次のコードを思いつきました。基本的に、無効なリスト ボックスのスクロールバーの上に別のスクロールバーを重ねるという greg のアイデアを実装しました。私のコードでは、別の ListBox コントロール (スクロール バーのみが表示されるようにサイズ変更) を動的に作成し、そのスクロール バーを使用して実際の ListBox をスクロールします。また、Windows API の使用を明確に避けました (への呼び出しを除く)。GetSystemMetricsシステム上のスクロールバーの幅を把握するために使用しました)。別の ListBox のスクロールバーを使用することの良い点は、テーマが適切に設定されることです (ListBox はスクロールバーを表示するときに OS のテーマを使用しますが、VB.Scrollbar はそうしないため、場違いに見えます)。2 番目の ListBox を使用して最初のリスト ボックスをスクロールするもう 1 つの利点は、スクロール ロジックの実装が非常に簡単であることです (2 番目のリスト ボックスがスクロールされるたびに、最初の ListBox の TopIndex プロパティを 2 番目の ListBox の TopIndex プロパティに設定するだけです)。

また、できるだけ影響が少ないように設定しました (Form_Loadイベントで 1 つの関数を呼び出すだけで機能します)。

使用法

  1. CustomScrollingSupport.clsとをプロジェクトに追加ListBoxExtras.basします。

  2. フォームのForm_Loadイベントに、次の行を追加します。

    AddCustomListBoxScrolling Me

    これにより、フォーム上のすべての VB.ListBox が無効になっていてもスクロールがサポートされます。この機能を選択した数の ListBox にのみ追加したい場合は、AddCustomScrollingSupport代わりに呼び出して、特定の ListBox コントロールを渡すことができます。

興味深いメモ

このコードの古いバージョンではZOrder、2 番目のリストボックス (スクロールバーを提供するもの) でメソッドを呼び出して、最初のリストボックスの上に表示されるようにしていませんでした。これは、2 番目のリストボックスが実際には最初のリストボックスの後ろにあることを意味します。興味深いことに、最初の ListBox が無効になっていても、2 番目の ListBox のスクロールは機能していました。どうやら、最初の ListBox が無効になっている場合、その ListBox に移動するマウスとキーボードのイベントはすべて 2 番目の ListBox に「流出」するため、スクロールのサポートは引き続き機能します。これがバグなのか設計によるものなのかはわかりません (無効なコントロールの背後にあるコントロールがイベントを受け取ることができるのは理にかなっていると主張することができます...)。ただし、スクロールが時々少しぎくしゃくすることがわかったので、追加することにしました.ZOrder 0最初のリストボックスの上に 2 番目のリストボックスをレンダリングします。これには、2 番目のリストボックス (スクロール バーの左側) のフレーム境界が表示されるという欠点があります。これは、最初のリスト ボックスの後ろに隠れている場合には表示されませんが、スクロールはよりスムーズになります。


CustomScrollingSupport.cls

VB.ListBoxこのクラスは、"カスタム スクロール サポート" (より適切な名前がないため) をコントロールに追加するために必要なロジックをまとめたものです。直接使用するのではなく、モジュールAdd*内のメソッドの 1 つを使用してくださいListBoxExtras.bas(このモジュールのコードは、記事の後半で提供します)。

Option Explicit

Private Declare Function GetSystemMetrics Lib "user32" (ByVal nIndex As Long) As Long
Private Const SM_CXVSCROLL = 2
Private Const SM_CXFRAME = 32

Private m_runningScrollers As Collection
Private WithEvents m_list As VB.listbox
Private WithEvents m_listScroller As VB.listbox

'--------------------------------------------------------------'
' Bind                                                         '
'                                                              '
'   Adds custom scrolling support to a ListBox control.        '
'   Specifically, it allows the ListBox to be                  '
'   scrolled even when it is disabled.                         '
'                                                              '
'   Parameters:                                                '
'                                                              '
'   + list                                                     '
'       the ListBox control to add custom scrolling support to '
'                                                              '
'   + runningScrollers                                         '
'       a Collection of CustomScrollingSupport objects. Passed '
'       in so that this object can remove itself from the list '
'       when it is terminated.                                 '
'                                                              '
'--------------------------------------------------------------'

Public Sub Bind(ByVal list As VB.listbox, runningScrollers As Collection)

    Set m_list = list
    Set m_runningScrollers = runningScrollers

    'Create another ListBox loaded with the same number of entries as the real listbox'
    Set m_listScroller = m_list.Container.Controls.Add("VB.ListBox", list.Name & "_scroller")
    LoadScrollerList

    Dim nScrollbarWidth As Long
    nScrollbarWidth = GetSystemMetricScaled(SM_CXVSCROLL, m_list) + _
                      GetSystemMetricScaled(SM_CXFRAME, m_list)

    'Display the other listbox (the "scroller"), just wide enough so that only its scrollbar is visible'
    'and place it over the real listboxs scroll bar'
    With m_listScroller
        .Left = m_list.Left + m_list.Width - nScrollbarWidth
        .Top = m_list.Top
        .Height = m_list.Height
        .Width = nScrollbarWidth
        .Enabled = True
        .Visible = True
        .ZOrder 0
    End With

End Sub

Private Sub m_listScroller_Scroll()
    'If the master list has changed, need to reload scrollers list'
    '(not ideal, but there is no ItemAdded event that we could use to keep the lists in sync)'
    If m_list.ListCount <> m_listScroller.ListCount Then
        LoadScrollerList
    End If

    'Make any scrolling done on the scroller listbox occur in the real listbox'
    m_list.TopIndex = m_listScroller.TopIndex

End Sub

Private Sub Class_Terminate()

    Dim scroller As CustomScrollingSupport
    Dim nCurrIndex As Long

    If m_runningScrollers Is Nothing Then
        Exit Sub
    End If

    'Remove ourselves from the list of running scrollers'

    For Each scroller In m_runningScrollers
        nCurrIndex = nCurrIndex + 1
        If scroller Is Me Then
            m_runningScrollers.Remove nCurrIndex
            Debug.Print m_runningScrollers.Count & " scrollers are running"
            Exit Sub
        End If
    Next

End Sub

Private Sub LoadScrollerList()

    Dim i As Long

    m_listScroller.Clear
    For i = 1 To m_list.ListCount
        m_listScroller.AddItem ""
    Next

End Sub

Private Function GetSystemMetricScaled(ByVal nIndex As Long, ByVal ctrl As Control)
    GetSystemMetricScaled = ctrl.Container.ScaleX(GetSystemMetrics(nIndex), vbPixels, ctrl.Container.ScaleMode)
End Function

ListBoxExtras.bas

このモジュールには、次の 2 つのユーティリティ メソッドが含まれています。

AddCustomScrollingSupport個々のVB.ListBox コントロール

AddCustomListBoxScrollingにカスタム スクロール機能を追加します 特定のコントロールのすべてのVB.ListBox コントロールにカスタム スクロール機能を追加しますForm

Option Explicit

Public Sub AddCustomScrollingSupport(ByVal list As VB.listbox)

    Static runningScrollers As New Collection

    Dim newScroller As CustomScrollingSupport
    Set newScroller = New CustomScrollingSupport

    runningScrollers.Add newScroller
    newScroller.Bind list, runningScrollers

End Sub

Public Sub AddCustomListBoxScrolling(ByVal frm As Form)

    Dim ctrl As Control
    For Each ctrl In frm.Controls

        If TypeOf ctrl Is VB.listbox Then
            AddCustomScrollingSupport ctrl
        End If

    Next

End Sub
于 2008-11-17T00:06:12.570 に答える
1

クリックを無視するAPIを探すのではなく、イベントを無視するだけではいけませんか?(つまり、ユーザーが何かをクリック/選択したときに実行しないでください)。

SelectionModeそして、複数選択を無効にして単一選択にするプロパティがあると思います。

ユーザーが何も選択できないようにする場合は、SelectionIndexChangedイベントにフックしSelectionIndexて-1に設定してみてください。

私のVB6は少し錆びているので、イベント/プロパティ名が完全に一致しない場合は申し訳ありません。

于 2008-11-15T21:25:55.280 に答える
1

ハックといえば、マウスがスクロール バーの上を移動しているときにスクロール バーを有効にするとどうなるでしょうか。

あるいは、ListBox の SB の上に別のスクロール バーを配置し、API を使用して無効な LB をスクロールします。

于 2008-11-15T23:01:32.123 に答える
1

無効なリストボックスでスクロールバーだけを有効にすることは可能ですが (私は思います)、Windows API を掘り下げて、SendMessage やその他の恐ろしいことを行う必要があります。

チェックアウトしたところ、リストボックスが無効になっている場合でも、コントロールの ListIndex プロパティを変更することで、プログラムで上下にスクロールできます。したがって、gregが提案するようなことを行い、有効な垂直スクロールバーをリストボックスのバーの上に「浮かせ」、このスクロールバーのValue_Changedイベントを使用して(私はそれが呼ばれるものだと思います)、リストボックスのListIndexプロパティを変更します。

于 2008-11-16T16:23:53.860 に答える
0

これは完全なVBハックですが、リストボックスを有効のままにして、スクロールバーを除くすべてのリストボックスに透明なラベル(空白のテキスト付き)をドラッグすることができると思います。ラベルはマウスクリックをインターセプトします(ただし、これはキーストロークには影響しません)。

これは、私が覚えているようにラベルが透明である場合にのみ機能します(VBでこのように機能するのは、画像コントロール(画像が読み込まれていない場合)である可能性があります)。

于 2008-11-15T22:42:46.937 に答える