Страницы: 1
RSS
Доработка макроса ведения журнала сделанных в книге изменений
 
Тут попросили меня друзья на работе помочь вычислить, какой гад в общем, лежащем на сервере, Excel-файле учёта работ отдела "хулиганит" -  данные, ежедневно вносимые и сверяемые, задним числом подправляет. А потом общий отчёт за месяц не сводится...  
Вспомнил я, что The_Prist как-то выкладывал тему "Ведение журнала сделанных в книге изменений" на <EM>http://www.excel-vba.ru/index.php?file=Tips_Macro_Log</EM>  
Попробовал с мужиками на тестовом фауле на сервере. Здорово работает. А лист LOG я сделал VeryHidden и проект VBA запаролил от дураков.  
По ходу тестирования нашёл одну недоработочку - вылетает в дебаггер если выделить пустой диапазон вне UsedRange (пустую строку/столбец) или очистить строку/столбец на границе UsedRange.  
Ошибка возникает из-за того, что тогда получается, что Intersect(Target, Sh.UsedRange) = Nothing и цикл по ячейкам, естественно, становится невозможен.  
И небольшие доработки по логике и удобству работы с программой:    
1 - если юзверг удаляет, например, данные из целой строки или просто большого диапазона, то формируемые циклами из старых и новых значений строковые переменные получаются такой бешенной длины, что проку от них - НОЛЬ, да и циклы по ячейкам тормозят. Поэтому я сделал ограничение накопления данных  "что было"-"что стало" количеством, задаваемым в декларациях модуля величиной Const MaxCells% = 16  
2 - символ-разделитель перечисляемых значений тоже задаётся в декларациях модуля параметром Const Sep$ = "; "  
 
Доработанный файл - в приложении.  
 
Осталась не решенной всего одна, но как высянилось, очень важная проблема: из-за работы макросов, ведущих лог, становится невозможной отмена изменений - это наикрутейший облом, т.к. "демаскирует" работу макроса!  
В связи с зтим есть вопрос к Дмитрию и другим макрописцам: нет ли у кого-нибудь мыслей, как сделать возможными отмены действий пользователя (не макроса!)  
Пытался я когда-то разобраться с макросом OnUndo (кажется, Дмитрия-The_Prist), но что-то ничего не вышло.  
Если кто-то найдёт время, может поможите его "присобачить" к моему примеру?  
_________________  
64646 !!!
С уважением, Алексей (ИМХО: Excel-2003 - THE BEST!!!)
 
Ну, поставить повышенный уровень безопасности чтобы не работали вообще все макросы книги никто и пробовать не будет, т.к. там много окошек с моими любимыми "удобными автофильтрами", а также - форма для поиска-выбора-ввода наименований и автоматом-адресов объектов (узлов связи). А если хоть один символ в паре имя-адрес не соответствует утвержденному списку, то ввод будет запрещен.  
Да и уровень знаний у большинства наших "орлов" такой, что в Ворде выравнивают пробелами, а межстрочный интервал меняют Enter-ами. В Ёкселе про Alt+Enter тоже мало кто знает - пробелами между слов переносы в ячейках лепят (ЗАДОЛБАЛИ!!!)  
Нужно бы, конечно, учет работ на Access перевести, но на это же время для разработки нужно...  
Да... Если побороть невозможность отмены пользователем СВОИХ действий, то это засада!  
А счастье казалось так близко... И макрос быстро нашёл (спасибо, Дмитрий за <EM>www.excel-vba.ru</EM> !) и баг легко нашёл, и "причесал"...
С уважением, Алексей (ИМХО: Excel-2003 - THE BEST!!!)
 
У меня возникла следующая проблема после вставки данной процедуры: при копировании формулы ее значение обновляется только, только если изменение сохранить или нажать Enter. Это крайне не удобно. Подскажите, пожалуйста, что с этим можно сделать? Самое интересное, что когда я удалила процедуру, проблема осталась.
 
Почему не один ни другой макрос с LOG не работает в компании с такими кодами  
Private Sub Workbook_Open()  
Application.ScreenUpdating = False  
   Dim wsSh As Worksheet  
   Sheets("1").Visible = -1  
   For Each wsSh In ThisWorkbook.Sheets  
       If wsSh.Name <> "1" Then wsSh.Visible = 2  
   Next wsSh  
Dim hh As Worksheet  
' Îòêëþ÷èòü òîðìîçà  
On Error Resume Next  
Application.ScreenUpdating = False  
Application.EnableEvents = False  
' Îáðàáîòàòü âñå ëèñòû  
 Const MyPassword = "Top2007"  
