Страницы: 1
RSS
Запрет на переключение на другие приложения до окончания работы макроса в рабочей книге.
 
 Добрый день.
 Есть книга с макросами (для облегчения рутины). Отдал книгу коллегам. Коллеги жалуются что не работает (выходит окно аварийного завершения работы макроса по различным причинам).
 Как оказалось - во время работы макроса пользователь переключается (мышкой или клавишами) (колесико крутится а им скучно) на другую книгу эксель/программу и появляется ошибка (что вполне логично: в другой книге другие данные и структура).
 Вопрос: как запретить переключение между рабочей книгой и другими книгами эксель и другими программами, пока не закончит работу макрос в рабочей книге (посмотрел на просторах не нашёл).
Спасибо.
 
mamalot, Нужно не переключение запрещать, а макросы записать так, чтоб работа не зависела от того, какое окно или приложение активно.
По вопросам из тем форума, личку не читаю.
 
Доброе время суток
Цитата
mamalot написал:
оявляется ошибка (что вполне логично: в другой книге другие данные и структура).
А стоит ли идти на столь драконовские меры? Достаточно переписать макросы :)  Идея-то в общем проста и лежит на поверхности. Достаточно в начале кода запуска макроса прописать
Код
Dim workBook As Workbook
Set workBook = ActiveWorkbook

и дальше в коде работать всегда с workBook - с той самой книгой, с которой был запущен макрос. Не ленитесь определять, где, когда и с чем вы работаете - коллеги будут довольны :)
 
Спасибо.
Буду пробовать.
Я просто пытаюсь учиться доброму, вечному, светлому - но получается не всегда.
Спасибо.
 
Добрый день.
Наконец дошли руки, ноги, мозги (мозгов, кстати, нет).
Выполнил совет из #3 (строка 5,6 - наверно я балбес). Но проблема осталась: макрос (лежит в модуле листа) отрабатывает, и если в это время переключиться на другую книгу - заканчивает свои действия в этой другой книге (что очень не хорошо).
Макрос (марккодерный мусор-знаю)-плод моей неравной борьбы с криворукими юзерами, по частям был собран с помощью Планетян (за что огромное спасибо не равнодушным).
Ткните носом пожалуйста.
Код
Private Sub Worksheet_Change(ByVal Target As Range)
Dim i As Long, cOlZ As Long, strOk As Long, strZ As Long
Dim tMp As Variant
Dim cLr As Boolean
Dim Workbook As Workbook
Set Workbook = ActiveWorkbook
With ThisWorkbook
'ВСТАВЛЯЕМ ТОЛЬКО ЗНАЧЕНИЯ
If Target.Columns.Count > 6 Then Exit Sub
If Cells(1, 1).Value > 0 Then
    Application.ScreenUpdating = False
    Application.DisplayAlerts = False
If Application.CutCopyMode Then
        Application.EnableEvents = 0
        Application.Undo: Target.PasteSpecial xlPasteValues
        Application.EnableEvents = -1
End If
    Application.ScreenUpdating = True
    Application.DisplayAlerts = True
End If

'ТЕКСТ В ЧИСЛА
  If Cells(1, 1).Value > 0 Then
   Dim rArea As Range
   On Error Resume Next ' обработчик ошибок
   'ActiveWindow.RangeSelection   ' диапазон выбранных ячеек листа даже если выбран графический объект
   'ActiveWindow.RangeSelection.SpecialCells(xlCellTypeConstants).Select ' в выбранном диапазоне выделить ячейки с константами _
   так будет быстрее, чем обрабатывать все ячейки в Selection
   If Err Then Exit Sub ' если нужных ячек не оказалось, то их невозможно выбрать и будет ошибка
   With Application: .ScreenUpdating = False: .EnableEvents = False: .Calculation = xlManual: End With ' отключаем все замедляющие процедуры

   For Each rArea In Selection.Areas 'т.к. выбранными скорее всего окажутся не смежные ячейки, а области, то обрабатывать нужно каждую из областей
      rArea.FormulaLocal = rArea.FormulaLocal ' значения во всех ячейках области заменить на них же. При этом произойдёт обновление форматов (это такая не документированная особенность Excel)
   Next rArea
   With Application: .ScreenUpdating = True: .EnableEvents = True: .Calculation = xlAutomatic: End With ' включаем все обратно в обычный режим.
  End If
  
