Отслеживать изменения в excel vba

Как вы могли отслеживать ячейки листа, если данные были изменены в Excel? Это может помочь вам как можно быстрее идентифицировать измененные ячейки. В этой статье я расскажу о некоторых интересных методах решения этой задачи в Excel.

Отслеживайте изменения ячеек в Excel с помощью функции отслеживания изменений

Отслеживайте изменения ячеек в Excel с помощью кода VBA


стрелка синий правый пузырь Отслеживайте изменения ячеек в Excel с помощью функции отслеживания изменений

В Excel есть полезный Отслеживать изменения функция, она может помочь вам отметить измененные ячейки, пожалуйста, сделайте следующее:

1. Нажмите Обзор > Отслеживать изменения > Выделить изменения, см. снимок экрана:

изменения в мониторе документов 1

2. В Выделить изменения диалоговом окне выполните следующие операции:

(1.) Проверить Отслеживайте изменения во время редактирования. Это также разделяет вашу книгу.

(2.) Под Выделите, какие изменения В разделе укажите нужные вам элементы Когда, Кто и Где.

(3.) Наконец, проверьте Выделите изменения на экране опцию.

изменения в мониторе документов 2

3. После завершения настройки нажмите OK кнопка, теперь, когда вы меняете любые значения ячеек в указанных ячейках, вокруг измененных ячеек появляется граница с треугольным значком, см. снимок экрана:

изменения в мониторе документов 3

Внимание: С помощью этого метода ваша книга станет общей.


стрелка синий правый пузырь Отслеживайте изменения ячеек в Excel с помощью кода VBA

Следующий код VBA также может помочь вам отслеживать значения ячеек при их изменении, пожалуйста, сделайте следующее:

1. Щелкните правой кнопкой мыши вкладку листа, на которой вы хотите отслеживать изменения ячеек, и выберите Просмотреть код из контекстного меню в открывшемся Microsoft Visual Basic для приложений окна, скопируйте и вставьте следующий код VBA в модуль:

Код VBA: отслеживание изменений ячеек на листе Excel:

Private Sub Worksheet_Change(ByVal Target As Range)
'Updateby Extendoffice 20160728
    Dim xrng As Range
    Set xrng = Range("A1:E7")
    If Not Application.Intersect(xrng, Range(Target.Address)) _
           Is Nothing Then
        MsgBox "Cell " & Target.Address & " has changed.", vbInformation, "Kutools for Excel"
    End If
End Sub

изменения в мониторе документов 4

Примечание: В приведенном выше коде A1: E7 — это диапазон данных, который вы хотите отслеживать при изменении ячейки, вы можете изменить его по своему усмотрению.

2. Затем сохраните и закройте это окно кода, и теперь, когда вы измените значение ячейки в указанном диапазоне, появится окно сообщения, напоминающее вам, см. Снимок экрана:

изменения в мониторе документов 5


Лучшие инструменты для работы в офисе

Kutools for Excel Решит большинство ваших проблем и повысит вашу производительность на 80%

  • Снова использовать: Быстро вставить сложные формулы, диаграммы и все, что вы использовали раньше; Зашифровать ячейки с паролем; Создать список рассылки и отправлять электронные письма …
  • Бар Супер Формулы (легко редактировать несколько строк текста и формул); Макет для чтения (легко читать и редактировать большое количество ячеек); Вставить в отфильтрованный диапазон
  • Объединить ячейки / строки / столбцы без потери данных; Разделить содержимое ячеек; Объединить повторяющиеся строки / столбцы… Предотвращение дублирования ячеек; Сравнить диапазоны
  • Выберите Дубликат или Уникальный Ряды; Выбрать пустые строки (все ячейки пустые); Супер находка и нечеткая находка во многих рабочих тетрадях; Случайный выбор …
  • Точная копия Несколько ячеек без изменения ссылки на формулу; Автоматическое создание ссылок на несколько листов; Вставить пули, Флажки и многое другое …
  • Извлечь текст, Добавить текст, Удалить по позиции, Удалить пробел; Создание и печать промежуточных итогов по страницам; Преобразование содержимого ячеек в комментарии
  • Суперфильтр (сохранять и применять схемы фильтров к другим листам); Расширенная сортировка по месяцам / неделям / дням, периодичности и др .; Специальный фильтр жирным, курсивом …
  • Комбинируйте книги и рабочие листы; Объединить таблицы на основе ключевых столбцов; Разделить данные на несколько листов; Пакетное преобразование xls, xlsx и PDF
  • Более 300 мощных функций. Поддерживает Office/Excel 2007-2021 и 365. Поддерживает все языки. Простое развертывание на вашем предприятии или в организации. Полнофункциональная 30-дневная бесплатная пробная версия. 60-дневная гарантия возврата денег.

вкладка kte 201905


Вкладка Office: интерфейс с вкладками в Office и упрощение работы

  • Включение редактирования и чтения с вкладками в Word, Excel, PowerPoint, Издатель, доступ, Visio и проект.
  • Открывайте и создавайте несколько документов на новых вкладках одного окна, а не в новых окнах.
  • Повышает вашу продуктивность на 50% и сокращает количество щелчков мышью на сотни каждый день!

офисный дно

Комментарии (7)


Оценок пока нет. Оцените первым!

Хитрости »

1 Май 2011              273586 просмотров


Ведение журнала сделанных в книге изменений

Проблема очень актуальна для больших организаций, когда одним файлом пользуются несколько человек. И каждый может сделать какие-то свои изменения. И конечно всегда наступает момент когда надо узнать — а кто сделал то или иное изменение? Возможно просто для информации, а бывает и хуже, когда необходимо узнать кто внес конкретное изменение, которое делать было нельзя и по возможности восстановить хоть часть того, что было.

  • Отслеживание изменений при помощи встроенных средств — Общий доступ к книге
  • Отслеживание изменений и ведение журнала при помощи кода

