How to speed up this VBA code with slicers? - vba

I have a spreadsheet with seven tables (tbl_1, tbl_2 ...tbl_7) each controlled by its own slicer. Each slicer has six buttons (10, 20, 30, 40, 50, 60) referring to Team Codes. I use the code below to select one team on every slicer, then create a PDF for each team / slicer setting. As of now, the code takes anywhere from 5-7min to run. Any help is much appreciated.
Sub SlicerTeam()
Dim wb As Workbook
Dim sc As SlicerCache
Dim si As SlicerItem
On Error GoTo errHandler
Application.ScreenUpdating = False
Application.EnableEvents = False
Set wb = ThisWorkbook
For x = 1 To 6
For i = 1 To 7
Set sc = wb.SlicerCaches("tbl_" & i)
sc.ClearAllFilters
For Each si In sc.VisibleSlicerItems
Set si = sc.SlicerItems(si.Name)
If Not si Is Nothing Then
If si.Name = x * 10 Then
si.Selected = True
Else
si.Selected = False
End If
Else
si.Selected = False
End If
Next si
Next i
Call PDFCreate
Next x
exitHandler:
Application.ScreenUpdating = True
Application.EnableEvents = True
Exit Sub
errHandler:
MsgBox ("Error in updating slicer filters.")
Resume exitHandler
End Sub

Assuming that these slicers are slicing pivot tables, try the below code. It may help speed things up, depending on how big your PivotTables are.
Sub SlicerTeam()
Dim wb As Workbook
Dim sc As SlicerCache
Dim si As SlicerItem
dim pt as PivotTable
On Error GoTo errHandler
Application.ScreenUpdating = False
Application.EnableEvents = False
Set wb = ThisWorkbook
For Each pt in wb.PivotTables
pt.ManualUpdate = True
Next
For x = 1 To 6
For i = 1 To 7
Set sc = wb.SlicerCaches("tbl_" & i)
sc.ClearAllFilters
For Each si In sc.VisibleSlicerItems
Set si = sc.SlicerItems(si.Name)
If Not si Is Nothing Then
If si.Name = x * 10 Then
si.Selected = True
Else
si.Selected = False
End If
Else
si.Selected = False
End If
Next si
Next i
For Each pt in wb.PivotTables
pt.ManualUpdate = True
Next
Call PDFCreate
Next x
exitHandler:
Application.ScreenUpdating = True
Application.EnableEvents = True
Exit Sub
errHandler:
MsgBox ("Error in updating slicer filters.")
Resume exitHandler
End Sub

After several trials.. found this is the best option.
Disable calculations:
Application.ScreenUpdating = False
With Application
.EnableEvents = False
.Calculation = xlCalculationManual
End With
type code to Remove slicer conections.... example:
ActiveWorkbook.SlicerCaches("Slicer_Area").PivotTables.RemovePivotTable ( _
ActiveSheet.PivotTables("PivotDatosGraficoAbsoluto"))
Set slicer value to true, and others to false... example:
Set MySlicerCache = ActiveWorkbook.SlicerCaches("Slicer_Area")
For i = 1 To MySlicerCache.SlicerItems.Count
With MySlicerCache.SlicerItems(i)
If .Name = "Comercial GJ" Then
.Selected = True
'Range("E1").Value = .Name
Else:
.Selected = False
End If
End With
Next i
Do the Slicer conections.. example:
ActiveWorkbook.SlicerCaches("Slicer_Area").PivotTables.AddPivotTable ( _
ActiveSheet.PivotTables("PivotDatosGraficoAbsoluto"))
Enable Events:
With Application
.EnableEvents = True
.Calculation = xlCalculationAutomatic
End With
This will save aprox 40% of waiting time

Related

Trying to use vba lookup to get values from other workbooks

Another go still not working
Private Sub Worksheet_Change(ByVal Target As Range)
If Me.ListBox4 = "Fill Details" Then
On Error GoTo ErrHandler
Application.ScreenUpdating = False
Dim src As Workbook
Dim JCM As Worksheet
Set src = Workbooks.Open("\\TGS-SRV01\Share\ShopFloor\PRODUCTION\JOB BOOK\JOB RECORD SHEET.xlsm", True, True)
Set JCM = Worksheets("Job Card Master")
Dim iTotalRows As Integer
iTotalRows = src.Worksheets("sheet1").Range("A1:A" & Cells(rows.Count, "A").End(xlUp).row).rows.Count
Dim iCnt As Integer
For iCnt = 2 To iTotalRows
Sheet1.Cells(40 & iCnt) = Application.WorksheetFunction.VLookup(JCM.Cells("G2"), _
Sheets(JCM).Range("A4"), iCnt, 0)
Next iCnt
src.Close False
Set src = Nothing
ErrHandler:
Application.EnableEvents = True
Application.ScreenUpdating = True
MsgBox "Successfully entered Job Book data to Job Card Master Headers"
End If
End Sub

Adding array to sheet names

