kuklp написал: RoMuLX , это еще модеры Вашего никнейма не видели.
Вообще-то модераторы уже видели мой никнейм и даже помогали без всяких замечаний, за что им низкий поклон. Это вы бы могли и сами заметить,если б внимательнее прочли мой пост. Вообще воспринимайте мой никнейм как торговую марку с утвержденным фиксированным регистром уже более 15 лет (нигде проблем не было).
Вы свой-то никнейм видели?!) Это ж бессмысленным набором символов))
Цитата
kuklp написал: И то что Вы вторглись в чужую тему со своим вопросом им тоже вряд ли понравится.
И не вторгся, а продолжил ту же тему. Я наступал на те же грабли, что и описаны выше. Обсуждения в данной теме уже 22 Мар 2017 15:58:53 было закончено, соответственно мой пост не вносит путаницу. Если заметили, уже однажды до меня (22 Мар 2017 12:28:10) тема так же поднималась и ничего, никого не заблокировали за "нарушение".
И вы, наверно, плохо сами прочитали правила форума:
Цитата
3. Запрещено: 3.7. Создавать темы с вопросами, ответы на которые даны в Приемах или прошлых темах форума.
4. Не рекомендуется: 4.5. Самовольное модерирование. Т.е. когда некий участник форума, не являющийся модератором данного форума, делает замечания другим участникам.
Не вижу у вас надписи "модератор"- поэтому либо не флудите\оффтопте, либо помогите.
Я нашел поиском последнюю открытую и продолжил, т.к. в моем случае есть нюансы. И я не пишу как халявщик, я полностью все оформил в соответствии с правилами - описал и дал пример, и даже свой код не до конца правильный выложил. И проблему рваного копирования ячеек мной была решена немного по-другому, но не до конца (только в одну сторону).
Доброй ночи, магистрам VBA!) Моя предыстория тут У меня есть фиксированная таблица(см. пример) защищенные ячейки я удалил из примера, а оставил все ячейки, которые пользователи могут заполнять(незащищенные ячейки), других ячеек для заполнения не появиться. Мне необходимо при открытии файла копировать все незащищенные ячейки с расчетного листа на резервный (для удобства я решил, что ячейки должны иметь те же адрес) - получается рваный диапазон, да еще и объединенные ячейки есть. А перед закрытием файла необходимо обратно копировать из резерва в расчетный лист и удалить значения в резервном листе. Копирование нужно в фоне (не на активных листах)
Поиском оч много тем нашел и перечитал по поводу рваного копирования и для себя решил применить наиболее простой и понятный (некоторые коды еще слишком сложны мне для понимания как их адаптировать под свои нужды):
Код
Public Sub Workbook_Open()
Application.ScreenUpdating = False
Dim a As Range
Dim aa As Range
Set a = Worksheets("1. Расчет расходов").Range("D13:D70")
Set aa = Worksheets("Резерв").Range("D13")
a.Copy
aa.PasteSpecial Paste:=xlPasteValues
Dim b As Range
Dim bb As Range
Set b = Worksheets("1. Расчет расходов").Range("D8")
Set bb = Worksheets("Резерв").Range("D8")
b.Copy
bb.PasteSpecial Paste:=xlPasteValues
Dim c As Range
Dim cc As Range
Set c = Worksheets("1. Расчет расходов").Range("F13:I70")
Set cc = Worksheets("Резерв").Range("F13")
c.Copy
cc.PasteSpecial Paste:=xlPasteValues
Dim d As Range
Dim dd As Range
Set d = Worksheets("1. Расчет расходов").Range("AA13:AA70")
Set dd = Worksheets("Резерв").Range("AA13")
d.Copy
dd.PasteSpecial Paste:=xlPasteValues
Dim e As Range
Dim ee As Range
Set e = Worksheets("1. Расчет расходов").Range("D76:D94")
Set ee = Worksheets("Резерв").Range("D76")
e.Copy
ee.PasteSpecial Paste:=xlPasteValues
Dim f As Range
Dim ff As Range
Set f = Worksheets("1. Расчет расходов").Range("F76:L94")
Set ff = Worksheets("Резерв").Range("F76")
f.Copy
ff.PasteSpecial Paste:=xlPasteValues
Dim g As Range
Dim gg As Range
Set g = Worksheets("1. Расчет расходов").Range("M76:Z94")
Set gg = Worksheets("Резерв").Range("M76")
g.Copy
gg.PasteSpecial Paste:=xlPasteValues
Dim h As Range
Dim hh As Range
Set h = Worksheets("1. Расчет расходов").Range("AA76:AA94")
Set hh = Worksheets("Резерв").Range("AA76")
h.Copy
hh.PasteSpecial Paste:=xlPasteValues
Application.CutCopyMode = False
Application.ScreenUpdating = True
End Sub
Public Sub Workbook_BeforeClose(Cancel As Boolean)
Application.ScreenUpdating = False
aa.Copy << выдает ошибку run-time error '424'
a.PasteSpecial Paste:=xlPasteValues
bb.Copy
b.PasteSpecial Paste:=xlPasteValues
и т.д.
Application.CutCopyMode = False
aa.ClearContents << не очищает диапазон, выдает ошибку
или
bb.Clear << не очищает диапазон, выдает ошибку
и т.д.
Application.ScreenUpdating = True
End Sub
копирование в резерв работает на ура!) а вторая часть кода на возврат и последующее удаление не работает! еще код слишком много места занимает (конечно, гораздо компактнее, чем получилось макрорекордером), но можно ли как-то упростить код? для мох целей это оптимальное решение? Или всё же есть метод копирования всех незащищенных ячеек сразу?
The_Prist написал: В вашем случае оптимально делать просто копию листа на временном листе книги(скрытом). И в нужный момент просто копировать оттуда все ячейки на рабочий лист. И никаких откатов не надо отслеживать.
Спасибо! буду искать нужную тему и пробовать)
Надеюсь у меня получится: у меня в файле 6 вкладок расчетов и в каждой только от 5 до 100 ячеек для заполнения в разных местах листа, остальные ячейки с формулами и защищены паролем от изменений. и еще 6 вкладок сводящих результаты с предыдущих листов.
The_Prist, хорошо, расскажу полную ситуацию) внимание: много букв)) У меня есть инженерный расчетный файл. Он считает таблицы без макросов. А макрос как раз на отслеживание входа из этой темы: http://www.planetaexcel.ru/techniques/5/196/ Но тут проблема, что окошко при выходе не вылезает, да и всегда идет сохранение файла (значит можно что-то по ошибке испортить и выйти).
В итоге у меня форма fmQueryClose на "сохранить" "не сохранять" "отмена".
1. Если жмем "сохранить" - то в реестр добавляется пользователь+дата, потом скрывает все листы, потом идет сейв, потом выход. 2. Если жмем "не сохранять" - то откатывает все изменения, потом скрывает все листы, потом идет сейв, потом выход. 3. Если жмем "отмена" - то просто закрывается форма и ничего больше.
Во всех этих вариантах стандартного диалога при выходе не будет.
и такой код у меня склепался из вышеперечисленных источников:
Код
Private Sub Workbook_Open()
For Each sh In ActiveWorkbook.Worksheets 'отображаем все листы
sh.Visible = True
Next sh
Worksheets("Предупреждение").Visible = xlSheetVeryHidden 'скрываем лист ПРЕДУПРЕЖДЕНИЕ
Worksheets("Реестр изменений").Rows("2:2").Insert Shift:=xlDown 'вставляем между строками 1 и 2 новую строку
Worksheets("Реестр изменений").Rows("1001:1001").Delete Shift:=xlUp 'удаляем строку 1001 (реестр на 1000 строк)
Worksheets("Реестр изменений").Cells(2, 1) = Environ("USERNAME") 'запись в первую ячейку второй строки
Worksheets("Реестр изменений").Cells(2, 2) = Now 'запись во вторую ячейку второй строки
ActiveWorkbook.Save
End Sub
Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
Worksheets("Реестр изменений").Rows("2:2").Insert Shift:=xlDown 'вставляем между строками 1 и 2 новую строку
Worksheets("Реестр изменений").Rows("1001:1001").Delete Shift:=xlUp 'удаляем строку 1001 (реестр на 1000 строк)
Worksheets("Реестр изменений").Cells(2, 1) = Environ("USERNAME") 'запись в первую ячейку второй строки
Worksheets("Реестр изменений").Cells(2, 3) = Now 'запись в третью ячейку второй строки
End Sub
Private Sub Workbook_BeforeClose(Cancel As Boolean)
If Not Me.Saved Then
fmQueryClose.Show
Select Case fmQueryClose.DialogResult
Case VbMsgBoxResult.vbYes: Me.Save
Worksheets("Предупреждение").Visible = True 'скрываем все листы, кроме листа ПРЕДУПРЕЖДЕНИЕ
For Each sh In ActiveWorkbook.Worksheets
If sh.Name = "Предупреждение" Then
sh.Visible = True
Else
sh.Visible = xlSheetVeryHidden
End If
Next sh
ActiveWorkbook.Save
Case VbMsgBoxResult.vbNo: Me.Saved = True
>>>> Тут как раз и нужен код на откат всех изменений <<<<
Worksheets("Предупреждение").Visible = True 'скрываем все листы, кроме листа ПРЕДУПРЕЖДЕНИЕ
For Each sh In ActiveWorkbook.Worksheets
If sh.Name = "Предупреждение" Then
sh.Visible = True
Else
sh.Visible = xlSheetVeryHidden
End If
Next sh
ActiveWorkbook.Save
Case VbMsgBoxResult.vbCancel: Cancel = True
End Select
Unload fmQueryClose
End If
End Sub
При выходе без сохранения я подумал именно про откаты(Undo), т.к. вручную-то я могу после открытия откатить все, что исправил в ячейках, зажатием Ctrl+Z. Получаем только открытый открытый файл, но после отката нужно скрыть все страницы.
Цитата
До какого момента, кстати?
Откат до открытия файла
Цитата
Как понять, когда закончить откатывать?
Закончить откат, когда уже нечего отменять (кнопка Undo будет неактивна)
Цитата
Ведь количество откатов может быть разным на разных ПК.
Да, кто-то может 1 ячейку косякнуть и выйти, а кто-то и 40. в файле в принципе не более 100 ячеек для ввода данных (остальное ВПРом подцепляется в зависимости от того что ввели в исходных + математические формулы )
Цитата
Да и событие-то какое: перед сохранением.
Да, уже подумал что лучше перед выходом + форма (то о чем я писал выше. Надеюсь из кода понятно что я хочу)
Цитата
Через Undo это сделать нереально.
Спасибо, я не знал. Надеюсь, сейчас подскажите, как сделать то, что мне нужно)
Ну если что, буду использовать методы для отмены действий макросов (по идее должно помочь)
Юрий М, я думал, что Application.Undo полностью заменяет Ctrl+Z, т.к. если заполнить к примеру 5 ячеек и потом нажать 5 раз Ctrl+Z, то сотрутся все 5 ячеек в порядке убывания ввода. Мне бы макрос на это. Но, блин, макрорекордер не пишет командуCtrl+Z))
kuklp, Ваш код я ввел и после нажатия сохранения зависает файл. Может это и то что мне нужно, но потом надо придумать "стоп-кран" от зависания. и можно потом будет добавить после "стоп-крана" дописать еще мою часть кода?
Цитата
Worksheets("лог").Cells(2, 2) = Now ActiveWorkbook.Save
Не знаю как вы вставляете код так красиво, чтоб с подсветкой синтаксиса. Если что у меня Excel 13.
RoMuLX написал: ПС: Описал максимально подробно, чтоб помогли именно с этой конкретной задачей, а не предлагали другие варианты решения.
часто тут читал, что вместо конкретной задачи предлагают совсем не то...( Я не хотел читать комменты типа "а зачем тебе откатывать? можно же просто выйти без сохранения" и т.д. ....
Я видел темы по откатам макросов, значит можно реализовать нужный мне макрос по откатам простых действий и код будет проще (надеюсь). Про цикл я не утверждаю)
Доброго времени суток! Говорю сразу: я новичок в VBA. Мне необходимо придумать макрос на отмену всех действий пользователя перед сохранением книги. Подразумевается не отмена действия макросов, а откат обычных заполнений ячеек пользователем введенных вручную, то есть пользователь мог бы и сам все отменить командой "Ctrl+Z", но мне надо это сделать макросом)
к примеру, пользователь после открытия и до сохранения успел заполнить 5 разных ячеек - пишу такой "топорный" код) в результате: - стирает последнюю ячейку (то что и нужно) - возвращает последнюю ячейку (а нужно чтоб стёр предпоследнюю) - стирает последнюю ячейку - возвращает последнюю ячейку - стирает последнюю ячейку
Код
Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
Application.Undo
Application.Undo
Application.Undo
Application.Undo
Application.Undo
End Sub
Вообще пользователь может и 100 ячеек скорректировать и даже на разных листах, а потом нажал сохранить (а надо сначала откатить все изменения с начала открытия, а потом сохраниться) - может посоветуете какой то цикл к отмене?
В итоге мы получаем две кнопки отмены при выходе)
ПС: Описал максимально подробно, чтоб помогли именно с этой конкретной задачей, а не предлагали другие варианты решения. Там не так все просто, после сохранения предусмотрен откат действий (надеюсь каким то циклом который упрется в то что уже откатывать нечего и закончит работу цикла), но потом допишет время сохранения файла. В итоге: пользователь нажав сохранить ничего не изменит, только добавит дату сохранения) Дату умею добавлять ) Заранее спасибо!