'УСТАНОВКА ОДИНОЧНОГО КОММЕНТАРИЯ НАЧАЛО
If Target.Columns.Count > 6 Then Exit Sub
If Cells(1, 1).Value = 2 Then

   Application.ScreenUpdating = True
   Application.Calculation = xlCalculationAutomatic
   Application.EnableEvents = True
   Application.DisplayStatusBar = True
   Application.DisplayAlerts = True
   Application.ScreenUpdating = False
   Application.DisplayAlerts = False
  
    Dim vValue
    On Error Resume Next
    If Target <> vValue Then Target.Interior.Color = vbGreen
 
    Application.ScreenUpdating = True
    Application.DisplayAlerts = True
End If
 'УСТАНОВКА ГРУППОВОГО КОММЕНТАРИЯ КОНЕЦ
 
'УСТАНОВКА ОДИНОЧНОГО КОММЕНТАРИЯ НАЧАЛО2
If Target.Columns.Count > 6 Then Exit Sub
If Sheets("Бюджет").Cells(10, 138).Value = 1 Then
    Application.ScreenUpdating = False
    Application.Calculation = xlCalculationManual
    Application.EnableEvents = False
    Application.DisplayStatusBar = False
    Application.DisplayAlerts = False
ActiveSheet.Unprotect Password:="123"
    Dim OldComment As String, NewComment As String, objCell As Range
    If Target.Cells.Count = 1 Then
    NewComment = Now() & "; " & Application.UserName
    If Target.Comment Is Nothing Then
        Target.AddComment NewComment
    Else
        OldComment = Target.Comment.Text
        Target.Comment.Text NewComment & vbLf & OldComment
    End If
    Target.Comment.Shape.TextFrame.AutoSize = True
    Target.Comment.Visible = True
    DoEvents
        Target.Comment.Visible = False
 'УСТАНОВКА ОДИНОЧНОГО КОММЕНТАРИЯ КОНЕЦ2
 'УСТАНОВКА ГРУППОВОГО КОММЕНТАРИЯ НАЧАЛО2
    Else
    Set cc = Selection.SpecialCells(xlCellTypeVisible)
    For Each c In cc
    NewComment = Now() & "; " & Application.UserName
    On Error Resume Next
    If c.Comment Is Nothing Then
        c.AddComment NewComment
    Else
        OldComment = c.Comment.Text
        c.Comment.Text NewComment & vbLf & OldComment
    End If
    c.Comment.Shape.TextFrame.AutoSize = True
    c.Comment.Visible = True
    DoEvents
        c.Comment.Visible = False
    i = i + 1
    Next
    End If
    ActiveSheet.Protect Password:="123", UserInterfaceOnly:=True, AllowFormattingCells:=True, AllowFormattingColumns:=True, _
        AllowFormattingRows:=True, AllowFiltering:=True
        
    Application.ScreenUpdating = True
    Application.Calculation = xlCalculationAutomatic
    Application.EnableEvents = True
    Application.DisplayStatusBar = True
    Application.DisplayAlerts = True
    Application.Calculation = xlAutomatic
    End If
 'УСТАНОВКА ГРУППОВОГО КОММЕНТАРИЯ КОНЕЦ2

