Страницы: 1
RSS
Событие change листбокса иногда запускается два раза подряд вместо одного
 
Есть файл, в нём таблица. При нажатии на кнопку вызывается форма с листбоксами (листбоксы с мультивыбором и полем для галочки). Далее заголовки таблицы распределяются по листбоксам и, если столбец с заголовком таблицы виден, то в листбокс ставится галочка, если скрыт, то галочка не ставится. И вот форма в таком виде отобразилась перед пользователем. Пользователь должен нажимать на элементы листбоксов (ставить и убирать галочки) и скрывать/отображать таким образом столбцы в таблице. Код скрытия/отображение представлен в модуле класса.

В целом всё работает, но есть стабильно появляется «плавающая» ошибка (или глюк). Заключается она в том, что нажимаешь на какой-то элемент листбокса, а ничего не происходит, только листбокс мерцает и всё. Нажимаешь повторно и вот теперь элемент листбокса на который нажали меняет значение выделения. И так может быть с 2-мя, 3-мя листбоксами после запуска формы, потом глюк пропадает.  Я вывел сообщение, которое говорит нам о том, что событие изменения листбокса сработало и оказалось, что на самом деле не ничего не происходит, а наоборот, событие срабатывает 2 раза. То есть пользователь нажимает на элемент, его выделение меняется, макрос изменения запускается и после окончания макроса опять срабатывает событие изменения.

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

Просьба помочь разобраться. Это глюк листбокса или ошибки в коде?
 
Попробуйте событие Click, вместо Change.
Файл не смотрел.
 
Попробовал. Реакция на это событие отсутствует. Я так понимаю, что событие Click для ListBox работает только при свойстве MultiSelect  = 0 (без мультивыбора).
 
Да, Вы правы - с мультивыбором не срабатывает (
 
Попробуйте так.
Владимир
 
Владимир, у меня в скачанном примере всегда после запуска формы дважды срабатывает листбокс № 2, 3 и 4 при первом нажатии. Три вопроса:
1) У вас тоже есть такая проблема?
2) Вы код оставили без изменений и только уменьшили размер файла?
3) Как вы уменьшили размер файла?
 
1. Я думаю, что у многих (всех?) будет подобная проблема. Пока на разных конфигурациях не смотрел.
3. Размер файла уменьшен стандартным образом: Userform экспортирована в файл, удалена, импортирована обратно.
2. Дополнительно поменял Tab Order элементов управления. Ушли (?) проблемы с 1-м и 6-м Listbox, новые проблемы появились.
Изменено: sokol92 - 12.08.2019 21:08:57
Владимир
 
Что интересно,  так это то, что если сперва выделить бокс правой кнопкой, а после этого в нем проводить выбор, то повторного события не наблюдается.
По вопросам из тем форума, личку не читаю.
 
Уберите класс, сделайте обычную обработку lList_Change.
Один ListBox. Первый столбец - номера столбцов листа, второй - категория (цены, ссылки), третиий - наименование
Часть кода из рабочей программы:
Код
Dim rRng As Range, bFlag As Boolean
' при инициализации формы заполнение listBox. 
' Перед заполнением  bFlag = True, после - bFlag = False

Private Sub lbList_Change()
    If bFlag = False Then Call ColumnsVisibleHidden
End Sub

Private Sub ColumnsVisibleHidden()
    Dim j As Long

    With lbList
        If .ListIndex = -1 Then Exit Sub ' выход, если элемент не выбран
        j = .List(.ListIndex, 0) ' в скрытом столбце - номера столбцов листа
        Application.ScreenUpdating = False
        rRng(j).EntireColumn.Hidden = Not rRng(j).EntireColumn.Hidden
        Application.ScreenUpdating = True
    
        lbList.Height = 400 ' высота ListBox
    End With
End Sub

Так ли нужно сообщение после каждого изменения? Меня, например, напрягло - каждый раз закрывать сообщение.
 
Есть предложение: вместо ЛистБоксов с мультивыбором использовать группы ЧекБоксов, в свойствах  Tag каждого, указав номер столбца.
 
Цитата
vikttur написал:
Так ли нужно сообщение после каждого изменения?
думаю Максим Зобов,  это для наглядности вставил, чтоб было видно что дублируется.
По вопросам из тем форума, личку не читаю.
 
Большое спасибо за ответы! Варианты решений интересные, но по каждому из ний есть «но»...
vikttur, хочется оставить модуль класса, т. к. это избавляет от необходимости дополнять код при создании новых листбоксов. Хотя в вашем варианте как я понял принципиально другой подход, с одним листбоксом из трёх столбцов (первый из которых скрыт). Нужно будет попробовать и оценить такой вариант в действии, на предмет удобства пользователя. Сообщение действительно для наглядности, пользователь его конечно видеть не должен.
Юрий М, с чекбоксами ситуация осложняется тем, что в реальной таблице сейчас 47 столбцов и они могут добавляться, удаляться, переставляться и кочевать из одной группы листбоксов в другую. Плюс 47 чекбоксов сложнее спозиционировать аккуратно, чем десяток листбоксов. Даже програмно. Вообщем я на форуме в одной из тем вычитал (кажется как раз в вашем сообщении), что вместо чекбоксов можно использовать листбокс с мультивыбором и галочкой. И это оказалось проще, удобнее, лаконичнее и вообще перевернуло моё сознание :) Так что к чекбоксам в этой задаче я уже не вернусь, к хорошему быстро привыкаешь.

