Разрешить вставку в лист без перезаписи заблокированных ячеек - PullRequest
3 голосов
/ 25 мая 2010

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

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

Пример
Рабочий лист 1:

Act1 100 100 100
Act2 100 100 100
Act3 100 100 100

Рабочий лист 2: (второй ряд заблокирован)

Act1 300 300 300
Act2 200 200 200
Act3 100 100 100

После копирования / вставки Рабочий лист 2 должен выглядеть следующим образом:

Act1 100 100 100
Act2 200 200 200
Act3 100 100 100

Значения из таблицы 1 заполняются, и заблокированные строки не нарушаются.

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

Ответы [ 4 ]

2 голосов
/ 28 мая 2010

Требования:

  1. Разрешить вставку в защищенные листы
  2. Сохранить содержимое в заблокированных ячейках после операции вставки
  3. Сохранить статус защиты листа

Метод:

  1. Обрабатывать все возможные операции вставки в пользовательском модуле вместо способа Excel
  2. Поскольку при снятии защиты содержимое из буфера обмена удаляется на временный лист
  3. запомните, куда пользователь должен вставить пасту
  4. запишите заблокированные ячейки на защищенном листе (содержимое и адрес)
  5. снять защиту листа
  6. вставка в ячейки из временного листа
  7. удалить временный лист и защитить основной лист

Я сослался на образец Catch Paste Яна Карела для справки. Возможно, вы захотите добавить все способы, которыми он ловит операции вставки.

В модуле ThisWorkbook добавьте ниже код

Private mdNextTimeCatchPaste As Double

Private Sub Workbook_Activate()
    REM Add Paste event handler
    CatchPaste
End Sub

Private Sub Workbook_BeforeClose(Cancel As Boolean)
    REM Restore Paste event handler
    StopCatchPaste
    mdNextTimeCatchPaste = Now
    Application.OnTime mdNextTimeCatchPaste, "'" & ThisWorkbook.Name & "'!UnProtectPasteToSheet"
End Sub


Private Sub Workbook_Deactivate()
    REM Restore Paste event handler
    StopCatchPaste
    On Error Resume Next
    REM Cancel scheduled macroREM s,
    REM because we might be closing the file
    Application.OnTime mdNextTimeCatchPaste, "'" & ThisWorkbook.Name & "'!UnProtectPasteToSheet", , False
End Sub

Private Sub Workbook_Open()
    REM Add Paste event handler
    CatchPaste
End Sub

Добавить новый модуль и добавить код ниже

REM Add Paste event handler
Public Sub CatchPaste()
REM these are the ways you can Paste in to Excel
REM refer to http://www.jkp-ads.com/articles/catchpaste.asp for more details
Application.OnKey "^v", "UnProtectPasteToSheet"
Application.OnKey "^{Insert}", "UnProtectPasteToSheet"
Application.OnKey "+{Insert}", "UnProtectPasteToSheet"
Application.OnKey "~", "UnProtectPasteToSheet"
Application.OnKey "{Enter}", "UnProtectPasteToSheet"
End Sub
REM restore all default events
Public Sub StopCatchPaste()
Application.OnKey "^v", ""
Application.OnKey "^{Insert}", ""
Application.OnKey "+{Insert}", ""
Application.OnKey "~", ""
Application.OnKey "{Enter}", ""
End Sub

REM Here we will check the sheet is protected, if it is then paste to a temp sheet,
REM unprotect main sheet, paste the values, and restore locked cells
Private Sub UnProtectPasteToSheet()
On Error GoTo ErrHandler
Dim bProtected As Boolean, oSheet As Worksheet, oTempSheet As Worksheet, sPasteLocation As String
Dim oCell As Range, oCollAddress As New Collection, oCollValue As New Collection, iCount As Integer

REM check protection status
If Not ThisWorkbook.ActiveSheet.ProtectContents Then
    Selection.PasteSpecial Paste:=xlAll
Else
    bProtected = True
    Set oSheet = ThisWorkbook.ActiveSheet
    REM save paste location
    sPasteLocation = Selection.Address
    REM unprotecting clears Clipboard in Excel!! strange but true..
    REM So paste it to a new sheet before unprotecting
    Set oTempSheet = ThisWorkbook.Worksheets.Add
    REM oSheet.Visible = xlSheetVeryHidden
    oTempSheet.Paste
    REM unprotect the sheet
    oSheet.Unprotect

    REM make a note of all locked cells
    For Each oCell In oSheet.UsedRange
        If oCell.Locked Then
            oCollAddress.Add oCell.Address
            oCollValue.Add oCell.Value
        End If
    Next

    REM paste
    oTempSheet.UsedRange.Copy
    oSheet.Activate
    oSheet.Range(sPasteLocation).Select
    REM you need to paste only values since pasting format will lock all those cells
    REM since in Excel default status is "Locked"
    Selection.PasteSpecial xlValues

    REM remove temp sheet
    Application.DisplayAlerts = False
    oTempSheet.Delete
    Application.DisplayAlerts = True

    REM restore locked cells
    For iCount = 1 To oCollAddress.Count
        Range(oCollAddress.Item(iCount)) = oCollValue.Item(iCount)
    Next
    REM restore protection
    oSheet.Protect

End If
Exit Sub

ErrHandler:
    Debug.Print Err.Description
    If bProtected Then
        ThisWorkbook.ActiveSheet.Protect
    End If
End Sub

Примечание: я добавляю REM вместо ', чтобы сохранить форматирование Stackoverflow счастливым. Попробуйте и дайте мне знать, как это происходит ..

0 голосов
/ 28 мая 2010