'''''''''''''''''''''''''''''''''''''''''''''''
'ЗАМЕНА ПУСТЫХ НА ДРАНТЯ
If Target.Column = 12 Then
If Target.Value = "" Then
Application.ScreenUpdating = False
Application.EnableEvents = False
Application.DisplayStatusBar = False
Application.DisplayAlerts = False
Dim cell As Range 'переменная для перебора ячеек
        Dim r As Range 'переменная для диапазона используемых ячеек
   For Each cell In Selection
lRow = Cells(Rows.Count, 23).End(xlUp).Row + 1
'lRow = Selection.Row 'первая строка
lLastrowInSelectedRange = Selection.Row + Selection.Rows.Count - 1 'последняя строка
        If cell.Value = "" Then
If lLastrowInSelectedRange < lRow Then
            cell.Value = "90001676"
End If
        End If
   Next
   End If
    Application.ScreenUpdating = True
    Application.EnableEvents = True
    Application.DisplayStatusBar = True
    Application.DisplayAlerts = True
   End If
 '''''''''''''''''''''''''''''''''''''''''''''''
'ЗАМЕНА НУЛЕЙ И ТЕКСТА
'If Target.Column = 15 Then
    'Application.EnableEvents = False
    'For Each cel In Target.Cells
    '    If Application.WorksheetFunction.IsText(cel) Then Application.Undo
    '    If cel.Value & "" = "0" Then Application.Undo
    'Next
   'Application.EnableEvents = True