Отслеживание изменений при помощи встроенных средств — Общий доступ к книге
Есть относительно простой способ отслеживать изменения(если это можно так назвать): дать книге общий доступ
Excel 2007 и выше: вкладка Рецензирование(Review)Доступ к книге(Share workbook).
В более новых версиях(таких как Excel 2021 и выше, а так же Office 365) на вкладке Рецензирование(Review) нет команды Доступ к книге(Share workbook). Она спрятана, т.к. считается устаревшей и вместо неё Microsoft принуждает использовать общий доступ через OneDrive. Достать устаревшую возможность общего доступа можно через меню:
Файл(File) -Параметры(Options) -либо Панель быстрого доступа(Quick Access Toolbar) либо Настроить ленту(Customize ribbon) -в списке Выбрать команды из(Choose commands from) выбираем Все команды(All commands) и находим там пункт: Общий доступ к книге(старые версии)(Share workbook(Legacy) и Выделить исправления(Highlight changes). Перемещаем их либо на панель быстрого доступа(если она была выбрана изначально), либо на ту же вкладку Рецензирование(Review), если команда выбиралась в Настроить ленту(Customize ribbon).
После этого выбираем команду Общий доступ к книге(старые версии)(Share workbook(Legacy)
В появившемся окне поставить галочку разрешить изменять файл нескольким пользователям одновременно(Allow changes by more then one user at the same time):
Доступ к файлу
Далее можно настроить срок хранения лога изменений, конфликты и пр — вкладка Подробнее(Advanced):
Параметры доступа
Регистрация изменений(Track changes)

  • Хранить журнал в течение(keep change history for): — если необходимо вести журнал изменений(а нам необходимо!) то оставляем этот пункт включенным и устанавливаем количество дней, в течение которых необходимо сохранять историю. По умолчанию это 30 дней. Здесь имеются ввиду последние 30 дней от текущей даты. Т.е. по истечению этих 30 дней более ранние данные истории будут затерты
  • Не хранить журнал изменений(don’t keep change history): после выбора этого пункта и подтверждения журнал будет удален(если он был создан) и история вестись не будет

Обновлять изменения

  • При сохранении файла(When file is saved) — это самый оптимальный вариант. Данные об изменениях в файле будут обновляться только тогда, когда мы сами сохраним файл.
  • Каждые(Automatically every): указывается промежуток времени в минутах, через который книга сама автоматически будет сохраняться и регистрировать изменения. Не очень удобен данный пункт если в файле одновременно работает несколько человек. При этом необходимо будет обязательно выбрать какое действие будет производится по умолчанию:
    • сохранить мои изменения и просмотреть чужие(save my changes and see others’ changes)
    • только просмотреть чужие изменения(just see other users’ changes)

    Пункты говорят сами за себя, можно отметить лишь один нюанс: принимать решение о сохранении тех или иных изменениях будет тот пользователь, который первым открыл файл.

Для противоречивых изменений(Conflicting changes between users)

    данный пункт управляет разрешением конфликтов, если при одновременном пользовании файлом несколькими пользователями два и более пользователя сделали изменения в одной и той же ячейке листа.

  • запрашивать чьи изменения имеют преимущество(ask me which changes win) — самый оптимальный вариант. Первый, открывший файл пользователь определяет какие изменения надо принять, а какие отклонить
  • ранее сохраненные имеют преимущество(the changes being saving win) — не очень правильный вариант, но все зависит от ситуации. По логике при данном пункте при возникновении конфликта автоматически будут приняты лишь те изменения, которые были сделаны ранее. Может сыграть нехорошую шутку, поэтому надо быть острожным с этим пунктом

Включить в личное представление(Include in personal view)

    Данный пункт управляет настройками печати и фильтра общей книги для нескольких пользователей.

  • параметры печати(Print settings) — Обычно, в одном файле когда мы настраиваем параметры печати, они сохраняются внутри файла и при следующем открытии их не надо уже заново настраивать. Здесь тоже самое, но хранится для каждого пользователя отдельно. Т.е. даже если в этом файле один пользователь настроил одни параметры печати, а другой – иные, то для каждого пользователя эти параметры сохраняться. В обычной книге применились бы те параметры, которые были назначены перед последним сохранением книги.
  • фильтры(Filter settings) — если один пользователь отфильтровал данные по «Юго-Восточный округ», а другой тот же столбец по «Северный округ», то при установленном данном пункте у каждого пользователя файл откроется с отфильтрованными строками именно по установленным ими параметрам — для каждого свой
  • Но оба эти пункта имеют большой недостаток: в зависимости от количества пользователей и их действий они могут сильно «раздувать» файл и приводить к значительным его «тормозам». Поэтому без необходимости лучше их не использовать

Теперь самое главное: как увидеть все сделанные изменения
После того, как пользователи поработали с файлом и стало необходимо увидеть сделанные изменения необходимо перейти на вкладке Рецензирование(Review)Исправления(Track changes)Выделить исправления(Highlight changes)
Просмотреть изменения
Здесь можно выбрать какие изменения показывать

  • по времени(When) — если хотите увидеть только какие-то конкретные изменения, то надо установить галочку на этом пункте и выбрать нужное. Доступно выбрать: Со времени последнего сохранения, Все, Еще не просмотрено, С даты. Пункты достаточно красноречивы и понятны, расписывать каждый не вижу смысла. Если хотите просмотреть все изменения — галочку с этого пункта надо снять
  • пользователем(Who) можно показать изменения, сделанные конкретным пользователем, всеми пользователями, или всеми пользователями, кроме того, кто запросил отчет об изменениях(т.е. кроме себя любимого)
  • в диапазоне(Where) можно указать конкретный диапазон на листе и отчет об изменения будет выведен только для ячеек этого диапазона.

Выделять исправления на экране(Highlight changes on screen): если установить эту галочку, то изменения будут созданы в виде примечаний к ячейкам, изменения в которых были сделаны. В левом верхнем углу ячейки в этом случае появится черный треугольник, а при наведении на эту ячейку появится примечание с информацией о том кто изменил, когда и на что:
Изменения в примечании

Вносить изменения на отдельный лист(List changes on a new sheet): в этом случае будет создан новый лист с именем «Журнал», в котором будут перечислены ячейки, в которые были внесены изменения с указанием даты и времени изменения, пользователя сделавшего изменение, старое и новое значение измененной ячейки:
Изменения в отдельном листе

Примечание: После того, как книге дан общий доступ книгу одновременно могут менять несколько пользователей. Однако я не рекомендую делать это без крайней необходимости, т.к. одновременный доступ к файлам Excel реализован очень плохо и работает это нестабильно. В какой-то момент файл может просто отказаться работать и все данные будут утеряны. Так же неизбежно будут возникать спорные ситуации, когда изменения внесли два человека одновременно и не сохранилось в результате ни одно из внесенных.

Но самый главный недостаток: книги в общем доступе имеют ряд ограничений, среди которых такие как:

  • невозможно удалять листы
  • невозможно создавать диаграммы, можно лишь просматривать созданные ранее
  • невозможно создавать сводные таблицы, можно лишь просматривать созданные ранее
  • невозможно создавать или изменять группировку данных, можно использовать ранее созданную
  • невозможно изменять параметры защиты листов и книги
  • невозможно использовать расширенный фильтр
  • невозможно использовать Текст по столбцам
  • невозможно создавать новые проверки данных, а так же изменять существующие. Допускается лишь обвести или удалить обводку с неверных данных
  • невозможно добавлять или изменять ранее созданные формулы массива
  • и т.д.

Плюс невозможно не только использовать умные таблицы, но и сделать книгу общей, если в ней есть хоть одна умная таблица. Если будет попытка сделать общий доступ к книге с умной таблицей Excel покажет предупреждение, что этого делать нельзя и проинструктирует как преобразовать такую таблицу в диапазон для возможности использовать общий доступ.
Так же хочу отметить, что есть распространенное заблуждение о невозможности использования макросов в книгах с общим доступом. Это не так, коды Visual Basic for Applications разрешается применять и в большинстве случаев они будут работать корректно и как задумывались, если они только не пытаются произвести действия, перечисленные как запрещенные для книг с общим доступом. Плюс невозможно просматривать и изменять коды в книгах с общим доступом.


Отслеживание изменений и ведение журнала при помощи кода

Изменения можно отслеживать и при помощи кода. При этом такой метод дает не менее полное представление об изменениях в ячейках и при этом давать общий доступ книге нет необходимости, а следовательно и все ограничения, применимые для книг в общем доступе тоже остаются за бортом, что делает такой подход порой предпочтительнее. Единственное, при таком режиме файл нельзя будет редактировать одновременно нескольким пользователям. Но в большинстве случаев этого и не надо.
Я могу предложить небольшой код, который будет отслеживать следующие параметры:

  • Имя пользователя(учетная запись пользователя на компьютере), сделавшего изменения
  • адрес ячейки, в которую были внесены изменения
  • дата и время внесения изменений
  • имя листа, в котором были сделаны изменения
  • значение ячейки до изменения(старое значение)
  • значение ячейки после изменения(новое значение).

Итак, Вы решили реализовать данный процесс. Изначально необходимо разрешить макросы, без этого данный способ ведения журнала не сработает. Далее необходимо добавить в книгу новый лист с именем LOG и вставить приведенный код в модуль книги, изменения в которойнеобходимо отслеживать:

Option Explicit
Public sValue As String
Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)
    If Sh.Name = "LOG" Then Exit Sub
    Dim sLastValue As String
    Dim lLastRow As Long
 
    With Sheets("LOG")
        lLastRow = .Cells.SpecialCells(xlLastCell).Row + 1
        If lLastRow = Rows.Count Then Exit Sub
        Application.ScreenUpdating = False: Application.EnableEvents = False
        .Cells(lLastRow, 1) = CreateObject("wscript.network").UserName
        .Cells(lLastRow, 2) = Target.Address(0, 0)
        .Cells(lLastRow, 3) = Format(Now, "dd.mm.yyyy HH:MM:SS")
        .Cells(lLastRow, 4) = Sh.Name
        .Cells(lLastRow, 5).NumberFormat = "@"
        .Cells(lLastRow, 5) = sValue
        If Target.Count > 1 Then
            Dim rCell As Range, rRng As Range
            On Error Resume Next
            Set rRng = Intersect(Target, Sh.UsedRange): On Error GoTo 0
            If Not rRng Is Nothing Then
                For Each rCell In rRng
                    If Not IsError(Target) Then sLastValue = sLastValue & "," & rCell Else sLastValue = sLastValue & "," & "Err"
                Next rCell
                sLastValue = Mid(sLastValue, 2)
            Else
                sLastValue = ""
            End If
        Else
            If Not IsError(Target) Then sLastValue = Target.Value Else sLastValue = "Err"
        End If
        .Cells(lLastRow, 6).NumberFormat = "@"
        .Cells(lLastRow, 6) = sLastValue
    End With
    Application.ScreenUpdating = True: Application.EnableEvents = True
End Sub
 
Private Sub Workbook_SheetSelectionChange(ByVal Sh As Object, ByVal Target As Range)
    If Sh.Name = "LOG" Then Exit Sub
    If Target.Count > 1 Then
        Dim rCell As Range, rRng As Range
        On Error Resume Next
        Set rRng = Intersect(Target, Sh.UsedRange): On Error GoTo 0
        If rRng Is Nothing Then Exit Sub
        For Each rCell In rRng
            If Not IsError(rCell) Then sValue = sValue & "," & rCell Else sValue = sValue & "," & "Err"
        Next rCell
        sValue = Mid(sValue, 2)
    Else
        If Not IsError(Target) Then sValue = Target.Value Else sValue = "Err"
    End If
End Sub

Что такое модуль книги и как туда вставить код подробно описано в этой статье. Если кратко: открываем редактор VBA(Alt+F11) -находим в списке объектов ЭтаКнига(ThisWorkbook) -двойной щелчок по ней и в окно редактора справа вставляется этот код.

Лист «LOG» рекомендую сделать скрытым, иначе смысла в отслеживании действий мало, т.к. любой сможет перейти на этот лист и стереть историю своих изменений. Надежно скрыть лист поможет эта статья: Как сделать лист очень скрытым.


Для того, чтобы хранить историю изменений в отдельном текстовом файле или отдельной книге Excel можно применить такой код:

Option Explicit
Public sValue As String
Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)
    If Sh.Name = "LOG" Then Exit Sub
    Dim sLastValue As String
    Dim lLastRow As Long, wbLOG As Workbook
    Dim sPath as String
    Const sLOGName As String = "LOG.txt" '"LOG.xls"
    sPath = Application.DefaultFilePath
    Application.ScreenUpdating = False
    '==============   только для записи в текстовый файл   ======================
    If Dir(sPath & sLOGName, vbDirectory) = "" Then
        Open sPath & sLOGName For Output As #1: Close #1
    End If
    '==============   только для записи в отдельный файл Excel ======================
