2015-11-09 4 views
1

Я пытаюсь создать пользовательскую форму, посредством которой люди могут размещать столько запросов, сколько захотят, с возможностью удаления запросов, которые они больше не хотят, а также других функций. У меня возникла проблема с удалением динамически создаваемых объектов после того, как функции add-remove-add были использованы в этой последовательности.Excel VBA - динамическая пользовательская форма с добавлением/удалением функциональности объекта

В приведенном ниже коде есть фрагмент объектов, добавленных в форму пользователя, а также изменения размеров в пользовательскую форму и объекты, уже встроенные в пользовательскую форму. Другие определенные части не включены ниже.

Dim RemoveButtonArray() As New Class_RemoveRequest 

For i = Last To Last 
    Set AddRemoveButton = GenPurchaseRequest.Controls.Add("Forms.Image.1", "btnRemove" & ObjID) 
    With AddRemoveButton 
     'properties 
    End With 
    Set AddRemoveLabel = GenPurchaseRequest.Controls.Add("Forms.Label.1", "lblRemove" & ObjID) 
    With AddRemoveLabel 
     'properties 
    End With 
    Set AddRequest = GenPurchaseRequest.Controls.Add("Forms.Frame.1", "Frame" & ObjID) 
    With AddRequest 
     'properties 
     .Caption = "Purchase Request - " & ObjID 
    End With 
    With AddRequestButton 
     .Top = 168 + (126 * i) 
     .Left = 18 
    End With 
    With SubmitButton 
     .Top = 168 + (126 * i) 
     .Left = 200 
    End With 
    With CancelButton 
     .Top = 168 + (126 * i) 
     .Left = 381 
    End With 
    With GenPurchaseRequest 
     .ScrollHeight = 200 + (126 * i) 
     .ScrollTop = 200 + (126 * i) 
    End With 
ReDim Preserve RemoveButtonArray(0 To i) 
Set RemoveButtonArray(i).RemoveButton = AddRemoveButton 
Next i 

ObjID = ObjID + 1 
Last = Last + 1 

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

Public WithEvents RemoveButton As MSForms.Image 

Private Sub RemoveButton_click() 

Dim ConfirmRemoval As Integer 
Dim rbRefNo As String 
Dim rbRefNoConvert As Integer 

ConfirmRemoval = MsgBox("Are you sure you would like to remove this request?", vbYesNo) 

If ConfirmRemoval = vbYes Then 
rbRefNo = Mid(Me.RemoveButton.Name, 10) 
rbRefNoConvert = CInt(rbRefNo) 
    With GenPurchaseRequest 
     If Last > 1 Then 
     .Controls.Remove ("Frame" & rbRefNo) 
     .Controls.Remove ("btnRemove" & rbRefNo) 
     .Controls.Remove ("lblRemove" & rbRefNo) 

      For i = rbRefNoConvert + 1 To Last - 1 
      .Controls("Frame" & i).Top = .Controls("Frame" & i).Top - 126 
      .Controls("btnRemove" & i).Top = .Controls("btnRemove" & i).Top - 126 
      .Controls("lblRemove" & i).Top = .Controls("lblRemove" & i).Top - 126 
      Next i 

     .AddRequestButton.Top = .AddRequestButton.Top - 126 
     .SubmitButton.Top = .SubmitButton.Top - 126 
     .CancelButton.Top = .CancelButton.Top - 126 
     .ScrollTop = .ScrollTop - 126 
     .ScrollHeight = .ScrollHeight - 126 

     Last = Last - 1 

     Else 
     MsgBox "There is only one active Purchase Request." 
     End If 
    End With 
Else 
'do nothing 
End If 

End Sub 

Пользователь затем может вернуться добавить дополнительные запросы, а также удалить больше запросов, что они больше не хотят. Проблема возникает, когда они добавляют больше запросов, а затем пытаются удалить последний, добавленный непосредственно после удаления. Например: я добавил 4 запроса, а затем удалил второй. Затем я добавил другой запрос, но хотел удалить 4-й запрос, однако кнопка удаления больше не работает.

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

For j = 0 To Last 
If j = rbRefNoConvert Then 
j = j + 1 
Else 
ReDim RemoveButtonArray(0 To j) 
Set RemoveButtonArray(j).RemoveButton = AddRemoveButton 
End If 
Next j 

