Excel vba как отключить обновление экрана

Хитрости »

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


Рано или поздно у пишущих на 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
ссылки
статистика

Благодарю всех за пояснения.

БМВ, Ваш пример и правда гораздо нагляднее.
sokol92, Вы  правы, думаю и у меня так и было раньше, а проблема не в  этом. Значение  у меня в False переключается, а вот обновление экрана  при этом по  прежнему происходит.
Дмитрий(The_Prist) Щербаков, Ваши пояснения особо в тему, потому что это как раз то, что мне нужно.

Моя «основная» процедура выглядит примерно так:

Код
Private Sub General()
Application.ScreenUpdating = False
'...
Call SubProcedure
'...
Debug.Print Application.ScreenUpdating
Application.ScreenUpdating = True
End Sub

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

Однако несмотря на то, что ScreenUpdating=False, обновление экрана все равно происходит, это заметно чисто визуально. Хотя до недавнего времени этот же файл работал нормально (изменений в коде не производилось). Поэтому я и подумал, что ScreenUpdating включается при выходе из подпроцедур, хотя теперь понимаю что это не так.

Любопытный момент: если убрать строчку Application.ScreenUpdating = True из головной процедуры, всё начинает работать корректно (обновление экрана включается только в самом конце — при выходе из головной процедуры — автоматически).

Я не могу найти никакого логичного объяснения такому поведению приложения.

Return to VBA Code Examples

In this Article

  • Disable ScreenUpdating
  • Enable ScreenUpdating
  • VBA ScreenUpdating Example
  • ScreenUpdating Refresh
    • VBA Settings – Speed Up Code
  • VBA Coding Made Easy

As cool as it looks watching your VBA macro manipulate the screen, you can help your Macro run faster if you turn off (disable) ScreenUpdating.

Disable ScreenUpdating

1. To disable ScreenUpdating, At the beginning of your code put this line:

Application.ScreenUpdating = False

Enable ScreenUpdating

2. To re-enable ScreenUpdating, At the end of your code put this line:

Application.ScreenUpdating = True

VBA ScreenUpdating Example

Your procedure will then look like this:

Sub ScreenUpdating_Example()
    Application.ScreenUpdating = False

    'Do Something
    Range("a1").Copy Range("b1")
    Range("a2").Copy Range("b2")
    Range("a3").Copy Range("b3")


    Application.ScreenUpdating = True
End Sub

vba screen updating

ScreenUpdating Refresh

Disabling ScreenUpdating will make your VBA code run MUCH faster, but it will also make your work appear more professional. End-users typically don’t want to see the behind the scenes actions of your procedures (especially when the procedure runs slow). Also, you may not want end-users to see the behind the scenes functionality (ex. Hidden Worksheets). I recommend disabling (and re-enabling) ScreenUpdating in virtually all of your procedures.

However, there are some times when you want the screen to refresh. To refresh the screen, you will need to temporarily turn back on ScreenUpdating (there is no screen “refresh” command):

    Application.ScreenUpdating = True
    'Do Something
    Application.ScreenUpdating = False

VBA Settings – Speed Up Code

There are several other settings to play with to improve your code speed.

Disabling Automatic Calculations can make a HUGE difference in speed:

Application.Calculation = xlManual

Disabling the Status Bar will also make a small difference:

Application.DisplayStatusBar = False

If your workbook contains events you should usually disable events at the beginning of your procedure:

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 disable displaying page breaks 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!

VBA Turn Off On ScreenUpdating

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!
vba save as

Learn More!

If you ever worked with VBA, you could probably be in a situation where your code is not as fast as you would want it to be. There are a couple of things that you can do to speed it up a little bit.

In the example below, we will show how to speed up the code by turning the screen updating off in VBA.

Screen updating can be turned on or off through the VBA module. In simple terms, it has to be done at the application level.  We are going to use the following sentence:

Application.ScreenUpdating = False (turning it off)

Application.ScreenUpdating = True (turning it on)

