VBA Code optimize , the code running too slowly - excel

I made a macro that take data from closed workbook but unfortunately the code runs too slowly for me.
Just when i start the macro it loading around 2 or 3 second. I will be very thankful if you help me to optimize the code :
Hire is my code:
Sub Button4_Click()
Dim SRC As Workbook
Application.ScreenUpdating = False
Set SRC = Workbooks.Open("C:\Users\a1068434\Desktop\TEST\asdasd.CSV", True, True)
ActiveWindow.Visible = False
ThisWorkbook.Activate
Dim R As Range
Set R = Worksheets("Sheet1").Cells(Rows.Count, 1).End(xlUp) 'last cell in Column A with data
If Len(R.Value) > 0 Then Set R = R.Offset(1)
R.Value = SRC.Worksheets("asdasd").Range("G14").Formula
SRC.Close SaveChanges:=False
End Sub

Since your working with csv and just pulling but one value out of it, why not parse the text?
Private Sub Button4_Click()
On Error GoTo Wrapup
Application.ScreenUpdating = False
Open "C:\Users\a1068434\Desktop\TEST\asdasd.CSV" For Input As #1
'skip to line 14
For i = 1 To 14
Line Input #1, LineFromFile
Next i
'read in the 7th column
LineItems = Split(LineFromFile, ",")
result = LineItems(6)
'Output
Dim R As Range
Set R = Worksheets("asdasd").Cells(Rows.Count, 1).End(xlUp)
If Len(R.Value) > 0 Then Set R = R.Offset(1)
R.Value = result
Wrapup:
Close #1
Application.ScreenUpdating = True
End Sub

Nothing will make Excel open/close a workbook faster, other than getting a faster hard drive and opening/closing smaller files.
There are a number of ways your code can be improved though, notably:
Using explicit access modifiers. Click handlers have no reason to be implicitly public
Code that toggles off ScreenUpdating should always toggle it back on whether there's an error or not
Getting the Len of a Variant with an unknown subtype is dangerous: you never know if you're going to hit a Variant/Error, and Len(CVErr(xlErrNA)) throws a type mismatch error and you don't want that. So, verify whether the value IsError first.
You never (99.99999% accurate) need to Activate anything. Worksheets that exist in ThisWorkbook at compile-time can (should) be accessed by their code name identifier.
Private Sub Button4_Click()
On Error GoTo CleanFail
Application.ScreenUpdating = False
Const path As String = "C:\Users\a1068434\Desktop\TEST\asdasd.CSV"
Dim source As Workbook
Set source = Application.Workbooks.Open(path, True, True)
ActiveWindow.Visible = False '<~ why bother?
Dim lastCellWithData As Range '<~ no need for comments when names are descriptive
Set lastCellWithData = Sheet1.Cells(Sheet1.Rows.Count, 1).End(xlUp)
If Not IsError(lastCellWithData.Value) Then
Dim lastCellStringValue As String
lastCellStringValue = lastCellWithData.Value
If Len(lastCellStringValue) > 0 Then
lastCellWithData.Offset(1).Value = source.Worksheets("asdasd").Range("G14").Formula '<~ do you really mean .Formula?
End If
End If
CleanExit:
source.Close SaveChanges:=False
Application.ScreenUpdating = True
Exit Sub
CleanFail:
Debug.Print Err.Description
Resume CleanExit
Resume '<~ for step-through debugging; make this the next stmt to highlight the error statement
End Sub

Related

Out of Memory Error when running Drill Down Script

The purpose of the macro is to avoid creating a new worksheet each time a user double clicks / drills down on a pivot table value. Instead the script copies the data to a dedicated "DrillDown" sheet.
After several clicks, I get an Excel error stating I am out of memory.
The raw dataset is not very big.
I am wondering if there is an issue with the script, or perhaps I need to add something further?
Maybe there is some temp data I need to clear first?
My code:
Module1
Public CS$
This Workbook
Private Sub Workbook_NewSheet(ByVal Sh As Object)
If CS <> "" Then
With Application
ScreenUpdating = False
Dim NR&
With Sheets("DrillDown")
'Set this to always start at the top of the page
NR = 1
'..and to clear the Drilldown tab..
.Cells.ClearContents
'instead of this..
'If WorksheetFunction.CountA(.Rows(1)) = 0 Then
' NR = 1
'Else
' NR = .Cells.Find(What:="*", After:=[A1], SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row + 2
'End If
Range("A4").CurrentRegion.Copy .Cells(NR, 1)
End With
.DisplayAlerts = False
ActiveSheet.Delete
.DisplayAlerts = True
'Below is commented out to stop user being returned to Pivot
' Sheets(CS).Select
.ScreenUpdating = True
End With
End If
End Sub
It could be the event triggers while the data is still being written to the sheet. You could retain the newly created sheet and delete the previous to avoid copying.
Private Sub Workbook_NewSheet(ByVal Sh As Object)
If CS = "" Then Exit Sub
With Application
.DisplayAlerts = False
On Error Resume Next
Sheets("DrillDown").Delete
Sh.Name = "DrillDown" ' renamenew sheet
On Error GoTo 0
.DisplayAlerts = True
End With
End Sub