Я думаю, что ключ в том, чтобы изящно заблокировать стандартную функцию вставки и повторить вставку контролируемым образом

Я слышал, что в более поздних версиях Excel есть событие «При вставке» (не уверен), но оно недоступно в 2003 году. Я перехватываю действия «Вставить» следующим кодом в 2003 году (который вызывается подходящим событием процедура, подобная Sheet_Activate ()):

Sub SetPasteTrap(Mode As Boolean)
' TRUE sets the trap, FALSE releases trap
    If Mode Then
        Application.CommandBars("Edit").Controls("Paste").OnAction = "TrappedPaste"
        Application.CommandBars("Edit").Controls("Paste Special...").OnAction = "TrappedPaste"
        Application.CommandBars("Cell").Controls("Paste").OnAction = "TrappedPaste"
        Application.CommandBars("Cell").Controls("Paste Special...").OnAction = "TrappedPaste"
        Application.OnKey "^v", "TrappedPaste"
    Else
        Application.CommandBars("Edit").Controls("Paste").OnAction = ""
        Application.CommandBars("Edit").Controls("Paste Special...").OnAction = ""
        Application.CommandBars("Cell").Controls("Paste").OnAction = ""
        Application.CommandBars("Cell").Controls("Paste Special...").OnAction = ""
        Application.OnKey "^v"
    End If
End Sub

Этим мы фиксируем главное меню, контекстное меню и клавишу Ctrl-V - этого должно быть достаточно. Свойство OnAction переходит к подпрограмме, содержащейся в аргументе

Sub TrappedPaste()
    If ActiveSheet.ProtectContents Then
        ' as long as sheet is protected, we don't paste at all
        MsgBox "Sheet is protected, all Paste/PasteSpecial functions are disabled." & vbCrLf & _
               "At your own risk you may unprotect the sheet." & vbCrLf & vbCrLf & _
               "When unprotected, you can copy/paste from other text, WORD, HTML or EXCEL files." & vbCrLf & _
               "All Paste operations will implicitly be executed as PasteSpecial/Values", _
               vbOKOnly, "Paste"
        Exit Sub
    End If

    ' silently do a PasteSpecial/Values
    On Error GoTo TryExcel
    ' try to paste text
    ActiveSheet.PasteSpecial Format:="Text", Link:=False, DisplayAsIcon:=False
    Exit Sub
TryExcel:
    On Error GoTo DoesntWork
    Selection.PasteSpecial xlPasteValues
    Exit Sub
DoesntWork:
    MsgBox "Sorry - wrong format for pasting", vbExclamation + vbOKOnly, "PasteSpecial ..."
End Sub

Я добавляю это, потому что это показывает, что вам нужно немного заботиться о том, что находится в буфере (excel, text, html и т. Д.)

Вам потребуется заменить ядро ​​процедуры TrappedPaste () кодом, который

1) вставляет содержимое в скрытый лист / диапазон (вы можете использовать код выше)

2) снимает защиту целевого листа

3) перемещает содержимое в ячейку целевого диапазона за ячейкой при условии, что

4) целевая ячейка удовлетворяет условию отсутствия блокировки, проверки или подобного

5) повторно защищает целевой лист

6) очистить скрытый лист / диапазон

Обратите внимание, что с такой конструкцией пользователь не сможет использовать функцию UNDO!

Надеюсь, это поможет - Удачи MikeD

0 голосов
/ 26 мая 2010

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

В предыдущих версиях Excel и на незащищенных листах (но с несколькими заблокированными ячейками, которые не служат какой-либо цели) у вас может быть функция отмены изменений, если какая-либо изменяемая ячейка заблокирована.

Private Sub Worksheet_Change(ByVal Target As Range)
Dim oCell As Range
For Each oCell In Target
    If oCell.Locked = True Then
        'disable events to prevent recursive function call
       Application.EnableEvents = False
       'undo the paste
       Application.Undo
       'enable events
       Application.EnableEvents = True
       Exit For
    End If
Next
End Sub

Изменить: После публикации этого ответа я понял, что в Excel все вызовы помечены как заблокированные по умолчанию. Поэтому, если они вставляются с обычного листа, скорее всего, ячейка назначения будет читать «Заблокировано», потому что прошлое только что заблокировало ее !! Итак, у меня есть улучшенный способ, который позволит вам вставить что-то на лист, он просто сохранит «заблокированные» ячейки нетронутыми.

Идея в том, что мы запишем новый статус после вставки, а затем отменим все изменения. Затем мы пройдемся по ячейкам, которые были только что изменены, и проверим, были ли они заблокированы перед операцией вставки. Если их не было, то мы снова заселим вставленное значение. Используя этот код, вы получите результаты, которые вы запрашивали в своем примере.

Private Sub Worksheet_Change(ByVal Target As Range)
Dim oCell As Range, oCollAddress As New Collection, oCollValue As New Collection, iCount As Integer
'get all pasted content in to a collection
For Each oCell In Target
    oCollAddress.Add oCell.Address
    oCollValue.Add oCell.Value
Next

'undo the changes done, and re-paste it for unlocked cells
'disable events to prevent infinite calls
Application.EnableEvents = False
Application.Undo
For iCount = 1 To oCollAddress.Count
    If Range(oCollAddress.Item(iCount)).Locked = False Then
        Range(oCollAddress.Item(iCount)) = oCollValue.Item(iCount)
    End If
Next
Application.EnableEvents = True
End Sub

Редактировать 27.05.2010: Хорошо, тогда вам нужно захватить операцию вставки (событие) и обработать ее вручную вместо Excel. Я добавляю новый ответ, так как он слишком большой ..

0 голосов
/ 25 мая 2010

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

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

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