VBA crash when changing worksheet from dropdown - vba

I have a dropdown with an associated macro, which looks like:
Sub Drop()
If Range("Hidden1!A1") = "1" Then
Sheets("Sheet1").Select
End If
If Range("Hidden1!A1") = "2" Then
Sheets("Sheet2").Select
End If
If Range("Hidden1!A1") = "3" Then
Sheets("Sheet3").Select
End If
End Sub
This makes my Excel 2010 completely crash and want to send a report to Microsoft. Any ides of how to rewrite this so it does not crash, or is it an Excel bug?

sandos,
I was able to reproduce the problem as you described. Adding a DoEvents command at the beginning of the sub fixed it. It's also always a good idea to qualify your sheet names and ranges with the workbook they belong to, like ThisWorkbook.Sheets(1).Range("A1"). Also, you don't really need all those If Endif statements (if you did you'd want one long If, ElseIf, Elseif, End). Anyways you can ignore these comments and just put DoEvents at the beginning and it should work:
Sub Drop()
DoEvents
With ThisWorkbook
.Worksheets("Sheet" & .Worksheets("Hidden1").Range("A1")).Select
End With
End Sub

Related

Do While ActiveCell <> Range

I have this VBA excel macro code
Sub fillcells()
Range("J14").Select
Do While ActiveCell <> Range("J902")
ActiveCell.Copy
ActiveCell.Offset(6, 0).Select
ActiveCell.PasteSpecial
Loop
End Sub
At first it was working fine but now sometimes when I try to run the macro the loop suddenly stops at cell J242, other times is arising an error 'mismatch type' and sometimes the macro just select cell J14 without doing the loop
Not sure what you want to do, but (as noted in the comments to your OP), don't use .Select/.Activate. The following should do what (I think) you wanted:
Sub fillcells()
Dim i& ' Create a LONG variable to count cells
For i = 14 To 901 Step 6
Cells(i, 10).Offset(6, 0).FormulaR1C1 = Cells(i, 10).FormulaR1C1
Loop
End Sub
This will loop from cell J14 to J901, copy/paste* to a cell 6 rows offset.
* Note I didn't actually copy/paste. Since your original code used PasteSpecial, I'm assuming you just want the values pasted. In this case, you can set the two ranges/cells equal.
Just an addition to what #BruceWayne already said: whenever you have this typical phenomenon that something happens only "sometimes" it is often a case of using keywords such as Active or Current or Selection. These are not specific but change each time that you call the macro. Whatever you have selected is the starting point. You might even start clicking around and thus change Selection while the macro is running. In short, you should start coding explicitly and don't allow VBA / Excel to assume / make the decision for you.
Let's start with Range("J14").Select. This line of code asks VBA to make already two assumptions:
If you have several Excel files open. Which Excel file should it start with?
Within the file there might be several sheets. On which of these sheets should J14 be selected?
Explicit coding means that you (hopefully at all times) be very specific what you are referring to. So, instead of just stating Range("J14") you should use:
ThisWorkbook.Worksheets("SheetNameYouWantToReferTo").Range("J14")
But is pointed out in the other answer, this is not even necessary in this case. Rather loop the rows as shown and use:
ThisWorkbook.Worksheets("SheetNameYouWantToReferTo").Cells(i, 10).Offset(6, 0).Formula = ThisWorkbook.Worksheets("SheetNameYouWantToReferTo").Cells(i, 10).Offset(i, 10).Formula
Since this is a bit lengthy you can shorting it by using a With statement:
With ThisWorkbook.Worksheets("SheetNameYouWantToReferTo")
.Cells(i, 10).Offset(6, 0).Formula = .Cells(i, 10).Formula
End With

VB, excel macro pause and resume working if possible

I cannot figure out the best way to do the following problem. Basically my macro (excel, VB) is checking several (100+) worksheets for correct values, if wrong value is found, I want it to stop, give me a warning, then I could have a look into the reason why the value is wrong, correct it manually and then I want to resume the macro, or remember the last value checked so if I return, it remembers where to continue (resume).
My current problem is that it finds the wrong value, then I can either make it stop so I check the problem, or it goes through all the sheets and then I have to remember which sheets had the wrong value.
What I thought of is make a list where the name of sheet is added every time a wrong value is found. The problem is that usually there is more than 1 wrong value in the same sheet if there is a wrong value at all and this added the same sheet name several times to the list. Another problem with that is that I cannot correct the values straight away.
I'm very inexperienced with programming and so would appreciate your idea on how to best approach this problem (I don't want to spend a long time on coding something which wouldn't be efficient for such a "simple" problem).
When the error is found (I'm assuming you've already been able to identify this), you can use the Application.InputBox function to prompt you for a new value.
For example, if rng is a Range variable that represents the cell being checked, and you have some logic to determine where the error happens, then you can just do:
rng.Value = Application.InputBox("Please update the value in " & rng.Address, "Error!", rng.Value)
The inputbox function effectively halts execution of the procedure, while waiting for input from the user.
If InputBox isn't robust enough, then you can create a custom UserForm to do the same sort of thing. But for modifying single range values, one at a time, the InputBox is probably the easiest to implement.
I believe you can handle this task by using one or two static local variables in your macro. A variable declared with "static" rather than "dim" will remember its value from the last time that procedure was run. This can hold where you left off so you can resume from there.
One thing that could be a problem with this solution would be if the macro gets recompiled. That would probably cause VBA to clear the value that the static variable was holding. Just doing a data edit in Excel should not cause a recompile, but you will want to watch for this case, just to make sure it doesn't come up. It almost certainly will if you edit any code between executions.
Create a public variable that stores the cell address of the last checked cell and use a conditional statement to see if it's "mid-macro" for want of a better phrase. here is a very crude example...
Public lastCellChecked As String
Sub Check_Someting()
Dim cell As Excel.Range
Dim WS As Excel.Worksheet
If Not lastCellChecked = vbNullString Then Set cell = Evaluate(lastCellChecked)
'// Rest of code...
'// Some loop here I'm assuming...
lastCellChecked = "'" & WS.Name & "'!" & cell.Address
If cell.Value > 10 Then Exit Sub '// Lets assume this is classed as an error
'// Rest of loop here...
lastCellChecked = vbNullString
End Sub
The best way to do this is to create a userform and as mentioned by prior users create a public variable. When the program finds an error store the cell and initiate the userform. Your code will stop on the userform. When you're done checking the problem have a button on the userform that you can click to continue checking. Your loop can be something like the below.
public y as integer
sub temp1 ()
rw1= range("a500000").end(xlup).row 'any method to create a range will do
if y = null then y=1
for x = y to rw1
cells(x,1).select
'check for the problem your looking for
if errorX=true then
userform1.show
y = activecell.row
exit sub
end if
next x
end sub
What about inserting a button (on the sheet or in a menubar) for stopping?
Insert the code below:
'This at the top of the module
Public mStop As Boolean
'This in the module
Sub MyBreak()
mStop = True
End Sub
'This is your macro
Sub YourMacro()
'This at the top of your code
mStop = False
'Your code
'...
'This code where you want to break
DoEvents '<<<< This makes possible the stop
If mStop Then
mCont = MsgBox("Do you want to continue?", vbYesNo)
If mCont = vbNo Then
Exit Sub
Else
mStop = False
End If
End If
'Your code
'...
End Sub
Now you need to create a button and link it to the macro called "MyBreak".

Excel 2010 VBA: .Names.Add does not work after .Hyperlinks.Add

I have run into a problem in Excel 2010 VBA on Windows 7 64-bit version which I have not been able to solve. The issue can easily be recreated by pasting the code below in a module in a new workbook and run it.
What I want to do is to loop through a number of sheets and add a defined name and a hyperlink on each sheet.
Sub Test()
Dim i As Integer
Dim ws As Worksheet
Dim defName As String
For i = 1 To 2
Set ws = Sheets(i)
defName = "Name_" & ws.Name
ws.Names.Add Name:=defName, RefersToR1C1:="=OFFSET(Sheet3!R1C1,0,0,1)"
ws.Hyperlinks.Add Anchor:=ws.Range("A1"), _
Address:="", SubAddress:="=Sheet3!A1"
Next i
End Sub
Running the code gives the following error on the second iteration, on the ws.Names.Add call: Run-time error '1004: The formula you typed contains an error.
Doing any of the following makes the error disappear:
Change the for iteration to "i = 1 To 1" or "i = 2 To 2"
Put a debug breakpoint inside the for loop and pressing F5 when it has stopped
Change the cell reference to
ws.Names.Add Name:=defName, RefersToR1C1:="=Sheet3!R1C1", i.e. removing the OFFSET command
Adding DoEvents to the first line of the for loop or setting Application.EnableEvents = False does not solve the problem.
Does anyone know the cause of this error or how to get around it? I am thankful for any help.
Edit: The issue occurs no matter what the hyperlink links to. Changing the hyperlink to the following does not solve the issue
ws.Hyperlinks.Add Anchor:=ws.Range("A1"), Address:="http://www.google.com"
Edit2: Managed to recreate the issue with an even simpler code:
Sub Test()
With Sheets(1)
.Hyperlinks.Add Anchor:=.Range("A1"), Address:="http://www.google.com"
.Names.Add Name:="myDefName", RefersToR1C1:="=OFFSET(Sheet1!R1C1,0,0,1)"
End With
End Sub
I solved this by separating the for loops into two loops, one for the .names.add calls and one for the hyperlinks.add calls. This way all the names get defined before the first hyperlink is created.
Sorry if it is not correct of me to post this as an answer.

Excel VBA: Formula is too complex for object

This may seem like a simple problem, but it's been very frustrating. I've written a couple (relatively simple) macros in VBA for a spreadsheet that I want to make very user-friendly.
In other words, I want all macros to be run by buttons. However, whenever I try to assign buttons to macros I am getting the error:
Formula is too complex to be assigned to object
This happens even when I try to assign it to an empty subroutine. It worked, but only for the first macro I wrote. Once I added other subroutines to the module, I could no longer assign new buttons to macros.
This is the code I've written:
Sub Button1_Click()
selName = Range("C2").Value
div = Range("E2").Value
cost = Range("F2").Value
diff = div - cost
If diff < 0 Then
diff = 0
End If
Range("G2").Select
ActiveCell.FormulaR1C1 = diff
x = Range("A2").Value + 1
Worksheets("VIP_TEMPLATE.PIVOT").Select
Range("J" & x).Select
ActiveCell.FormulaR1C1 = diff
Worksheets("CALCULATE").Select
Range("F2").Select
ActiveCell.ClearContents
End Sub
I have another subroutine in the module, which I think may be contributing to the problem? I think this because when I simply copy-pasted my data into a new worksheet, I could assign a button to the routine. I don't think it has anything to do with my file path because I don't use any (I think) offending characters.
I have found the problem. It turns out that I did actually have brackets in my file path (buried way in there).

Spell check an Excel sheet in VBA

I have scoured the Internet and I have found a handful of possible solutions to this issue, but I wanted to ask here as well.
The goal is to click a button, and spell check an entire sheet.
Here's some code
Sub spellCheck()
Sheet1.Cells.CheckSpelling
End Sub
Also, I found this:
Sub SpellCheck()
Dim Checkword As String, Result As Boolean
Checkword = Selection.Value
Result = Application.CheckSpelling(Checkword)
Selection.Offset(0, 1) = Result
End Sub
Any ideas? Neither is working for me. Thanks!
You can check the whole workbook by doing something like:
Sub SpellCheck()
For Each sh In Worksheets
Sheets(sh.Name).Cells.CheckSpelling
Next
End Sub
this will cycle through each sheet in the entire book and run a spellcheck on each one. What I can't figure out yet is how to make the spell checker actually move to the position of the spelling error. So, with the above you just get a list of spelling errors with no context with which to asses them.
I noticed I just had a typo in my code.
Below works:
Sub spellCheck()
Sheet1.Cells.CheckSpelling
End Sub
But, if anyone knows how to do the entire workbook, I'd be interested in that. Thanks.
This code will work on selected cells .This will highlight if any spell mistakes in a cell
Dim Myrange As Range
Selection.SpecialCells(xlVisible).Select
For Each Myrange In Selection
If Application.CheckSpelling(word:=Myrange.Value) = False Then
Myrange.Font.Color = vbRed
End If
Next
OK, so you can use the following command to invoke the toolbar's spellchecker which does move you to the position of the spelling error as long as you have screen updating enabled at the time.
Application.CommandBars("Tools").Controls("Spelling...").Execute
You can use this command embedded in the loop above to loop through the sheets in the workbook and invoke this command on each new sheet.
Cap
This uses a code snippet from a previous answer to restrict the area used for spellchecking to a specific region. Something I needed to do in a small project. This give the full functionallity of the spellchecker with errors shown in context. The rowNumber is calculated elsewhere.The selection range can be fully controlled elsewhere in your code to suit your particular need. Thought this might help others searching this posting.
With Sheets("Sheet1")
slic = CStr(rowNumber)
.Range("AL3:AN" & slic).Select
Application.CommandBars("Tools").Controls("Spelling...").Execute
End With
Thanks to previous posters this solved a problem form me. I am most grateful.