2017-02-15 2 views
2

ПредысторияЭкземпляр формы Excel-VBA открывается с ошибкой, если она была закрыта из правого верхнего красного `x`

Я прочитал лучшие практики для создания формы, в отношении того факта, что всегда следует обращаться к объекту формы, а не к самой форме. Таким образом, я решил построить для меня форму котельной.

Проблема

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

enter image description here

Ошибка на objPresenter.Show (см код ниже). Очевидно, что он не входит в if выше. Но проблема в том, что закрытие с X не работает нормально. Когда я закрываю форму с кнопки End, все работает. И даже, если я скопирую код для закрытия с btnEnd на UserForm_QueryClose, он все равно не работает.

Форма

Таким образом, у меня есть modMain, frmMain и clsSummaryPresenter, которые все заботиться о форме. Я начинаю код из modMain

Моей формы выглядит следующим образом:

enter image description here

имеет btnRun, btnExit, lblInfo. Название класса: frmMain.

Код

В frmMain:

Option Explicit 

Public Event OnRunReport() 
Public Event OnExit() 

Public Property Get InformationText() As String 

    InformationText = lblInfo.Caption 

End Property 

Public Property Let InformationText(ByVal value As String) 

    lblInfo.Caption = value 

End Property 

Public Property Get InformationCaption() As String 

    InformationCaption = Caption 

End Property 

Public Property Let InformationCaption(ByVal value As String) 

    Caption = value 

End Property 

Private Sub btnRun_Click() 

    RaiseEvent OnRunReport 

End Sub 

Private Sub btnExit_Click() 

    RaiseEvent OnExit 

End Sub 

Private Sub UserForm_QueryClose(CloseMode As Integer, Cancel As Integer) 

    If CloseMode = vbFormControlMenu Then 
     Cancel = True 
     Hide 
     'Even if I change the two lines above with this the error happens: 
     'RaiseEvent OnExit 
     'However, if I simply write END in stead of those two lines 
     'anything works quite ok... 
     'but that is a bit brutal. 

    End If 

End Sub 

В clsSummaryPresenter

Option Explicit 

Private WithEvents objSummaryForm As frmMain 

Private Sub Class_Initialize() 

    Set objSummaryForm = New frmMain 

End Sub 

Private Sub Class_Terminate() 

    Set objSummaryForm = Nothing 

End Sub 

Public Sub Show() 

    If Not objSummaryForm.Visible Then 
     objSummaryForm.Show vbModeless 
     Call ChangeLabelAndCaption("Press Run to Start", "Starting") 
    End If 

    With objSummaryForm 
     .Top = CLng((Application.Height/2 + Application.Top) - .Height/2) 
     .Left = CLng((Application.Width/2 + Application.Left) - .Width/2) 
    End With 

End Sub 

Public Sub Hide() 

    If objSummaryForm.Visible Then objSummaryForm.Hide 

End Sub 

Public Sub ChangeLabelAndCaption(strLabelInfo As String, strCaption As String) 

    objSummaryForm.InformationText = strLabelInfo 
    objSummaryForm.InformationCaption = strCaption 
    objSummaryForm.Repaint 

End Sub 

Private Sub objSummaryForm_OnRunReport() 

    MainGenerateReport 
    Refresh 

End Sub 

Private Sub objSummaryForm_OnExit() 

    Hide 

End Sub 

Public Sub Refresh() 

    With objSummaryForm 
     .lblInfo = "Ready" 
     .Caption = "Task performed" 
    End With 

End Sub 

modMain В

Option Explicit 

Private objPresenter As clsSummaryPresenter 

Public Sub MainGenerateReport() 

    objPresenter.ChangeLabelAndCaption "Starting and running...", "Running..." 
    GenerateNumbers 

End Sub 

Public Sub GenerateNumbers() 

    Dim lngLong   As Long 
    Dim lngLong2  As Long 

    tblMain.Cells.Clear 

    For lngLong = 1 To 4 
     For lngLong2 = 1 To 1 
      tblMain.Cells(lngLong, lngLong2) = lngLong * lngLong2 
     Next lngLong2 
    Next lngLong 

End Sub 

Public Sub ShowMainForm() 

    If (objPresenter Is Nothing) Then 
     Set objPresenter = New clsSummaryPresenter 
    End If 

    objPresenter.Show 

End Sub 

Вопрос

Еще раз, почему я не могу закрыть форму с красным X? Я могу заменить код UserForm_QueryClose на End, но это немного жестоко. Есть идеи?

+0

Я видел эту ошибку, когда люди имеют версии Excel старше и пытаются работать в Win7 или новее. Я считаю, что это связано с тем, как вызывается вызываемый пользовательский формуляр. UserForm1.Show (или аналогичный) должен быть так, как вызывается UserForm. Все остальное в новых версиях Excel, как известно, дает ошибку 80010007. – Cyril

+0

Не уверен, что дает, но что-то не так. Если вы удалите код Скрыть из события Queryclose, форма все равно будет закрыта. – jkpieterse

+0

@ Кирилл: Никогда не слышал об этом. Я всегда вызываю userforms с помощью переменных объекта, никогда не испытываю проблем, как вы предлагаете. В любой версии Excel начиная с '97 до 2016 года включительно. – jkpieterse

ответ

3

Изменение режима форме от vbModeless к vbModal дает более раннюю и более информативную недостаточность:

run-time error: "automation error; connection to type library or object library for remote process has been lost."

Проблема похоже, потому что назначение Cancel = True в обработчике QueryClose не работает по какой-либо причине.

Подпись для QueryClose обработчика выглядит следующим образом:

Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer) 

Твое:

Private Sub UserForm_QueryClose(CloseMode As Integer, Cancel As Integer) 

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

QueryClose event in the dropdown

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

VBA действительно не заботится об именах параметров в обработчиках: способ совпадения времени выполнения с обработчиком заключается в сопоставлении индексов параметров и их типов с ожидаемыми. Поскольку оба параметра QueryClose являются значениями Integer, инвертирование их компилируется просто отлично - за исключением случаев, когда вы устанавливаете Cancel = True, то, что видит во время выполнения, является то, что вы назначили CloseMode = -1и оставили только параметр Cancel.

Это означает, что ваша форма не отменяет ее закрытие, и, таким образом, объект уничтожается каждый раз.

Инвертировать параметры в вашем обработчике QueryClose, и все работает отлично и точно так, как предполагалось.

+0

Теперь он работает! Перемещение двух целых чисел было действительно тем, что я проигнорировал. – Vityata

+0

И да, использование автоматического 'QueryClose' с правильной подписью должно быть выполнено. – Vityata

+1

@Vityata спасибо за это - [Rubberduck issue # 2695: Проверка несоответствия подписи] (https://github.com/rubberduck-vba/Rubberduck/issues/2695) для захватов! –

-1

Вызов формы, как так прекрасно работает для меня:

Option Explicit 
dim mfrmMain as ufMain 

Sub ShowMainForm2() 
    If ufMain Is Nothing Then 
     Set ufMain = New mfrmMain 
    End If 
    mfrmMain.Show vbModeless 
End Sub 
+0

Можете ли вы поделиться остальной частью кода? Что такое ufMain? Это проект «frmMain»? – Vityata

+1

ufMain - это имя объекта формы desiger в редакторе VBA. – jkpieterse

+2

IMO Этот ответ полностью пропускает точку –

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

  • Нет связанных вопросов^_^