Приложение.Выход из пользовательской формы пытается выполнить остальную часть макроса перед выходом

#vba #excel #userform #quit

#vba #excel #пользовательская форма #ВЫЙТИ

Вопрос:

Мой вопрос: используя VBA в Excel 2013, как я могу корректно закрыть весь экземпляр Excel, когда пользователь решает, что не хочет заполнять пользовательскую форму, и нажимает «Выйти» или «Отменить»?

В настоящее время, если пользователь нажимает «Выйти» или «Отменить», я проверяю, является ли мой экземпляр единственным открытым. Если это не так, я могу использовать ThisWorkbook.Закройте, и я думаю, со мной все будет в порядке. Однако, если это так, я не хочу, чтобы приложение все еще присутствовало, поэтому я использовал Application.Quit. Это, однако, пытается завершить выполнение макроса, выдает ошибки (первоначально «несоответствие типов», потому что я выгружаю форму) и закрывается только после того, как я нажимаю «Debug» или «End» (что он делает так быстро, что я не могу отлаживать).). Пока я игнорирую первый случай и просто пытаюсь выйти из всего приложения. Это очень длинный макрос с множеством подпрограмм и функций, поэтому для отладки и публикации здесь я сократил его. Ошибка несоответствия типов больше не возникает, но я считаю, что это было следствием фактической ошибки: вызывается код, выполняемый после команды закрытия приложения.

Во-первых, вот код, который запускает все:

 Private Sub CommandButton1_Click()

    Call form_variables
    frm_REQUEST.Show
    Call a_REQUEST_main

End Sub
 

Подпрограмма

 form_variables
 

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

 frm_REQUEST.Show
 

инициализирует (включая вызов функции, которая находит другую книгу, извлекает список, выполняет некоторое форматирование, закрывает книгу и вводит список в раскрывающийся список userforms) и показывает форму, и, наконец,

 a_REQUEST_main
 

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

Код, который выполняется, когда .Show вызывается:

 Private Sub UserForm_Initialize()

    ' Get job numbers from other workbook
    Dim job_selection_list As Variant
    job_selection_list = get_job_list()

    With frm_REQUEST.Job_Number_ComboBox
        .List = job_selection_list
    End With

    ' set focus on Job Numbers
    JN_combobox.SetFocus

End Sub

Private Sub cancel_button_Click()

    Set job_selection_list = Nothing

    Unload Me

    Application.Quit

End Sub


Private Sub submit_button_Click()

    ' Values from userform saved as global (?) variables so other subroutines can access.

End Sub
 

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

 Call a_REQUEST_main
 

но на самом деле это должно просто закрыть все. Я попытался выполнить команды «сохранить» и изменить порядок вещей, а также прочитать об объектах, для которых необходимо установить значение nothing (отсюда и настройка job_selection_list, которая создается при инициализации выпадающего списка), но, похоже, я не могу заставить это работать или найти что-нибудь в Интернете. Может кто-нибудь дать некоторые рекомендации или сообщить мне о лучшем способе закрытия экземпляра Excel? Помоги мне, Кеноби, переполнение стека, ты моя единственная надежда!

Спасибо.

Комментарии:

1. Еще один вопрос: зачем беспокоиться о пользовательской кнопке «отмена», когда в пользовательской форме уже есть кнопка отмены, которая запускает процедуру QueryClose and / or Terminate , если они у вас есть. Я думаю, вы делаете это излишне сложным, пытаясь реплицировать встроенный обработчик событий с помощью кнопки.

2. Это, вероятно, звучит неубедительно, но с точки зрения пользовательского интерфейса, я думаю, что моя пользовательская база предпочла бы иметь красивую кнопку с надписью «Отмена», поэтому я добавил ее. Затем отключение функциональности закрытия показалось излишне сложным, поэтому я просто вставил Call cancel_button_Click блок QueryClose кода, но, как я объясню в ответ на ваш комментарий ниже, я не думаю, что что-либо из этого действительно имело значение…

3. QueryClose Обработчик действительно необходим только в том случае, если вам нужно перехватить какое-то условие, которое приведет Terminate к тому, что оно не произойдет. Если у вас нет ничего существенного в этом событии, просто используйте Terminate обработчик сам по себе 🙂

Ответ №1:

Просто добавьте переменную для учета, когда пользователь закрывает форму

в форме

 'hold flag if users cancels form
Public btnCancel As Boolean
Private Sub CommandButton1_Click()
Unload Me
btnCancel = True
End Sub

'set the flag each time the form active
Private Sub UserForm_Activate()
btnCancel = False
End Sub
 

затем в вашем коде

 Call form_variables
frm_REQUEST.Show

If frm_REQUEST.btnCancel Then
    Application.Quit
Else
    Call a_REQUEST_main
End If
 

Комментарии:

1. Спасибо, Волшебники! Я немного изменил ваш код и просто попробовал его. Сработало как шарм.

Ответ №2:

Поместите Application.Quit в обработчик событий формы Terminate вместо обработчика событий кнопки Click .

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

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

Примечание: Вам может быть предложено сохранить / отменить изменения (если таковые имеются) в рабочей книге.

Комментарии:

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

2. Сделайте это вместо того, где оно у вас сейчас есть.

3.Я не включил его в приведенный выше код, потому что он казался слишком длинным, но у меня есть Terminate , QueryClose , и cancel_button_Click все с той же пользовательской формой. Я продолжал пытаться отлаживать после публикации и понял, что Unload Me in cancel_button_Click выполняет выполнение блока QueryClose кода и переходит в Terminate (который находится прямо под ним), затем обратно к cancel_button_Click , в конечном итоге пробиваясь через три Exit Sub команды!

4. На самом деле не имеет значения, есть ли у вас эти процедуры… не зная, что в них, я не могу вам помочь. Что в них ? Избавьтесь от Application.QUit обработчика нажатия кнопки, как я предлагал выше. Полностью избавьтесь от него в этой процедуре. И поместите его в Terminate обработчик. Вы можете избавиться от QueryClose события, если вы активно не используете его для некоторых других проверок.

5. Кстати: «прорыв» Exit Sub ? Что еще вы ожидаете от него? Exit Sub просто завершает текущую процедуру и возвращается к вызывающей процедуре, если таковая имеется.