Vba excel отключить пересчет формул

Return to VBA Code Examples

In this Article

  • Turn Off Automatic Calculations
  • Turn Automatic Calculations Back On
  • Disable Automatic Calculations Macro Example
  • Manual Calculation
    • VBA Settings – Speed Up Code
  • VBA Coding Made Easy

Whenever you update a cell value, Excel goes through a process to recalculate the workbook. When working directly within Excel you want this to happen 99.9% of the time (the exception being if you are working with an extremely large workbook). However, this can really slow down your VBA code. It’s a good practice to set your calculations to manual at the beginning of macros and restore calculations at the end of macros. If you need to recalculate the workbook you can manually tell Excel to calculate.

Turn Off Automatic Calculations

You can turn off automatic calculation with a macro by setting it to xlmanual. Use the following piece of VBA code:

Application.Calculation = xlManual

Turn Automatic Calculations Back On

To turn back on automatic calculation with the setting xlAutomatic:

Application.Calculation = xlAutomatic

I recommend disabling Automatic calculations at the very beginning of your procedure and re-enabling Automatic Calculations at the end. It will look like this:

Disable Automatic Calculations Macro Example

Sub Auto_Calcs_Example()
    Application.Calculation = xlManual

    'Do something


    Application.Calculation = xlAutomatic
End Sub

vba disable automatic calculations

Manual Calculation

When Automatic calculations are disabled, you can use the Calculate command to force Excel to recalculate:

Calculate

You can also tell Excel to recalculate only an individual worksheet:

Worksheets("sheet1").Calculate

You can also tell VBA to recalculate just a range (click to read our article about VBA calculation methods)

Here is how this might look inside a macro:

Sub Auto_Calcs_Example_Manual_Calc()
    Application.Calculation = xlManual

    'Do Something

    'Recalc
    Calculate
    
    'Do More Things


    Application.Calculation = xlAutomatic
End Sub

VBA Settings – Speed Up Code

If your goal is to speed up your code, you should also consider adjusting these other settings:

Disabling Screenupdating can make a huge difference in speed:

Application.ScreenUpdating = False

Turning off the Status Bar will also make a small difference:

Application.DisplayStatusBar = False

If your workbook contains events you should also disable events at the start of your procedures (to speed up code and to prevent endless loops!):

Application.EnableEvents = False

Last, your VBA code can be slowed down when Excel tries to re-calculate page breaks (Note: not all procedures will be impacted).  To turn off DisplayPageBreaks use this line of code:

ActiveSheet.DisplayPageBreaks = False

VBA Coding Made Easy

Stop searching for VBA code online. Learn more about AutoMacro – A VBA Code Builder that allows beginners to code procedures from scratch with minimal coding knowledge and with many time-saving features for all users!

alt text

Learn More!

 

bobyjoy

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

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

Уважаемые коллеги добрый день

Подскажите пожалуйста есть как в коде в ВБА прописать перед началом работы макроса отключение автоматического пересчета формул КРОМЕ текущего листа (где работает макрос) в VBA и затем после отработки макроса, обратно включить везде пересчет формул?

 

JayBhagavan

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

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

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

Цикл по листам. У неугодных вырубаем калькуляцию (sheets(i).enablecalculation=false). Перед окончанием кода в цикле врубаете калькуляцию.

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

 

The_Prist

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

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

Профессиональная разработка приложений для MS Office

#3

21.04.2017 16:45:46

Куда практичнее вырубить калькуляцию для всего приложения, а потом в нужных местах для нужных диапазонов делать пересчет. Или для всего диапазона нужного листа:

Код
Sheets(2).UsedRange.Calculate

Даже самый простой вопрос можно превратить в огромную проблему. Достаточно не уметь формулировать вопросы…

 

bobyjoy

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

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

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

 

bobyjoy

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

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

The_Priest
Sheets(2).UsedRange.Calculate вроде сработало, А как макросом отключать везде пересчет сразу  активбук? и потом включать, я понимаю, что могу записать макрос, но думаю, есть лучше код.

 

The_Prist

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

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

Профессиональная разработка приложений для MS Office

#6

25.04.2017 10:40:25

Цитата
bobyjoy написал:
везде пересчет сразу  активбук

