Страницы: 1
RSS
как сохранить историю при работе макроса, при запуске макросы затирают буфер обмена и историю откатов
 
Здравствуйте, я использую макросы для перерасчета автофильтров по мере ввода данных и проверки этих самых данных. Таким образом маленькие макросы срабатывают практически при каждом изменении таблицы и или перелистывании листа.

При этом почему-то теряются две возможности:
1) отката действий пользователя. На случай ввел что-то что выглядит правдоподобно, но хотел ввести другое или в другое место, а пути назад уже нет - только заново вбивать.
2) возможность вставки заранее скопированных данных. Например, скопировал данные на одном листе, хотел вставить на другом, а данных (в буфере) уже нет.

Собственно эти две возможности и хотелось бы сохранить.

P.S. Видела тему про откат действий макроса, но у меня задача можно сказать обратная. Т.е. мне не надо хранить данные которые меняет макрос, а только то что меняет пользователь, но в не зависимости от того было это до или после работы макроса.
когда мозг программиста отдыхает процессор работает на 100%, и наоборот
 
по поводу буфера обмена - вообще-то запуск макроса не очищает буфер автоматом.
но кто ж знает, что именно и как делают ваши макросы?
к примеру, если они использую команду Copy для диапазонов или других объектов - то ничего удивительного.

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

решать можно. и решить можно.
организовать собственный стек изменений, отлавливающий действия пользователя (причем часть отловить не получится - напр., изменение формата) и собственный "undo", работающий с этим стеком.
геморрой (извините за выражение) ещё тот...
но более простого способа я не знаю.
Изменено: ikki - 14.04.2013 12:35:38
фрилансер Excel, VBA - контакты в профиле
"Совершенствоваться не обязательно. Выживание — дело добровольное." Э.Деминг
 
Цитата
по поводу "выборочной" отмены - приведите пример хотя бы одной программы, предлагающей подобное?

ну, фотошоп, например... или CorelDraw - в одном из них я точно видел такую штуку

Мой взгляд на проблему:
1) про отмену действий забыть (макросы с ней несовместимы)
2) проблема с буфером обмена решается незначительной правкой макроса
(удалением Select и подобного - можно копировать данные из одних ячеек в другие, не используя буфер обмена)
 
ну я же сказал  :)
Цитата
ikki пишет: для некоторых частных случаев может выглядеть осмысленно.
если действия производились над разными объектами, не связанными между собой (да даже можно и связанными, но каким-нибудь ограниченным способом) - то чисто теоретически можно и выборочно отменять.
но, наверное, на практике реализовать это довольно сложно.
или на практике такие потребности возникают достаточно редко.

в любом случае - в Excel это не реализовано.
пока что.
фрилансер Excel, VBA - контакты в профиле
"Совершенствоваться не обязательно. Выживание — дело добровольное." Э.Деминг
 
Есть возможность отмены ГРУППЫ действий: например, последние 5 или 4, или 3... Т.е. небольшой выбор есть)
 
Цитата
ikki пишет:
по поводу буфера обмена - вообще-то запуск макроса не очищает буфер автоматом.
но кто ж знает, что именно и как делают ваши макросы?

Мне казалось, что я ничего особенного не делаю... Вот собственно мой макрос
Код
Private Sub Set_Filter()
    
    Unprotect "*****"
     
    If OptionButtonAll.Value Then
        Cells(30, 4).AutoFilter Field:=30, Criteria1:=">=0", Operator:=xlAnd
    Else
        Cells(30, 4).AutoFilter Field:=30, Criteria1:=">0", Operator:=xlAnd
    End If
    
    Protect "*****", DrawingObjects:=True, Contents:=True, Scenarios:=True _
            , AllowFormattingCells:=True, AllowFormattingColumns:=True, _
            AllowFormattingRows:=True, AllowFiltering:=True

End Sub


Цитата
ikki пишет: по поводу "выборочной" отмены ... вы хотите странного.
Видимо коряво сформулировала вопрос. Будут ли оседать в истории действия макроса мне не важно - главное чтоб история просто не прерывалась. И если пользователь случайно перетер нужные данные, он мог бы их вернуть пусть не одним, а 2, 3, 10-ю отменами последних действий. В такой формулировке, есть более легкое решение?
когда мозг программиста отдыхает процессор работает на 100%, и наоборот
 
Цитата
tagetes пишет:
Мне казалось, что я ничего особенного не делаю...
включение/отключение защиты листа очищает буфер.
любым способом - вручную или макросом.

