VB и Excel
Есть список ListBox (большой), который приходится пролистывать нажатием на стрелки полосы прокрутки. Что надо сделать, чтобы листать его с помощью "колесика" мыши?
p.s. заранее благодарю всех, кто откликнется.
Помогите, кто может!
Есть список ListBox (большой), который приходится пролистывать нажатием на стрелки полосы прокрутки. Что надо сделать, чтобы листать его с помощью "колесика" мыши?
p.s. заранее благодарю всех, кто откликнется.
Тут дело не в Экселе, а в драйвере мышки. Если его нет, то Винда понимает эту мышь как стандартную майкрософтовскую IntelliMouse. В итоге прокручивается колесиком далеко не все.
Если же у тебя мышка, скажем, Genius NetScroll или еще какая-нибудь нормальная мыша, то к ней поставляются фирменные драйвера - их можно скачать на сайте производителя. Тогда будет прокручиваться почти все.
Попробую, чуть-чуть пояснить. В самом excel'е у меня все прокручивается с помощью этого "колеса". Не работает скролинг именно в формах (Listbox), созданных в VBA. Может быть надо подключить какую-нибудь библиотеку?
Посьавила драйвера, которые прилагались к мыше - НЕ ПОМОГЛО!!!!
Попробую, чуть-чуть пояснить. В самом excel'е у меня все прокручивается с помощью этого "колеса". Не работает скролинг именно в формах (Listbox), созданных в VBA. Может быть надо подключить какую-нибудь библиотеку?
М-да. Печально. У меня тоже при таком раскладе не прокручивается. Боюсь, что тогда никак (если конечно не писать собственных драйверов. :) ).
Если, что узнаете нового, то сообщите мне, ПОЖАЛУЙСТА.
Главная проблема - это програмнмо прокрутить ListBox, для этого в Access применяется уже стнадартное средство - посылка этому ListBox сообщения - WM_VSCROLL.
Однако ListBox в Excel'e не только не реагирует на колесико мышки, так он еще и плюет на событие WM_VSCROLL, а когда ему щелкаешь по скролбару, возникают какая-та череда сообщений типа SetCusror, MouseMove, которые он как-то преобразует в прокрутку, теперь пытаюсь понять как же именно он это делает... но это конечно просто капец какой-то, я то думал, он только WM_MouseWheel не поддерживает, а оказалось, он вообще половину сообщений ListBox игнорирует.... :-(
p.s. огромное спасибо, что откликнулись на мой зов о помощи.
Буду ждать с нетерпением результатов. Если что-то получиться обязательно сообщите. Ну а если нет, тогда черт с ним.
p.s. огромное спасибо, что откликнулись на мой зов о помощи.
Может, эта проблема решена в Офисе ХР?
Остается тогда просто сымитировать действия пользователя нажимающего на скроллбар или, как вариант, сымитировать стрелки/PgUp - но тогда правда будет меняться и текущая запись, в отличии от классического прокручивания колесиком...
Но конечно трудновато ему, сабклассинг в Excel'e - это приличные тормоза. Судя по всему в работу вмешивается сам Excel и это напрягает всю систему, правда тормоза эти проявляются в основном в том, что мышка нехочет закрывать форму и двигать ее за заголовок, пока не отключишь сабклассинг, а так внутри конечно пашет.
Общий принцип заключается вот в чем (для справки, кто не знает что такое сабклассинг) - стандартную оконную функцию обработки сообщений нашей формы мы подменяем на свою (через HookForm/UnHookForm), которая принимает все сообщения для нашей формы, обрабатывает те какие нас интересует и потом вызывает пред. оконную функцию для дальнейшей стандартной обработки этих сообщений.
Отловив т.о. сообщение WM_MouseWheel, которое обычно игнорируется окном для ListBox, мы определяем из этого сообщения куда крутилось колесико и посылаем нашему ListBox нажатие клавиши Вверх/Вниз (PgUp/PgDn по сложнее будет, это я чуть позже сделаю), вот и все в принципе.
Вот текст модуля:
'================================
Private Declare Function apiGetFocus Lib "user32" Alias "GetFocus" () As Long
Private Declare Function GetParent Lib "user32" (ByVal hwnd As Long) As Long
Private Declare Function GetClassName Lib "user32" Alias "GetClassNameA" (ByVal hwnd As Long, ByVal lpClassName As String, ByVal nMaxCount As Long) As Long
Private Declare Function PostMessage Lib "user32" Alias "PostMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Private Const GWL_WNDPROC = (-4)
Private Const WM_MouseWheel As Long = &H20A
Private Const WM_KEYDOWN As Long = &H100
Private Const WM_KILLFOCUS As Long = &H8
Private Const WM_MOUSEMOVE As Long = &H200
Private Const WM_LBUTTONDOWN As Long = &H201
Private Const WM_LBUTTONUP As Long = &H202
Private Const WM_LBUTTONDBLCLK As Long = &H203
Private Const WM_RBUTTONDOWN As Long = &H204
Private Const WM_RBUTTONUP As Long = &H205
Private Const WM_RBUTTONDBLCLK As Long = &H206
Private Const WM_MBUTTONDOWN As Long = &H207
Private Const WM_MBUTTONUP As Long = &H208
Private Const WM_MBUTTONDBLCLK As Long = &H209
Private Const VK_DOWN As Long = &H28
Private Const VK_UP As Long = &H26
Public lpPrevWndProc As Long ' hWnd станд. функции обработчика окна
Public hndForm As Long ' hWnd нашей формы
Public Sub HookForm(frm As Object)
' Устанавливает наш обработчик событий для формы
'[frm] - ссылка на нашу форму. Передавайте так: Me
On Error GoTo Err_
If Len(frm.Caption) > 0 Then
hndForm = FindWindow("ThunderDFrame", frm.Caption)
If hndForm > 0 Then
lpPrevWndProc = SetWindowLong(hndForm, GWL_WNDPROC, AddressOf WindowProc)
Else
Err.Raise vbObjectError + 1002
End If
Else
Err.Raise vbObjectError + 1001
End If
Ex_:
Exit Sub
Err_:
If Err.Number = 1001 Then
MsgBox "Переданная форма имеет пустой заголовок(Caption)"
Else
MsgBox "Не получилось зарег. свой обработчик событий для формы."
End If
Resume Ex_
End Sub
Public Sub UnHookForm()
' Возвращает обратно станд. обработчик
On Error GoTo Err_
If hndForm > 0 Then _
SetWindowLong hndForm, GWL_WNDPROC, lpPrevWndProc
Ex_:
Exit Sub
Err_:
MsgBox "Возникла ошибка при возвращении обратно станд. обработчика."
Resume Ex_
End Sub
Public Function WindowProc(ByVal hwnd As Long, ByVal uMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
' Наш обработчик событий
Dim hWndFocus As Long
Dim hWndParent As Long
Dim lpClassName As String
Dim WHEEL_DELTA As Long
Dim i As Integer
' обрабатываем событие - поворот колесика
If uMsg = WM_MouseWheel Then
' проверям стоит ли фокус на каком-нибудь ListBox
'------------------------------------------------
hWndFocus = apiGetFocus
' буфер для имени класса окна
lpClassName = Space(256)
' получаем имя класса активного элемента
i = GetClassName(hWndFocus, lpClassName, 256)
' от пробелов освобождаемся
lpClassName = Left(lpClassName, i)
If lpClassName = "F3 Server 60000000" Then
' у родителя ListBox'a должен быть такой же класс,
' а если родителя нет, то это не ListBox, а клиент. часть формы
'----------------------------------------------
hWndParent = GetParent(hWndFocus)
If hWndParent > 0 Then
lpClassName = Space(256)
i = GetClassName(hWndFocus, lpClassName, 256)
lpClassName = Left(lpClassName, i)
If lpClassName = "F3 Server 60000000" Then
' все OK, это ListBox работаем с ним дальше
'------------------------------------------
' параметр WHEEL_DELTA хранится в High-word wParam
WHEEL_DELTA = wParam / (2 ^ 8)
If WHEEL_DELTA > 0 Then
i = PostMessage(hWndFocus, WM_KEYDOWN, VK_UP, vbNull)
Else
i = PostMessage(hWndFocus, WM_KEYDOWN, VK_DOWN, vbNull)
End If
End If
End If
End If
End If
' при потери фокуса возращаем старый обработчик
' чтобы тормозов было поменьше
' If uMsg = WM_KILLFOCUS Then
' UnHookForm
' End If
' вызываем станд. функцию (которая была раньше)
WindowProc = CallWindowProc(lpPrevWndProc, hwnd, uMsg, wParam, lParam)
End Function
А в форме вставляем такой текст:
Call HookForm(Me)
End Sub
Private Sub ListBox1_Exit(ByVal Cancel As MSForms.ReturnBoolean)
Call UnHookForm
End Sub
Обычно конечно HookForm/UnHookForm ставят на Load/UnLoad формы, но засунув их ListBox1_.. я хотел уменьшить тормоза, чтобы лишний раз не напрягать систему.
Опять же от UnHookForm я хотел избавиться добавив в WindowProc условие uMsg = WM_KILLFOCUS с Call UnHookForm, но чето оно не всегда срабатывает, пока разбираюсь с ним...
WHEEL_DELTA = wParam / (2 ^ 8)
Кстати Catty Sark хотел у тебя уточнить, просвети меня неуча, правильно я делаю, когда пытаюсь добраться до high-word в параметре wParam через: wParam / (2 ^ 8)???
а то что-то я запутался с этими битовыми операциями
В тексте модуля почему то строка обрезалась:
WHEEL_DELTA = wParam / (2 [знак степени] 8)
Кстати Catty Sark хотел у тебя уточнить, просвети меня неуча, правильно я делаю, когда пытаюсь добраться до high-word в параметре wParam через: wParam / (2 [знак степени] 8)???
а то что-то я запутался с этими битовыми операциями
Блин, чето цифру восемь никак не хочет показать после слов [знак степени]
1. По поводу high-word. Я, конечно, и сам неуч. Но мне кажется, что во-первых должно быть 2^16, а во-вторых она не отбрасывает дробную часть, а округляет, поэтому нужно сначала вычесть x Mod (2^16), а потом делить.
2. По поводу смайликов. При наборе мессиджа есть галочка "Отключить смайлы". Если в сообщении есть ":D" или "8)", то стоит эту галку поставить. Но я, как мега-флудер, конечно привык понимать фразы типа СУММ(D1:D8) и в смайлах понимаю.
К сожалению этот код представляет больше теоретический интерес, потому как с включенным сабклассингом в форме (и вне формы) работать еще можно, а вот все попытки перетащить форму мышкой или закрыть ее через крестик до нее не доходят, форма остается в глубоком ступоре, пока не отключишь сабклассинг - именно поэтому я запускал/выключал сабклассинг как только пользователь вошел/вышел в ListBox, чтобы по максимуму уменьшить вредное влияние... все таки это не VB6, где ты сам хозяин своей формы, тут начальник - Excel и с этим приходится считаться.
Код я еще немного не доделал - хотел на поворот колесика посылать не клавишу вверх/вниз, а PgUp/PgDn - поудобнее крокручивать; и пока она еще учитывает величину поворота колесика - надо заняться калибровкой.... сейчас еще покодим немного.
P.S. после компиляции итогового файла и его тестирования обнаружилось, что глюки с тормоза при переносе окна и его закрытии по крестику при включеном сабклассинге куда то исчезли... хм... прокрутка PgDn раньше тоже прокручивала только первый экран, а потом шла построчно - теперь все нормально...когда глюки исчезают, это приятно... вообщем попробуйте сами, как будет работать у вас, я тестировал на OfficeXp.
P.P.S. в коде есть небольшая привязка к названию класса окна формы Excel, которое может меняться от версии к версии, так что если Вы скажите какой у Вас Office и где возникает ошибка, мы сможем дополнить код проверкой на версию, чтобы он работал на любой ... (а то у меня под рукой только Xp)
97-й русский
в Sub HookForm в строке
lpPrevWndProc = SetWindowLong(hndForm, GWL_WNDPROC, AddressOf WindowProc) - ошибка синтаксиса.
Сереж, у тебя аська есть (яху_мессенджер тоже подойдет)? А то через форум можно и замучаться тестить...
Кстати, в предыдущем посте ругается, кажись на AddressOf (хотя я не на 100% уверен).
На 2000-м английском ошибок нет, но та том компе, где этот офис стоит, мышка без колесика :{ , поэтому сказать работает или нет - трудно.
Кстати, в предыдущем посте ругается, кажись на AddressOf (хотя я не на 100% уверен).
Да совершенно, верно, совсем забыл, что у оператор AddressOf только с Office2000 появился, так что с 97 видно не судьба...
По поводу icq, это моя головная боль, она не работает, не пробивается через корпоративную проксю, по моим иследованиям, судя по всему наш админ (или админы) закрыли доступ ко всем известным icq сервакам по имени и даже по ip'шнику , остается тогда только через настраивать соединение через еще одну проксю (не считая корпоративной) - видел в сети программки, которые могут организовывать цепочки из проксей для всех соединений компа, но пока еще не пробовал, думаю... одного у нас работе поймали когда он по WEB через анонимный прокси лазил, правда он был чемпионом по пожиранию трафика и увеселительных сайтов, так что есть надежда, что на скромный трафик через один неизвестный прокси они не обратят внимание...
А вот что такой за зверь, этот яху_месенджер? судя по всему этот вриант для меня более привлекательный.
Примерчик посмотрела. Все работает. у меня тоже XP. Правда не поняла про какой-то сабклассинг.
У меня все перемещается и закрывается и "его" не надо выключать.
Постараюсь сегодня внедрить все это в свою программульку.
Да совершенно, верно, совсем забыл, что у оператор AddressOf только с Office2000 появился, так что с 97 видно не судьба...
По поводу icq, это моя головная боль, она не работает, не пробивается через корпоративную проксю, по моим иследованиям, судя по всему наш админ (или админы) закрыли доступ ко всем известным icq сервакам по имени и даже по ip'шнику , остается тогда только через настраивать соединение через еще одну проксю (не считая корпоративной) - видел в сети программки, которые могут организовывать цепочки из проксей для всех соединений компа, но пока еще не пробовал, думаю... одного у нас работе поймали когда он по WEB через анонимный прокси лазил, правда он был чемпионом по пожиранию трафика и увеселительных сайтов, так что есть надежда, что на скромный трафик через один неизвестный прокси они не обратят внимание...
А вот что такой за зверь, этот яху_месенджер? судя по всему этот вриант для меня более привлекательный.
У одного моего приятеля админы тоже зверствуют на работе: "все порты закрыты кроме 80 и 443, только веб остался, вот и аська ходит по 443 ССЛ протоколу" (я в этом мало понимаю, но он долго жил без аськи, а теперь как-то решил эту проблему.)
А Yahoo_Messenger - тоже интернет-пейджер (есть еще и AOL_что-то-там, и еще один какой-то, забыл название). Можешь его качнуть с http://www.yahoo.com справа вверху "Messenger", там разберешься. В отличие от аськи, там буквы в никах тоже есть. Меня, например, зовут "zaitsev_sergey". Так что если получится - пиши. ;)
Раз пошла такая пьянка, то процедуры HookForm/UnHookForm следует размещать как полагается в событиях формы Load/Unload (в Excel'e это Initialize/QueryClose), код будет выглядеть более аккуратно, и после этого колесико должно работать у всех ListBox размещенных на форме без всяких доп. строчек в их обработчиках событий.
2Cutty Sark: с портами у icq все более менне понятно, раньше она лазила по своему - 443 и его админы и закрывали, а теперь icq научилась лазить по любому порту, в том числе и по 80, так что если WEB доступен, то и icq пролезет, тем же путем, ..... если только только админ не поставит фильтрацию адресов и не запретит обращение к некоторым адресам (раньше по имени закрывали, можно было вводить ip и такой пакет проскакивал, теперь уже и ip проверяют), у нас например даже через браузер не зайдешь на icq.com, т.е. как пишут в поездах заколочено на зиму...
Попробую Yahoo_Messenger, надеюсь до него еще наши админы не додумались, по крайне мере yahoo.com хоть грузится в браузере, да и прикрытие хорошее - поисковая система.... :)
:( Xt-то не хочет yahoo_messenger регистрироваться. Так вроде шустро начинает имял, пол спрашивает, потом начинает проверять на серваке, минут на 10 замолкает, а потом пишит, что сервак пока занят, попробуйте попозже...мда...
Ты знаешь, я сейчас спокойно зарегистрировался на пробу. А сам мессенджер у тебя установился?
Если да, то давай я тебя зарегистрирую, попробуешь зайти. Пришли мне на korzz(собака)pisem(точка)net свои фио, пароль какой-нибудь и какое бы слово ты хотел иметь в качестве ника. Если же он совсем не запускается, то тогда засада.
Ок, сейчас в приват мессадж отправлю тебе данные.
Преогромнейшее спасибо. Без Вас у меня ничего бы не получилось.
А можно мне еще один вопросик задать? Заранее извиняюсь, если он покажется глупым. Надеюсь это не очень нагло с моей стороны.
Можно ли из макроса обращаться к Excel'евскому файлу, к конкретному диапазону, не открывая его,
т.е. файл? А то все жутко моргает, когда, то открываешь, то закрываешь.
Все работает! УРРААААА!!!
Преогромнейшее спасибо. Без Вас у меня ничего бы не получилось.
А можно мне еще один вопросик задать? Заранее извиняюсь, если он покажется глупым. Надеюсь это не очень нагло с моей стороны.
Можно ли из макроса обращаться к Excel'евскому файлу, к конкретному диапазону, не открывая его,
т.е. файл? А то все жутко моргает, когда, то открываешь, то закрываешь.
Не открывая - нельзя.
А чтоб не моргало, сделай Application.ScreenUpdating = False
(это вообще полезно в макросах вставлять)
проще наверное все-таки в приват мессадж???
Это наш корпоративный почтовый сервак такой тормозной наверное, уже замечал за ним такое, бывает по полдня письмо может идти... я отправлял в - 17:05
проще наверное все-таки в приват мессадж???
Да, давай, конечно. Я просто про него забыл, а то бы сразу предложил. Тогда еще мейл свой в инфу включи. Он при регистрации просит мейл указать, присылает письмо, и надо оттуда щелкнуть по ссылочке. Надеюсь, это твой почтовый сервер пропустит. Если нет, то я на свой мейл зарегистрируюсь и подтвержу. Давай, жду.