VBA Crashes on first line Set Var = Workbooks("name").Worksheets("name")

Below is a simple code to check for changes between 2 workbooks. 1 is a master workbook the other is a list of changes sent to me. I literally have both opened and I have ensured they are opened within the same instance. Code is stored within my personal macro workbook so I can check multiple files.
My code literally crashes on the first line. Set cSheet Workbooks("CNO_CostGroups_v2.xlsx").Worksheets("CostCenters") No errors, no messages, nothing. Excel simply goes into not responding, crashes, and reopens everything in an auto recovered version. I have stepped through this code line by line using F8 on my keyboard. Excel crashes each time and I can't get past here.
This code was working when written a few weeks ago and was used a couple times after that. My only guess is that perhaps my Excel updated, but no real indication that it happened. I don't know what version it may have been when code is written, but what is on my machine now is 64 bit, Version 2002, Build 12527.21416. I know I didn't change from 32 bit to 64 bit.
My question is what can I do? I've even tried running this code in Immediate Window and it correctly returns the value of A1 ?Workbooks("CNO_CostGroups_v2.xlsx").Worksheets("CostCenters").Range("A1").Value.
What is causing it to crash? It seems like a simple enough line to me, and as you can see all variables have been declared appropriately.
Sub CheckForChanges()
Dim nSheet As Worksheet, cSheet As Worksheet, cIndexRng As Range, nHeadRng As Range, nIndexRng As Range
Dim C As Range, col1 As Long, col2 As Long, row1 As Long, row2 As Long
'Must have master version of cost center groups open
'Set intitial values
Set cSheet = Workbooks("CNO_CostGroups_v2.xlsx").Worksheets("CostCenters")
Set cIndexRng = cSheet.Range("P1", cSheet.Range("P1").End(xlDown))
Set nSheet = ActiveSheet
Set nHeadRng = nSheet.Range("A1", nSheet.Range("A1").End(xlToRight))
Set nIndexRng = nSheet.Range("P2", nSheet.Range("P2").End(xlDown)) 'Ensure This part is referencing the correct index column (currently in column P)
col1 = 1
col2 = nHeadRng.Count
'Check the file structures are the same
For Each C In nSheet.Range("A1", nSheet.Range("A1").End(xlToRight))
If C.Value <> cSheet.Cells(1, col1).Value Then
MsgBox ("Make sure you have open a current Cost Center file and that the column headers match")
Exit Sub
End If
col1 = col1 + 1
Next C
'Begin checking file for changes. Needs updates in Yellow, new lines all together in Green
For Each C In nIndexRng
row1 = C.Row
If IsFound(C.Value, cIndexRng, row2) Then
If row1 = row2 Then nSheet.Cells(row1, 16).Interior.Color = RGB(146, 208, 80)
For col1 = 1 To col2
If nSheet.Cells(row1, col1).Value <> cSheet.Cells(row2, col1).Value Then
nSheet.Cells(row1, col1).Interior.Color = RGB(255, 255, 0)
End If
Next col1
Else
nSheet.Range(nSheet.Cells(row1, 1), nSheet.Cells(row1, col2)).Interior.Color = RGB(146, 208, 80)
End If
Next C
End Sub
UPDATES:
The issue is not bad names.
Try to dim the workbook:
Dim wb As Workbook
Dim cSheet As Worksheet, ' ...
Set wb = Workbooks("CNO_CostGroups_v2.xlsx")
Set cSheet = wb.Worksheets("CostCenters")
' snip
I am not sure what could be causing this, but try optimising code by turning off few features and also try to declare variables to see if that works for you or not.
'initialising the optimisation
Sub InitOptimisation()
'optimising code by turning off few features
Application.DisplayAlerts = False
Application.CutCopyMode = False 'to disable the ants crawling
Application.ScreenUpdating = False
Application.Interactive = False
Application.Calculation = xlCalculationManual
Application.EnableEvents = False
End Sub
'turn on the optimisation again
Sub DestroyOptimisation()
Application.DisplayAlerts = True
Application.CutCopyMode = True 'to disable the ants crawling
Application.ScreenUpdating = True
Application.Interactive = True
Application.Calculation = xlCalculationAutomatic
Application.EnableEvents = True
End Sub
Sub calling()
Call InitOptimisation
Dim costGroup_wb As Workbook
Dim costCenter As Worksheet
Set costCenter = Workbooks("CNO_CostGroups_v2.xlsx").Worksheets("CostCenters")
'do your logic
Call DestroyOptimisation
End Sub