'    If Dir(sPath & sLOGName, vbDirectory) = "" Then
'        Set wbLOG = Workbooks.Add
'        wbLOG.SaveAs sPath & sLOGName, xlNormal
'    End If
    Set wbLOG = Workbooks.Open(sPath & sLOGName)
    '============================================================================
    With wbLOG.Sheets(1)
        lLastRow = .Cells.SpecialCells(xlLastCell).Row + 1
        If lLastRow = .Rows.Count Then Exit Sub
        Application.ScreenUpdating = False: Application.EnableEvents = False
        .Cells(lLastRow, 1) = CreateObject("wscript.network").UserName
        .Cells(lLastRow, 2) = Target.Address(0, 0)
        .Cells(lLastRow, 3) = Format(Now, "dd.mm.yyyy HH:MM:SS")
        .Cells(lLastRow, 4) = Sh.Name
        .Cells(lLastRow, 5).NumberFormat = "@"
        .Cells(lLastRow, 5) = sValue
        If Target.Count > 1 Then
            Dim rCell As Range, rRng As Range
            On Error Resume Next
            Set rRng = Intersect(Target, Sh.UsedRange): On Error GoTo 0
            If Not rRng Is Nothing Then
                For Each rCell In rRng
                    If Not IsError(Target) Then sLastValue = sLastValue & "," & rCell Else sLastValue = sLastValue & "," & "Err"
                Next rCell
                sLastValue = Mid(sLastValue, 2)
            Else
                sLastValue = ""
            End If
        Else
            If Not IsError(Target) Then sLastValue = Target.Value Else sLastValue = "Err"
        End If
        .Cells(lLastRow, 6).NumberFormat = "@"
        .Cells(lLastRow, 6) = sLastValue
    End With
    wbLOG.Close 1
    Application.ScreenUpdating = True: Application.EnableEvents = True
End Sub
 
Private Sub Workbook_SheetSelectionChange(ByVal Sh As Object, ByVal Target As Range)
    If Sh.Name = "LOG" Then Exit Sub
    If Target.Count > 1 Then
        Dim rCell As Range, rRng As Range
        On Error Resume Next
        Set rRng = Intersect(Target, Sh.UsedRange): On Error GoTo 0
        If rRng Is Nothing Then Exit Sub
        For Each rCell In rRng
            If Not IsError(rCell) Then sValue = sValue & "," & rCell Else sValue = sValue & "," & "Err"
        Next rCell
        sValue = Mid(sValue, 2)
    Else
        If Not IsError(Target) Then sValue = Target.Value Else sValue = "Err"
    End If
End Sub

Файл хранится в папке «Мои документы» пользователя. Имя файла — LOG.txt задается посредством константыConst sLOGName As String = «LOG.txt»

Чтобы вести изменения в отдельной книге Excel надо будет всего лишь закомментировать строки под «только для записи в текстовый файл» и раскомментировать строки под «только для записи в отдельный файл Excel» и поменять значение для константыConst sLOGName As String = «LOG.xls»
Не следует оставлять оба этих блока — они противоречат друг другу и если оставить оба, то будет создан текстовый файл, но изменения все равно будут заноситься в отдельную книгу Excel.
Если хотите, чтобы файл с историей изменений хранился в папке, отличной от Мои документы, то необходимо
Application.DefaultFilePath заменить на нужный путь, к примеру такой:sPath = «C:UsersThe_PristРабочий стол»

При изменении данного параметра необходимо учитывать, что не у всех пользователей может быть доступ к конкретной папке.


Все чаще стали появляться вопросы типа «А как отследить изменения только в конкретном диапазоне?». На самом деле не очень сложно. Надо добавить пару строк, которые будут определять в каких ячейках были изменения и какие отслеживать. Только добавить строки надо будет в обеих процедурах: Workbook_SheetChange и Workbook_SheetSelectionChange.
Например, код ниже будет отслеживать только те ячейки, для которых значение изменили только в диапазоне B:F:

Option Explicit
Public sValue As String
Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)
    If Sh.Name = "LOG" Then Exit Sub
    Dim rCells As Range
    'если изменения произошли не в диапазоне "B:F" - ничего не делаем
    On Error Resume Next
    Set rCells = Intersect(Target, Range("B:F"))
    If rCells Is Nothing Then Exit Sub
    On Error GoTo 0
 
    Dim sLastValue As String
    Dim lLastRow As Long, wbLOG As Workbook
    Dim sPath as String
    Const sLOGName As String = "LOG.txt" '"LOG.xls"
    sPath = Application.DefaultFilePath
    Application.ScreenUpdating = False
    '==============   только для записи в текстовый файл   ======================
    If Dir(sPath & sLOGName, vbDirectory) = "" Then
        Open sPath & sLOGName For Output As #1: Close #1
    End If
    '==============   только для записи в отдельный файл Excel ======================
'    If Dir(sPath & sLOGName, vbDirectory) = "" Then
'        Set wbLOG = Workbooks.Add
'        wbLOG.SaveAs sPath & sLOGName, xlNormal
'    End If
    Set wbLOG = Workbooks.Open(sPath & sLOGName)
    '============================================================================
    With wbLOG.Sheets(1)
        lLastRow = .Cells.SpecialCells(xlLastCell).Row + 1
        If lLastRow = .Rows.Count Then Exit Sub
        Application.ScreenUpdating = False: Application.EnableEvents = False
        .Cells(lLastRow, 1) = CreateObject("wscript.network").UserName
        .Cells(lLastRow, 2) = Target.Address(0, 0)
        .Cells(lLastRow, 3) = Format(Now, "dd.mm.yyyy HH:MM:SS")
        .Cells(lLastRow, 4) = Sh.Name
        .Cells(lLastRow, 5).NumberFormat = "@"
        .Cells(lLastRow, 5) = sValue
        If rCells.Count > 1 Then
            Dim rCell As Range, rRng As Range
            On Error Resume Next
            Set rRng = Intersect(rCells, Sh.UsedRange): On Error GoTo 0
            If Not rRng Is Nothing Then
                For Each rCell In rRng
                    If Not IsError(Target) Then sLastValue = sLastValue & "," & rCell Else sLastValue = sLastValue & "," & "Err"
                Next rCell
                sLastValue = Mid(sLastValue, 2)
            Else
                sLastValue = ""
            End If
        Else
            If Not IsError(Target) Then sLastValue = Target.Value Else sLastValue = "Err"
        End If
        .Cells(lLastRow, 6).NumberFormat = "@"
        .Cells(lLastRow, 6) = sLastValue
    End With
    wbLOG.Close 1
    Application.ScreenUpdating = True: Application.EnableEvents = True