For Each hh In Sheets  
If hh.Name <> "LOG" Then  
If hh.ProtectContents Then  
Else  
hh.Unprotect Password:=MyPassword  
hh.EnableOutlining = True  
hh.Protect Password:=MyPassword, DrawingObjects:=True, Contents:=True, Scenarios:=True, _  
AllowFiltering:=True, UserInterfaceOnly:=True  
End If  
End If  
Next  
For Each hh In Sheets  
hh.Cells(1).EntireRow.Hidden = True  
hh.Cells(1).EntireColumn.Hidden = True  
Next  
Application.ScreenUpdating = True  
Sheets("ÎÃËÀÂËÅÍÈÅ").Select  
End Sub  
 
Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)  
Dim sOldValue As String  
Const Sep$ = "; " ' ðàçäåëèòåëü ïðè ïåðå÷èñëåíèè çíà÷åíèé ÿ÷ååê  
Const MaxCells% = 16 ' ìàêñèìàëüíîå êîëè÷åñòâî çíà÷åíèé ÿ÷ååê ïðè èõ ïåðå÷èñëåíèè  
  '---------------------------------------------------------------------------------------  
  ' Procedure : Workbook_SheetChange  
  ' Author    : The_Prist (èäåÿ) & Alex_St (äîðàáîòêà)  
  ' URL       : http://www.excel-vba.ru/index.php?file=Tips_Macro_Log  
  ' Date      :  
  ' Purpose   : Âåäåíèå ËÎÃ-ôàéëà ïðîèçâåäåííûõ èçìåíåíèé íà ëèñòå LOG  
  ' Notes     :  
  '---------------------------------------------------------------------------------------  
  If Sh.Name = "LOG" Then Exit Sub  
  Dim sNewValue As String  
  Dim lLastRow As Long  
  Dim rCell As Range  
 
  With Sheets("LOG")  
     lLastRow = .UsedRange.Row + .UsedRange.Rows.Count  
     If lLastRow = .Rows.Count Then Exit Sub  
     Application.ScreenUpdating = False: Application.EnableEvents = False  
     .Cells(lLastRow, 1) = CreateObject("wscript.network").UserName  
     .Cells(lLastRow, 2) = Format(Now, "dd.mm.yyyy HH:MM:SS")  
     .Cells(lLastRow, 3) = Sh.Name  
     .Cells(lLastRow, 4) = Target.Address(0, 0)  
     .Cells(lLastRow, 5) = sOldValue  
     If Not Intersect(Target, Sh.UsedRange) Is Nothing Then  
        If Target.Count > 1 Then  
           For Each rCell In Intersect(Target, Sh.UsedRange)  
              If Not IsError(Target) Then sNewValue = sNewValue & Sep & rCell Else sNewValue = sNewValue & Sep & "Err"  
              If UBound(Split(sNewValue, Sep)) > MaxCells - 1 Then sNewValue = sNewValue & Sep & "...": Exit For  
           Next rCell  
           sNewValue = Mid(sNewValue, Len(Sep) + 1)  
        Else  
           If Not IsError(Target) Then sNewValue = Target.Value Else sNewValue = "Err"  
        End If  
     End If  
     .Cells(lLastRow, 6) = sNewValue  
  End With  
  Application.ScreenUpdating = True: Application.EnableEvents = True  
End Sub  
Private Sub Workbook_SheetSelectionChange(ByVal Sh As Object, ByVal Target As Range)  
Dim sOldValue As String  
Const Sep$ = "; " ' ðàçäåëèòåëü ïðè ïåðå÷èñëåíèè çíà÷åíèé ÿ÷ååê  
Const MaxCells% = 16 ' ìàêñèìàëüíîå êîëè÷åñòâî çíà÷åíèé ÿ÷ååê ïðè èõ ïåðå÷èñëåíèè  
  Dim rCell As Range, i%  
  sOldValue = ""  
  If Sh.Name = "LOG" Then Exit Sub  
  If Not Intersect(Target, Sh.UsedRange) Is Nothing Then  
     If Target.Count > 1 Then  
        For Each rCell In Intersect(Target, Sh.UsedRange)  
           If Not IsError(rCell) Then sOldValue = sOldValue & Sep & rCell Else sOldValue = sOldValue & Sep & "Err"  
              If UBound(Split(sOldValue, Sep)) > MaxCells - 1 Then sOldValue = sOldValue & Sep & "...": Exit For  
        Next rCell  
        sOldValue = Mid(sOldValue, Len(Sep) + 1)  
     Else  
        If Not IsError(Target) Then sOldValue = Target.Value Else sOldValue = "Err"  
     End If  
  End If  
End Sub  
Private Sub Workbook_BeforeClose(Cancel As Boolean)  
   Dim hh As Worksheet  
' Îòêëþ÷èòü òîðìîçà  
On Error Resume Next  
Application.ScreenUpdating = False  
Application.EnableEvents = False  
' Îáðàáîòàòü âñå ëèñòû  
 Const MyPassword = "Top2007"  
For Each hh In Sheets  
If hh.ProtectContents Then  
Else  
hh.Unprotect Password:=MyPassword  
End If  
Next  
For Each hh In Sheets  
hh.Cells(1).EntireRow.Hidden = True  
hh.Cells(1).EntireColumn.Hidden = True  
Next  
Application.ScreenUpdating = True  
   Dim wsSh As Worksheet  
   Sheets("1").Visible = -1  
   For Each wsSh In ThisWorkbook.Sheets  
       If wsSh.Name <> "1" Then wsSh.Visible = 2  
   Next wsSh  
End Sub
Страницы: 1
Читают тему
Наверх