Разрешить вертикальную прокрутку в списке, когда он отключен (VB6) - PullRequest
2 голосов
/ 15 ноября 2008

Мне нужно разрешить вертикальную полосу прокрутки в списке множественного выбора (VB6), однако, когда элемент управления отключен, я не могу прокручивать.

Я бы подумал, что есть API для этого, но мой любимый VB6-сайт (MVPS VB.NET) не имеет возможности.

Я играл с притворством, что оно было отключено, и игнорирую клики ... но делать это с кодом VB6 действительно некрасиво ... так что если это решение, мне нужен API, чтобы игнорировать клики.

Спасибо за вашу помощь.

Ответы [ 5 ]

4 голосов
/ 17 ноября 2008

Я придумал следующий код, который скрывает все мрачные детали за классом. По сути, я реализовал идею Грега об использовании наложения другой полосы прокрутки поверх полосы прокрутки отключенного списка. В моем коде я динамически создаю другой элемент управления ListBox (с измененным размером, чтобы была видна только его полоса прокрутки), и использую его полосу прокрутки для прокрутки фактического ListBox. Я также специально избегал использования Windows API (за исключением вызова GetSystemMetrics, который использовался для определения ширины полосы прокрутки в системе). Хорошая вещь об использовании другой полосы прокрутки ListBox состоит в том, что она будет правильно тематизирована (ListBox использует тему ОС, когда отображает свою полосу прокрутки, а VB.Scrollbar - нет, поэтому она будет выглядеть неуместно). Другое преимущество использования второго ListBox для прокрутки первого списка состоит в том, что действительно легко реализовать логику прокрутки (просто установите свойство TopIndex первого ListBox равным свойству TopIndex второго ListBox при каждой прокрутке второго).

Я также настроил его так, чтобы он был настолько слабым, насколько это возможно (вам нужно вызвать только одну функцию в вашем Form_Load событии, чтобы она работала).

Использование

  1. Добавьте CustomScrollingSupport.cls и ListBoxExtras.bas к вашему проекту.

  2. В событие Form_Load вашей формы добавьте следующую строку:

    AddCustomListBoxScrolling Me

    Это заставит все VB.ListBox в форме поддерживать прокрутку, даже когда они отключены. Если вы хотите добавить эту функцию только к выбранному числу ListBox, вы можете вместо этого вызвать AddCustomScrollingSupport, передав определенный элемент управления ListBox.

Интересная заметка

В более старой версии этого кода я не вызывал метод ZOrder во втором списке (тот, который предоставляет полосу прокрутки), чтобы убедиться, что он будет отображаться поверх первого списка. Это означало, что второй список был фактически за первым списком; Интересно то, что прокрутка на втором ListBox все еще работала, когда первый ListBox был отключен! По-видимому, когда первый ListBox отключен, любые события мыши и клавиатуры, которые должны были пройти в этот ListBox, «просочились» во второй ListBox, поэтому поддержка прокрутки по-прежнему работает. Я не уверен, является ли это ошибкой или намерением (я имею в виду, вы могли бы утверждать, что имеет смысл, что элементы управления за отключенным элементом управления смогут получать события ...). Тем не менее, время от времени я обнаружил, что прокрутка немного прерывистая, поэтому я решил добавить .ZOrder 0, чтобы второй список отображался поверх первого. Это имеет тот недостаток, что вы видите рамку рамки для второго списка (слева от полосы прокрутки), которую вы не увидите, если она будет скрыта за первым списком, но прокрутка будет более плавной.

<Ч />

CustomScrollingSupport.cls

Этот класс объединяет логику, необходимую для добавления «пользовательской поддержки прокрутки» (из-за отсутствия лучшего имени) в элемент управления VB.ListBox. Его не следует использовать напрямую, вместо этого используйте один из методов Add* в модуле 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

Этот модуль содержит два служебных метода:

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
1 голос
/ 16 ноября 2008

Возможно включить только полосу прокрутки в отключенном списке (но я думаю), но вам придется покопаться в Windows API, выполнить SendMessage и другие ужасные вещи.

Я только что проверил это, и когда список отключен, вы все равно можете прокручивать его вверх и вниз программно, изменяя свойство ListIndex элемента управления. Таким образом, вы можете сделать что-то наподобие того, что предлагает Грег, и «плавать» включенную вертикальную полосу прокрутки над списком в списке, и использовать событие Value_Changed этой полосы прокрутки (я думаю, это то, что оно называется), чтобы изменить свойство ListIndex списка. *

1 голос
/ 16 ноября 2008

Говоря о взломах, что если вы включите полосу прокрутки, когда мышь перемещается над полосой прокрутки?

Или, может быть ... поместите другую полосу прокрутки поверх SB ListBox и используйте API для прокрутки отключенного LB.

1 голос
/ 16 ноября 2008

Вместо того, чтобы искать API для игнорирования кликов, вы не можете просто игнорировать события? (т.е. просто не делайте, когда пользователь что-то щелкает / выбирает).

И, я думаю, есть свойство SelectionMode, чтобы отключить множественный выбор и сделать его одиночным выбором.

Если вы не хотите, чтобы пользователь вообще мог что-либо выбирать, вы можете попробовать подключиться к событию SelectionIndexChanged и установить SelectionIndex в -1.

Мой VB6 немного ржавый, поэтому извините, если имя события / свойства не совпадают точно.

0 голосов
/ 16 ноября 2008

Это полный взлом VB, но я думаю, что вы можете оставить список включенным, а затем перетащить прозрачную метку (с пустым текстом) по всему списку, кроме полосы прокрутки. Метка будет перехватывать любые щелчки мыши (хотя это не повлияет на нажатия клавиш).

Это будет работать только в том случае, если метка прозрачна, как я помню (это может быть элемент управления изображением - без загруженного изображения - который работает так в VB).

...