расшифруйте. Везде — это где? В активной книге, во всем приложении? Или что еще?  

Даже самый простой вопрос можно превратить в огромную проблему. Достаточно не уметь формулировать вопросы…

 

kuklp

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

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

E-mail и реквизиты в профиле.

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

Я сам — дурнее всякого примера! …

 

bobyjoy

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

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

У меня маркос лагает, медленно считает, если на любой книге открытой включая текущую ( в которой макрос) и сторонюю, есть какие либо масивы с формлами (не относятся к макросу). Если отключать автоматический пересчет, в таком случае он работает быстро. Я переключил пересчет на ручной и благодаря макросу Sheets(2).UsedRange.Calculate он стал работать быстро.

 

bobyjoy

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

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

Sheets(«Pivot2»).UsedRange.Calculate всетаки не много не корректно считает, подскажите пожалуйста отражает ли эта формула активизацию пересчта на всем листе (всех сводных и формул)?

 

The_Prist

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

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

Профессиональная разработка приложений для MS Office

UsedRange — это все ячейки, в которых есть значение, формула или форматирование. Следовательно да. Но сводные отдельные объекты и они не будут пересчитываться методом Calculate, т.к. пересчет на них вообще не влияет. У них есть метод Refresh.

Даже самый простой вопрос можно превратить в огромную проблему. Достаточно не уметь формулировать вопросы…

 

bobyjoy

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

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

#11

25.04.2017 12:02:13

Код
Sub ttt()
Application.ScreenUpdating = False
'arrBaza = Range("AH2:AH" & Cells(Rows.Count, "AH").End(xlUp).Row).Value
LB = Cells(Rows.Count, "AH").End(xlUp).Row
LS = Cells(Rows.Count, "H").End(xlUp).Row
Sheets("Итог").PivotTables("СводнаяТаблица3").PivotCache.Refresh
MsgBox LB
Application.Calculation = xlManual
For I = 2 To LB
    'Cells(I, "AI").Value = 10
    Sheets("Pivot2").UsedRange.Calculate
    ActiveSheet.PivotTables("СводнаяТаблица2").PivotCache.Refresh
    'MsgBox
    Application.StatusBar = Str(I)
    With ActiveSheet.PivotTables("PivotTable1").PivotFields("Barcode")
       .PivotItems(Trim(Str(Cells(I, "AH").Value))).Visible = True
       If I > 2 Then
        .PivotItems(Trim(Str(Cells(I - 1, "AH").Value))).Visible = False
       Else
        .PivotItems(Trim(Str(Cells(LB, "AH").Value))).Visible = False
       End If
       
    End With
    
    
    For K = 2 To LS
        Cells(2, "P") = Cells(K, "M").Value
        If Cells(1, "AD").Value = 0 Then Exit For
    Next
    
    
    If Cells(1, "AD").Value = 0 Then
    c = Cells(2, "AD").Value
    Else
    c = 0
    End If
    If c = 0 Then GoTo 1
    For J = 2 To LS
        If Trim(Cells(J, "H").Value) = Trim(Cells(2, "P").Value) Then
            Cells(J, "J") = Cells(J, "J").Value + c
            
        Exit For
        End If
    Next
    Cells(I, "AI").Value = Trim(Cells(2, "P").Value)
1:
Next
Application.ScreenUpdating = True
Application.Calculation = xlAutomatic
End Sub

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

Изменено: bobyjoy25.04.2017 13:30:07

 

The_Prist

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

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

Профессиональная разработка приложений для MS Office

#12

25.04.2017 12:11:33

Цитата
bobyjoy написал:
так что бы все свобные несмотря

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

Даже самый простой вопрос можно превратить в огромную проблему. Достаточно не уметь формулировать вопросы…

Хитрости »

20 Январь 2016              61478 просмотров