How to ask for Checkbox (True/False) in Macro using If-function

How can I hide/show columns and rows in another sheet ("Project Plan") within the same workbook using a checkbox? If the checkbox is checked, they should not be hidden. If the checkbox is not checked, they should be hidden. The checkboxes are in an own sheet ("Guidelines").
I tried the following but get the error "Run time error '424': Object required'"
Sub Team_Availability_Click()
Dim rng As Range
Set rng = ThisWorkbook.Sheets("Project Plan").Rows("5:8")
If Team_Availability.Value = False Then
rng.Hidden = True
ElseIf Team_Availability.Value = True Then
rng.Hidden = False
End If
End Sub
Alternatively, I tried out this way, found in a similar question using some kind of object:
Checking if a worksheet-based checkbox is checked
Sub Team_Availability_Click()
Dim rng As Range
Set rng = ThisWorkbook.Sheets("Project Plan").Rows("5:8")
If ThisWorkbook.Worksheets("Guidelines").Shapes("Team_Availability").OLEFormat.Object.Value = 0 Then
rng.Hidden = True
ElseIf ThisWorkbook.Worksheets("Guidelines").OLEFormat.Object.Value = 1 Then
rng.Hidden = False
End If
End Sub
Here I get the error
The Item with the specified name wasn't found.
I did not introduce the dim/set I guess. Now, this is the newest version:
Now I get the error in in line Set cb = ActiveSheet... saying
The item with the specified name wasn't found.
Sub Team_Availability_Click()
Dim cb As Shape
Dim rng As Range
Set cb = ThisWorkbook.Sheets("Guidelines").Shapes("Team_Availability")
Set rng = ThisWorkbook.Sheets("Project Plan").Rows("5:8")
If ThisWorkbook.Sheets("Guidelines").Shapes("Team_Availability").OLEFormat.Object.Value = -4146 Then
rng.Hidden = True
ElseIf ThisWorkbook.Sheets("Guidelines").Shapes("Team_Availability").OLEFormat.Object.Value = 1 Then
rng.Hidden = False
End If
End Sub
I've looked at your code and didn't really work when I tried it. This code worked for the task you describes hope it helps.
Sub CheckBoxHIDE()
Dim ws As Worksheet
Dim chk As CheckBox
Set ws = ActiveSheet
Set chk = ws.CheckBoxes(Application.Caller)
Select Case chk.Value
Case 1 'box is checked
Columns("D").Hidden = True
Case Else 'box is not checked
'do nothing
End Select
End Sub
I found the error together with a friend. In the top left corner I did not assign the specific name to the Control CheckBox. I had just set the macro/sub name and the description. Now it runs.

VBA - Runtime error with END IF

I am relatively new to VBA. And when I was working on a worksheet I created a code that automatically hides/unhides rows based on a condition in a column row (0 unhide/1 hide). This relatively easy macro worked well until I added a different sheet. As there are no macros in this sheet I dont think it is related. But now everytime it gives a runtime error on the END IF function and I don't know how to solve it. There is probably a simple solution, but I cannot find it.
Here is the code:
Private Sub Worksheet_Calculate()
Application.ScreenUpdating = False
Dim LastRow As Long, c As Range
Application.EnableEvents = False
LastRow = Cells(Cells.Rows.Count, "BA").End(xlUp).Row
On Error Resume Next
For Each c In Range("BA34:BA56,BA73:BA74,BA76:BA107")
If c.Value = 1 Then
c.EntireRow.Hidden = True
ElseIf c.Value = 0 Then
c.EntireRow.Hidden = False
End If
Next
On Error GoTo 0
Application.EnableEvents = True
Application.ScreenUpdating = True
End Sub
Remove or comment out the On Error Resume Next if you want more complete debugging information. It should not be necessary in an event macro that runs as often as Worksheet_Calculate.
Apply a parent worksheet reference to the range object. The worksheet may have volatile formulas that are triggering a calculation event due to changes on the other worksheet.
I've added a wide condition so that the code will only run if the parent worksheet holds the ActiveSheet property. The worksheet may have volatile¹ formulas that are triggering a calculation event due to changes on the other worksheet (or even another workbook).
LastRow does nothing after its assignment (which is problematic) so I removed it.
I simplified the Range.Hidden property to a single line.
Private Sub Worksheet_Calculate()
If Me.Name = Activesheet.Name Then
Application.ScreenUpdating = False
Application.EnableEvents = False
Dim c As Range
For Each c In Me.Range("BA34:BA56,BA73:BA74,BA76:BA107")
c.EntireRow.Hidden = CBool(c.Value2)
Next c
Application.EnableEvents = True
Application.ScreenUpdating = True
End If
End Sub
¹ Volatile functions recalculate whenever anything in the entire workbook changes, not just when something that affects their outcome changes. Examples of volatile functions are INDIRECT, OFFSET, TODAY, NOW, RAND and RANDBETWEEN. Some sub-functions of the CELL and INFO worksheet functions will make them volatile as well.
Just to finish the thread. I solved it based on a combination of the code you wrote and mine, as the 0 should be the trigger to unhide as well. I guess the error line caused the issue.
Private Sub Worksheet_Calculate()
Application.ScreenUpdating = False
Dim LastRow As Long, c As Range
Application.EnableEvents = False
LastRow = Cells(Cells.Rows.Count, "BA").End(xlUp).Row
On Error Resume Next
For Each c In Range("BA34:BA56,BA73:BA74,BA76:BA107")
If c.Value = 1 Then
c.EntireRow.Hidden = True
ElseIf c.Value = 0 Then
c.EntireRow.Hidden = False
End If
Next
Application.EnableEvents = True
Application.ScreenUpdating = True
End Sub