End Sub
 
Private Sub Workbook_SheetSelectionChange(ByVal Sh As Object, ByVal Target As Range)
    If Sh.Name = "LOG" Then Exit Sub
    Dim rCells As Range
    'если изменения произошли не в диапазоне "B:F" - ничего не делаем
    On Error Resume Next
    Set rCells = Intersect(Target, Range("B:F"))
    If rCells Is Nothing Then Exit Sub
    On Error GoTo 0
 
    If rCells.Count > 1 Then
        Dim rCell As Range, rRng As Range
        On Error Resume Next
        Set rRng = Intersect(rCells, Sh.UsedRange): On Error GoTo 0
        If rRng Is Nothing Then Exit Sub
        For Each rCell In rRng
            If Not IsError(rCell) Then sValue = sValue & "," & rCell Else sValue = sValue & "," & "Err"
        Next rCell
        sValue = Mid(sValue, 2)
    Else
        If Not IsError(Target) Then sValue = Target.Value Else sValue = "Err"
    End If
End Sub

Скачать пример

  Tips_Macro_LOG.xls (50,0 KiB, 8 023 скачиваний)

Так же см.:
Выделение сделанных изменений
Запись изменений на листе в примечания


Статья помогла? Поделись ссылкой с друзьями!

  Плейлист   Видеоуроки


Поиск по меткам



Access
apple watch
Multex
Power Query и Power BI
VBA управление кодами
Бесплатные надстройки
Дата и время
Записки
ИП
Надстройки
Печать
Политика Конфиденциальности
Почта
Программы
Работа с приложениями
Разработка приложений
Росстат
Тренинги и вебинары
Финансовые
Форматирование
Функции Excel
акции MulTEx
ссылки
статистика

118 / 80 / 1

Регистрация: 10.08.2011

Сообщений: 664

1

Есть ли событие, которое отслеживает, было ли в ячейке изменение данных

12.12.2012, 01:18. Показов 14241. Ответов 20


Студворк — интернет-сервис помощи студентам

Здравствуйте.

Будьте добры подскажите, есть ли событие, которое отслеживает, если в ячейке произошло изменение данных.



0



5468 / 1148 / 50

Регистрация: 15.09.2012

Сообщений: 3,514

12.12.2012, 06:31

2

Change — срабатывает, когда пользователь вносит изменения на лист вручную и когда макрос вносит изменения на лист;
Calculate — срабатывает, когда в ячейке находится формула и формула изменяется.



1



118 / 80 / 1

Регистрация: 10.08.2011

Сообщений: 664

12.12.2012, 09:14

 [ТС]

3

пасибб, буду думать.



0



Staniiislav

30 / 30 / 0

Регистрация: 07.07.2010

Сообщений: 50

12.12.2012, 10:13

4

Visual Basic
1
2
3
4
5
6
7
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Application.Intersect(Range("B1:B200"), Target) Is Nothing Then ' проверяем изменения ячейки входит в диапазон B1:B200, если да то продолжаем
    If Target.Cells.Count > 1 Then Exit Sub ' проверяем, если изменяет НЕ больше одной ячейки, если да то продолжаем
    If IsEmpty(ActiveCell) Then Cells(Target.Row, Target.Column - 1).ClearContents ' ну и теперь само действие, в данном случаи условие, если изменяемая ячейка стала пустой, то удаляем значения со столбца А, тойже строки
End If
End Sub



1



118 / 80 / 1

Регистрация: 10.08.2011

Сообщений: 664

12.12.2012, 12:25

 [ТС]

5

это именно то, что я искал Станислав.

какая функция или процедура возвращает активную строку и столбец ? я ищу ищу никак не могу найти и понять…



0



Staniiislav

30 / 30 / 0

Регистрация: 07.07.2010

Сообщений: 50

12.12.2012, 13:14

6

Visual Basic
1
2
3
Target.Row ' строка изменения
Target.Column ' столбец изменения
Cells(Target.Row, Target.Column) ' ячейка изменения



1



Second

118 / 80 / 1

Регистрация: 10.08.2011

Сообщений: 664

12.12.2012, 17:05

 [ТС]

7

имею следующий код:

Visual Basic
1
2
3
Private Sub CommandButton1_Click()
   Worksheets("Лист1").Range(Cells(ActiveCell.Row, 1), Cells(ActiveCell.Row, 1)).Value = "test"
 End Sub

работает прекрасно, заполняя первое поле в записи значением после нажатия кнопки в текущей записи

почему тоже самое не работает в обработчике события:

Visual Basic
1
2
3
Private Sub Worksheet_Change(ByVal Target As Range)
   Worksheets("Лист1").Range(Cells(ActiveCell.Row, 1), Cells(ActiveCell.Row, 1)).Value = "test"
End Sub



0



3827 / 2254 / 751

Регистрация: 02.11.2012

Сообщений: 5,930

12.12.2012, 17:38

8

почему не работает — работает. впишите в любую ячейку что нибудь и нажмите ввод.

Добавлено через 7 минут
может вам такой обработчик нужен
для книги Workbook_SheetSelectionChange(ByVal Sh As Object, ByVal Target As Range)



0



118 / 80 / 1

Регистрация: 10.08.2011

Сообщений: 664

12.12.2012, 17:45

 [ТС]

9

Цитата
Сообщение от Vlad999
Посмотреть сообщение

почему не работает — работает. впишите в любую ячейку что нибудь и нажмите ввод.

блин, у меня не работает второй обработчик +_+
я сам же разработал сей код под свои нужны и тем более непонятно почему в обработчике события по изменению у окружающих работает, а у меня нет.

Цитата
Сообщение от Vlad999
Посмотреть сообщение

для книги Workbook_SheetSelectionChange(ByVal Sh As Object, ByVal Target As Range)

я думаю это событие не изменения данных, а смены листа. Не знаю, как применить Ваш вариант =/



0



5468 / 1148 / 50

Регистрация: 15.09.2012

Сообщений: 3,514

12.12.2012, 19:09

10

Second, процедуры событий нужно помещать в модули листов.

Примечание: есть ещё стандартный модуль, модуль класса, модуль формы, модуль книги.



0



118 / 80 / 1

Регистрация: 10.08.2011

Сообщений: 664

12.12.2012, 19:40

 [ТС]

11

Цитата
Сообщение от Скрипт
Посмотреть сообщение

Second, процедуры событий нужно помещать в модули листов.

Примечание: есть ещё стандартный модуль, модуль класса, модуль формы, модуль книги.

ясно, зафтра уже буду решать поблему )



0



30 / 30 / 0

Регистрация: 07.07.2010

Сообщений: 50

13.12.2012, 10:32

12

Цитата
Сообщение от Second
Посмотреть сообщение

ясно, зафтра уже буду решать поблему )

Вы бы выложили пример с тем что хотите отслеживать, изменять или еще чего-то, и Вам бы уже готовый пример помогли сделать!



0



118 / 80 / 1

Регистрация: 10.08.2011

Сообщений: 664

13.12.2012, 10:51

 [ТС]

13

ситуация фантастическая, на моем рабочем месте обработчик категорически не работает, проверял у коллег — все прекрасно… моветон однако =/

есть какие-либо идеи почему такое может происходить ?

Добавлено через 2 минуты

Цитата
Сообщение от Staniiislav
Посмотреть сообщение

Вы бы выложили пример с тем что хотите отслеживать, изменять или еще чего-то, и Вам бы уже готовый пример помогли сделать!

я хочу, чтобы в назначенном поле ( для пользователя RO) автоматом проставлялась дата последнего обращения к записи.



0



Скрипт

5468 / 1148 / 50

Регистрация: 15.09.2012

Сообщений: 3,514

13.12.2012, 13:15

14

Second, такое событие у вас работает?

Visual Basic
1
2
3
Private Sub Worksheet_Change(ByVal Target As Range)
    MsgBox "Change Occur"
End Sub



0



118 / 80 / 1

Регистрация: 10.08.2011

