Есть форма с полями, связанными с некоторой таблицей. На BeforeUpdate полей висят проверки корректности введенных данных. Unload формы контролирует правильность логического заполнения записи в целом (все ли занесено).
Надо сделать так, что если пользователь что-то не то или не до конца ввел, а затем закрыл форму (нажал крестик), то никакие мои таблички не вылетали бы, а форма бы закрылась с отменой изменений последней записи (Undo). Ну, или с вопросом о закрытии или продолжении корректировкии.
А для этого надо как-то поймать сообщение форме на закрытие, до того, как форма пошлет полям потерю фокуса, изменения и пр., а так же перейдет к выгрузке записи в таблицу. Тогда я и успею сделать Undo.
Как это можно осуществить?
Спасибо за ответы.
Access, как отловить запрос на закрытие формы?
Модератор: Naeel Maqsudov
- Naeel Maqsudov
- Сообщения: 2570
- Зарегистрирован: 20 фев 2004, 19:17
- Откуда: Moscow, Russia
- Контактная информация:
Во первых посмотрите, не достаточно ли Вам свойства "Условие на значение" в полях таблиц, а также у самОй таблицы (что позволяет вести проверку записи).
Везде ли вы использовали свойство "Обязательное поле"
Т.е. проверьте все ли стандартные средства для этих проверок (позволяющих не прибегать к программированию Вы использовали?
Ну а обработка закрытия формы это конечно же Form_Close!
Еще не забывайте, что не только у полей, но и у самой формы есть BeforeUpdate, которое вызывается как раз перед сохранением измененной записи в таблицу. Так что по идее достаточно написать только обработчик Form_BeforeUpdate и не делать никаких Undo, а просто напросто делать Cancel=true
В этом случае Access НЕ ПУСТИТ пользователя в другую запись, пока тот не сделает все как надо в это. А при закрытии либо все будет проходить нормально, либо форма будет закрываться с сообщением типа "Невозможно сохранение в данный момент". (Закрываться с потерей недовведенных данных разумеется).
Везде ли вы использовали свойство "Обязательное поле"
Т.е. проверьте все ли стандартные средства для этих проверок (позволяющих не прибегать к программированию Вы использовали?
Ну а обработка закрытия формы это конечно же Form_Close!
Еще не забывайте, что не только у полей, но и у самой формы есть BeforeUpdate, которое вызывается как раз перед сохранением измененной записи в таблицу. Так что по идее достаточно написать только обработчик Form_BeforeUpdate и не делать никаких Undo, а просто напросто делать Cancel=true
В этом случае Access НЕ ПУСТИТ пользователя в другую запись, пока тот не сделает все как надо в это. А при закрытии либо все будет проходить нормально, либо форма будет закрываться с сообщением типа "Невозможно сохранение в данный момент". (Закрываться с потерей недовведенных данных разумеется).
Вся беда в том, что в Windows события возникают нормально. Сначала запрос на закрытие формы. Затем уже форма посылает сообщения своим элементам на BeforeUpdate, AfterUpdate и т.д. А потом, после их обработки, переходит обратно на свой Unload и Close.
Если по справке VBA полазить, то там есть такой обработчик, как Private Sub UserForm_QueryClose(cancel As Integer, closemode As Integer). Т.е., с его помощью можно отловить (и отменить) именно запрос на закрытие фомы, еще до того, как форма начнет сворачивать свои элементы.
Но в Access, кажись, ничего такого нет. Т.е., вся цепочка событий, от нажатия пользователем крестика, до вызова BeforeUpdate проходит незаметно. И BeforeUpdate - есть первое событие, которое возникает, как при переходе к другой записи, так и при попытке закрытия формы. Т.о., ну никак не получается различить, чем было вызвано BeforeUpdate - сменой записи, или закрытием формы. Тоже относится и к BeforeUpdate поля. Оно возникает еще раньше BeforeUpdate формы при ее закрытии.
Когда форма отображена как форма, то вопрос частично решается заменой стандартных кнопок навигации (влево/вправо + занести изменения) на свои. А в них уже прописывается проверка ошибок и фиксация изменений. Если же BeforeUpdate возникает, минуя кнопки, т.е., когда пользователь нажимакет крестик, то делается автоматическое Undo.
Но вот когда форма отображена как таблица, внутри другой формы, то это уже хуже. Ведь сменить строку - перейти к другой записи, пользователь может и мышью и клавиатурой. И BeforeUpdate будет первым возникшем при этом событием (еще до Current и прочих). И это BeforeUpdate, когда надо показывать табличку о некорректных данных записи, никак не отличить от BeforeUpdate, вызванном попыткой закрытия формы, когда надо либо отменять изменения и закрывать, либо показывать другую табличку с запросом о выходе или продолжении редактирования.
Пробовал сделать например так: OnDirty формы блокирует крестик и прочие возможности выхода. BeforeUpdate производит проверку логической правильности данных записи. Current или AfterUpdate восстанавливает крестик. Т.о., когда пользователь уже начал что-то вводить в поля записи, форму закрыть нельзя. Лишь после перехода к новой записи, естественно с проверкой по BeforeUpdate, возможность закрытия формы восстанавливается.
Но тут есть два неприятных моментя. Во-первых, не всякий пользователь правильно поймет данную идею, и вполне может запаниковать, когда крестик заблокируется, и будут постянно выскакивать таблички о необходимости корректировки данных. Конечно, будет предусмотрен выбор между продолжением коррекции или отменой, но, опять, нервы пользователя будут изредно подерганы.
А, во-вторых, ну не блокируется этот крестик. Другой элемент заблокировать можно, кнопку, например, через Enable. А вот CloseButton ничего присвоить не удается в ходе выполнения программы (Ошибка 2448 - невозможно присвоить значение объекту). Только прочитать. Хотя, в справке данное свойство описано как Read/Write.
Если по справке VBA полазить, то там есть такой обработчик, как Private Sub UserForm_QueryClose(cancel As Integer, closemode As Integer). Т.е., с его помощью можно отловить (и отменить) именно запрос на закрытие фомы, еще до того, как форма начнет сворачивать свои элементы.
Но в Access, кажись, ничего такого нет. Т.е., вся цепочка событий, от нажатия пользователем крестика, до вызова BeforeUpdate проходит незаметно. И BeforeUpdate - есть первое событие, которое возникает, как при переходе к другой записи, так и при попытке закрытия формы. Т.о., ну никак не получается различить, чем было вызвано BeforeUpdate - сменой записи, или закрытием формы. Тоже относится и к BeforeUpdate поля. Оно возникает еще раньше BeforeUpdate формы при ее закрытии.
Когда форма отображена как форма, то вопрос частично решается заменой стандартных кнопок навигации (влево/вправо + занести изменения) на свои. А в них уже прописывается проверка ошибок и фиксация изменений. Если же BeforeUpdate возникает, минуя кнопки, т.е., когда пользователь нажимакет крестик, то делается автоматическое Undo.
Но вот когда форма отображена как таблица, внутри другой формы, то это уже хуже. Ведь сменить строку - перейти к другой записи, пользователь может и мышью и клавиатурой. И BeforeUpdate будет первым возникшем при этом событием (еще до Current и прочих). И это BeforeUpdate, когда надо показывать табличку о некорректных данных записи, никак не отличить от BeforeUpdate, вызванном попыткой закрытия формы, когда надо либо отменять изменения и закрывать, либо показывать другую табличку с запросом о выходе или продолжении редактирования.
Пробовал сделать например так: OnDirty формы блокирует крестик и прочие возможности выхода. BeforeUpdate производит проверку логической правильности данных записи. Current или AfterUpdate восстанавливает крестик. Т.о., когда пользователь уже начал что-то вводить в поля записи, форму закрыть нельзя. Лишь после перехода к новой записи, естественно с проверкой по BeforeUpdate, возможность закрытия формы восстанавливается.
Но тут есть два неприятных моментя. Во-первых, не всякий пользователь правильно поймет данную идею, и вполне может запаниковать, когда крестик заблокируется, и будут постянно выскакивать таблички о необходимости корректировки данных. Конечно, будет предусмотрен выбор между продолжением коррекции или отменой, но, опять, нервы пользователя будут изредно подерганы.
А, во-вторых, ну не блокируется этот крестик. Другой элемент заблокировать можно, кнопку, например, через Enable. А вот CloseButton ничего присвоить не удается в ходе выполнения программы (Ошибка 2448 - невозможно присвоить значение объекту). Только прочитать. Хотя, в справке данное свойство описано как Read/Write.
А если убрать крестик закрытия окна и все операции с формой осуществлять через кнопки?
Сейчас так и сделал. Только вот конечным пользователям неудобно - по инерции все равно тычут в крестик.
А вообще, научился я все-таки через WinAPI SetWindowLong свой обработчик оконной функции устанавливать. Неудобство лишь в том, что данную возможность можно лишь перед самой компиляцией включать. Иначе IDE VBA виснет.
А вообще, научился я все-таки через WinAPI SetWindowLong свой обработчик оконной функции устанавливать. Неудобство лишь в том, что данную возможность можно лишь перед самой компиляцией включать. Иначе IDE VBA виснет.