Inputbox stopped accepting mouse selection in for each loop in excel vba because screenupdating changed in another sub--why?.

Why would an input box stop accepting a selection by mouse after a call to a sub with screenupdating variable changes?
I have a large workbook in excel that calculates a budget from different components on different sheets. I'm using named ranges in all of my formulas, and as I build the workbook I often need to move things around on the sheet, and thus edit the references to my named ranges so I made a macro to run through my named ranges and let me click to update their references.
I've included three subs from my workbook code; sheet 1 just has some values in the named range cells, a formula ( = CNGFixedCost1 + CNGFixedCost2 + CNGFixedCost3), and an activex check box. When I run RangeNameManager() the inputbox stops accepting mouse selections, due to the screenupdating variable in the Worksheet_Calculate() sub, . I figured out how to resolve the problem while writing this up (remove the screenupdating changes), but I'm still curious as to why this happens.
Option Explicit
'Name Ranges in workbook
Public Sub Workbook_Open()
Worksheets("Sheet1").Range("D3").Name = "CNGFixedCost1"
Worksheets("Sheet1").Range("D4").Name = "CNGFixedCost2"
Worksheets("Sheet1").Range("D5").Name = "CNGFixedCost3"
End Sub
'Update named ranges
Sub RangeNameManager()
Dim nm As Name
Dim nms As String
Dim xTitleID As String
Dim InputRng As Range
Dim asnms As String
On Error Resume Next
asnms = CStr(ActiveSheet.Name)
For Each nm In ActiveWorkbook.Names
nms = CStr(nm.Name)
If nm.RefersTo Like "*" & asnms & "*" Then
Set InputRng = ActiveSheet.Range("A1")
Set InputRng = Application.InputBox("The current range for" & nms & " is " & CStr(nm.RefersTo) & ". Select the new range.", InputRng.Address, Type:=8)
nm.RefersTo = InputRng
End If
Next
On Error GoTo 0
End Sub
' Update check box automatically
Private Sub Worksheet_Calculate()
Application.ScreenUpdating = False '***Removed to resolve problem.***
Dim errwksht As String
errwksht = ActiveSheet.Name
On Error GoTo ErrorHandler
If Worksheets("Sheet1").Range("CNGFixedCost1").Value > 0 Then
Worksheets("Sheet1").CheckBox1.Value = False
Else
Worksheets("Sheet1").CheckBox1.Value = True
End If
ErrorHandler:
Exit Sub
Application.ScreenUpdating = True '***Removed to resolve problem.***
End Sub
ScreenUpdating is a property of the Application object. If you turn it to false, then the application cuts off connection with the user (it won't take input, and it won't update the display).
It's very useful if you want to make something run faster, however it shouldn't be used during times when you need user interaction.
You're exiting the sub before turning screen updating back on, leaving the application in an unstable state.
' Update check box automatically
Private Sub Worksheet_Calculate()
Application.ScreenUpdating = False '***Removed to resolve problem.***
'...
ErrorHandler:
Exit Sub 'exits here
Application.ScreenUpdating = True ' so this NEVER executes
End Sub
This is easily fixed by resuming at your error handler, which would be better named CleanExit:. Here's how I would write it.
Private Sub Worksheet_Calculate()
On Error GoTo ErrorHandler
Application.ScreenUpdating = False '***Removed to resolve problem.***
'...
CleanExit:
Application.ScreenUpdating = True
Exit Sub
ErrorHandler:
' Actually do some error handling
Resume CleanExit
End Sub

Resources