Сообщений: 664

14.12.2012, 09:10

 [ТС]

15

обязательно опробую и дам ответ, завал пока )))

Добавлено через 14 часов 2 минуты
событие не работает, видимо какие-то трудности связаны с машиной на рабочем месте.
в любом случае мне все равно нужна помощь, так как надо доработать код и есть раб. машины, где он выполняется корректно.



0



Скрипт

5468 / 1148 / 50

Регистрация: 15.09.2012

Сообщений: 3,514

14.12.2012, 09:30

16

Second, сделайте новую книгу, поместите туда вот этот код:

Visual Basic
1
2
3
Private Sub Worksheet_Change(ByVal Target As Range)
    MsgBox "Change Occur"
End Sub

убедитесь, что у вас этот код не работает, и выложите книгу на форуме.

Ещё укажите, какая у вас версия Excel: 2003, 2007 или другая.



0



Second

118 / 80 / 1

Регистрация: 10.08.2011

Сообщений: 664

14.12.2012, 10:41

 [ТС]

17

так, большое спасибо макрос Ваш заработал на «проблемном» рабочем месте. Подозреваю где-то я в настройках мог накосячить.

Добавлено через 25 минут
итак, на текущий момент имеется код:

Visual Basic
1
2
3
Private Sub Worksheet_Change(ByVal Target As Range)
       Worksheets("Лист1").Range(Cells(ActiveCell.Row, 1), Cells(ActiveCell.Row, 1)).Value = "test"
End Sub

мне необходимо, чтобы в первое поле записи, в которой произошла редакция ячейки, вносилась текущая дата.
код работает только если после внесения изменения выйти Tab’ом, по Enter’у курсор скачет на след запись и вносит изменение в первом поле уже в след. записи, что крайне недопустимо.
Из моих скудных соображений подозреваю, что надо перехватить каким-нить событием чуть ранее, чем я делаю событием Change. Есть ли таковое ?



0



5468 / 1148 / 50

Регистрация: 15.09.2012

Сообщений: 3,514

14.12.2012, 10:44

18

Second, вместо ActiveCell и нужно использовать Target.
Target — это ячейка, где произошло изменение.



1



118 / 80 / 1

Регистрация: 10.08.2011

Сообщений: 664

14.12.2012, 11:01

 [ТС]

19

секунду опробую. Все корректно работает

Добавлено через 9 минут
осталось в ячейку внести текущую дату и желательно время,а еще бы идеально и пользователя +_+



0



Скрипт

5468 / 1148 / 50

Регистрация: 15.09.2012

Сообщений: 3,514

14.12.2012, 11:16

20

Second, дату и время автоматически можно вносить двумя способами:

  1. средствами самой программы Excel, используя функцию =ТДАТА(). Только дата и время в этом случае будут меняться, например, если внести какие-нибудь изменения на лист;
  2. с помощью средств программы VBA:
    Visual Basic
    1
    2
    3
    4
    5
    6
    7
    8
    
    Sub Procedure_1()
        
        'Чтобы увидеть результат работы кода: View - Immediate Window.
        Debug.Print Date
        Debug.Print Time
        Debug.Print Now
        
    End Sub

Пользователя можно так указать:

Visual Basic
1
2
3
4
5
Sub Procedure_2()
    
    Debug.Print Application.UserName
    
End Sub



1



 

Diana Tailor

Пользователь

Сообщений: 982
Регистрация: 28.12.2012

#1

07.12.2018 08:15:37

Здравствуйте.

Имеется необходимость отследить строки, в которых изменились ячейки.
Собственно, простейший макрос:

Код
Private Sub Worksheet_Change(ByVal Target As Range)
MsgBox Target.Address
End Sub

Если мы по одной ячейке изменяем, все корректно. Если работаем с диапазоном – не очень.

Пример: пустой лист.

Код
Range(“A1”)=1
Range(“A3”)=1

Как видно, в ячейке A2 значений нет. Если выделить диапазон A1:A3 нажать Delete, то Excel считает, что изменения произошли во всем диапазоне, хотя по факту только в 1 и 3 строке.

Как отследить значения именно измененных строк? (т.е. если не было значений и удалились – это уже не изменение, а если были и удалились/поменялись – уже изменение).

Спасибо.

Изменено: Diana Tailor07.12.2018 12:16:39

 

DenSyo

Пользователь

Сообщений: 82
Регистрация: 15.05.2018

#2

07.12.2018 09:24:22

гугол подсказывает…

Код
Dim vOldVal 'Must be at top of module

Private Sub Worksheet_SelectionChange(ByVal Target As Range)
    vOldVal = Target
End Sub

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

Изменено: DenSyo07.12.2018 09:32:50

 
DenSyo

, спасибо. Пытаюсь разобраться

 

Jack Famous

Пользователь

Сообщений: 10852
Регистрация: 07.11.2014

OS: Win 8.1 Корп. x64 | Excel 2016 x64: | Browser: Chrome

#4

07.12.2018 10:25:25

Diana Tailor, доброго утра  :)

Цитата
Diana Tailor: отследить строки, в которых изменились ячейки

а для чего? Если для отката, то есть хороший способ: задублировать лист, на котором макрос выполняет изменения и, при отмене, просто удалить его, а при подтверждении удалить исходник

Изменено: Jack Famous07.12.2018 10:25:39

Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄

 
Jack Famous

, здрасьте :)
Ситуация такая: имеем в загруженном интерфейсе лист Excel. Путем скрытия/открытия блокировки/разблокировки столбцов заносим туда разные данные.
От этих данных зависят другие данные, т.е. мы занесли какие-то значения, поменяли, и нужно пересчитать зависящие от измененных ячеек данные.
Так вот, чтобы из 1006 строк не пересчитывать все подряд, потребовалось пересчитать только те строки, в которых были произведены изменения.

Как-то так :)

Насколько я понимаю, нужно считать диапазон до изменения в массив, потом после изменения в массив. Потом сравнить массивы и, следовательно, получить измененные строки.
Вот ищу алгоритмы теперь как быстро сравнить два массива.

 

Jack Famous

Пользователь

Сообщений: 10852
Регистрация: 07.11.2014

OS: Win 8.1 Корп. x64 | Excel 2016 x64: | Browser: Chrome

#6

07.12.2018 10:57:48

Цитата
Diana Tailor: пересчитать только те строки, в которых были произведены изменения

почитайте про Application.Calculate, Application.CalculateFull и Application.CalculateFullRebuild (обычно мне хватает первого). Если он пересчитывает очень долго, то стоит пересмотреть структуру организации данных и связей между ними.

Цитата
Diana Tailor: сравнить массивы

…можно очень быстро. Создавайте отдельную тему с примером и поможем  ;) Опять же, если Application.Calculate справится, то и сравнивать ничего не придётся.

Изменено: Jack Famous07.12.2018 10:58:57

Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄

 

Calculate — это круто, конечно, но снова-таки, учитывая размерность моих данных — Range(«A7:SW1006») тут любой calculate  загнется, поэтому расчеты происходят не автоматически, а в VBA по нажатию кнопки )

По поводу массивов — посмотрю, вроде у Димы Щербакова на сайте видела или у Игоря неплохие решения, вот ищу :)

 

JayBhagavan

Пользователь

Сообщений: 11833
Регистрация: 17.01.2014

ПОЛ: МУЖСКОЙ | Win10x64, MSO2019x64

#8

07.12.2018 11:08:06

Jack Famous, Calculate можно применять к конкретному диапазону. Пример из справки:

Код
Worksheets("Sheet1").UsedRange.Columns("A:C").Calculate

<#0>
Формула массива (ФМ) вводится Ctrl+Shift+Enter
Memento mori

 

DenSyo

Пользователь

Сообщений: 82
Регистрация: 15.05.2018

склоняюсь к варианту с undo/redo, если уж продолжать в этом направлении. заполнять массив на каждый клик слишком уж бессмысленно…

 
DenSyo

, спасибо за комментарий.
Теперь буду искать материалы в этом направлении :)

 

Jack Famous

Пользователь

Сообщений: 10852
Регистрация: 07.11.2014

OS: Win 8.1 Корп. x64 | Excel 2016 x64: | Browser: Chrome

#11

07.12.2018 11:23:51

Цитата
Diana Tailor: расчеты происходят не автоматически, а в VBA по нажатию кнопки

это, конечно правильно, но

