Ограничить vba Найти и заменить активным листом - PullRequest
2 голосов
/ 18 апреля 2020

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

Private Sub cbFindReplace_Click()

    ActiveSheet.Unprotect Password:="*password*"

    Application.Dialogs(xlDialogFormulaReplace).Show

    ActiveSheet.Protect Password:="*password*", DrawingObjects:=True, Contents:=True, _ 
                    Scenarios:=True, AllowFiltering:=True

End Sub

Проблема в том, что это открывает диалоговое окно без кнопки «Параметры» и, таким образом, позволяет ограничить поиск и замену активным листом. Поэтому я заменил приведенную выше команду «Показать» на следующую:

ActiveSheet.Cells.Find what:="", LookAt:=xlWhole
Application.CommandBars("Worksheet Menu Bar").FindControl( _
  ID:=1849, recursive:=True).Execute

Открытое диалоговое окно «Найти и заменить» содержит кнопку «Параметры» и возможность ограничения активным листом, но это не модально и, следовательно, команда защиты листа выполняется сразу после открытия диалогового окна и предотвращает замену. У кого-нибудь есть решение, которое позволяет использовать существующее диалоговое окно Excel Find & Replace и НЕ создает пользовательскую форму для дублирования этой логики c.

Ответы [ 2 ]

0 голосов
/ 19 апреля 2020

Интересная проблема. К сожалению, решение Самуэля не работает на моем компьютере: / (Excel показывает мое диалоговое окно замены, но я не могу использовать функцию замены -Excel show error)

Это работает для меня:

#If VBA7 Then
    Private Declare PtrSafe Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
#Else
    Private Declare Function FindWindow Lib "User32.dll" Alias "FindWindowA" (ByVal lpszClass As String, ByVal lpszWindow As String) As Long
#End If

Sub DialogOpen()

    ActiveSheet.Unprotect
    Application.CommandBars.ExecuteMso ("ReplaceDialog")
    DoEvents

    Application.OnTime Now + TimeValue("00:00:01"), "OnTime"
End Sub


Sub OnTime()
    Dim wHandle As Long
    Dim wName As String

    wName = "Find and Replace"
    wHandle = FindWindow(vbNullString, wName)
    DoEvents
    If wHandle = 0 Then
        ActiveSheet.Protect
    Else
        Application.OnTime Now + TimeValue("00:00:01"), "OnTime"
    End If

End Sub
0 голосов
/ 19 апреля 2020

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

Обратите внимание, что, скорее всего, есть более эффективные способы обработки кода во время ожидания закрытия диалога find and replace - у меня не было точного решения для начала, но я подумал, что это может сработать - и это сработало.

Per Обнаружение открытого диалогового окна из wordribbon.tips. net Я позаимствовал код, чтобы найти открытое окно для диалога Find and replace. За статью;

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

Подтвердив, что это работает, как я ожидал, я сделал несколько изменений, которые Я объясню ниже код


Создание нового модуля в VBE (или добавление следующего к существующему модулю)

Public Declare Function FindWindow Lib "user32" Alias "FindWindowA" _
    (ByVal wClassName As Any, ByVal wWindowName As String) As Long

Обратите внимание, что это не будет работать в Sheet или модуль Workbook, вам нужно будет добавить его к тому, который вы создали - Вставить> Модуль


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

Function testDialogOpen() As Boolean
    Dim wHandle As Long
    Dim wName As String

    wName = "Find and Replace"
    wHandle = FindWindow(0&, wName)
    If wHandle = 0 Then
        testDialogOpen = False
    Else
        testDialogOpen = True
    End If
End Function

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

Sub unprotect_findandreplace_protect()

    Sheet1.Unprotect "abc123"

    Application.CommandBars("Edit").Controls("Find...").Execute

    While testDialogOpen()
    DoEvents
    Wend

    Sheet1.Protect "abc123"

End Sub

While...Wend l oop оценивает, открыто ли окно Find and Replace на каждой итерации. Это делается путем вызова функции testDialogOpen(), которая возвращает результат True или False. L oop будет продолжать работать до тех пор, пока не будет закрыто диалоговое окно Find and Replace, когда он выйдет из l oop и go на следующую строку, повторно защитив лист.


...