I am using the below code to retain sheets that I need and delete the rest.
Sub DeleteSheets1()
Dim xWs As Worksheet
Application.ScreenUpdating = False
Application.DisplayAlerts = False
For Each xWs In Application.ActiveWorkbook.Worksheets
If xWs.Name <> "Sheet1" And xWs.Name <> "Sheet2" Then
xWs.Delete
End If
Next
Application.DisplayAlerts = True
Application.ScreenUpdating = True
End Sub
I have around 6 sheets that I want to retain. I need help modifying the syntax to accommodate multiple sheets. Something like below
if xWs.Name <> ("sheet1", "sheet2"....) then xws.delete
Here arr is an array of the sheets to retain:
Sub DeleteSheets1()
Dim xWs As Worksheet, s As String, i As Long
Dim skp As Boolean
arr = Array("Sheet1", "Sheet2", "Sheet3")
Application.ScreenUpdating = False
Application.DisplayAlerts = False
n = ActiveWorkbook.Worksheets.Count
For i = n To 1 Step -1
s = Sheets(i).Name
skp = False
For Each a In arr
If s = a Then skp = True
Next a
If Not skp Then Sheets(i).Delete
Next
Application.DisplayAlerts = True
Application.ScreenUpdating = True
End Sub
The valueInArray boolean function could work the code easier:
Public Function valueInArray(myValue As Variant, myArray As Variant) As Boolean
Dim cnt As Long
For cnt = LBound(myArray) To UBound(myArray)
If CStr(myValue) = CStr(myArray(cnt)) Then
valueInArray = True
Exit Function
End If
Next cnt
End Function
Sub DeleteSheets()
Application.DisplayAlerts = False
Application.ScreenUpdating = False
Dim cnt As Long
cnt = Worksheets.Count
Dim arrWks As Variant
arrWks = Array("Sheet1", "Sheet2", "Sheet3")
For cnt = Worksheets.Count To 1
If Not valueInArray(Worksheets(cnt).Name, arrWks) Then
Worksheets(cnt).Delete
End If
Next cnt
Application.DisplayAlerts = True
Application.ScreenUpdating = True
End Sub
The valueInArray function gets value to search for myValue and array where to search for this value myArray. It loops through all elements of the array and if it finds the same String of the passed value, it returns True and exits. If it is not found, it returns False, as this is the default.
Another approach
Sub Test()
Dim ws As Worksheet
Dim arr As Variant
arr = Array("Sheet1", "Sheet2", "Sheet3")
Application.ScreenUpdating = False
Application.DisplayAlerts = False
For Each ws In ThisWorkbook.Worksheets
If Not IsNumeric(Application.Match(ws.Name, arr, 0)) Then ws.Delete
Next ws
Application.DisplayAlerts = True
Application.ScreenUpdating = True
End Sub
Ok, this one doesn't quite fulfil the requirement of an array, but it's another way of using a single loop.
It looks for an occurrence of the sheet name in the RetainSheets string. Each sheet name is surrounded by | just in case there's a sheet name within a sheet name eet1Sh as an example.
The code will not attempt to delete the last worksheet in the workbook either.
Sub Test()
Dim wrkSht As Worksheet
Dim RetainSheets As String
RetainSheets = "|Sheet1|Sheet2|"
Application.ScreenUpdating = False
Application.DisplayAlerts = False
For Each wrkSht In Worksheets
If InStr(RetainSheets, wrkSht.Name) = 0 And Worksheets.Count > 1 Then
wrkSht.Delete
End If
Next wrkSht
Application.ScreenUpdating = True
Application.DisplayAlerts = True
End Sub

VBA Code to Control Multiple Pivot Table Slicers

I'm trying to set-up some VBA code that will allow me to control multiple pivot tables (and data sources) with 1 slicer.
In the past, I have only needed to implement VBA code that controls 1 additional slicer, but now I am trying to set-it up to control 2 slicers and am running into issues.
Here is my code that I used in the past for controlling 1 slicer:
As a module:
Public PrevCat As String
In ThisWorkbook:
Private Sub Workbook_Open()
PrevCat = Sheet27.Range("O5").Value
End Sub
Primary code:
Option Explicit
Private Sub Worksheet_Calculate()
Application.ScreenUpdating = False
Dim pt As PivotTable
Dim Field As PivotField
Dim NewCat As String
NewCat = Sheet27.Range("O5").Value
If NewCat <> PrevCat Then
Application.EnableEvents = False
Set pt = Sheet27.PivotTables("Pivot Match 2")
Set Field = pt.PivotFields("Region")
With Field
.ClearAllFilters
On Error Resume Next
.CurrentPage = NewCat
On Error GoTo 0
End With
pt.RefreshTable
PrevCat = NewCat
Application.EnableEvents = True
End If
Application.ScreenUpdating = True
End Sub
Like I said, this code works perfectly for controlling 1 additional slicer. However, I need the code to control 2 slicers. All i did was add an additional If statement, but it doesn't seem to work:
Option Explicit
Private Sub Worksheet_Calculate()
Application.ScreenUpdating = False
Dim pt As PivotTable
Dim Field As PivotField
Dim NewCat As String
NewCat = Sheet27.Range("O5").Value
If NewCat <> PrevCat Then
Application.EnableEvents = False
Set pt = Sheet27.PivotTables("Pivot Match 2")
Set Field = pt.PivotFields("Region")
With Field
.ClearAllFilters
On Error Resume Next
.CurrentPage = NewCat
On Error GoTo 0
End With
pt.RefreshTable
PrevCat = NewCat
Application.EnableEvents = True
End If
If NewCat <> PrevCat Then
Application.EnableEvents = False
Set pt = Sheet27.PivotTables("Pivot Match 3")
Set Field = pt.PivotFields("Region")
With Field
.ClearAllFilters
On Error Resume Next
.CurrentPage = NewCat
On Error GoTo 0
End With
pt.RefreshTable
PrevCat = NewCat
Application.EnableEvents = True
End If
Application.ScreenUpdating = True
End Sub
Any ideas on how i can get this to work?

