I’m very new to Excel VBA but managed to create three buttons in a staff timesheet. All buttons work as needed, however, one particular button is causing random issues – about 90% of the time it works, but from time to time it will crash Excel or give an error such as runtime error '-2147417848 (800 10 108)': Automation error The object invoked has disconnected from its clients. Other times it’s a similar message, saying Method ‘Insert’ of object ‘Range’ failed.
It’s happening in different versions of Excel on different computers. The task is not complex but I’m stumbling with my VBA knowledge.
The user clicks the button to set up each formatted row in the sheet called “Timesheet”, i.e. clicking the button in “Timesheet” copies a row from sheet4 (formatted and containing formulae) and inserts it into the “Timesheet” above the button.
I’d be very grateful if someone could suggest alternative code that won’t crash Excel - many thanks in advance!
Sub NewSlot()
' NewSlot Macro used in Timesheet
'
'turn protection off
Worksheets("Sheet4").Unprotect Password:="mypasswd"
Worksheets("Timesheet").Unprotect Password:=" mypasswd "
' select row 8 in sheet4
Sheets("Sheet4").Select
Rows("8").Select
Selection.Copy
' go back to timesheet
Sheets("Timesheet").Select
' insert copied row
Dim r As Range
Set r = ActiveSheet.Buttons(Application.Caller).TopLeftCell
Range(Cells(r.Row, r.Column), Cells(r.Row, r.Column)).Offset(0, 0).Select
Selection.Insert shift:=xlDown
Application.CutCopyMode = False
'turn protection on
Worksheets("Sheet4").Protect Password:=" mypasswd "
Worksheets("Timesheet").Protect Password:=" mypasswd"
End Sub
If you are going to use VBA to repeatedly modify a protected worksheet, unprotect it then protect it once with UserInterfaceOnly:=True.
sub protectOnce()
worksheets("Timesheet").unprotect password:="mypasswd"
worksheets("sheet4").unprotect password:="mypasswd"
worksheets("Timesheet").protect password:="mypasswd", UserInterfaceOnly:=True
worksheets("sheet4").protect password:="mypasswd", UserInterfaceOnly:=True
end sub
After that has been done once you will not have to unprotect to modify with VBA. If you have to unprotect it for another reason, reprotect it with with UserInterfaceOnly:=True.
This cuts your NewSlot code down significantly. It is considered 'best practise' to avoid using Select and Activate, particularly across worksheets.
Sub NewSlot()
' select row 8 in sheet4
workSheets("Sheet4").Rows("8").Copy
' go back to timesheet
with workSheets("Timesheet")
' insert copied row
Dim r As Range
Set r = .Buttons(Application.Caller).TopLeftCell
.Cells(r.Row, "A").entirerow.Insert shift:=xlDown
end with
End Sub
Related
I have real-time data streaming from another application into Excel and making =RTD() calls successfully in a complex workbook.
Trying to (a) compare historical data as of a moment in time to current/live data, and, (b) run stats on snapshots taken. Say I have RTD data in 4 rows and 8 columns A1:H4.
The "freeze": Is it possible to push a button (to run a macro) and render, say, row 2 (A2:H2) 'inert', so it's no longer RTD? Basically, copy then-current values and paste them into the same cells (A2:H2) as values, removing the RTD formulas so that the data stops changing at that moment.
The "snapshot": Make a copy of the 3rd row, A3:H3, and paste it into A5:H5 periodically by timer, and have the copy become 'inert', i.e., no longer RTD or linked to RTD in row 5 while row 3 remains RTD. And place a timestamp for this action in cell I5 next to the copy.
This should also theoretically enable me to chart the snapshot data. I can't get RTD data to chart - expected that chart would update as streaming data changed, but charts won't display at all. So that's a secondary but related issue. It would appear that if I can snapshot the data and make it inert, I should be able to chart.
I've tried all kinds of manual processes from paste special/values, go to / special / formulas, highlight, etc. to using a third party tool. I've looked for VBA macros and found one which I'm pasting below, but I can't get it to work (the macro runs on cells to which it's directed, does not error out, but nothing happens). And even if it did work, it would only solve part of the problem as per above.
I do not speak VBA but write enough code in other languages that I should be able to figure out what it does and mod it, if someone is able to offer the base functionality. Any help would be greatly appreciated.
'This code should go in a regular module sheet, and won't work properly if installed anywhere else. _
The next (Dim) statement must occur before any subs or functions.
Dim NextTime As Double
Sub RecordData()
Dim Interval As Double
Dim cel As Range, Capture As Range
Interval = 5 'Number of seconds between each recording of data
Set Capture = Worksheets("Sheet1").Range("A1:A5") 'Capture this column of data
With Worksheets("Sheet2") 'Record the data on this worksheet
Set cel = .Range("A2") 'First timestamp goes here
Set cel = .Cells(.Rows.Count, cel.Column).End(xlUp).Offset(1, 0)
cel.Value = Now
cel.Offset(0, 1).Resize(1, Capture.Cells.Count).Value = Application.Transpose(Capture.Value)
End With
NextTime = Now + Interval / 86400
Application.OnTime NextTime, "RecordData"
End Sub
Sub StopRecordingData()
On Error Resume Next
Application.OnTime NextTime, "RecordData", , False
On Error GoTo 0
The above code is initiated when the workbook is opened, and stopped when the workbook is closed by code in ThisWorkbook code pane.
'These subs must go in ThisWorkbook code pane. They won't work at all if installed anywhere else!
Private Sub Workbook_BeforeClose(Cancel As Boolean)
StopRecordingData
End Sub
Private Sub Workbook_Open()
RecordData
End Sub
End Sub
I have looked up the question and have seen several solutions addressing things like Select or having protected worksheets, none of which apply to me here.
For various reasons, I can't post the entire code, but I will give a description of what it does and post the exact sub that is giving me issues.
I have a Macro that generates a number of worksheets based on the Month and Year input by the user (so "1" - "31" or "1" - "30" etc). To generate these worksheets, the macro makes copies of a worksheet fittingly named "EXAMPLE". One thing that is copied is a picture (just a rectangle with the word 'Export' on it) that has a macro attached to it.
I recently made what I thought was a cosmetic change by moving the location of this picture, since then, when I run the macro I get an error:
"Run-time error '1004':
Microsoft Excel cannot paste the data."
And options for 'End' 'Debug' and 'Help'
If I select 'Debug' it points me to a second macro which is called during the process of the generation macro'
Sub CopyAllShapes()
Dim ws As Worksheet
' Sets the non-generated worksheets as an array
nSheets = Array("EXAMPLE", "Weekly Totals", "Menu")
' Copies the Picture from the EXAMPLE sheet to all worksheets not in the array and then assigns a
' seperate Macro called "Export" to the picture on each of these sheets.
For Each ws In ActiveWorkbook.Worksheets
If Not IsNumeric(Application.Match(ws.Name, nSheets,0)) Then
Sheets("EXAMPLE").Shapes("Picture 1").Copy
ws.Range("J62").PasteSpecial
ws.Shapes("Picture 1").OnAction = "Export"
End If
Next ws
Application.CutCopyMode = xlCopy
End Sub
The Debug option highlights the line
ws.Range("J62").PasteSpecial
What really confuses me is that if I select 'End' instead of 'Debug', the macro stops, but all the the sheets have had the picture pasted as well as the Export Macro assigned and everything works as expected. If I were the only person using this, it would be a minor annoyance, but this document is used by many people that can't reliable be told to "just ignore" the error. Since the macro is functioning as expected, how can i troubleshoot what is causing the problem and make the error go away?
As I said, I can't post the entire macro, but I can post some bits and pieces if anyone needs more info.
Not a pure fix, but this code will retry the Copy/Paste if it fails (up to 3 times), instead of just dropping it:
Const MaxRetries AS Long = 3
Sub CopyAllShapes()
Dim ws As Worksheet
Dim TimesRetried As Long
' Sets the non-generated worksheets as an array
nSheets = Array("EXAMPLE", "Weekly Totals", "Menu")
' Copies the Picture from the EXAMPLE sheet to all worksheets not in the array and then assigns a
' seperate Macro called "Export" to the picture on each of these sheets.
For Each ws In ActiveWorkbook.Worksheets
If Not IsNumeric(Application.Match(ws.Name, nSheets,0)) Then
TimesRetried = 0
CopyExampleShape:
On Error Resume Next
Sheets("EXAMPLE").Shapes("Picture 1").Copy
ws.Range("J62").PasteSpecial
'If the Copy/Paste fails, retry
If Err Then
On Error GoTo -1 'Clear the Error
'Don't get stuck in an infinite loop
If TimesRetried < MaxRetries Then
'Retry the Copy/paste
TimesRetried = TimesRetried + 1
DoEvents
GoTo CopyExampleShape
End If
End If
On Error GoTo 0
ws.Shapes("Picture 1").OnAction = "Export"
End If
Next ws
Application.CutCopyMode = xlCopy
End Sub
I have come across a similar issue before, and it was been down to another program (in one case Skype) reacting to data being added to the Clipboard by "inspecting" it. That then briefly locked the clipboard, so the Paste/PasteSpecial operation failed. This then caused the Clipboard to be wiped clean... All without Excel doing anything wrong.
"It is possible to commit no mistakes and still lose. That is not a weakness; that is life." ~ Jean-Luc Picard
On moving to Office 365 and Win10 (can't say which of those was the culprit) I found a bunch of existing macros which would give that same error when trying to paste a copied image onto a worksheet.
When entering debug, the "paste" line would be highlighted, but if I hit "Continue" it would (after one or two attempts) run with no errors.
I ended up doing this:
'paste problem fix
Sub PastePicRetry(rng As Range)
Dim i As Long
Do While i < 20
On Error Resume Next
rng.PasteSpecial
If Err.Number <> 0 Then
Debug.Print "Paste failed", i
DoEvents
i = i + 1
Else
Exit Do
End If
On Error GoTo 0
i = i + 1
Loop
End Sub
...which looks like overkill but was the only reliable fix for the problem.
EDIT: cleaned up and refactored into a standalone sub.
Just wanted to let everyone know I have found a (sort of) solution. Based on the answers/comments from Tim Williams and PeterT I modified the code to look like this:
Sub CopyAllShapes()
Dim ws As Worksheet
' Sets the non-generated worksheets as an array
nSheets = Array("EXAMPLE", "Weekly Totals", "Menu")
' Copies the Picture from the EXAMPLE sheet to all worksheets not in the array and then assigns a
' seperate Macro called "Export" to the picture on each of these sheets.
For Each ws In ActiveWorkbook.Worksheets
If Not IsNumeric(Application.Match(ws.Name, nSheets,0)) Then
Sheets("EXAMPLE").Shapes("Picture 1").Copy
On Error Resume Next
ws.Range("J62").PasteSpecial
On Error Goto 0
ws.Shapes("Picture 1").OnAction = "Export"
End If
Next ws
Application.CutCopyMode = xlCopy
End Sub
This has successfully ignored the error and everything is working properly now! Thanks everyone for your help, hopefully this aids someone else in the future!
I have a large VBA/Excel project .xlsm file that has all of a sudden begun to stop responding (am forced to force quit Excel) when I click the Remove Row button that calls my RemoveComparison sub. The strange thing is that the sub occasionally works (and has worked in the past). It is as if Excel sometimes maxes out on memory when this RemoveComparison gets called and other times it does not. The problem goes away if I comment out Application.Calculation = xlAutomatic in the last line. When RemoveComparison does work, however, it takes about 2 full seconds to complete since I believe the hiding of rows or maybe the deleting of the OLEObjects triggers a large recalculation on other sheets when I set calculation mode back to xlAutomatic.
Does anyone spot what could be causing Excel to stop responding?
Here is a screenshot of the Workbook. The Remove Row button calls the sub RemoveComparison() that deletes ComboBoxManagerComparison7 in this case (the one with S&P 500) and also deletes Comparison7CheckBox before hiding the cells (which contain formulas referencing other sheets). If the Remove Row works like it did before, clicking the button a second time would remove Comparison6, etc.
Sub RemoveComparison()
Application.Calculation = xlManual
Dim CurrentNumberOfComparisons As Integer
With Sheets("Manager")
'get current number of comparisons (to determine which ComboBox, etc. to remove)
CurrentNumberOfComparisons = .Range("NumberOfComparisons").Value
If CurrentNumberOfComparisons = 1 Then
MsgBox ("Min 1 comparison")
Exit Sub
End If
Dim ComboBoxName As String
'determine name of ComboBox to remove
ComboBoxName = "ComboBoxManagerComparison" & CurrentNumberOfComparisons
Call DeleteComboBox(ComboBoxName, Sheets("Manager"))
#If DEBUGREMOVECOMPARISON Then
Debug.Print "Deleted ComboBox"
#End If
Dim CheckBoxName As String
'determine name of CheckBox to remove
CheckBoxName = "Comparison" & CurrentNumberOfComparisons & "CheckBox"
Call DeleteCheckBox(CheckBoxName, Sheets("Manager"))
#If DEBUGREMOVECOMPARISON Then
Debug.Print "Deleted CheckBox"
#End If
Dim ComparisonCellToHideNamedRange As String
'determine which cells to hide
ComparisonCellToHideNamedRange = "selectedManagerComparison" & CurrentNumberOfComparisons & "Name"
Dim ComparisonCellToHide As Range
Set ComparisonCellToHide = .Range(ComparisonCellToHideNamedRange)
Range(Rows(ComparisonCellToHide.row), Rows(ComparisonCellToHide.row + 3)).Hidden = True
'update current number of comparisons
.Range("NumberOfComparisons").Value = CurrentNumberOfComparisons - 1
#If DEBUGREMOVECOMPARISON Then
Debug.Print "Success"
#End If
End With
Application.Calculation = xlAutomatic
End Sub
Sub DeleteComboBox(ComboBoxName As String, Sheet As Worksheet)
With Sheet
.OLEObjects(ComboBoxName).Delete
End With
End Sub
Sub DeleteCheckBox(CheckBoxName As String, Sheet As Worksheet)
With Sheet
.OLEObjects(CheckBoxName).Delete
End With
End Sub
EDIT: Still unclear why the switch from xlManual back to xlAutomatic in the sub leads to Not Responding, but if I comment out the last line of the sub Application.Calculation = xlAutomatic and manually click Formulas->Calculation Options->Automatic, the entire worksheet is recalculated even if no cells are edited. I understand that hiding cells causes a recalculation, but should hiding a row cause the recalculation of the whole worksheet (even when the hidden row has no dependents)?
EDIT: Excel stops crashing if I move the ComboBoxes and CheckBoxes to another part of the sheet rather than deleting them in the sub. I am not sure why the deletion of these OLEObjects caused Excel enter not responding.
I'm a VERY new learner to VBA trying to decypher functions and build an interactive file. With help from one user here (who will certainly know who he is ;)), I could learn quite a few things.
Now I'm stuck at one ridiculous piece of code : I want to 1/unhide a sheet, 2/go to that sheet and 3/re-hide the sheet when the user selects the "back to the start page-button".
So I made this code :
Sub FRtoEN()
'
' FRtoEN Macro
' Emmène au Glossaire FR ==> EN
'
Sheets("synthèse_FR&EN").Visible = True
Sheets("Synthèse_FR&EN").Select
End Sub
and it works well. But I cannot find out how to tell excel in VBA-language that I want it to re-hide the tab once the user is done and clicks the exit button.
Could you help me?
Ferndiando's answer is brilliant when you want to have one button where you first show the hidden sheet and next time you click on the same button it hide the same sheet.
Making one button to show a sheet and another button to hide the same sheet, do the following;
In the first button you will make the code visible:
Sub FRtoEN()
'
' FRtoEN Macro
' Emmène au Glossaire FR ==> EN
'
Sheets("synthèse_FR&EN").Visible = True
Sheets("Synthèse_FR&EN").Activate
End Sub
In the second button that which will take the user back to the "Main Page" you can add this code:
Sub StartPage()
Sheets("Start Page").Activate 'First go to Start page
Sheets("synthèse_FR&EN").Visible = False 'Then hide the sheet they currently visited, that makes the experience a little bit more "working in background"
End Sub
If I assume you use this "back to the start page-button" for several sheets, you could hide other sheets too every time someone goes to start page.
Sub StartPage()
Sheets("Start Page").Activate 'First go to Start page
Sheets("synthèse_FR&EN").Visible = False
Sheets("synthèse_FR&DE").Visible = False 'Example 1 - No matter which sheet you visit, it will hide this sheets.
Sheets("synthèse_FR&SP").Visible = False 'Example 2 - No matter which sheet you visit, it will hide this sheets.
End Sub
If you want the code to perform things on hidden sheets, while they still are hidden for the user (for example background filtering/calculations/copy data etc..) this will give the user a smooth experience:
Sub StartPage()
Application.ScreenUpdating = False 'Turn of all visual updates the macro does. Macro works in background without showing every step visually in Excel.
Sheets("synthèse_FR&EN").Visible = True 'Unhide the sheet you want to work at.
'Do some filtering stuff // copy stuff
Sheets("synthèse_FR&EN").Visible = False 'Re-hide the sheet again.
Application.ScreenUpdating = False 'Turn ON all visual updates the macro does. Macro now works and shows every step visually in Excel.
End Sub
:)
If i understood your question you can use this code:
Sub myButton()
'Hide and Show Sheet2 with same button
' you can change the sheet name as you prefer
If (Sheets("Sheet2").Visible) Then ' control if the sheet is visible
Sheets("Sheet2").Visible = False ' hide sheet2 because before was showed
Sheets("Sheet1").Select ' select sheet1
Else
Sheets("Sheet2").Visible = True ' show sheet2 because before was hidden
Sheets("Sheet2").Select 'select sheet2
End If
End Sub
I hope this help you.
I've created a table for data entering. However, as user use it, they insert rows in the middle of the table. That messes the formula up as the functions were designed only work forward. Also sometimes when the user add row manually (just by typing into the next row after the last row of the table), the function were filled automatically but the function is incorrect quite often.
So I added a button to add the rows to the table and that works without problems. Now I want to disable the ability for user to add rows manually, meaning rows can ONLY be added via clicking the button.
As far as I research, people all suggesting using protect sheet functionality. But it would remove all ability to add rows including via VBA. Other offer the VBA that only prevent inserting rows via right click at the Rows Column. I need to disable all user-accessible ways.
This is the code for the button (if it's of any relevant).
Sub InsertRow_Click()
Dim i As Integer
For i = 1 To 10
ActiveSheet.ListObjects("Invoice").ListRows.Add alwaysinsert:=True
Next i
End Sub
When using sheet protection, you could add Userinterfaceonly= true, this will prevent user interference, but VBA code will still work.
Private Sub Workbook_Open()
Dim ws As Worksheet
For Each ws In ThisWorkbook.Worksheets
ws.Protect Password:="secret", UserInterFaceOnly:=True
Next ws
End Sub
or if you want to protect just one sheet:
Private Sub Workbook_Open()
Worksheets("YourSheetName").Protect Password:="secret", UserInterFaceOnly:=True End Sub
Or just take protection off before running your macro and put it on afterwards:
Sub InsertRow_Click()
ActiveSheet.Unprotect Password:="secret"
Dim i As Integer
For i = 1 To 10
ActiveSheet.ListObjects("Invoice").ListRows.Add alwaysinsert:=True
Next i
ActiveSheet.protect Password:="secret"
End Sub
Userinterfaceonly and tables looks if it's no good match