2

Somehow 10s of thousands of checkboxes were created in some spreadsheets that we have. I'm not sure how this happened but we cannot open the sheets in Excel 2010 only in Excel 2003 because of it. I wrote some VBA script to go through and delete the extra checkboxes and it works for most of the files. But, some files seem to have way more checkboxes than others and the script dies with an Out of Memory error. This is my script:

Sub ProcessFiles()
  Dim Filename, Pathname, LogFileName As String
  Dim wb As Workbook
  Dim fso As Object

  Set fso = CreateObject("Scripting.FileSystemObject")
  Set log = fso.OpenTextFile("Z:\Temp\Fix.log", 8, True, 0)

  PrintLog ("*** Beginning Processing ***")

  Pathname = "Z:\Temp\Temp\"
  Filename = Dir(Pathname & "*.xls")
  Do While Filename <> ""
    PrintLog ("Opening " & Pathname & Filename)
    Set wb = Workbooks.Open(Pathname & Filename)
    DoWork wb
    PrintLog ("Saving file " & Pathname & Filename)
    wb.Close SaveChanges:=True
    Filename = Dir()
  Loop

  log.Close
End Sub

Sub DoWork(wb As Workbook)
  Dim chk As CheckBox
  Dim c As Integer

  With wb
    Worksheets("Vessel & Voyage Information").Activate
    PrintLog ("Getting count of checkboxes")
    c = ActiveSheet.CheckBoxes.Count
    PrintLog (c & " checkboxes found")
    If (c <= 43) Then
      PrintLog ("Correct # of checkboxes.  Skipping...")
    Else
      c = 0
      For Each chk In ActiveSheet.CheckBoxes
        If Not (Application.Intersect(chk.TopLeftCell, Range("D29:D39")) Is Nothing) Then
          chk.Delete
          c = c + 1
        End If
      Next
      PrintLog ("Deleted " & c & " checkboxes.")
    End If
  End With
End Sub

Public Sub PrintLog(argument As String)
    If Not log Is Nothing Then
        log.WriteLine Format(Now(), "yyyy-MM-dd hh:mm:ss") & ": " & argument
    End If
End Sub

The script fails at the c = ActiveSheet.CheckBoxes.Count in DoWork or, if I comment that line out, then at the For Each chk In ActiveSheet.CheckBoxes. I am guessing that calling ActiveSheet.CheckBoxes gathers up all the checkboxes and there are too many so it dies.

Is there a way to step through each checkbox on a worksheet without using ActiveSheet.CheckBoxes?

Thomas G
  • 9,886
  • 7
  • 28
  • 41
Caynadian
  • 747
  • 2
  • 12
  • 37
  • What does `debug.print c` say? – findwindow Apr 20 '16 at 16:07
  • 1
    If you think there are too many, a quick check would be to do `Dim c as Long`. – BruceWayne Apr 20 '16 at 16:09
  • 2
    I don't think c would be assigned because it dies before that statement completes. – Caynadian Apr 20 '16 at 16:09
  • I don't think I'm overflowing the integer variable. I think Excel is trying to load to many checkboxes in to the ActiveSheet.Checkboxes object. – Caynadian Apr 20 '16 at 16:10
  • D'oh, you're right. Does [this page](http://www.ozgrid.com/forum/showthread.php?t=57891) provide any help? or [this one](http://www.xtremevbtalk.com/archive/index.php/t-86538.htmlc)? I don't think that it's you're trying to load too many, I think it's *how* you're trying to get it. (It could be that you have too many, I just doubt that VBA would crash because of too many checkboxes). – BruceWayne Apr 20 '16 at 16:11
  • Then don't grab the entire sheet. Grab ranges at a time? – findwindow Apr 20 '16 at 16:11
  • WAIT. There is no workbook XD Edit: nevermind, you did pass it. Ignore me! Edit2: kinda silly to `with` workbook but not sheet? – findwindow Apr 20 '16 at 16:12
  • @findwindow: The workbook is passed in as wb var. Also, because the checkboxes are on the sheet but not technically in a cell, I can't grab just a range of them. – Caynadian Apr 20 '16 at 16:15
  • Oh. Did not know checkboxes were a sheet object XD. I am so bad. – findwindow Apr 20 '16 at 16:16
  • what about using a for loop with an indexer ActiveSheet.CheckBoxes (index) – Sorceri Apr 20 '16 at 16:16
  • @BruceWayne: I will check out those suggestions. I'm not sure that the checkboxes I'm using are OLE controls but I will try it out. The files I'm dealing with that work with the script above have more than 30,000 checkboxes. Then ones that don't work are double the file size so I'm guessing there are upwards of 60,000 checkboxes. – Caynadian Apr 20 '16 at 16:17
  • 1
    Uh pretty sure 30K exceeds `int` type? Edit: as Batman suggested above, dim it as `long`. Edit: goes just past [32K](http://stackoverflow.com/questions/10558540/vba-macro-crashes-after-32000-rows). – findwindow Apr 20 '16 at 16:18
  • Doh! Yeah, max int is 32767. Let me try that and see. Have to head to a meeting so will update results later. – Caynadian Apr 20 '16 at 16:26
  • @Caynadian - further to @findwindow comments about the With statement ... you haven't really connected your activesheet object to wb. I would expect to see `.Worksheets("Vessel & Voyage Information").Activate` instead of `Worksheets("Vessel & Voyage Information").Activate` and `.ActiveSheet.CheckBoxes.Count` instead of `ActiveSheet.CheckBoxes.Count`. There are several occurrences of this. It probably won't solve your problem however. – OldUgly Apr 20 '16 at 17:57
  • Have you stepped through the code using F8 and monitored Excel's memory change? It's possible the memory bloats somewhere else and a small change at the lines you suspect is putting it over the top. – OldUgly Apr 20 '16 at 17:59
  • @OldUgly if using `with`, `activate` is moot. – findwindow Apr 20 '16 at 18:12

2 Answers2

2

I would try with the shape collection and with an indexer intead of an iterator:

Sub DeleteCheckBoxes()
  Dim itms As shapes, i&, count&, deleted&
  Set itms = ActiveSheet.Shapes

  On Error GoTo ErrHandler
  For i = 1& To &HFFFFFFF
    If itms(i).Type = msoFormControl Then
      If itms(i).FormControlType = xlCheckBox Then
        count = count + 1
        If count > 43 Then 
          itms(i).Delete
          deleted = deleted + 1
          i = i - 1
        End If
      End If
    End If
  Next

ErrHandler:
  Debug.Print "Count   " & count
  Debug.Print "Deleted " & deleted
End Sub
Florent B.
  • 41,537
  • 7
  • 86
  • 101
0

From this page, does this work:

Sub Count_CheckBoxes()
Dim cnt     As Long
Dim cbx     As OLEObject

cnt = 0
'Count CheckBoxes
For Each cbx In ActiveSheet.OLEObjects
    If TypeName(cbx.Object) = "CheckBox" Then
        cnt = cnt + 1
    End If
Next

End Sub
BruceWayne
  • 22,923
  • 15
  • 65
  • 110
  • Nope. As I guessed, the checkboxes are not OLEObjects. cnt is 0 if I use the function above but "cnt = ActiveSheet.CheckBoxes.Count" returns 25,429. – Caynadian Apr 20 '16 at 16:21