что значит "случайно перетёр"?
когда он это обнаружит?
в какой-то ячейке - правильно "перетёр", в какой-то - неправильно?
и кто за него должен это определить?

есть хороший способ бороться с ошибками - не допускать их.
фрилансер Excel, VBA - контакты в профиле
"Совершенствоваться не обязательно. Выживание — дело добровольное." Э.Деминг
 
Здесь не то?
 
кстати, по поводу защиты - можно использовать для метода protect параметр userinterfaceonly (действует до закрытия файла, подробнее - в справке).
в этом случае при использовании фильтра в макросе не нужно будет каждый раз включать-отключать защиту.
возможно, и буфер обмена очищаться не будет.
фрилансер Excel, VBA - контакты в профиле
"Совершенствоваться не обязательно. Выживание — дело добровольное." Э.Деминг
 
Цитата
ikki пишет: включение/отключение защиты листа очищает буфер.
любым способом - вручную или макросом.
Не знала, теперь хотя бы знаю в чем проблема. Спасибо )

Цитата
ikki пишет: что значит "случайно перетёр"?
Например, рядом есть колонки типа "запланировано" и "сделано". Хотел подправить "сделано", но промахнулся и вбил в планы, потом хватился, но что планировалось уже затерто. Определить это может только пользователь, поэтому и не могу я эти ошибки макросом перехватить.

Цитата
ikki пишет: есть хороший способ бороться с ошибками - не допускать их.
Я же не себе делаю - свои мозги не вставишь, да и не ошибается только тот кто ничего не делает.
когда мозг программиста отдыхает процессор работает на 100%, и наоборот
 
ну, часть задач может помочь решить инструмент "проверка данных".
вы его используете?

а вообще - сходите по ссылке, данной Юрием М.
только вам ещё понадобится использование данных. записанных в журнал изменений - ну, например, нарисовать формочку со списком последних введённых значений и с тем, что было до ввода изменений...
пользователь щёлкает по нужной позиции в списке - и макрос "перевбивает" в нужную ячейку старое значение.

довольно муторно, но один раз тщательно проработать - и можно будет забыть  :)
Изменено: ikki - 14.04.2013 13:42:23
фрилансер Excel, VBA - контакты в профиле
"Совершенствоваться не обязательно. Выживание — дело добровольное." Э.Деминг
 
Юрий М, там, в принципе, то, и даже больше чем мне надо (мне не важно кто и когда менял), но хочется чего-то по-проще, хотя если ничего лучше не найду - применю и этот подход.
когда мозг программиста отдыхает процессор работает на 100%, и наоборот
 
и все-таки не совсем то ( макрос глючит в случа использован я автозаполнения. Ввод, копирование и вставка обрабатываются на ура, а с протягиванием проблема. В принципе, по идее мне это автозаполнение не особо нужно, но как тогда запретить пользователю им пользоваться?
когда мозг программиста отдыхает процессор работает на 100%, и наоборот
 
Для себя решил проблему так просто копированием листа по событию изменение в листе. Десять скрытых листов и циклическая перезапись. Способ дубовый, но может Вам такая идея подойдет.
 
У меня в книге 4 листа, соответственно, добавить надо будет 4*10 = 40 листов, с учетом что у пользователя машина оч. слабенькая боюсь тормозить сильно будет. Хотя... наверно, можно подумать в сторону комбинирования резервной копии с журналом - как-то так чтоб копия была одна но благодаря ей получалось вести журнал...

Начала думать и наткнулась на глупый вопрос - а как не переводя курсор скопировать заданный диапазон с одного листа на другой?

Вариант тип
Код
    Range("A1:C14").Select
    Selection.Copy
    Sheets("Лист2").Select
    Range("A1").Select
    Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks :=False, Transpose:=False

Не подходит, т.к. хочу повесить этот макрос на событие активации листа и при перелистывании получится бесконечный цикл.
Изменено: tagetes - 09.05.2013 19:08:47 (вопрос по ходу разборок)
когда мозг программиста отдыхает процессор работает на 100%, и наоборот
 
Цитата
tagetes пишет:
не переводя курсор скопировать заданный диапазон с одного листа на другой?
Код
Sheets("Лист2").Range("A1:C14").Value=activesheet.Range("A1:C14").Value

activesheet писать необязательно, просто самодокументация кода  ;)
фрилансер Excel, VBA - контакты в профиле
"Совершенствоваться не обязательно. Выживание — дело добровольное." Э.Деминг
 