Но это ссылка на объект неправильно, и я не знаю, как ссылаться на него правильно. Я попытался обратиться к самому контролю, но это не сработало.

Я очень новичок в использовании модулей классов, массивов и динамических пользовательских форм, поэтому извините за длительный вопрос!

Любая помощь будет очень признательна!

+1

Там много кода, поэтому сложно точно выяснить, что происходит. Более простой пример, используя только массив кнопок, вероятно, будет легче следовать. Вместо повторной организации массива всякий раз, когда заказ удаляется, вы можете просто установить этот элемент в массиве Nothing, а затем добавить любые новые порядки в конец массива (расширяя по мере необходимости). Чтобы перестроить компоновку формы, просто перейдем к массиву, игнорируя «пустые» элементы. –

+0

[Этот ответ] (http://stackoverflow.com/a/7000798/1698517), который показывает, как удалить элемент из массива, может оказаться полезным. – Jaycal

+0

@TimWilliams - Единственные элементы управления, которые я использую с массивами, будут элементами управления, которым нужен обработчик событий. Используя ваш пример, мне нужно будет поместить все мои элементы управления в отдельные массивы? –

ответ

0

Я пытался несколько вещей:

(1) Установка ссылки на элемент управления, я хотел, чтобы удалить как ничто в массиве.

(2) Добавление элементов управления в коллекцию, а не в динамический массив.

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

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

Public WithEvents RemoveButton As MSForms.Image 

Private Sub RemoveButton_click() 

'Defines appropriate variables 
Dim ConfirmRemoval As Integer 
Dim rbRefNo As String 
Dim rbRefNoConvert As Integer 

'Asks user for input to remove a control 
ConfirmRemoval = MsgBox("Are you sure you would like to remove this request?", vbYesNo) 

If ConfirmRemoval = vbYes Then 
'Extracts the name identifier from the control to be removed and also converts it into a number 
rbRefNo = Mid(Me.RemoveButton.Name, 10) 
rbRefNoConvert = CInt(rbRefNo) 
With GenPurchaseRequest 
    If ObjID > 1 Then 
     'Loops through the dynamic form controls and adjusts the user-inputs to account for the removed control 
     For i = rbRefNoConvert To ObjID - 1 
      If i < (ObjID - 1) Then 
       .Controls("txtVendor" & i).Text = .Controls("txtVendor" & i + 1).Text 
       .Controls("txtItem" & i).Text = .Controls("txtItem" & i + 1).Text 
       .Controls("txtQuantity" & i).Text = .Controls("txtQuantity" & i + 1).Text 
       .Controls("txtProject" & i).Value = .Controls("txtProject" & i + 1).Value 
       .Controls("txtCatalog" & i).Text = .Controls("txtCatalog" & i + 1).Text 
       .Controls("txtDate" & i).Value = .Controls("txtDate" & i + 1).Value 
      Else 
       .Controls("txtVendor" & i).Text = .Controls("txtVendor" & i).Text 
       .Controls("txtItem" & i).Text = .Controls("txtItem" & i).Text 
       .Controls("txtQuantity" & i).Text = .Controls("txtQuantity" & i).Text 
       .Controls("txtProject" & i).Value = .Controls("txtProject" & i).Value 
       .Controls("txtCatalog" & i).Text = .Controls("txtCatalog" & i).Text 
       .Controls("txtDate" & i).Value = .Controls("txtDate" & i).Value 
      End If 
     Next i 
     'Removes selected remove button and associated form controls 
     .Controls.Remove ("Frame" & ObjID - 1) 
     .Controls.Remove ("AddRequestOptions" & ObjID - 1) 
     'Re-formats userform to adjust for removed controls 
     .AddRequestButton.Top = .AddRequestButton.Top - 126 
     .CopyRequestButton.Top = .CopyRequestButton.Top - 126 
     .SubmitButton.Top = .SubmitButton.Top - 126 
     .CancelButton.Top = .CancelButton.Top - 126 
     .ScrollTop = .ScrollTop - 126 
     .ScrollHeight = .ScrollHeight - 126 
     'Adjusts the object identifier variable to account for removed control 
     ObjID = ObjID - 1 
    Else 
     MsgBox "There is only one active Purchase Request." 
    End If 
End With 
Else 
'do nothing 
End If 

End Sub 
Смежные вопросы