Fixing a mismatch error within a loop

continuation of my previous question. I think I've made some progress but gotten stuck again:
I've created two loops - one for month to be checked by user. Other will remain hidden but carries location of each file. I'd like it to pick values from the other file ("Training1" in each) and bring it to "2017 Actuals" of current file.
I've tested portions and I think I'm going wrong at the following which gives me a mismatch error, but any tips will be helpful:
Set wks = wkb.Sheets("Training1")
Full code here:
Private Sub UpdateActuals_Click()
Application.DisplayAlerts = False
Application.ScreenUpdating = False
Application.AskToUpdateLinks = False
Dim p As Integer
Dim i As Integer
For i = 1 To 12
If Me.Controls("Month" & i).Value = True Then
For p = 1 To 12
Dim wkb As Workbook
Dim wks As Workbook
Set wkb = Workbooks.Open(Me.Controls("Location" & p))
Set wks = wkb.Sheets("Training1")
ThisWorkbook.Sheets("2017 Actuals").Range(i + 1, 5) = wks.Range("Start:Finish")
Next p
End If
Next i
wkb.Close
Application.DisplayAlerts = True
Application.AskToUpdateLinks = True
Application.ScreenUpdating = True
End Sub
You need to declare your wks as type Worksheet.
So in your block of code, update it to this:
If Me.Controls("Month" & i).Value = True Then
For p = 1 To 12
Dim wkb As Workbook
Dim wks As Worksheet ' Not Workbook
Set wkb = Workbooks.Open(Me.Controls("Location" & p))
Set wks = wkb.Sheets("Training1")
ThisWorkbook.Sheets("2017 Actuals").Range(i + 1, 5) = wks.Range("Start:Finish")
Next p
End If

When locking a sheet, the VB Code stops working

Here is my code; when I lock the sheet the code stops working and will not pop up on the double click.
On another note is there a way to activate the code without requiring it to double click?
Private Sub Worksheet_Activate()
End Sub
'==========================
Private Sub Worksheet_BeforeDoubleClick(ByVal Target As Range, _
Cancel As Boolean)
Dim str As String
Dim cboTemp As OLEObject
Dim ws As Worksheet
Set ws = ActiveSheet
Set cboTemp = ws.OLEObjects("NameBox")
On Error Resume Next
With cboTemp
'clear and hide the combo box
.ListFillRange = ""
.LinkedCell = ""
.Visible = False
End With
On Error GoTo errHandler
If Target.Validation.Type = 3 Then
'if the cell contains a data validation list
Cancel = True
Application.EnableEvents = False
'get the data validation formula
str = Target.Validation.Formula1
str = Right(str, Len(str) - 1)
With cboTemp
'show the combobox with the list
.Visible = True
.Left = Target.Left
.Top = Target.Top
.Width = Target.Width + 5
.Height = Target.Height + 5
.ListFillRange = str
.LinkedCell = Target.Address
End With
cboTemp.Activate
'open the drop down list automatically
Me.NameBox.DropDown
End If
errHandler:
Application.EnableEvents = True
Exit Sub
End Sub
'=========================================
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
Dim str As String
Dim cboTemp As OLEObject
Dim ws As Worksheet
Set ws = ActiveSheet
Application.EnableEvents = False
Application.ScreenUpdating = True
If Application.CutCopyMode Then
'allow copying and pasting on the worksheet
GoTo errHandler
End If
Set cboTemp = ws.OLEObjects("NameBox")
On Error Resume Next
With cboTemp
.Top = 10
.Left = 10
.Width = 0
.ListFillRange = ""
.LinkedCell = ""
.Visible = False
.Value = ""
End With
errHandler:
Application.EnableEvents = True
Exit Sub
End Sub
'====================================
'Optional code to move to next cell if Tab or Enter are pressed
'from code by Ted Lanham
'***NOTE: if KeyDown causes problems, change to KeyUp
Private Sub NameBox_KeyDown(ByVal _
KeyCode As MSForms.ReturnInteger, _
ByVal Shift As Integer)
Select Case KeyCode
Case 9 'Tab
ActiveCell.Offset(0, 1).Activate
Case 13 'Enter
ActiveCell.Offset(1, 0).Activate
Case Else
'do nothing
End Select
End Sub
'====================================