We will show its importance in one example. To do this, we need to open the Excel file, click on ALT + F11, and then right-click on the left window that appears, go to Insert >> Module:

When a new window appears in which we should write our code, we can start with it.

This is what our code will look like:

Sub AddingSheets()

    Application.ScreenUpdating = FALSE

    Dim sTime As Single, ElapsedTime As Single, sec As Single

    sTime = Timer        ‘find out starting time

    Worksheets.Add after:=Sheets(Sheets.Count)

    ElapsedTime = Timer sTime        ‘Save the elapsed time to ElapsedTime variable

    ‘Extract seconds

    sec = ElapsedTime

    Debug.Print «Time passed: « & sec & » sec»

End Sub

This is what our code looks like in the module itself:

This code first declares variables that we going to use, and then it sets variable sTime to be equal to the Timer:

Dim sTime As Single, ElapsedTime As Single, sec As Single

sTime = Timer

Then we need concrete action. In our case, our action is to add a worksheet at the end of our workbooks, i.e. after the end of our sheets list.

After that, we calculate ElapsedTime as the difference between the Timer and start time, and we store that number in the ElapsedTime variable.

Worksheets.Add after:=Sheets(Sheets.Count)

ElapsedTime = Timer sTime

For the next part, we want to extract seconds from our variable, so we do just that by setting the sec variable to be equal to ElapsedTime.

Now, for the final part, we will use the Debug.Print option to show us the time that it took for our sheet to be created:

Debug.Print «Time passed: « & sec & » sec»

Now, Debug.Print option is great for us because it will give us the information that we need (the time spent creating a sheet) without having to store this information in a variable or without showing it in a message box.

To use Debug.Print option, we need to turn on the Immediate window. We will do it by going to the View tab in our Module and choosing the Immediate window, or simply clicking CTRL + G:

With this window visible, we will execute our code (by going into the code and clicking F5) and we will see the message in our Immediate window:

Time passed: 0.015625 seconds

Or in our Module:

We will also have a new sheet created, as defined in our code.

To speed up the execution of our code, we will simply add an Application.ScreenUpdating = False above our code and beneath the part where we defined subroutine (Sub….):

Now, when we execute our code again, these are the results that we will get:

Time passed: 0.0078125 seconds

Or in the module:

To turn on the screen updating again, we just need to insert:

Application.ScreenUpdating = True

You will notice that our code is executed so much faster without screen updating. Although it is a matter of seconds in our case that is only because we defined such a small portion of code (sheet to be added) to be executed. Just imagine how much time can you spare when it comes to more complex code.

Post Views: 111

Home / VBA / VBA ScreenUpdating | How to Turn it ON and OFF

What is VBA Screen Updating?

ScreenUpdating is a property in VBA that you can use to turn “ON” and “OFF” the screen updating while running the code. You can turn it off before running a code that makes your code run faster and then turn it on once the execution of the code completes. You can read and write this property.

By default, screen updating is “ON” in Excel. When you normally run a code it takes a lot of flickering if that code takes time, but if you turn OFF the screen updating it will take less time than normal to run.

Turn OFF Screen Updating in VBA

  1. First, type the keyword “Application”.
  2. After that, press a dot “.” to open the properties and methods list.
  3. Now, select “ScreenUpdating”.
  4. In the end, specify “False” to it.

Once you turn off screen updating, VBA will not turn it ON once the code is executed. So it’s always better to turn it off from your end. The code would be like something below.

Points to Consider

  • Make sure to have the screen updating “ON” when you are using a user form.
  • If you are debugging code, it is better to have a screen updating “ON” so that you can see all the activities as they are.

There’s More

VBA With Statement | VBA Wait and Sleep Commands | VBA Status Bar | VBA Random Number | Line Break in a VBA Code | VBA Immediate Window (Debug.Print) | VBA Concatenate | VBA Module | VBA Random Number

Понравилась статья? Поделить с друзьями:
  • Excel vba как остаток от деления
  • Excel vba как остановить выполнение кода
  • Excel vba массив сортировка
  • Excel vba массив символов
  • Excel vba массив размер