Winapi 禁用列表框时允许在列表框中垂直滚动(VB6)

Winapi 禁用列表框时允许在列表框中垂直滚动(VB6),winapi,vb6,listbox,Winapi,Vb6,Listbox,我需要在multiselect列表框(VB6)中允许垂直滚动条,但是,当控件被禁用时,我无法滚动 我认为有一个API可以实现这一点,但我最喜欢的API没有办法 我假装它被禁用了,并忽略了点击。。。但是用VB6代码来做这件事真的很难看。。。因此,如果这是一个解决方案,我需要一个API来忽略点击 感谢您的帮助。与其寻找API来忽略点击,不如直接忽略事件?(即,当用户单击/选择某个内容时,不要这样做) 而且,我认为有一个SelectionMode属性可以禁用multiselect并使其成为单选 如果您

我需要在multiselect列表框(VB6)中允许垂直滚动条,但是,当控件被禁用时,我无法滚动

我认为有一个API可以实现这一点,但我最喜欢的API没有办法

我假装它被禁用了,并忽略了点击。。。但是用VB6代码来做这件事真的很难看。。。因此,如果这是一个解决方案,我需要一个API来忽略点击


感谢您的帮助。

与其寻找API来忽略点击,不如直接忽略事件?(即,当用户单击/选择某个内容时,不要这样做)

而且,我认为有一个
SelectionMode
属性可以禁用multiselect并使其成为单选

如果您不希望用户能够选择任何内容,您可以尝试挂接到
SelectionIndexChanged
事件,并将
SelectionIndex
设置为-1


我的VB6有点生锈,如果事件/属性名称不完全匹配,那么很抱歉。

这是一个完全的VB攻击,但我认为您可以保持列表框处于启用状态,然后在除滚动条之外的所有列表框上拖动一个透明标签(带有空白文本)。标签将拦截任何鼠标点击(尽管这不会影响击键)


这只在标签像我记得的那样透明的情况下才起作用(可能是图像控件,没有加载的图像,在VB中就是这样工作的)。

说到黑客,如果当鼠标在滚动条上移动时启用滚动条会怎么样


或者也许。。。在列表框的SB上放置另一个滚动条,并使用API来查找禁用的LB。

在禁用的列表框上只启用滚动条是可能的(我认为),但您必须深入Windows API并执行SendMessage和其他一些可怕的操作


我刚刚签出它,当一个列表框被禁用时,您仍然可以通过更改控件的ListIndex属性,通过编程方式上下滚动它。因此,您可以按照greg的建议,在列表框上的垂直滚动条上“浮动”一个已启用的垂直滚动条,并使用此滚动条的Value_Changed事件(我想这就是它的名称)来更改列表框的ListIndex属性。

我提出了以下代码,它隐藏了类后面的所有粗糙细节。基本上,我实现了greg的想法,即在禁用列表框的滚动条上覆盖另一个滚动条。在我的代码中,我动态地创建了另一个ListBox控件(调整大小以便只有它的滚动条可见),并使用它的滚动条滚动实际的ListBox。我还特别避免使用Windows API(除了调用
GetSystemMetrics
,我用来计算滚动条在系统上的宽度)。使用另一个ListBox的滚动条的好处是,它将正确地设置主题(ListBox在显示其滚动条时使用操作系统的主题,但是VB.scrollbar不使用,因此看起来不合适)。使用第二个列表框滚动第一个列表框的另一个优点是,实现滚动逻辑非常容易(只要在滚动第二个列表框时将第一个列表框的TopIndex属性设置为第二个列表框的TopIndex属性即可)

我还将其设置为尽可能低的影响(您只需在
表单\u Load
事件中调用单个函数即可使其工作)

用法
  • CustomScrollingSupport.cls
    ListBoxExtras.bas
    添加到项目中

  • 在表单的
    form\u Load
    事件中,添加以下行:

    addCustomListBoxScrollingMe

    这将使表单上的每个VB.ListBox都支持滚动,即使它们被禁用。如果只想将此功能添加到选定数量的列表框中,则可以调用
    AddCustomScrollingSupport
    ,传入特定的列表框控件

  • 有趣的音符 在这段代码的旧版本中,我没有在第二个列表框(提供滚动条的列表框)上调用
    ZOrder
    方法来确保它显示在第一个列表框的顶部。这意味着第二个列表框实际上在第一个列表框后面;有趣的是,当第一个列表框被禁用时,第二个列表框上的滚动仍然有效!显然,当第一个列表框被禁用时,任何可能进入该列表框的鼠标和键盘事件都会“溢出”到第二个列表框,因此滚动支持仍然有效。我不确定这是一个bug还是设计(我的意思是,你可能会说禁用控件后的控件能够接收事件是有意义的…)。但是,我发现滚动有时有点不稳定,所以我决定添加
    .ZOrder 0
    ,使第二个列表框呈现在第一个列表框的顶部。这有一个缺点,即您可以看到第二个列表框的框架边框(在滚动条的左侧),您无法看到它是否隐藏在第一个列表框后面,但滚动更平滑


    自定义滚动支持.cls

    这个类总结了向
    VB.ListBox
    控件添加“自定义滚动支持”(因为没有更好的名称)所需的逻辑。它不应该直接使用,而是使用
    ListBoxExtras.bas
    模块中的
    Add*
    方法之一(稍后我将提供该模块的代码)


    是的,我担心“什么都不做”不是答案,因为VB在点击事件后更改了选择本身。你需要做额外的工作才能什么都不做。。。我只是还不知道是什么。任何有帮助的API都将不胜感激。我不知道该用哪一个我真的很喜欢这个想法,但它不会与标签或图像控制工作。它们都不能放在列表框的前面以捕获点击事件。对不起,我发誓这是可能的。
    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
    
    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