Цитата
размерность моих данных — Range(«A7:SW1006»)

— это перебор  :D

Цитата
вот ищу

вангую, создав тему, результат будет лучше))

Цитата
JayBhagavan: Calculate можно применять к конкретному диапазону

да — я в курсе, спасибо  ;)

Изменено: Jack Famous07.12.2018 11:24:08

Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄

 

БМВ

Модератор

Сообщений: 21385
Регистрация: 28.12.2016

Excel 2013, 2016

#12

07.12.2018 11:28:05

Цитата
Diana Tailor написал:
Range(«A7:SW1006»)

конечно все зависит от того что делается, но объем данных не такой и большой.
#2 не прокатит в случае выделения нескольких диапазонов.

По вопросам из тем форума, личку не читаю.

 

Если не получится отточить быстродейственный макрос, попрошу модератора перенести тему в форум основной :)

 

bedvit

Пользователь

Сообщений: 2477
Регистрация: 02.04.2015

Виталий

Diana Tailor, напишите, что вам нужно в конечном итоге, возможно вам посоветуют другой подход к решению вашего вопроса. Хорошо бы приложить и файл пример, что есть/что нужно получить.

«Бритва Оккама» или «Принцип Калашникова»?

 

Собственно, пример во вложении :)

 

Суть такова: в диапазоне (только он намного больше) изменяем ячейки, в этих же строках от измененных ячеек будут произведены дальнейшие вычисления. Вот и приходится искать строки, в которых были изменены ячейки, и в них уже принудительно в vba производить расчет

 

Neufazendnik

Гость

#18

07.12.2018 12:34:59

У меня в Логпрог данная задача остро стоит и решена следующим образом:
Листы, на которых идет контроль измененных строк содержат обработчик:

Код
Private Sub Worksheet_Change(ByVal Target As Range)
Call hi(Target)
End Sub

Таких листов у меня несколько. Номер активного контролируется глобальной переменной ge18.
Существует процедура hi, которая заполняет глобальную переменною — массив ge102(ge18,ххх),содержающю номера для ххх строк листа ge18, в которых произошли изменения.
число ххх помещенных в массив элементов вписывается в ge102(ge18,0)
Код наверняка можно оптимизировать. Мне некогда. Меня устраивает, что он рабочий и с удалением строк справляется корректно.

Код
Sub hi(Target As Range)
'проставляет номера строк, в которых были сделаны изменения данных в массив ge102
'эта подпрограмма отрабатывается до selectionCange, поэтому vc1 содержит именно строку, которая модифицировалась, а не строку, в которой уже находится фокус ввода.
Static hi01 As Long 'номер ВЕРХНЕЙ строки, в которой произошло изменение.
Static hi02 As Long 'Число строк, которые изменялись одновременно.
Static hi03 As Long 'уже вписанное в ge102 до этого число строк.
Static hi04 As Long 'текущий номер индекса в ge102
Static hi05 As Long 'номер элемента в  ge102
'hi06 -loop
Static hi07 As Long 'число вписанных элементов в ge102
Dim hi08 As Long 'число элементов hi102 обработано
Dim hi09 As Long 'номер строки, вписываемый в ge102
Dim hi10 'элемент target
Dim hi11 As String 'address hi10

If Target.Columns.Count = Columns.Count Then Exit Sub
If TypeName(Selection) = "Range" And Selection.Columns.Count = Columns.Count Then Exit Sub
'If Selection.EntireColumn.Count  ge158 Then 'http://www.planetaexcel.ru/forum/index.php?PAGE_NAME=message&FID=1&TID=100712&TITLE_SEO=100712-otslezhivanie-komandy-udaleniya-strok-iz-worksheetchange&MID=832563#message832563 Target.Address  Target.EntireRow.Address Then ' обходим случай  MsgBox "Удаляются строки, игнорируем обработку"
  hi07 = 0
  hi03 = ge102(ge18, 0)
  For Each hi10 In Target
    hi11 = hi10.Address
    hi09 = Range(hi11).Row
    If hi09 > ge126 - 1 Then 'на строки заголовка и вышележащие не реагируем.
      hi04 = hi03 + hi07
      For hi05 = 1 To hi03 + hi07
        If ge102(ge18, hi05) = hi09 Then GoTo hi06
        Next
      hi04 = hi03 + hi07 + 1
      If hi04 > ge129 Then
        If ge102(ge18, 0)  ge129 Then MsgBox ("Изменена информация одновременно более, чем в " & ge129 & " строках. Сохранение будет произведено только для первых " & ge129 & " изменений. Остальная модифицированная информация не сохранится.")
        ge102(ge18, 0) = ge129
  Exit Sub
        End If
      hi07 = hi07 + 1
      ge102(ge18, hi04) = hi09
      End If
hi06:
    Next
  ge102(ge18, 0) = hi03 + hi07
  'End If
End Sub

Изменено: Neufazendnik07.12.2018 12:37:35

 

bedvit

Пользователь

Сообщений: 2477
Регистрация: 02.04.2015

Виталий

#19

07.12.2018 13:49:13

Цитата
Diana Tailor написал:
Вот и приходится искать строки, в которых были изменены ячейки,

Diana Tailor, Excel сам помечает какие ячейки надо пересчитать.
Для ИНФО см.

Пересчет в Excel

Цитата
Вычисление листов в Excel можно рассматривать как процесс из трех этапов:
1.Создание дерева зависимостей
2.Создание цепочки вычислений
3.Пересчет ячеек

Если вы используете VBA, возможно проставить программно ячейки для пересчета, для этого вам пригодится связка Range.Dirty —  Range.Calculate :

Цитата
Начиная с Microsoft Excel 2002, объект Range в Microsoft Visual Basic для приложений (VBA) поддерживает метод Range.Dirty, который отмечает ячейки как требующие подсчета. Когда он используется совместно с методом Range.Calculate, он включает принудительный пересчет ячеек в заданном диапазоне. Это удобно при выполнении ограниченного вычисления в макросе, где установлен ручной режим подсчета (для избежания избытка вычисляемых ячеек, не относящихся к функции макроса). Методы подсчета диапазонов недоступны через API C ( … к моему сожалению.)

Если вы считаете все в VBA, а данные храните на листах Excel, думаю здесь в любом случае нужно идти через Worksheet_Change.
Далее, уже сверять изменились ли данные — было/стало и делать пересчет по изменениям. Пока не совсем ясно. как изменяется ваш большой массив, пользователь вставляет данные сразу массивом? Как с ним работает пользователь? зачем пользователю тысячи строк и множество столбцов для изменения? Если вставляется массив, обрабатывайте сразу массивом изменения.

«Бритва Оккама» или «Принцип Калашникова»?

 

Diana Tailor

Пользователь

Сообщений: 982
Регистрация: 28.12.2012

#20

07.12.2018 14:25:50

Как много сегодня нового узнала :)

bedvit

,

Neufazendnik

спасибо, что помогаете!

Цитата
Пока не совсем ясно. как изменяется ваш большой массив, пользователь вставляет данные сразу массивом? Как с ним работает пользователь?

Приложила более подробный пример.
Вводим данные путем поячейного ввода, как в толбец, так и в строку, либо путем копирования диапазона из одной книги в другую.

Например, ввели/изменили значение в D7, возникла необходимость посмотреть, как изменились значения в C7, F7, G7. Нажали кнопочку, все посчиталось. Поэтому необходим весь гигантский диапазон «под рукой».

Или, пакетно ввели информацию в ячейки D7:E17, нажали рассчитать, посмотрели, что получилось везде.

После сохранения, происходит выгрузка информации со всего листа в базу данных (это уже отдельная история, пока у меня просто копируется лист в новый файл, сохраняется в отдельную книгу, так как до БД мне далековато на VBA).

Перерасчет ячеек идет построчно, т.е. если значения менялись только в одной строке, то перерасчет будет только в этой же строке…

Прикрепленные файлы

  • 2 Пример 18-12-07.xlsx (9.86 КБ)

Изменено: Diana Tailor07.12.2018 14:28:36
(не то прикрепила :) )

 

БМВ

Модератор

Сообщений: 21385
Регистрация: 28.12.2016

Excel 2013, 2016

#21

07.12.2018 15:16:30

Повторю

Цитата
БМВ написал:
Diana Tailor  написал:Range(«A7:SW1006»)конечно все зависит от того что делается, но объем данных не такой и большой.

