Как использовать коллекцию Controls в Access 2003 и VBA - PullRequest
1 голос
/ 17 декабря 2009

У меня чертовски много времени, чтобы понять это.

Я хочу передать коллекцию Controls в функцию, но получаю несоответствие типов. Вот объявление функции:

Public Function DoStuffToCollection(topCtlList As Controls, isLocked As Boolean)

А вот как я это называю:

Call DoStuffToCollection(myPage.Controls, isLocked)

myPage - это элемент управления Page из TabControl. Я прошел по коду, чтобы увидеть, есть ли что-то в myPage.Controls и есть ли.

Ради интереса, я передал Me.Controls (который был бы коллекцией элементов управления формы) вместо myPage.Controls и никакого несоответствия типов. Есть ли разница между коллекцией элементов управления Form и коллекцией элементов управления Page? Это сводит меня с ума.

Немного больше копания, отладчик вызывает myPage.Controls Children / Children как тип и Me.Controls как Controls / Controls как тип. Почему это?

[Изменить] Просто добавив немного информации. doStuffToCollection - это функция, которая возвращает только блокированные связанные поля и отключает любые виды кнопок в элементе управления вкладками. Ранее мне просто удавалось заблокировать его на уровне страницы, но затем я добавил страницу с кнопкой. Кнопка не отключилась со страницей. Я знаю об этом http://allenbrowne.com/ser-56.html. Мне не удалось адаптировать его к моим потребностям.

Ответы [ 4 ]

3 голосов
/ 19 декабря 2009

@ Предложение Тима Лентина очень хорошее и, по-моему, прямо отвечает на ваш вопрос.

Но я бы, наверное, никогда не написал подпрограмму, которая оперирует всей коллекцией элементов управления формы. Причина в том, что это на самом деле довольно неэффективно. Но будет ли это уместно, зависит от того, как часто и когда вы ходите по этой коллекции.

Если вы проходите его один раз в событии OnLoad формы (вы не захотите делать это в OnOpen, потому что привязанные к данным свойства элементов управления не обязательно будут полностью инициализированы в этот момент - вы хотя он все еще может работать со свойствами формата - но все готово к работе к моменту запуска события OnLoad), в этом нет ничего особенного, и передача этой коллекции во внешнюю подпрограмму была бы уместной.

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

По сути, вы инициализируете коллекцию в событии OnLoad формы. Обычно я пишу частную подпрограмму, чтобы сделать это, чтобы я мог повторно инициализировать, если произойдет сброс кода:

  Private Sub SetupCollections()
    If mcolCriteria.Count = 0 Then
       Call PopulateCollections(Me, mcolCriteria, "Criteria")
    End If
  End Sub

  Public Sub PopulateCollections(frm As Form, pcol As Collection, strTag As String)
    Dim ctl As Control

    For Each ctl In frm.Controls
      If ctl.Tag = strTag Then
         pcol.Add ctl, ctl.Name
      End If
    Next ctl
    Set ctl = Nothing
  End Sub

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

  Public Sub PopulateCollections(frm As Form, pcol As Collection, intControlType As AcControlType)
    Dim ctl As Control

    For Each ctl In frm.Controls
      If ctl.ControlType = intControlType
         pcol.Add ctl, ctl.Name
      End If
    Next ctl
    Set ctl = Nothing
  End Sub

Чтобы использовать это, вы можете, например, создать коллекцию элементов управления Nullable, например:

  If mcolControlsNullable.Count = 0 Then
     Call PopulateCollections(Me, mcolControlsNullable, acTextBox)
     Call PopulateCollections(Me, mcolControlsNullable, acComboBox)
     Call PopulateCollections(Me, mcolControlsNullable, acListBox)
   End If

Для логических элементов управления:

  If mcolControlsBoolean.Count = 0 Then
     Call PopulateCollections(Me, mcolControlsBoolean, acCheckBox)
  End If

Для групп параметров или других элементов управления, имеющих значение по умолчанию:

  If mcolControlsWithDefaults.Count = 0 Then
     Call PopulateCollectionsWithDefaults(Me, mcolControlsWithDefaults, acTextBox)
     Call PopulateCollectionsWithDefaults(Me, mcolControlsWithDefaults, acComboBox)
     Call PopulateCollectionsWithDefaults(Me, mcolControlsWithDefaults, acListBox)
     Call PopulateCollectionsWithDefaults(Me, mcolControlsWithDefaults, acCheckBox)
     Call PopulateCollectionsWithDefaults(Me, mcolControlsWithDefaults, acOptionGroup)
  End If

  Public Sub PopulateCollectionsWithDefaults(frm As Form, pcol As Collection)
    Dim ctl As Control

    For Each ctl In frm.Controls
      If Len(ctl.DefaultValue) > 0 Then
         pcol.Add ctl, ctl.Name
      End If
    Next ctl
    Set ctl = Nothing
  End Sub

  Private Sub SetControlValuesFromDefaults(pcol As Collection)
    For Each ctl in pcol 
      ctl = ctl.DefaultValue
    Next ctl 
  End Sub

