Страницы: 1
RSS
Как разрешить редактировать данные только по двойному клику для всех TextBox и ComboBox в форме
 
Всем доброй охоты!

Рисую форму, в которой будет около 20 текстбоксов и комбобоксов разного размера. Хочу, чтобы данные в них можно было вносить только по двойному щелчку. Менять свойство на Locked для каждого элемента и прописывать событие onDoubleClick лениво. Вроде бы это всё делается через ClassModule, но я с ними не особо дружу и реализовал всё как-то коряво, на мой взгляд. Как правильно создать и использовать customTextBox и customComboBox?

myClass
Код
Option Explicit

Private WithEvents cbX As MSForms.ComboBox
Private WithEvents tbX As MSForms.TextBox

Public Sub setCont(ByVal cont)
    If TypeName(cont) = "ComboBox" Then
        Set cbX = cont
        cbX.Locked = True
    ElseIf TypeName(cont) = "TextBox" Then
        Set tbX = cont
        tbX.Locked = True
    End If
End Sub

Private Sub cbX_DblClick(ByVal Cancel As MSForms.ReturnBoolean)
    cbX.Locked = False
    cbX.BackColor = vbGreen
End Sub

Private Sub tbX_DblClick(ByVal Cancel As MSForms.ReturnBoolean)
    tbX.Locked = False
    tbX.BackColor = vbGreen
End Sub
Код в форме
Код
Option Explicit

Private contList() As myClass

Private Sub UserForm_Initialize()
    Dim cntrX As Control
    ReDim contList(0 To 0)

    For Each cntrX In frmTest.Controls
        ReDim Preserve contList(0 To UBound(contList) + 1) 'да, нулевой элемент массива пустой, но я с этим массивом работать не собираюсь. Он просто костыль.
        Set contList(UBound(contList)) = New myClass
        contList(UBound(contList)).setCont cntrX
    Next cntrX
    
End Sub

'Событие Exit вроде как нельзя описать в Class Module, так что придётся писать для каждого элемента. Можно как-то это сократить?
'Ещё один вопрос: я могу как-то обратиться к элементу, на котором произошло событие? This (ничего)? Me (форма)?
Private Sub cb1_Exit(ByVal Cancel As MSForms.ReturnBoolean)
    cb1.Locked = True
    cb1.BackColor = &H80000005
End Sub

Private Sub tb1_Exit(ByVal Cancel As MSForms.ReturnBoolean)
    tb1.Locked = True
    tb1.BackColor = &H80000005
End Sub

Private Sub tb2_Exit(ByVal Cancel As MSForms.ReturnBoolean)
    tb2.Locked = True
    tb2.BackColor = &H80000005
End Sub
В комментариях к коду ещё 2 маленьких вопроса, ответ на которые вроде бы "никак", но спросить-то всё-равно надо.
Изменено: Wiss - 04.07.2020 01:18:19
Я не волшебник, я только учусь.
 
Здравствуйте. Я думаю, все на много проще можно сделать. Создать отдельную процедуру в форме и вызывать её из события какого-нибудь CheckBox-a или ToggleButton-a, в итоге получится код короче и без класса. Действия процедуры: пройтись циклом по всем элементам формы и если тип является TextBox, то блокируем.
Код
Dim c As Control
For Each c In UserForm1.Controls 
   If TypeName(c) = "TextBox" Then ' или If TypeOf Ctrl Is TextBox
   c.Locked = True
Next c
Изменено: DANIKOLA - 04.07.2020 08:15:04
 
Если попробуете мой файл-пример, то увидите, что при двойном клике тестбокс красится зелёным и его можно редактировать. После выхода из текстбокса он возвращается к обычному цвету и редактировать его снова нельзя. Просто залочить все мне мало. Каждый текстбокс должен 2 события иметь. Одно я повесил через класс, но как то криво, второе мне тоже не очень нравится.
Я не волшебник, я только учусь.
 
А можно я немножко нарушу правила и апну тему? Мне кажется, это была плохая идея просить помощи в выходной день в час ночи.
Изменено: Wiss - 07.07.2020 12:45:06
Я не волшебник, я только учусь.
 
См. вариант для TextBox1
 
Юрий М, подход мне очень понравился. Сначала показалось, что для многих текстбоксов придётся для flag и text делать что-то типа коллекции, но и так всё отлично работать будет, но всё-равно для каждого текстбокса придётся прописывать 3 процедуры, а у меня их около 30.

Попробую ещё раз сформулировать свою проблему: есть форма, на ней 30 текстбоксов, в которые нужно разрешить редактировать только по двойному щелчку. Для каждого из 30 текстбоксов описывать одни и те же события - не наш метод. Задача частично решена через Class, но "есть нюансы":
1. Class к TextBox как-то криво применён (неужели нет более красивого варианта наследования и я это правильно сделал?!).
2. В Class Module нету события onExit (неужели для каждого TextBox его отдельно описывать)?!
3. В событии onExit для каждого элемента приходится подставлять его имя. Разве нельзя как-то сослаться на элемент, на котором сработало событие? (гуглил, не нашёл)
Изменено: Wiss - 07.07.2020 13:37:30
Я не волшебник, я только учусь.
 
Да, событие Exit в классе для ТекстБокса отсутствует. Придётся менять подход.
 
Цитата
Юрий М написал:
Придётся менять подход.
А почему сразу менять?! DblClick через класс, а onExit ручками 30 раз:(  Всё-равно альтернативы не вижу (для формы чего-то типа ActiveElementChange нету, в Class module тоже ничего не подходит)
Я не волшебник, я только учусь.
 
Попытался через модуль класса сделать, но для того что бы убрать цвета с уже подсвеченных пришлось вынести глобальные переменные в отдельный модуль.
Сделал, как понял  :D
Изменено: Nordheim - 07.07.2020 19:25:12
"Все гениальное просто, а все простое гениально!!!"
 
Nordheim, спасибо. Ответили на мой основной вопрос. Видимо, наследование в VBA работает таким странным образом. А вот с "возвратом цвета" бяда осталась прежней. В Вашей версии все текстбоксы возвращаются к начальному состоянию при двойном нажатии на один из них. Если я, например, после двойного клика, один  раз нажму на какой-то другой из них (например, чтобы скопировать данные), то текстбокс всё-ещё останется зелёным (хоть он уже и не активный даже).

Вдохновлённый Вашим кодом, хотел ещё и на onClick поставить not_color, но такого события в VBA нет:)  Неужели придётся писать 30 однотипных, но не идентичных onExit?

Может быть можно как-то ActiveControl найти? Тогда перед выходом можно будет перебирать все элементы формы и блокировать активный (этот).
Я не волшебник, я только учусь.
Страницы: 1
Наверх