Вариант решения проблемы. Навеяно заметкой БМВ
Цитата
БМВ написал: если сперва выделить бокс правой кнопкой, а после этого в нем проводить выбор, то повторного события не наблюдается.
Попробовал выделять каждый листбокс програмно, во время инициализации формы, через ListBox.SetFocus. И двойное срабатывание пропало. Ещё раз большое спасибо каждому за внимание к теме! Здорово, что с помощью форума удалось решить такую странную проблему.
Изменено: mvzobov - 13.08.2019 13:25:40 (слетела цитата)
 
Спасибо за интересное исследование!
Владимир
 
Решение есть, а причина?
 
Виктор, это к разработчику.
Владимир
 
Значит, баг... Я тему по диагонали просматривал ) Надо детальнее вникнуть.
 
Вот проблема в "чистом" виде. Выполняем макрос Runform.
Щелкаем по элементу третьего Listbox. Событие Change выполняется два раза.
Владимир
 
W10 x64, Office2019
проблема не воспроизвелась, все работает как написано
Программисты - это люди, решающие проблемы, о существовании которых Вы не подозревали, методами, которых Вы не понимаете!
 
второй третий и четвертый дуплят. Win10X64/2016x64 (16.0.4849)
Изменено: БМВ - 13.08.2019 19:46:13
По вопросам из тем форума, личку не читаю.
 
Коллеги, спасибо! Проверял на Win 10 Excel 2016 (32-, ru) и Win 10 Excel 2016 (64-, en), Win XP Excel 2007. Проблема есть.
Изменено: sokol92 - 13.08.2019 19:33:49
Владимир
 
sokol92, прокуренный, но пытливый ум медведя
Код
Lb.MatchEntry = 2

Почему - ХЗ. Но если со всех снять, то появляется дублет.
Проставил TabIndex-
Код
Lb.TabIndex = lbi  
нет дуплета.
Изменено: БМВ - 13.08.2019 20:09:00
По вопросам из тем форума, личку не читаю.
 
Михаил, у меня не спасает. Щелкаем по одному элементу в листбоксах: 1,6,3
А вот (Ваш же) вариант

Код
Lb.Setfocus
пока держится.
Изменено: sokol92 - 13.08.2019 20:09:39
Владимир
 
С табом, блин, закрыл открыл заново и правда снова дуплит.
Изменено: БМВ - 13.08.2019 20:11:39
По вопросам из тем форума, личку не читаю.
 
SetFocus пока держится. Tab Order я испытывал еще в #7. Также пробовал изменить событие Change на мышиные клавиши (сейчас кот примчится) - эффект не меняется.
Изменено: sokol92 - 13.08.2019 20:22:01
Владимир
 
Да, и 3-й, и 4-й... Предварительное выделение помогает.
Поменял TabIndex
3-й - 0
4-й - 1
Теперь двоят 4, 5 и 6, иногда 1... Какой-либо зависимости не обнаружил.
Код
Private Sub ListBox1_change()
    If intlz Then
        intlz = False
        x = x + 1:  Debug.Print x
        Application.Wait Time:=Now + TimeValue("0:00:02") 
        intlz = True
    End If
End Sub

Ни задержка, ни изменение флага внутри процедуры не помогают - событие change срабатывает 2 раза
 
Я заметил, что этот баг появляется при условии, если включен на Listbox SpecialEffect=0 и BorderStyle=1.
Меняешь любой из параметров на другой, например, если ставишь SpecialEffect=2, то баг не появляется.
Ещё если SpecialEffect=0, чуть на пару точек высоту Listbox больше делаешь и баг больше не появляется при включеном BorderStyle=1.
В общем если содержимое в Listbox перекрывает видимую область, то лучше не ставить SpecialEffect=0 и BorderStyle=1.
Мастерство программиста не в том, чтобы писать программы, работающие без ошибок.
А в том, чтобы писать программы, работающие при любом количестве ошибок.
 
Цитата
Alemox написал: если содержимое в Listbox перекрывает видимую область,
Еще один баг ListBox'а - иногда последняя запись не видна.
 
vikttur, Есть такое дело, поэтому в таких случаях я делаю Userform, которую мышкой можно расширять. Там ещё бывает, что у Listbox прокрутка горизонтальная скрывается.
Мастерство программиста не в том, чтобы писать программы, работающие без ошибок.
А в том, чтобы писать программы, работающие при любом количестве ошибок.
 
Цитата
sokol92 написал:
мышиные клавиши
А? Что, где?
 
Цитата
Alemox написал: ... этот баг появляется при условии, если включен на Listbox SpecialEffect=0 и BorderStyle=1.
Изначально выставлял эти параметры вдохновившись статьёй о внешнем виде форм. Попробовал поменять настройки, как вы описали, и ситуация без изменений, продолжают двоить некоторые листбоксы.
Страницы: 1
Наверх