1

Disclaimer: I am relatively new to vba and macros.

I have written a macro to update value and formatting in some individual cells after reading and parsing a json through http and the process is very slow, so I broke down the code into different portions to see where the bottleneck might be. Turns out the cell updating is the problem, I have the following code:

Sub test()
    Application.ScreenUpdating = False
    Application.Calculation = xlCalculationManual
    Application.EnableEvents = False
    Application.EnableCancelKey = False
    t = Timer
        With Range("A1")
            .Font.Italic = True
            .Interior.ColorIndex = 37
            .Value = 3412
        End With
    Debug.Print Timer - t
    Application.ScreenUpdating = True
    Application.Calculation = xlCalculationAutomatic
    Application.EnableEvents = True
    Application.EnableCancelKey = True
End Sub

the debug print is about 0.3 to 0.5 sec... I have afterwards further wrapped the timer around each of the italic, colorIndex, and value lines and they all turns out take about 0.015 sec each... I have tried searching online how to make the code more efficient, hence the screenupdating toggles as well as no selection, but 0.5 sec still seem a bit slow in updating a cell to me.

please note that I am not whining, I just want to know if I am doing the right thing here. Is there a more efficient way to implement the formatting and value changes that I posted here, or is it just a fact that excel takes this amount of time to update the cell? I am just very curious because the json reading and parsing that I also implemented are significantly faster than this.

Also I have tested this script on at least 3 computers and they all take around the same time so I don't think it's an individual computer problem. And I used excel 2007 and 2010 to test.

pnuts
  • 58,317
  • 11
  • 87
  • 139
minovsky
  • 857
  • 1
  • 15
  • 28
  • 1
    I tested your code in my machine with Excel 2010 and it took *125ms*. Adding the *ScreenUpdating* set to *False* resulted to *121.0938ms*. Adding the turning on/off of *Calculation* worsen it to *140.625ms* so I don't recommend it. If *0.125* seconds is not fast enough then we can do nothing about it. I think that's just how fast Excel could go. – L42 Jul 28 '14 at 02:59
  • @L42 - 0.125s is good, it took 0.5 sec for me... and on 3 computers. mind sharing your specs? the one i am currently using is i5 2.67GHz with 4GB RAM, and I don't have lots of process running and have shut and reloaded a fresh instance of excel before testing... – minovsky Jul 28 '14 at 03:02
  • That's even better than mine, I'm just running on i3 at 2.4GHz at 32 bit OS :) – L42 Jul 28 '14 at 03:05
  • uh oh so it does sound like an individual computer problem... well at least the code is fine. thanks for testing :) – minovsky Jul 28 '14 at 03:29
  • 1
    Couple of points: 1) your code shows you are using `Timer` to time your code. This has a resolution of 1sec. Take care when evaluating results with this method, I would suggest `GetTickCount`, it has a resolution of about 16ms. 2) I assume you are wanting to format more than a single cell? If so, it will be faster to create a range reference to all the cells requiring the same format (it need not be contiguous), then apply the required format to that range object in one step. – chris neilsen Jul 28 '14 at 03:36
  • @chrisneilsen - I didn't know range doesn't have to be contiguous! Can you show me an example how to create that range? and let me read up about `GetTickcount` – minovsky Jul 28 '14 at 03:40
  • I'll add an example as an answer – chris neilsen Jul 28 '14 at 03:41

1 Answers1

2

I assume you are wanting to format more than a single cell? If so, it will be faster to create a range reference to all the cells requiring the same format (it need not be contiguous), then apply the required format to that range object in one step

Following example demo's creating a range reference, and applying format in one go

Option Explicit

Private Declare Function GetTickCount Lib "kernel32" () As Long

Sub Demo()
    Dim t As Long
    Dim n As Long, i As Long
    Dim m As Long
    Dim ws As Worksheet
    Dim cl As Range
    Dim rSearch As Range
    Dim rResult  As Range

    Set ws = ActiveSheet ' or another sheet...

    Set rSearch = ws.Range("A1:A1000")

    ' note, this is an inefficient loop, can be made much faster
    ' details will depend on the use case
    For Each cl In rSearch
        ' determine if cell is to be formatted
        If cl.Row Mod 2 = 0 Then
            ' add cl to Result range
            If rResult Is Nothing Then
                Set rResult = cl
            Else
                Set rResult = Application.Union(rResult, cl)
            End If
        End If
    Next

    Debug.Print "Result Range includes ", rResult.Cells.Count, "Cells"
    t = GetTickCount
    ' Apply format
    With rResult
        .Font.Italic = True
        .Interior.ColorIndex = 37
        .Value = 3412
    End With
    Debug.Print (GetTickCount - t) / 1000, "seconds"

End Sub
chris neilsen
  • 52,446
  • 10
  • 84
  • 123