Цитата
Юрий М пишет:
Здесь не то?

Цитата
YuryK пишет:
Для себя решил проблему так просто копированием листа по событию изменение в листе. Десять скрытых листов и циклическая перезапись. Способ дубовый, но может Вам такая идея подойдет.

И так, я решила скомбинировать 2 подхода. Собственно проблема подхода от Юрий М была в том, что в случае протягивания ячейки не правильно заполнялось поле старого значения, все остальное вроде бы было правильно. Вот я и решила использовать подход YuryK для поучения корректных данных для поля старого значения.
И так, мои правки в модулях найденных здесь.
1) добавила второй служебный лист "back" (для получения старых значений)
2) добавила к каждому рабочему листу копирование данных с листа на "back" по событию активации листа (собственно мне достаточно не всего листа, а только его зоны, но это детали)
3) заменила обработчик Workbook_SheetSelectionChange на подобную функцию get_sValue, с тем чтоб функция добывала старые значения из резервной копии, а не запоминала при смене выделения.
4) в обработчик Workbook_SheetChange добавила обращение к функции get_sValue (в начале) и обновление резервной копии (в конце)

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

А теперь вопрос. Как мне сделать так, чтоб журнал продолжался не до бесконечности (на самом-то деле до конца листа), а включал в себя только N последних изменений записанных на строках с 2 по N+2 в хронологическом порядке? Т.е. при N+1 изменении удалить строку 2 (с тем чтоб все строки сдвинулись на одну вверх) и дополнить журнал снизу. По идее правка должна быть не большой, но я что-то не могу разобраться в коде. Свое творчество прилагаю (служебные листы не скрыты т.к. это рабочий вариант).
когда мозг программиста отдыхает процессор работает на 100%, и наоборот
 
Файл не смотрел. Вариант: присвоить некой константе/переменной значение (максимальное к-во строк в архиве). Например, х1 = 1000. После отработки кода считаем общее количество строк - это будет х2.
Если х2 > 1000, то Rows(2).Delete
Если в архив добавляется по несколько строк, тогда и удалять эту разницу (диапазон строк).
 
Итак общими усилиями сделали файлик в котором с помощью макросов и 2 дополнительных листов организовано сохранение истории. И даже кнопочки при нажатии на которые происходит действие аналогичное действию Ctrl+z и Ctrl+Shift+z получились.
Но, опять проблема, попробовала повесить макрос на кнопки Ctrl+z, а перехват этой комбинации перестает работать после любого срабатывания одной из кнопок. В чем может быть дело? После любой правки документа перехват начинает работать дальше. А кнопки работают постоянно. Ниже обработчик нажатия кнопки "undo" тоже самое (с точностью до имени процедуры) должно вызываться при нажатии Ctrl+z.
Код
Private Sub CommandButton2_Click()
    Dim ptr As Integer
    Dim rng As Range
    Dim val As Variant
    Dim i As Integer
    Dim Cell As Range
    
    ptr = Sheets("LOG").Range("h1").Value
    If Sheets("LOG").Range("b" & ptr).Value = "" Then
         MsgBox ("сохраненная история кончилась...")
         Application.EnableEvents = True
         Exit Sub
    End If
    Application.EnableEvents = False
    Set rng = Worksheets(Sheets("LOG").Range("d" & ptr).Value).Range(Sheets("LOG").Range("b" & ptr).Value)
    
    val = Sheets("LOG").Range("e" & ptr).Value
    If InStr(val, "#") <> 0 Then
          val = WorksheetFunction.Transpose(Split(val, "#"))
          i = 1
          For Each Cell In rng
                 Cell.Value = val(i, 1)
                 i = i + 1
          Next
    Else
          rng.Value = val
    End If
    
    Worksheets("Back").Range("a1:t400").Value = ActiveSheet.Range("a1:t400").Value
    Sheets("LOG").Range("h1").Value = Sheets("LOG").Range("h1").Value - 1
    Application.EnableEvents = True
End Sub


так же прилагаю и весь получившийся файл - может не правильно поняла где ошибка и/или еще кому-то пригодиться.
P.S. если б еще придумать как повесить макросы на пункты меню "отмена", "возврат" и на стрелочки... Совсем модно вышло бы.
Изменено: tagetes - 30.04.2013 20:49:12
когда мозг программиста отдыхает процессор работает на 100%, и наоборот
Страницы: 1
Читают тему
Наверх