#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 / orTerminate
, если они у вас есть. Я думаю, вы делаете это излишне сложным, пытаясь реплицировать встроенный обработчик событий с помощью кнопки.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
incancel_button_Click
выполняет выполнение блокаQueryClose
кода и переходит вTerminate
(который находится прямо под ним), затем обратно кcancel_button_Click
, в конечном итоге пробиваясь через триExit Sub
команды!4. На самом деле не имеет значения, есть ли у вас эти процедуры… не зная, что в них, я не могу вам помочь. Что в них ? Избавьтесь от
Application.QUit
обработчика нажатия кнопки, как я предлагал выше. Полностью избавьтесь от него в этой процедуре. И поместите его вTerminate
обработчик. Вы можете избавиться отQueryClose
события, если вы активно не используете его для некоторых других проверок.5. Кстати: «прорыв»
Exit Sub
? Что еще вы ожидаете от него?Exit Sub
просто завершает текущую процедуру и возвращается к вызывающей процедуре, если таковая имеется.