Рано или поздно у пишущих на Visual Basic for Applications возникает проблема — код хоть и облегчает жизнь и делает все автоматически, но очень долго. В этой статье я решил собрать несколько простых рекомендаций, которые помогут ускорить работу кода VBA, при этом в некоторых случаях весьма внушительно — в десятки, а то и больше, раз. Основной упор в статье сделан на начинающих, поэтому в начале статьи приводятся самые простые методы оптимизации. Более «глубокие» решения по оптимизации кода приведены в конце статьи, т.к. для применения данных решений необходим достаточный опыт работы в VB и сходу такие методы оптимизации кому-то могут быть непонятны.

  1. Если в коде есть много всяких Activate и Select, тем более в циклах — следует немедленно от них избавиться. Как это сделать я писал в статье: Select и Activate — зачем нужны и нужны ли?
  2. Обязательно на время выполнения кода отключить:
    • автоматический пересчет формул. Чтобы формулы не пересчитывались при каждой манипуляции на листе во время выполнения кода — это может дико тормозить код, если формул много:
      Application.Calculation = xlCalculationManual

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

      Range("A1:C60").Calculate
    • обновление экрана, чтобы действия по изменению значений ячеек и пр. не мелькали. Зачем это надо? Т.к. все эти действия обращаются к графическому процессору и заставляют его трудиться для перерисовки экрана — это может значительно тормозить код:
      Application.ScreenUpdating = False
    • На всякий случай отключаем отслеживание событий. Нужно для того, чтобы Excel не выполнял никаких событийных процедур, которые могут быть в листе, в котором производятся изменения. Как правило это события изменения ячеек, активации листов и пр.:
      Application.EnableEvents = False
    • Если книга выводилась на печать или выводится на печать в процессе выполнения кода, то лучше убрать разбиение на печатные страницы.
      ActiveWorkbook.ActiveSheet.DisplayPageBreaks = False

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

    • На всякий случай можно отключить отображение информации в строке статуса Excel(в каких случаях там вообще отображается информация и зачем можно узнать в статье: Отобразить процесс выполнения). Хоть это и не сильно поедает ресурсы — иногда может все же ускорить работу кода:
      Application.StatusBar = False

    Главное, что следует помнить — все эти свойства необходимо включить обратно после работы кода. Иначе могут быть проблемы с работой внутри Excel. Например, если забыть включить автопересчет формул — большинство формул будут пересчитывать исключительно принудительным методом — после нажатия сочетания клавиш Shift+F9. А если забыть отключить обновление экрана — то есть шанс заблокировать себе возможность работы на листах и книгах. Хотя по умолчанию свойство ScreenUpdating и должно возвращаться в True, если было отключено внутри процедуры — лучше не надеяться на это и привыкать возвращать все свойства на свои места принудительно. По сути все это сведется к нескольким строкам:

    'Возвращаем обновление экрана
    Application.ScreenUpdating = True
    'Возвращаем автопересчет формул
    Application.Calculation = xlCalculationAutomatic
    'Включаем отслеживание событий
    Application.EnableEvents = True

    Как такой код выглядит на практике. Предположим, надо записать в цикле в 10 000 строк значения:

    Sub TestOptimize()
    'отключаем обновление экрана
    Application.ScreenUpdating = False
    'Отключаем автопересчет формул
    Application.Calculation = xlCalculationManual
    'Отключаем отслеживание событий
    Application.EnableEvents = False
    'Отключаем разбиение на печатные страницы
    ActiveWorkbook.ActiveSheet.DisplayPageBreaks = False
     
    'Непосредственно код заполнения ячеек
    Dim lr As Long
    For lr = 1 To 10000
        Cells(lr, 1).Value = lr 'для примера просто пронумеруем строки
    Next
     
    'Возвращаем обновление экрана
    Application.ScreenUpdating = True
    'Возвращаем автопересчет формул
    Application.Calculation = xlCalculationAutomatic
    'Включаем отслеживание событий
    Application.EnableEvents = True
    End Sub

    Разрывы печатных страниц можно не возвращать — они тормозят работу в любом случае.

  3. Следует избегать циклов, вроде Do While для поиска последней ячейки. Часто такую ошибку совершают начинающие. Куда эффективнее и быстрее вычислять последнюю ячейку на всем листе или в конкретном столбце без этого тормозного цикла Do While. Я обычно использую
    lLastRow = Cells(Rows.Count,1).End(xlUp).Row

    другие варианты определения последней ячейки я детально описывал в статье: Как определить последнюю ячейку на листе через VBA?