А для других коллекций:

  Public Sub SetControlValues(pcol As Collection, varValue As Variant)
    For Each ctl in pcol
      ctl = varValue
    Next ctl
  End Sub

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

  Private Sub SetupCollections()
    If mcolControlsNullable.Count = 0 Then
       Call PopulateCollections(Me, mcolControlsNullable, acTextBox)
       Call PopulateCollections(Me, mcolControlsNullable, acComboBox)
       Call PopulateCollections(Me, mcolControlsNullable, acListBox)
     End If
    If mcolControlsBoolean.Count = 0 Then
       Call PopulateCollections(Me, mcolControlsBoolean, acCheckBox)
    End If
    If mcolControlsWithDefaults.Count = 0 Then
       Call PopulateCollectionsWithDefaults(Me, mcolControlsWithDefaults, acTextBox)
       Call PopulateCollectionsWithDefaults(Me, mcolControlsWithDefaults, acComboBox)
       Call PopulateCollectionsWithDefaults(Me, mcolControlsWithDefaults, acListBox)
       Call PopulateCollectionsWithDefaults(Me, mcolControlsWithDefaults, acCheckBox)
       Call PopulateCollectionsWithDefaults(Me, mcolControlsWithDefaults, acOptionGroup)
    End If
  End Sub

... тогда вы хотите, чтобы подпрограмма инициализировала управляющие значения:

  Private Sub InitializeControls()
    Call SetControlValues(mcolControlsNullable, Null)
    Call SetControlValues(mcolControlsBoolean, False)
    Call SetControlValuesFromDefaults(mcolControlsWithDefaults)
  End Sub

... чтобы потом можно было все настроить в событии OnLoad формы:

  Call SetupCollections()
  Call InitializeControls()

Теперь, конечно, есть менее запутанные способы сделать это. Возможно, вы захотите, чтобы ваша процедура инициализации прошла один раз по коллекции элементов управления:

  Private Sub SetupCollections()
    Dim ctl As Control

    For Each ctl in Me.Controls
      If Len(ctl.DefaultValue) > 0 then
         mcolControlsWithDefaults.Add ctl, ctl.Name
      Else
         Select Case ctl.ControlType
           Case acTextBox, acComboBox, acListBox
             mcolControlsNullable.Add ctl, ctl.Name
           Case acCheckBox
             mcolControlsBoolean.Add ctl, ctl.Name
         End Select
      End If
    Next ctl
    Set ctl = Nothing
  End Sub

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

  Private Property Get colControlsNullable() As Collection
    Static colNullable As Collection

    If colNullable.Count = 0 Then
       Call PopulateCollections(Me, mcolControlsNullable, acTextBox)
       Call PopulateCollections(Me, mcolControlsNullable, acComboBox)
       Call PopulateCollections(Me, mcolControlsNullable, acListBox)       
    End If
    Set colControlsNullable = colNullable
  End Property

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

Итак, я не использую пользовательские свойства для этих коллекций, даже если бы хотел. С другой стороны, если бы у меня была только одна коллекция пользовательских элементов управления, я бы это сделал.

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

2 голосов
/ 19 декабря 2009

Кажется странным, что вы не можете напрямую передать контрольную коллекцию страницы. Это может быть связано с тем, что сама коллекция Pages является особым типом коллекции элементов управления .

Другой альтернативой может быть объявление параметра "topCtlList" как объекта вместо элементов управления. Это делает код менее читаемым и потенциально более подверженным ошибкам, но должно устранить ошибку несоответствия типов.

Public Function DoStuffToCollection(topCtlList As Object, isLocked As Boolean)
'Debug.Print TypeName(topCtlList)
Dim ctl As Control
For Each ctl In topCtlList
   Debug.Print ctl.Name
Next ctl

End Function
0 голосов
/ 12 января 2010

Сейчас я иду другим путем. В моей вкладке у меня есть только подчиненные формы. Итак, я взял игру из ООП и создал функцию для каждой подчиненной формы с именем EnableForm. Теперь подчиненная форма может обрабатывать все, что ей нужно делать сама. В форме, содержащей элемент управления вкладками, я просто перебираю страницы элемента управления вкладками, проверяю, содержит ли страница подчиненную форму, а затем вызываю функцию EnableForm.

Это чертовски грязно, но работает, и я запишу это в коде. Чего-то не хватало этой вещи (и большинства других БД доступа) с самого начала.

0 голосов
/ 18 декабря 2009

Одной из альтернатив будет передача формы в виде объекта формы с использованием «Я». Очевидно, есть разница, в чем я не уверен.

Также покопайтесь в Page Object в справке. Вы можете передать объект Page.

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