Excel это не сложно

Основные форумы => Вопросы по Word и VBA => Тема начата: evgchud от 25.02.2018, 17:07:21



Название: Динамическое создание пользовательской формы
Отправлено: evgchud от 25.02.2018, 17:07:21
Возникла необходимость создать форму не вручную, используя встроенный редактор, а программно, в зависимости от внешних условий. Нашел пример как можно создать форму, поместить на нее заданное количество текстовых полей и кнопку. А также указать обработчики событий для каждого элемента.
Т.е. сначала программно добавляется в проект форма, затем на эту форму добавляются компоненты, далее компоненты связываются с событиями. В проекте создается три модуля: обычный программный модуль и два модуля класса. В одном модуле класса определяются коллекции, в которые добавляются компоненты по мере их добавления на форму. Второй класс будет отвечать за события, происходящие с компонентами.

Программный модуль:
Код: (vb)

    1 Option Explicit
    2 Dim COF As ControlsOnForm, EOC As EventsOfControls
    3
    4 Sub CreateForm(NumberOfTextBoxes As Integer)
    5 'Добавляем пустую форму и код процедуры, которая выполняется при запуске формы
    6 Dim oNewForm 'Новая форма
    7 Dim sCode 'Переменная для хранения кода формы
    8 '  Application.VBE.MainWindow.Visible = False
    9 'Создаем форму
   10 Set oNewForm = ThisDocument.VBProject.VBComponents.Add(3) 'vbext_ct_MSForm
   11 'Добавляем конструкторы классов для событий формы
   12 sCode = ""
   13 'Создаем процедуру инициализации формы
   14 sCode = sCode & "Sub UserForm_Initialize()" & vbCrLf
   15 sCode = sCode & vbTab & "GetControlsForForm Me, " & NumberOfTextBoxes & vbCrLf
   16 '  sCode = sCode & vbTab & "UpdateControls" & vbCrLf
   17 sCode = sCode & "End Sub" & vbCrLf
   18 'Вставляем код формы
   19 oNewForm.CodeModule.InsertLines oNewForm.CodeModule.CountOfLines + 1, sCode
   20 'Показываем форму
   21 VBA.UserForms.Add(oNewForm.Name).Show
   22 'Удаляем форму из рабочей книги
   23 ThisDocument.VBProject.VBComponents.Remove oNewForm
   24
   25 End Sub
   26 'Процедура, создающая указанное количество текстовых полей на указанной форме, и кнопку
   27 Sub GetControlsForForm(ByVal oForm As Object, ByVal NumberOfTextBoxes As Integer)
   28 'Переменные для объектов на форме
   29 Dim oBtn As MSForms.CommandButton
   30 Dim oTxt As MSForms.TextBox
   31 'Верхний левый угол компонента
   32 Dim iLeft As Integer, iTop As Integer
   33 'Счетчик
   34 Dim i As Integer
   35 'Максимальный размер формы
   36 Dim iMaxWidth As Integer, iMaxHeight As Integer
   37
   38 'Заполняем форму компонентами
   39 Set COF = New ControlsOnForm
   40 iLeft = 6: iTop = 6 'Верхний левый угол первого текстового поля
   41 For i = 1 To NumberOfTextBoxes
   42 'Создаем кнопку
   43 Set oTxt = oForm.Controls.Add("Forms.TextBox.1", "txtNumber" & i)
   44 With oTxt
   45 .Text = .Name
   46 .Left = iLeft: .Top = iTop
   47 iTop = iTop + .Height
   48 iMaxWidth = iLeft + .Width + 6
   49 iMaxHeight = iTop - .Height + 20
   50 End With
   51 'Связываем текстовое поле с обработчиком событий
   52 Set EOC = New EventsOfControls: Set EOC.TextBoxEv = oTxt
   53 'Добавляем в коллекцию
   54 COF.TextBoxes.Add EOC
   55 Next i
   56 'Теперь добавляем кнопку
   57 Set oBtn = oForm.Controls.Add("Forms.CommandButton.1", "btnTest")
   58 With oBtn
   59 .Caption = "Моя кнопка"
   60 .Left = iLeft
   61 .Top = iTop
   62 iMaxWidth = iLeft + .Width + 6
   63 iMaxHeight = iTop + .Height + 20
   64 End With
   65 'Связываем кнопку с обработчиком событий
   66 Set EOC = New EventsOfControls: Set EOC.ButtonEv = oBtn
   67 'Добавляем в коллекцию
   68 COF.Buttons.Add EOC
   69 'Подгоняем размеры формы
   70 oForm.Height = iMaxHeight: oForm.Width = iMaxWidth
   71 End Sub
   72
   73 'Основная процедура, запускающая весь процесс
   74 Sub СоздатьФорму()
   75 Dim TBCount As Integer
   76 Dim sInput As String
   77 Do
   78 sInput = InputBox("Введите число нужных текстовых полей", "Динамическое создание формы", 5)
   79 If Len(sInput) = 0 Then Exit Sub 'Если ничего не ввели, или нажали отмену
   80 'Если ввели не число, предлагаем ввод еще раз
   81 If IsNumeric(sInput) Then TBCount = CInt(sInput) Else sInput = ""
   82 Loop Until Len(sInput) > 0
   83 CreateForm (TBCount)
   84 End Sub


Модуль класса 1:
Код: (vb)

    1 Option Explicit
    2 'Класс, для хранения в коллекциях элементов формы
    3 Public Buttons As New Collection
    4 Public TextBoxes As New Collection

Модуль класса 2:
Код: (vb)

    1 Option Explicit
    2 'Этот класс содержит в себе обработчики событий для различных элементов формы
    3 'Элемент, ответсвтвенный за обработку событий в текстовом поле
    4 Public WithEvents TextBoxEv As MSForms.TextBox
    5 'Обработчик событий кнопки
    6 Public WithEvents ButtonEv As MSForms.CommandButton
    7
    8 Private Sub ButtonEv_Click()
    9   Dim oForm As Object
   10   Set oForm = Me.ButtonEv.Parent
   11   MsgBox "Вы кликнули на кнопке " & Me.ButtonEv.Name & vbCr & _
   12     "На форме расположено " & Me.ButtonEv.Parent.Controls.Count - 1 & " текстовых полей", vbInformation, _
   13     "Динамическое создание формы"
   14 End Sub
   15 'Обработчик двойного нажатия в текстовом поле
   16 Private Sub TextBoxEv_DblClick(ByVal Cancel As MSForms.ReturnBoolean)
   17   MsgBox "Вы дважды кликнули мышкой в текстовом поле " & Me.TextBoxEv.Name & "!", vbInformation, _
   18     "Динамическое создание формы"
   19 End Sub


При запуске ругается на отсутствие объявления пользовательских типов ControlsOnForm, EventsOfControls.
Пожалуйста, помогите довести скрипт до работоспособного состояния.


Название: Re:Динамическое создание пользовательской формы
Отправлено: Дмитрий Щербаков(The_Prist) от 25.02.2018, 19:52:33
В таком виде это невозможно сделать наверняка. Вместо голых листингов приложите файла. Пока только одна догадка: модули класса у Вас не ControlsOnForm и EventsOfControls, а стандартно: Class1 и Class2.