Использование переменной модуля класса в пользовательской форме (необходим объект «Ошибка 424») - PullRequest
0 голосов
/ 07 февраля 2019

У меня есть модуль класса, в котором размещается подпункт worksheet_change, и в этом подпункте должна появиться пользовательская форма.Я хочу использовать ряд переменных из модуля класса в коде пользовательской формы.Однако что бы я ни делал, я не могу заставить его работать.

Я пытался применить метод из этого очень длинного руководства , но безрезультатно.Другие потоки на SO не смогли мне помочь.

Private cell As Range

Public WithEvents m_wb As Workbook

Property Get cellr() As Range
    Set cellr = cell
End Property

Property Set cellr(cellrange As Range)
    Set cell = cellrange
End Property

Public Property Set Workbook(wb As Workbook)
    Set m_wb = wb
End Property

Public Property Get Workbook() As Workbook
    Set Workbook = m_wb
End Property

Public Sub m_wb_SheetChange(ByVal Sh As Object, ByVal Target As Range) 'simplified, but accurate
    Application.EnableEvents = False

    For each cell in Target
        ReplaceTask.Show
    Next cell

    Application.EnableEvents = True
End Sub

В макросе userform_initialize мне нужно иметь возможность получить имя книги m_wb, а также ячейку (предпочтительно как переменная range, иначе просто адрес) в цикле For each cell in Target.Для каждой переменной в коде ниже я получаю

Ошибка '424' требуется объект

, который показывает, что переменные не являются общедоступными ..

Private Sub UserForm_Initialize()
Debug.Print cellrange.Address
Debug.Print cell.Address
Debug.Print cellr.Address
Debug.Print m_wb.Name
'....

Я уверен, что моя неспособность понять, как работают эти свойства, сдерживает меня .. Если кто-то может пролить свет на то, что я делаю неправильно, пожалуйста!

Ответы [ 2 ]

0 голосов
/ 07 февраля 2019

Форма пользователя и класс с обработчиком событий - две разные области видимости.Вы не можете ожидать, что сможете ссылаться на членов другой области без определения этой области.Код в UserForm_Initialize интерпретирует cellrange и cellr как локальные переменные, объявленные в самой форме пользователя.У вас нет таких переменных, объявленных в пользовательской форме, и вы не используете Option Explicit, поэтому вместо ошибки времени компиляции вы получаете ошибку времени выполнения 424, когда код неявно предполагает, что он Dim cellrange As Variant, который никогда не был инициализирован ипоэтому Empty.

Чтобы устранить проблему, необходимо указать экземпляру пользователя, для какого экземпляра класса обработки событий он должен получить свойства.Для этого было бы достаточно поместить это в UserForm:

Private m_ParentClass As ThatClassThatCreatesForms

Friend Sub Init(ByVal p As ThatClassThatCreatesForms)
  Set m_ParentClass = p
End Sub

и изменить цикл For Each в родительском классе следующим образом:

For each cell in Target
    ReplaceTask.Init Me
    ReplaceTask.Show
Next cell

Вы должны иметь отдельныйМетод "Init", потому что классы VBA не могут иметь конструкторов с параметрами.

Тогда код в ReplaceTask может использовать m_ParentClass.cell, m_ParentClass.Workbook и т. Д. Но вы не можете сделать это из UserForm_Initialize, потому что Initеще не был вызван.Это не проблема, просто переместите код из UserForm_Initialize в Init.


Чтобы сделать это еще на шаг вперед, я бы посоветовал вам прекратить использовать неявную форму экземпляр .Рекомендуется создавать экземпляры вручную:

For each cell in Target
    Dim f As ReplaceTask
    Set f = New ReplaceTask
    f.Init Me
    f.Show
Next cell
0 голосов
/ 07 февраля 2019

Для того, чтобы это работало, ему нужна как минимум публичная переменная объекта типа вашего класса.И эта переменная объекта должна быть установлена, чтобы быть новым экземпляром вашего класса.Тогда эта переменная объекта и только эта переменная объекта являются общедоступным экземпляром вашего класса.

Пример:

Пусть ваш класс будет иметь имя clsWorkbook и иметь следующий код:

Option Explicit

Private m_cell As Range

Private WithEvents m_wb As Workbook

Property Let cell(cellrange As Range)
    Set m_cell = cellrange
End Property

Property Get cell() As Range
    Set cell = m_cell
End Property

Public Property Let Workbook(wb As Workbook)
    Set m_wb = wb
End Property

Public Property Get Workbook() As Workbook
    Set Workbook = m_wb
End Property

Private Sub m_wb_SheetChange(ByVal Sh As Object, ByVal Target As Range) 'simplified, but accurate
    Application.EnableEvents = False

    For Each m_cell In Target
        ReplaceTask.Show
    Next m_cell

    Application.EnableEvents = True
End Sub

Пусть ваша пользовательская форма с именем ReplaceTask имеет следующий код:

Option Explicit

Private Sub UserForm_Initialize()
 Debug.Print oWB.Workbook.Name
 Debug.Print oWB.cell.Address
End Sub

И в модуле по умолчанию есть следующий код:

Option Explicit

Public oWB As clsWorkbook

Public Sub test()
 Set oWB = New clsWorkbook
 oWB.Workbook = ThisWorkbook
End Sub

Теперь, после Sub test()был выполнен, внесите изменения в лист в рабочей книге, в которой находится код. Это должно вызвать Sub m_wb_SheetChange(ByVal Sh As Object, ByVal Target As Range) вашего объекта класса oWB, который показывает форму пользователя, которая также может получить доступ к oWB.Workbook.Name и oWB.cell.Address.


Из-за дискуссии о необходимости глобального экземпляра clsWorkbook давайте приведем полный пример, который можно восстановить и который показывает, как clsWorkbook может быть членом частного класса:

Пусть ваш класс с именем clsWorkbook и имеет следующий код:

Option Explicit

Private m_cell As Range

Private WithEvents m_wb As Workbook

Property Let Cell(cellrange As Range)
    Set m_cell = cellrange
End Property

Property Get Cell() As Range
    Set Cell = m_cell
End Property

Property Let Workbook(wb As Workbook)
    Set m_wb = wb
End Property

Property Get Workbook() As Workbook
    Set Workbook = m_wb
End Property


Private Sub m_wb_SheetChange(ByVal Sh As Object, ByVal Target As Range) 'simplified, but accurate
    Application.EnableEvents = False

    Dim frm As ReplaceTask
    For Each m_cell In Target
        Set frm = New ReplaceTask
        frm.Init Me
        frm.Show
    Next m_cell

    Application.EnableEvents = True
End Sub

Пусть ваша пользовательская форма с именем ReplaceTask имеет следующий код:

Option Explicit

Private m_ParentClass As clsWorkbook

Friend Sub Init(ByVal p As clsWorkbook)
    Set m_ParentClass = p
    Me.Caption = p.Workbook.Name & " : " & p.Cell.Address
End Sub

И в классе по умолчаниюмодуль ThisWorkbook имеет следующиекод:

Option Explicit

Private oWB As clsWorkbook

Private Sub Workbook_Open()
    Set oWB = New clsWorkbook
    oWB.Workbook = Workbooks.Open("P:/Mappe1.xlsx")
End Sub

Теперь экземпляр clsWorkbook создается при открытой книге и является частным членом ThisWorkbook, а его член книги является книгой, которая была открыта дополнительно.Там SheetChange прослушивается экземпляром clsWorkbook oWB.

И поскольку пользовательская форма ReplaceTask создается в clsWorkbook и получает экземпляр класса в качестве параметра, эта пользовательская форма также знает членов класса.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...