Для более опытных пользователей VBA я приведу несколько решений по оптимизации кодов в различных ситуациях:

  • Самая хорошая оптимизация кода, если приходится работать с ячейками листа напрямую, обрабатывать их и, возможно, изменять значения, то быстрее все обработки делать в массиве и разом выгружать на листе. Например, код выше по заполнению ячеек номерами будет в этом случае выглядеть так:
    Sub TestOptimize_Array()
    'Непосредственно код заполнения ячеек
    Dim arr, lr As Long
    'запоминаем в массив одним махом все значения 10000 строк первого столбца
    arr = Cells(1, 1).Resize(10000).Value
    'если нужно заполнение для двух и более столбцов
    'arr = Cells(1, 1).Resize(10000, 2).Value
    'или 
    'arr = Range(Cells(1, 1),Cells(10000, 2)).Value
    'или автоматически вычисляем последнюю ячейку и заносим в массив данные, начиная с ячейки А3
    'llastr = Cells(Rows.Count, 1).End(xlUp).Row 'последняя ячейка столбца А
    'arr = Range(Cells(3, 1),Cells(llastr, 2)).Value
    For lr = 1 To 10000
        arr(lr,1) = lr 'заполняем массив порядковыми номерами
    Next
    'Выгружаем обработанный массив обратно на лист в те же ячейки
    Cells(1, 1).Resize(10000).Value = arr
    End Sub

    Но здесь следует учитывать и тот момент, что большие массивы могут просто вызвать переполнение памяти. Наиболее актуально это для 32-битных систем, где на VBA и Excel выделяется памяти меньше, чем в 64-битных системах

  • Если используете быстрый ЕСЛИ — IIF, то замените его на IF … Then … Else
  • Так же лучше вместо Switch() и Choose() применить тот же IF … Then … Else
  • В большинстве случаев проверять строку на «не пусто» лучше через Len(), чем прямое сравнение с пустотой: Len(s)=0 вместо s = «». Связано с тем, что работа со строками значительно медленнее, чем с числовыми данными и Len по сути не подсчитывает длину переменной, а берет это число непосредственно уже готовое из памяти. При сравнении же текста с пустой строкой(«»), VBA сначала создает в памяти переменную нулевой длинны, а уже потом сравнивает с ней наш текст. Поэтому в некоторых случаях так же ускоряет сравнение и в таком виде: s = vbNullString
  • Не применять объединение строк без необходимости. Например, s = «АВ», будет быстрее, чем: s =»А» & «В»
  • Не применять сравнение текстовых величин напрямую. Лучше применить встроенную функцию StrComp:
    If s <> s1 Then будет медленнее, чем
    If StrComp(s, s1, vbBinaryCompare) <> 0
    и тем более, если при сравнении необходимо не учитывать регистр:
    If LCase(s) <> LCase(s1) Then будет медленнее, чем
    If StrComp(s, s1, vbTextCompare) <> 0
  • Циклы For … Next в большинстве случаев работает быстрее, чем цикл Do … Lоор
  • Избегать присвоения переменным типа Variant. Хоть соблазн и велик — этот тип забирает много памяти и в дальнейшем замедляет работу кода. Так же для объектных переменных следует избегать по возможности безликого глобального типа Object и применять конкретный тип:
    Dim rRange as Object, wsSh as Object

    будет медленнее работать, чем:

    Dim rRange as Range, wsSh as Worksheet

    Причина в том, что при объявлении As Object мы не даем VBA практически никакой информации о типе данных, кроме того, что это какой-то объект. И VBA приходится «на лету» внутри кода при каждом обращении к такой переменной определять её конкретный тип(Range, Worksheet, Workbook, Chart и т.д.). Что опять же занимает время.

  • Если работаете с массивами, то можно при объявлении указать это явно:

    вместо

    Такая инициализация происходит быстрее.
    А еще лучше будет при этом еще и тип данных сразу присвоить:

    Dim arr() as string, arr2() as long

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

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


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

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


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



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

natalie

1

Как отключить расчет формул при работе макроса?

16.11.2010, 15:15. Показов 28076. Ответов 3


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

Народ, расскажите как отключить расчет формул при работе макроса, а то формул навалом и при каждом лишнем движении формулы заново расчитываются — по пятнадцать минут жду!
как отключить и как включить!
Заранее всем спасибо!!!

Dimakart

0 / 0 / 1

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