Что там считается?

По вопросам из тем форума, личку не читаю.

 
БМВ

, простите, как-то упустила Ваше сообщение :)

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

Очень много параметров рассчитывается в одной строке :)

Т.е. идет список точек опробования льда в столбце 1, а в других столбцах — параметры, соответствующие точке опробования.

 

На данный момент штудирую Range.Dirty, но, что-то мне подсказывает, придется обойтись свободным столбцом, в нем помечать, что в данной строке были изменения через Target, и, следовательно, пересчитать только эти строки. Более простого решения пока не нашла.

 

БМВ

Модератор

Сообщений: 21385
Регистрация: 28.12.2016

Excel 2013, 2016

Diana Tailor, Я не верю что для расчета таблицы нужен VBA . Функции листа справятся и снимут головняк определения что считать а что нет.

Посмотрите на

это

и формул много и пересчитываются все и ничего.

По вопросам из тем форума, личку не читаю.

 
БМВ

, я видела эту штуку :) мощно :)
я правильно понимаю алгоритм, что нужно будет прописать формулы в расчетных ячейках, протянуть их на все 1000 строк моих, поставить ручную калькуляшку, и калькулировать уже конкретный диапазон строк?

 

БМВ

Модератор

Сообщений: 21385
Регистрация: 28.12.2016

Excel 2013, 2016

#26

07.12.2018 16:06:41

Цитата
Diana Tailor написал:
поставить ручную калькуляшку, и калькулировать уже конкретный диапазон строк?

Зачем? пусть автомат считает

По вопросам из тем форума, личку не читаю.

 

bedvit

Пользователь

Сообщений: 2477
Регистрация: 02.04.2015

Виталий

Diana Tailor, лучшим решением, если есть такая возможность, будет расчет в самом листе Excel. Во-первых — сам Excel позаботится о пересчете изменений. Во-вторых это будет происходить в многопоточном режиме, в отличии от VBA. Собственно,БМВ, пишет о том же.

«Бритва Оккама» или «Принцип Калашникова»?

 
БМВ

,

bedvit

, спасибо!
Прописываю формулы, посмотрим, что получится :)

 

Выражаю слова благодарности всем, кто принял участие в обсуждении данной темы.
Также спасибо модераторам за терпение!
Перешла на Calculate в автоматическом режиме, работает значительно быстрее, чем в VBA.

 

БМВ

Модератор

Сообщений: 21385
Регистрация: 28.12.2016

Excel 2013, 2016

#30

08.12.2018 14:24:36

Цитата
Diana Tailor написал:
работает значительно быстрее, чем в VBA.

А я говорил :-) .
Diana Tailor, часто макрушники забывают про то, что сперва был табличный процессор потом к нему появился макро язык , на котором писать было прям скажем не удобно. С появлением VBA стало намного легче, но не следует превращать Excel в набор таблиц с данными и оболочку для обработки из при помощи скриптов. Есть то что без VBA не сделать, и всему есть свое применение.
Успехов.

По вопросам из тем форума, личку не читаю.

Отслеживание изменений и ведение журнала при помощи кода
Изменения можно отслеживать и при помощи кода. При этом такой метод дает не менее полное представление об изменениях в ячейках и при этом давать общий доступ книге нет необходимости, а следовательно и все ограничения, применимые для книг в общем доступе тоже остаются за бортом, что делает такой подход порой предпочтительнее. Единственное, при таком режиме файл нельзя будет редактировать одновременно нескольким пользователям. Но в большинстве случаев этого и не надо.
Я могу предложить небольшой код, который будет отслеживать следующие параметры:

  • Имя пользователя(учетная запись пользователя на компьютере), сделавшего изменения
  • адрес ячейки, в которую были внесены изменения
  • дата и время внесения изменений
  • имя листа, в котором были сделаны изменения
  • значение ячейки до изменения(старое значение)
  • значение ячейки после изменения(новое значение).

Итак, Вы решили реализовать данный процесс. Изначально необходимо разрешить макросы, без этого данный способ ведения журнала не сработает. Далее необходимо добавить в книгу новый лист с именем LOG и вставить приведенный код в модуль книги, изменения в которойнеобходимо отслеживать:

Option Explicit Public sValue As String Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range) If Sh.Name = «LOG» Then Exit Sub Dim sLastValue As String Dim lLastRow As Long With Sheets(«LOG») lLastRow = .Cells.SpecialCells(xlLastCell).Row + 1 If lLastRow = Rows.Count Then Exit Sub Application.ScreenUpdating = False: Application.EnableEvents = False .Cells(lLastRow, 1) = CreateObject(«wscript.network»).UserName .Cells(lLastRow, 2) = Target.Address(0, 0) .Cells(lLastRow, 3) = Format(Now, «dd.mm.yyyy HH:MM:SS») .Cells(lLastRow, 4) = Sh.Name .Cells(lLastRow, 5).NumberFormat = «@» .Cells(lLastRow, 5) = sValue If Target.Count > 1 Then Dim rCell As Range, rRng As Range On Error Resume Next Set rRng = Intersect(Target, Sh.UsedRange): On Error GoTo 0 If Not rRng Is Nothing Then For Each rCell In rRng If Not IsError(Target) Then sLastValue = sLastValue & «,» & rCell Else sLastValue = sLastValue & «,» & «Err» Next rCell sLastValue = Mid(sLastValue, 2) Else sLastValue = «» End If Else If Not IsError(Target) Then sLastValue = Target.Value Else sLastValue = «Err» End If .Cells(lLastRow, 6).NumberFormat = «@» .Cells(lLastRow, 6) = sLastValue End With Application.ScreenUpdating = True: Application.EnableEvents = True End Sub Private Sub Workbook_SheetSelectionChange(ByVal Sh As Object, ByVal Target As Range) If Sh.Name = «LOG» Then Exit Sub If Target.Count > 1 Then Dim rCell As Range, rRng As Range On Error Resume Next Set rRng = Intersect(Target, Sh.UsedRange): On Error GoTo 0 If rRng Is Nothing Then Exit Sub For Each rCell In rRng If Not IsError(rCell) Then sValue = sValue & «,» & rCell Else sValue = sValue & «,» & «Err» Next rCell sValue = Mid(sValue, 2) Else If Not IsError(Target) Then sValue = Target.Value Else sValue = «Err» End If End Sub

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

Option Explicit

Public sValue As String

Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)

    If Sh.Name = «LOG» Then Exit Sub

    Dim sLastValue As String

    Dim lLastRow As Long

    With Sheets(«LOG»)

        lLastRow = .Cells.SpecialCells(xlLastCell).Row + 1

        If lLastRow = Rows.Count Then Exit Sub

        Application.ScreenUpdating = False: Application.EnableEvents = False

        .Cells(lLastRow, 1) = CreateObject(«wscript.network»).UserName

        .Cells(lLastRow, 2) = Target.Address(0, 0)

        .Cells(lLastRow, 3) = Format(Now, «dd.mm.yyyy HH:MM:SS»)

        .Cells(lLastRow, 4) = Sh.Name

        .Cells(lLastRow, 5).NumberFormat = «@»

        .Cells(lLastRow, 5) = sValue

        If Target.Count > 1 Then

            Dim rCell As Range, rRng As Range

            On Error Resume Next

            Set rRng = Intersect(Target, Sh.UsedRange): On Error GoTo 0

            If Not rRng Is Nothing Then

                For Each rCell In rRng

                    If Not IsError(Target) Then sLastValue = sLastValue & «,» & rCell Else sLastValue = sLastValue & «,» & «Err»

                Next rCell

                sLastValue = Mid(sLastValue, 2)

            Else

                sLastValue = «»

            End If

        Else

            If Not IsError(Target) Then sLastValue = Target.Value Else sLastValue = «Err»

        End If

        .Cells(lLastRow, 6).NumberFormat = «@»

        .Cells(lLastRow, 6) = sLastValue

    End With

    Application.ScreenUpdating = True: Application.EnableEvents = True

End Sub

Private Sub Workbook_SheetSelectionChange(ByVal Sh As Object, ByVal Target As Range)

    If Sh.Name = «LOG» Then Exit Sub

    If Target.Count > 1 Then

        Dim rCell As Range, rRng As Range

        On Error Resume Next

        Set rRng = Intersect(Target, Sh.UsedRange): On Error GoTo 0

        If rRng Is Nothing Then Exit Sub

        For Each rCell In rRng

            If Not IsError(rCell) Then sValue = sValue & «,» & rCell Else sValue = sValue & «,» & «Err»

        Next rCell

        sValue = Mid(sValue, 2)

    Else

        If Not IsError(Target) Then sValue = Target.Value Else sValue = «Err»

    End If