'End If
 '''''''''''''''''''''''''''''''''''''''''''''''
If Target.Column <> 58 Then Exit Sub
Dim tx
    If Target.Count > 1 Then Exit Sub
    If Len(Target.Value) = 0 Then Exit Sub
    tx = Split(Target.Value, ",")
    For i = LBound(tx) To UBound(tx)
        If IsNumeric(tx(i)) Then
            If Val(tx(i)) > 12 Or Val(tx(i)) < 1 Then
                MsgBox "Ошибка!" & vbCrLf & vbCrLf & "Введите число или числа через запятую от 1 до 12" & vbCrLf & vbCrLf & "Нажмите 'ОК' и повторите"
                Exit Sub
            End If
        End If
    Next i
'Dim cell As Range 'переменная для перебора ячеек
 '       Dim r As Range 'переменная для диапазона используемых ячеек
        Set r = Range("BF14:BF10000") 'Все используемые ячейки
   For Each cell In r.Cells
        'Если один символ справа равен ","
        If Right(cell.Value, 1) = "," Then
            'замена значения ячейки на то же значение, но без последнего символа
            cell.Value = Left(cell.Value, Len(cell.Value) - 1)
        End If
   Next
'''''''''''''''''''''''''''''''''''''''''''''''''
'СНИМАЕМ АВОФИЛЬТР
Application.ScreenUpdating = False
'Application.EnableEvents = False
Application.DisplayStatusBar = False
Application.DisplayAlerts = False

Application.Run "Фильтр_очистить"
'''''''''''''''''''''''''''''''''''''''''''''''''
strZ = Target.Row
ActiveSheet.Unprotect Password:="123"
For cOlZ = 32 To 55
    If Left(Cells(strZ, cOlZ).Formula, 3) = "=IF" Then Exit For
Next cOlZ
If cOlZ >= 55 Then Exit Sub
strOk = strZ + 1
Do Until (Len(Cells(strOk, cOlZ)) = 0) Or (Left(Cells(strOk, cOlZ).Formula, 3) = "=IF")
    strOk = strOk + 1
Loop
strOk = strOk - 1
If cOlZ < 54 Then Range(Cells(strZ, cOlZ + 2), Cells(strOk, 55)).ClearContents
tMp = Split(Application.Substitute(Application.Substitute(Application.Substitute(Target.Value, " ", ""), Application.DecimalSeparator, "."), ",", "."), ".")
If UBound(tMp) < 0 Then Exit Sub
cLr = True
For i = 0 To UBound(tMp)
    If (Val(tMp(i)) <= 12) Or (Val(tMp(i)) >= 1) Then
        If cOlZ = 32 + 2 * (tMp(i) - 1) Then
            cLr = False
        Else
            Range(Cells(strZ, cOlZ), Cells(strOk, cOlZ + 1)).Copy Cells(strZ, 32 + 2 * (tMp(i) - 1))
        End If
    End If
Next i
If cLr Then Range(Cells(strZ, cOlZ), Cells(strOk, cOlZ + 1)).ClearContents
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
 'СТАВИМ АВТОФИЛЬТР С ЗАПОМНЕНЫМИ ЗНАЧЕНИЯМИ
 Application.Run "Фильтр_поставить"
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
ActiveSheet.Protect Password:="123", UserInterfaceOnly:=True, AllowFormattingCells:=True, AllowFormattingColumns:=True, _
        AllowFormattingRows:=True, AllowFiltering:=True
        
    Application.ScreenUpdating = True
    Application.EnableEvents = True
    Application.DisplayStatusBar = True
    Application.DisplayAlerts = True
End With
End Sub
Изменено: mamalot - 08.11.2019 08:25:58
 
Объект Selection относится к выделенной области на активном листе. Следовательно, его надо заменить на конкретный диапазон. А уж в случае с обработкой события Change и вовсе нелогично использовать Selection. Его скорее всего надо заменить на Target, хотя не факт - уж очень много всего у Вас собрано в кучу и когда и что должно выполняться непонятно(мне уж точно).
Даже самый простой вопрос можно превратить в огромную проблему. Достаточно не уметь формулировать вопросы...
 
Спасибо за ответ.
Но, на мой взгляд, не важно что делает макрос в книге, в которой он находится, важно не дать пользователю переключиться на другой файл эксель (или приложение) до завершения работы макроса.
Извините если что не так говорю.
 
Цитата
mamalot написал:
на мой взгляд, не важно что делает макрос в книге
ну с таким подходом советовать Вам нечего. Делайте как Вам кажется правильно, а не как советуют.
Но учтите, что для того, чтобы пользователь не мог переключаться между книгами надо блокировать клавиатуру и мышь, что не есть лучший способ. Да и не проще он ни разу, чем замена Ваших Selection на правильные объекты.
Можете просто скрыть приложение пока код выполняется тогда:
Код
Application.Visible = False

P.S. Если пользователь ничего не должен делать - то тем более Selection там не нужен
Изменено: Дмитрий(The_Prist) Щербаков - 08.11.2019 19:46:01
Даже самый простой вопрос можно превратить в огромную проблему. Достаточно не уметь формулировать вопросы...
 
Добрый день.
Спасибо за ответ.
Возможно я не правильно объяснил проблему:пользователь выполнил какое то действие в рабочей книге на листе-макрос, расположенный в модуле листа, запускается (по сути по любому "чиху") и делает то для чего предназначен-в этот момент пользователь активирует другую книгу эксель (а макрос ещё не завершил свою работу) и макрос завершает свою работу уже в другой книге, в моём случае ставит защиту на лист на который перешёл пользователь в другой книге.
Мои Selection (имеется в виду часть кода после-'ЗАМЕНА ПУСТЫХ НА ДРАНТЯ-как я понимаю).
Я понимаю что Selection это не есть хорошо,но к сожалению это всё на что я способен. В этом куске кода, когда пользователь выделил ячейку или диапазон ячеек именно в 12 столбике и нажал Delete, удалённые значения автоматически меняются на определённое числовое значение (cell.Value = "90001676")-если подскажете как сделать правильно-буду признателен.
Я сам отлавливал завершение работы макроса в другой книге и был свидетелем такого же у пользователя, при этом столбик 12 не был активирован, т.е. часть кода с Selection не отрабатывала.
Я понимаю-нужно либо увеличивать быстродействие работы макроса ("...очень много всего у Вас собрано в кучу..." - к сожалению убирать отсюда нежелательно-юзеры быстро приведут книгу в нечитабельное и нерабочее состояние, выше я писал, что всё это защита от юзеров), либо каким либо образом запрещать пользователю во время работы макроса переключаться на другую книгу, либо ещё что-то.
Как-то так.
Ещё раз спасибо за ответ.
 
mamalot,  При запуске макроса Вашего, определить и зафиксировать и книгу и листы и работать с ними забыв о Active.....
Это решит вашу проблему.
По вопросам из тем форума, личку не читаю.
Страницы: 1
Наверх