Сообщений: 48

16.11.2010, 18:21

2

Visual Basic
1
Application.Calculation = xlCalculateManual



0



1 / 1 / 0

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

Сообщений: 112

17.11.2010, 05:46

3

Да, но не забудь вернуть обратно на автомат. пересчет.
Еще очень полезно для скорости вставить в начало программы
[Application.ScreenUpdating.False]
а в конец
[Application.ScreenUpdating.True]



0



natalie

17.11.2010, 08:45

4

про screenupdating я знаю, а вот формулы отключать не умела
Большое спасибо!!!
Пошла ускорять свой ЧУДО — макрос

IT_Exp

Эксперт

87844 / 49110 / 22898

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

Сообщений: 92,604

17.11.2010, 08:45

Помогаю со студенческими работами здесь

Как в Excel отключить пересчет формул?
Для более быстрого расчета, мне нужно в Excel отключить вычесление формул. Через объект…

Мерцание курсора при работе макроса
Добрый день. Помогите разобраться. Есть процедура, которая запускается через каждую секунду…

Мерцание окна при работе макроса
Здравствуйте! Как убрать мерцание окна, если макрос работает с несколькими книгами? Он сначала…

Переполнение оперативной памяти при работе макроса
Добрый всем вечер!
Товарищи программисты, подскажите, пожалуйста, идеи по следующей проблеме….

Как отключить перерасчёт и вычисления формул книги, перед её сохранением
Здравствуйте форумчане! Подскажите пожалуйста как отключить перерасчёт и вычисления формул книги,…

Возникает ошибка при работе макроса (после выбора автофильтром)
Добрый день!
Помогите, пожалуйста, очень очень нужна ваша помощь. Никак не могу понять в чем дело….

Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:

4

Here is a workaround that might help if you want to have random values in a spreadsheet that can be recalculated at will and whose volatility can be turned on and off.

First, create a 1-cell named range, say «trigger»

Then, put the following code in a standard code module:

Function SemiVolatileRand(x As Variant) As Double
    SemiVolatileRand = x - x + Rnd()
End Function

Sub ReSample()
    Randomize
    Range("trigger").Value = Range("trigger").Value + 0.01
End Sub

Attach the ReSample sub to a button. Replace all occurrences of =RAND() by
=SemiVolatileRand(trigger). They will recalulcate whenever the button is pressed. Also, if you ever want to turn full volatility back on, just put the formula =RAND() in the trigger cell. (Getting full volatility in this last case seemed to require that my code does something with the dummy variable x, hence the somewhat poinless x - x).

Randomize reseeds the random number generator from the system clock. It should be called at least once per session. If you don’t, then each time you open an Excel workbook which uses VBA rnd, you will get the same sequence of random values. You can verify this by making a blank workbook and in the ThisWorkbook code module put:

Private Sub Workbook_Open()
MsgBox Rnd()
End Sub

The message block will display the same value each time you open the workbook. On the other hand if you put the line Randomize before the MsgBox then you will get different values each time you open it.

Note that the workbook open event is a natural place to put the statement Randomize if you are planning to use rnd.

The reason I didn’t put Randomize in the function itself was both to save CPU cycles and also because of a nagging concern that a certain percentage of the time you will be reseeding the random number generator with exactly the same system time. That might be impossible with modern architectures running recent versions of Excel, but e.g. does sometimes happen if you had Randomize Timer (which you sometimes encounter when reading other’s code) since the timer function has 1 millisecond resolution irrespective of the system clock.

The code I have does have the drawback that if you bypass the button and just change the trigger cell then you could miss the reseeding. If this is a concern, 1 possibility would be like this:

Public Initialized as Boolean

Function SemiVolatileRand(x As Variant) As Double
If Not Initialized Then
Randomize
Initialized = True
End If
SemiVolatileRand = x — x + Rnd()
End Function

This will prevent the function from running if rnd isn’t properly seeded.

Excel itself takes care of seeding automatically with the worksheet function Rand(), so it is strictly a VBA complication.

Like this post? Please share to your friends:
  • Vba excel отключить все сообщения
  • Vba excel отключить автофильтр
  • Vba excel отбросить дробную часть
  • Vba excel остановить таймер
  • Vba excel остановить процедуру