VBA: Как найти диапазон, редактируемый через «заполнить» или «копировать / вставить» (или любые несколько ячеек) в модуле рабочего листа - PullRequest
0 голосов
/ 02 апреля 2019

У меня есть две таблицы с пятью столбцами, которые я хочу отслеживать любые сделанные изменения.Я представляю исходное состояние этих столбцов на рабочем листе A и отмечаю изменение на рабочем листе B.

Снимок экрана рабочего листа B

Ниже приведен внешний вид рабочего листа B, скажем, что рабочий лист A имеетЧасть «ORIG», но с фильтрами и прочим: Comparions of Original State and New State

Примечание. Я уже написал другую подпрограмму рабочего листа, которая будет фильтровать «Все то же самое?»= False (это означает, что эта строка изменяется) всякий раз, когда активируется этот рабочий лист.

Я уже написал код, который будет работать для изменения одной ячейки (например, когда вы редактируете ячейку с помощью F2, а затемнажмите клавишу ВВОД, когда вы закончите) - подпрограмма рабочего листа, которая срабатывает при изменении рабочего листа.Подпрограмма проверит наличие измененного диапазона, и, если диапазон является указанной областью, соответствующая область будет обновлена ​​в другом листе.

Подпрограмма рабочего листа

Private Sub Worksheet_Change(ByVal target As Range)
    Dim start_row As Long: start_row = 4
    Dim last_row As Long: last_row = findLastRow()

' when values are changed in "REPORT", check if values are ouputable and update these values
    If IsInArray(Number2Letter(target.Column), inputColumns) And target.row >= start_row And target.row <= last_row Then
        ' Update corresponding cell in worksheetB
    End If
End Sub

Другой UDF / UDS

Public Function Number2Letter(ColumnNumber As Long) As String
'convert a given number into it's corresponding Letter Reference
    Dim columnLetter As String
    columnLetter = Split(Cells(1, ColumnNumber).Address, "$")(1)
    Number2Letter = columnLetter
End Function

Public Function IsInArray(valToBeFound As Variant, arr As Variant) As Boolean
'INPUT: Pass the function a value to search for and an array of values of any data type.
'OUTPUT: True if is in array, false otherwise

    Dim element As Variant
    On Error GoTo IsInArrayError: 'array is empty
        For Each element In arr
            If element = valToBeFound Then
                IsInArray = True
                Exit Function
            End If
        Next element
    Exit Function
IsInArrayError:
    On Error GoTo 0
    IsInArray = False
End Function

Public Function findLastRow() As Long
'Finds the last non-blank cell on a sheet
    Dim lRow As Long
        lRow = Cells.Find(what:="*", _
                        After:=Range("A1"), _
                        lookat:=xlPart, _
                        LookIn:=xlFormulas, _
                        SearchOrder:=xlByRows, _
                        SearchDirection:=xlPrevious, _
                        MatchCase:=False).row
    findLastRow = lRow
End Function

Для простоты я скрыл часть "сделать что-то", но эта часть уже работает.То же самое с UDF / UDS, как я показал им, только если кому-то интересно.Кроме того, массив inputColumns уже существует, поэтому не беспокойтесь об этой части.

Что я прошу:

1. Есть ли такое свойство, как targetRange , которое будет работать для заполнения или вставки, как я уже упоминал?2. Или есть другое событие листа , которое я могу использовать?3. Если ничего не существует, я думаю о том, чтобы пометить исходное состояние в массиве и сравнить его с тем, что видно на первом листе каждый раз, когда мы попадаем на лист B. Проблема с этим подходом состоит в том, что он потребляет как пространство, так и скорость.Не могли бы вы придумать лучший способ?

Спасибо!

1 Ответ

1 голос
/ 02 апреля 2019

Я думаю, что функция Intersect очень вам здесь поможет. Вы можете определить диапазон, который вы хотите «проверить», и сравнить его со всеми значениями, которые были изменены одной операцией в вашем рабочем листе. Если есть какое-либо совпадение, запишите значение этих ячеек в некоторый целевой пункт назначения.

Private Sub Worksheet_Change(ByVal target As Range)

    Dim AuditRange As Range
    Set AuditRange = Range("B4:F16") 'your "Audit Area"

    Set range_auditedAndChanged = Intersect(target, AuditRange)
    If Not range_auditedAndChanged Is Nothing Then

        For Each c In range_auditedAndChanged
                'put in whereever your audit workbook is for Sheets("Sheet2")
                Sheets("Sheet2").Range(c.Address).Value = c.Value
        Next c

    End If
End Sub

enter image description here enter image description here

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

Во всяком случае, я думаю, что это чище и довольно эффективно и имеет гораздо меньше UDF для управления. Надеюсь, это поможет.

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