複数選択リストボックス (VB6) で垂直スクロールバーを許可する必要がありますが、コントロールが無効になっているとスクロールできません。
これを可能にする API があると思いますが、私のお気に入りのVB6 サイト (MVPS VB.NET)には方法がありません。
無効になっているふりをして、クリックを無視しました...しかし、VB6コードでそれを行うのは本当に醜いです...したがって、これが解決策である場合、クリックを無視するAPIが必要です。
ご協力いただきありがとうございます。
複数選択リストボックス (VB6) で垂直スクロールバーを許可する必要がありますが、コントロールが無効になっているとスクロールできません。
これを可能にする API があると思いますが、私のお気に入りのVB6 サイト (MVPS VB.NET)には方法がありません。
無効になっているふりをして、クリックを無視しました...しかし、VB6コードでそれを行うのは本当に醜いです...したがって、これが解決策である場合、クリックを無視するAPIが必要です。
ご協力いただきありがとうございます。
クラスの背後にある危険な詳細をすべて隠す、次のコードを思いつきました。基本的に、無効なリスト ボックスのスクロールバーの上に別のスクロールバーを重ねるという greg のアイデアを実装しました。私のコードでは、別の ListBox コントロール (スクロール バーのみが表示されるようにサイズ変更) を動的に作成し、そのスクロール バーを使用して実際の ListBox をスクロールします。また、Windows API の使用を明確に避けました (への呼び出しを除く)。GetSystemMetrics
システム上のスクロールバーの幅を把握するために使用しました)。別の ListBox のスクロールバーを使用することの良い点は、テーマが適切に設定されることです (ListBox はスクロールバーを表示するときに OS のテーマを使用しますが、VB.Scrollbar はそうしないため、場違いに見えます)。2 番目の ListBox を使用して最初のリスト ボックスをスクロールするもう 1 つの利点は、スクロール ロジックの実装が非常に簡単であることです (2 番目のリスト ボックスがスクロールされるたびに、最初の ListBox の TopIndex プロパティを 2 番目の ListBox の TopIndex プロパティに設定するだけです)。
また、できるだけ影響が少ないように設定しました (Form_Load
イベントで 1 つの関数を呼び出すだけで機能します)。
CustomScrollingSupport.cls
とをプロジェクトに追加ListBoxExtras.bas
します。
フォームの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
クリックを無視するAPIを探すのではなく、イベントを無視するだけではいけませんか?(つまり、ユーザーが何かをクリック/選択したときに実行しないでください)。
SelectionMode
そして、複数選択を無効にして単一選択にするプロパティがあると思います。
ユーザーが何も選択できないようにする場合は、SelectionIndexChanged
イベントにフックしSelectionIndex
て-1に設定してみてください。
私のVB6は少し錆びているので、イベント/プロパティ名が完全に一致しない場合は申し訳ありません。
ハックといえば、マウスがスクロール バーの上を移動しているときにスクロール バーを有効にするとどうなるでしょうか。
あるいは、ListBox の SB の上に別のスクロール バーを配置し、API を使用して無効な LB をスクロールします。
無効なリストボックスでスクロールバーだけを有効にすることは可能ですが (私は思います)、Windows API を掘り下げて、SendMessage やその他の恐ろしいことを行う必要があります。
チェックアウトしたところ、リストボックスが無効になっている場合でも、コントロールの ListIndex プロパティを変更することで、プログラムで上下にスクロールできます。したがって、gregが提案するようなことを行い、有効な垂直スクロールバーをリストボックスのバーの上に「浮かせ」、このスクロールバーのValue_Changedイベントを使用して(私はそれが呼ばれるものだと思います)、リストボックスのListIndexプロパティを変更します。
これは完全なVBハックですが、リストボックスを有効のままにして、スクロールバーを除くすべてのリストボックスに透明なラベル(空白のテキスト付き)をドラッグすることができると思います。ラベルはマウスクリックをインターセプトします(ただし、これはキーストロークには影響しません)。
これは、私が覚えているようにラベルが透明である場合にのみ機能します(VBでこのように機能するのは、画像コントロール(画像が読み込まれていない場合)である可能性があります)。