End Sub

Что такое модуль книги и как туда вставить код подробно описано в этой статье. Если кратко: открываем редактор VBA(Alt+F11) -находим в списке объектов ЭтаКнига(ThisWorkbook) -двойной щелчок по ней и в окно редактора справа вставляется этот код.

Лист «LOG» рекомендую сделать скрытым, иначе смысла в отслеживании действий мало, т.к. любой сможет перейти на этот лист и стереть историю своих изменений. Надежно скрыть лист поможет эта статья: Как сделать лист очень скрытым.


Для того, чтобы хранить историю изменений в отдельном текстовом файле или отдельной книге Excel можно применить такой код:

Option Explicit Public sValue As String Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range) If Sh.Name = «LOG» Then Exit Sub Dim sLastValue As String Dim lLastRow As Long, wbLOG As Workbook Dim sPath as String Const sLOGName As String = «LOG.txt» ‘»LOG.xls» sPath = Application.DefaultFilePath Application.ScreenUpdating = False ‘============== только для записи в текстовый файл ====================== If Dir(sPath & sLOGName, vbDirectory) = «» Then Open sPath & sLOGName For Output As #1: Close #1 End If ‘============== только для записи в отдельный файл Excel ====================== ‘ If Dir(sPath & sLOGName, vbDirectory) = «» Then ‘ Set wbLOG = Workbooks.Add ‘ wbLOG.SaveAs sPath & sLOGName, xlNormal ‘ End If Set wbLOG = Workbooks.Open(sPath & sLOGName) ‘============================================================================ With wbLOG.Sheets(1) lLastRow = .Cells.SpecialCells(xlLastCell).Row + 1 If lLastRow = .Rows.Count Then Exit Sub Application.ScreenUpdating = False: Application.EnableEvents = False .Cells(lLastRow, 1) = CreateObject(«wscript.network»).UserName .Cells(lLastRow, 2) = Target.Address(0, 0) .Cells(lLastRow, 3) = Format(Now, «dd.mm.yyyy HH:MM:SS») .Cells(lLastRow, 4) = Sh.Name .Cells(lLastRow, 5).NumberFormat = «@» .Cells(lLastRow, 5) = sValue If Target.Count > 1 Then Dim rCell As Range, rRng As Range On Error Resume Next Set rRng = Intersect(Target, Sh.UsedRange): On Error GoTo 0 If Not rRng Is Nothing Then For Each rCell In rRng If Not IsError(Target) Then sLastValue = sLastValue & «,» & rCell Else sLastValue = sLastValue & «,» & «Err» Next rCell sLastValue = Mid(sLastValue, 2) Else sLastValue = «» End If Else If Not IsError(Target) Then sLastValue = Target.Value Else sLastValue = «Err» End If .Cells(lLastRow, 6).NumberFormat = «@» .Cells(lLastRow, 6) = sLastValue End With wbLOG.Close 1 Application.ScreenUpdating = True: Application.EnableEvents = True End Sub Private Sub Workbook_SheetSelectionChange(ByVal Sh As Object, ByVal Target As Range) If Sh.Name = «LOG» Then Exit Sub If Target.Count > 1 Then Dim rCell As Range, rRng As Range On Error Resume Next Set rRng = Intersect(Target, Sh.UsedRange): On Error GoTo 0 If rRng Is Nothing Then Exit Sub For Each rCell In rRng If Not IsError(rCell) Then sValue = sValue & «,» & rCell Else sValue = sValue & «,» & «Err» Next rCell sValue = Mid(sValue, 2) Else If Not IsError(Target) Then sValue = Target.Value Else sValue = «Err» End If End Sub

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

Option Explicit

Public sValue As String

Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)

    If Sh.Name = «LOG» Then Exit Sub

    Dim sLastValue As String

    Dim lLastRow As Long, wbLOG As Workbook

    Dim sPath as String

    Const sLOGName As String = «LOG.txt» ‘»LOG.xls»

    sPath = Application.DefaultFilePath

    Application.ScreenUpdating = False

    ‘==============   только для записи в текстовый файл   ======================

    If Dir(sPath & sLOGName, vbDirectory) = «» Then

        Open sPath & sLOGName For Output As #1: Close #1

    End If

    ‘==============   только для записи в отдельный файл Excel ======================

    If Dir(sPath & sLOGName, vbDirectory) = «» Then

        Set wbLOG = Workbooks.Add

        wbLOG.SaveAs sPath & sLOGName, xlNormal

    End If

    Set wbLOG = Workbooks.Open(sPath & sLOGName)

    ‘============================================================================

    With wbLOG.Sheets(1)

        lLastRow = .Cells.SpecialCells(xlLastCell).Row + 1

        If lLastRow = .Rows.Count Then Exit Sub

        Application.ScreenUpdating = False: Application.EnableEvents = False

        .Cells(lLastRow, 1) = CreateObject(«wscript.network»).UserName

        .Cells(lLastRow, 2) = Target.Address(0, 0)

        .Cells(lLastRow, 3) = Format(Now, «dd.mm.yyyy HH:MM:SS»)

        .Cells(lLastRow, 4) = Sh.Name

        .Cells(lLastRow, 5).NumberFormat = «@»

        .Cells(lLastRow, 5) = sValue

        If Target.Count > 1 Then

            Dim rCell As Range, rRng As Range

            On Error Resume Next

            Set rRng = Intersect(Target, Sh.UsedRange): On Error GoTo 0

            If Not rRng Is Nothing Then

                For Each rCell In rRng

                    If Not IsError(Target) Then sLastValue = sLastValue & «,» & rCell Else sLastValue = sLastValue & «,» & «Err»

                Next rCell

                sLastValue = Mid(sLastValue, 2)

            Else

                sLastValue = «»

            End If

        Else

            If Not IsError(Target) Then sLastValue = Target.Value Else sLastValue = «Err»

        End If

        .Cells(lLastRow, 6).NumberFormat = «@»

        .Cells(lLastRow, 6) = sLastValue

    End With

    wbLOG.Close 1

    Application.ScreenUpdating = True: Application.EnableEvents = True

End Sub

Private Sub Workbook_SheetSelectionChange(ByVal Sh As Object, ByVal Target As Range)

    If Sh.Name = «LOG» Then Exit Sub

    If Target.Count > 1 Then

        Dim rCell As Range, rRng As Range

        On Error Resume Next

        Set rRng = Intersect(Target, Sh.UsedRange): On Error GoTo 0

        If rRng Is Nothing Then Exit Sub

        For Each rCell In rRng

            If Not IsError(rCell) Then sValue = sValue & «,» & rCell Else sValue = sValue & «,» & «Err»

        Next rCell

        sValue = Mid(sValue, 2)

    Else

        If Not IsError(Target) Then sValue = Target.Value Else sValue = «Err»

    End If

End Sub


Файл хранится в папке «Мои документы» пользователя. Имя файла —
LOG.txt задается посредством константыConst sLOGName As String = «LOG.txt»

Чтобы вести изменения в отдельной книге Excel надо будет всего лишь закомментировать строки под «только для записи в текстовый файл» и раскомментировать строки под «только для записи в отдельный файл Excel» и поменять значение для константыConst sLOGName As String = «LOG.xls»
Не следует оставлять оба этих блока — они противоречат друг другу и если оставить оба, то будет создан текстовый файл, но изменения все равно будут заноситься в отдельную книгу Excel.
Если хотите, чтобы файл с историей изменений хранился в папке, отличной от
Мои документы, то необходимо
Application.DefaultFilePath заменить на нужный путь, к примеру такой:sPath = «C:UsersThe_PristРабочий стол»

При изменении данного параметра необходимо учитывать, что не у всех пользователей может быть доступ к конкретной папке.

Скачать пример

  Tips_Macro_LOG.xls (50,0 KiB, 5 286 скачиваний)

Like this post? Please share to your friends:
  • Отслеживание события в excel
  • Отступ текста в списке word
  • Отслеживание правок в word
  • Отступ слева для всего текста word
  • Отслеживание портфеля акций в excel