Please read this fully and understand that this program was working fine until I changed the way I was hiding the workbook.
I have a program that worked great while I was using Application.Visible = False and only showing the user form. I came to realize that this would hide all Excel windows and not just the one I was using. This is going to be distributed throughout the department and hiding all Excel windows was unacceptable.
I started using ActiveWindow.Visible = False, but I am now getting Error 91 anytime I search a worksheet for a value (Cells.Find).
Modifying the worksheet is not an option and the value for which I'm searching can move around the sheet depending on what has been added or removed.
Cells.Find worked out great for this reason. I need to either find another way to search the page, or find another way to hide the worksheet. Please help
When the window is not visible, the Cells reference is not qualified to a worksheet object (unless qualified, Cells refers to ActiveSheet.Cells and there is no ActiveSheet), so you can do like:
Sheets("sheetname").Cells.Find ' modifying "sheetname" as needed
This may also fail (with the same error), or it could also yield incorrect results if there are other open workbooks, so it's best to qualify to a workbook fully, e.g.:
Workbooks("workbookname").Sheets("sheetname").Cells.Find(...
It is still a good idea to test the result of Find before performing additional method/property calls against an object which could be Nothing, as per this answer:
Find command giving error: "Run-time Error '91': Object variable or With block variable not set"
Related
So I'm a bit new to excel VBA, and I'm creating a macro to run on financial worksheets. I want to shift the values in the totals to the right place, as they are a column to the left of the actual data (these weren't created by a formula, they were generated by a different program and are fixed text). The shifting I managed to do just fine. The problem here is finding where the totals column is, as it varies between worksheets.
This is what I have so far.
For totalRow = 7 To 2000
With ws
If ws.Visible = True Then
If InStr(Range(totalRow, "A").Value, "Totals:") > 0 Then
Exit For
End If
End If
End With
Next totalRow
Yet for some reason, it's giving me an error when I try to run it. I know it's probably something simple I'm overlooking, because I cannot for the life of me figure out the problem. I've tried using a Do-Until loop, same issue. Is it a problem with the variables I'm using?
Several suggestions:
This is the basic problem:
Error 1004 "Application-defined or Object-defined error"
Look here for several potential issues/potential fixes:
VBA Runtime Error 1004 "Application-defined or Object-defined error" when Selecting Range
Use the VBA debugger and step through your macro a line at a time, until you find the specific object it's barfing on:
https://www.techonthenet.com/excel/macros/vba_debug2013.php
EDIT:
Having said that, I think Tim Williams's suggestion is probably spot-on:
You should always scope your Range/Cells calls with a worksheet
object, otherwise they will reference whatever happens to be the
Activesheet.
But PLEASE:
If at all possible, make the effort to learn troubleshooting tools available to you (like the debugger).
One other "useful tips" link I'd urge you to look at:
http://www.jlathamsite.com/Teach/VBA/WritingBulletProofCode.pdf
I have some User Defined Functions in an Excel book. I used them for a while but, after a while, I deleted the calls to these functions from the cells because I found a better way to accomplish the same task (I didn't delete the function definition itself in the VBA editor). So, these functions are no longer being called neither in the book nor from any VBA code, I checked it using a search to be 100% sure.
Now I'm doing some review on my code and I noticed something strange: in a Sub procedure in the same workbook (which has nothing to do with these functions) I call Application.CalculateFullRebuild. When this happens those UDF get called, I can see it by setting a break point inside the UDF.
I'd like to know why is it happening and what can be done to avoid it, as it is slowing that Sub unnecessarily.
Thanks!
Application.CalculateFullRebuild MSDN reference has this to say:
The CalculateFullRebuild method is similar to re-entering all formulas. ... [When run] a full calculation of the data in all open workbooks is performed and the dependencies are rebuilt.
Further MSDN reference states:
Causes Excel to rebuild the dependency tree and the calculation chain
This means that any UDFs in the module code or sheet code will be recalculated because Excel is rebuilding and testing functions for dependency and use in the calculation chain.
If you are looking for a way to simply manually calculate the existing formulas in the sheet via your Sub, you can use 'Application.Calculate' (MSDN):
Application.Calculate 'for all open Sheets
Sheets("Name of Sheet").Calculate 'Specific Sheet
Sheets("Name of Sheet").Range("Name of Range").Calculate 'Specific Range
The system is working as it should. Consider:
Function qwerty() As String
qwerty = "qwerty"
MsgBox "XX"
End Function
It is non-Volatile and has no arguments. It will be calculated at the time it is entered in a worksheet cell. Application.Calculate may cause it to be calculated once, however:
Sub ytrewq()
Application.CalculateFullRebuild
End Sub
will cause the UDF to be re-calculated each time ytrewq is run.
To the moment my approach has been commenting all the code inside the UDF with two objectives: increasing speed on one side and checking if any side effect happened on the other side. To the moment, I have not observed any side effect, so more to the point that they are not being used anywhere.
Right now the application I'm developing is working quite well, but I'll try the solutions you're proposing just out of curiosity. By bets are on either it's being used somewhere hidden and forgoten or simply that I have some rubbish inide the workbook structure that is not getting cleaned.
Thanks!
Update
Tried again the next day and those UDF are no longer being called. Thus, I'll have to assume that something odd was going on with Excel that went away when I restarted it.
Anyway, thanks a lot for the Application.Caller thing, which I didn't know about.
Basically what I'm trying to accomplish is to search the document for blank rows and delete them, if any. This works great if there are blank rows to delete; however, if there are no blank rows, the macro ends with an error. I'd be eternally grateful if someone could advise me how to make this into an "if blank rows then this, if none then that"
Sheets ("xml") .Select
Cells.Select
Selection.SpecialCells(x1CellTypeBlanks).Select
Selection.EntireRow.Delete
Enter my second macro (this part works fine)
Regards
Let me point you to the canonical:
How to avoid using Select/Activate in Excel VBA macros
So you can start to understand why your current code fails or performs undesired operation. What happens when there are no blank cells in your selection? You'll get an error. Why?
Because in that circumstance, Selection.SpecialCells(xlCellTypeBlanks) evaluates to Nothing. (You can verify this using some debug statements) And because Nothing does not have any properties or methods, you'll get an error, because you're really saying:
Nothing.Select
Which is a null program, does not grok, does not compute, etc.
So, you need to test for nothingness with something like this:
Sheets("xml").Select
Cells.Select
If Not Selection.SpecialCells(x1CellTypeBlanks) Is Nothing Then
Selection.SpecialCells(x1CellTypeBlanks).EntireRow.Delete
End If
I still suggest avoiding Select at all costs (it is superfluous about 99% of the time and makes for sloppy code which is difficult to debug and maintain).
So you could do something more complete following that line of thought:
Dim blankCells as Range '## Use a range variable.
'## Assign to your variable:
Set blankCells = Sheets("xml").Cells.SpecialCells(xlCellTypeBlanks)
'## check for nothingness, delete if needed:
If Not blankCells Is Nothing then blankCells.EntireRow.Delete
Follow-up from comments
So in VBA we are able to declare variables which represent objects or data/values, much like a maths variable in an equation.
A Range is a type of object part of the Excel object model, which consists of the Workbook/Worksheets/Cells/Ranges/etc. (far more than I could hope to convey to you, here)
http://msdn.microsoft.com/en-us/library/office/ff846392(v=office.14).aspx
A good example of why to use variables might be here if you scroll down to the "Why Use Variables" section.
http://www.ozgrid.com/VBA/variables.htm
This is of course very simple... but the reader's digest version is that variables allow us to repeatedly refer to the same object (or value for sipmle data types) without explicitly referring to it each time.
THen there is the handy side-effect that the code bcomes more easy to read, maintain and debug, when we use variables instead of absolute references:
Dim rng as Range
Set rng = Sheets(1).Range("A1:Q543").Resize(Application.WorksheetFunction.CountA(Sheets(1).Range("A:A"),))
Imagine that fairly (but not ridiculously) complicated range construct. If you needed to refer to that range more than once in your code, it would be silly not to assign it to a variable, if for no other reason than to save your own sanity from typing (and possibly mistyping a part of it). It is also easy to maintain, since you need only modify the one assignment statement and all subsequent references to rng would reflect that change.
Set mainWB = Workbooks("Copy Paste.xlsb")
Set mainWS = mainWB.Sheets("Sheet1")
Set testWS = mainWB.Sheets("Sheet3")
mainWS.Select
I keep getting an error on the last line in Excel VBA:
"Method Select of Object '_Worksheet' failed"
Any idea why or how to fix this? Thank you!
As discussed in comments, cannot select Sheets in VBA that are not active (or Range objects on them).
For example the following code
Sheets(1).Activate
Sheets(2).Range("A1").Select
will cause the error you are receiving.
In your case, it seems you are attempting to Select a sheet which is not active - your mainWS object is presumably not the ActiveSheet at the point you are calling this code. An easy way to test if this is happening is if you add the following to the end of your code:
if (ActiveSheet.Name <> mainWS.Name) then
msgbox ("Going to crash after clicking ok!")
end if
mainWS.Select
Note that you can refer to the activated worksheet with the command ActiveSheet to either get properties or whatever other operations you are interested in doing.
This error can also happen if you have loop working thru all of the worksheets in the workbook and there are hidden sheets. Lookout for that.
Last, and unrelated to your specific error message, I assume you are declaring those variables somewhere and simply did not copy them here - if not I would consider using Option Explicit as you can often run into all sorts of issues without having Option Explicit at the top of your VBA code.
While I agree with the above, it is also important to note that the Delete function will not work if the worksheet's visibility is currently set to xlSheetVeryHidden
I had the same issue and looked at this post for ideas on how to fix it. My issue was resolved by using "Activate" as opposed to "Select" on the line that my code was failing on. So instead of using "mainWS.Select", try using "mainWS.Activate" instead.
Seems there is some bug. Can't resolve this problem, all code is running fine and I am able to see the AutoShape is getting copied from Excel file but it is not adding it to PowerPoint. Popping up an error Run-time error '-2147188160(80048240) View.Pastespecial : Invalid Request. The specified data type is unavailable
If Range("H" & i).Value = 1 And Range("B" & i).Value = "FRONT" Then
objPPT.Presentations(1).Slides(9).Select
objPPT.ActiveWindow.View.PasteSpecial DataType:=ppPasteEnhancedMetafile
Your code will be faster and possibly more reliable if you don't rely on selecting anything:
With objPPT.Slides(9).Shapes
Set objShape = .PasteSpecial(ppPasteEnhancedMetafile)(1)
With objShape
' set coordinates and such here
End With
End With
As to why you're getting the error message, try stopping the code after you've put something on the clipbard. Then switch to PowerPoint, use Paste Special to see what paste options are available. If EMF isn't one of them, that's your problem ... you're not putting anything in EMF format on the clipboard.
I had a similar issue, but I found a different solution; it may be specific to what I was doing though.
I setup a program where I would:
(manual) Copy an entire webpage that was a report on several performance metrics
(manual) Pasted it in to excel
Run the program to extract the values I want and then clear contents of the sheet I pasted them on.
Eventually after many tests, it would fail with this same automation error when I tried to access the sheet:
Sheets("PDX Paste").Activate
I was able to activate every other sheet except that particular one, even using the index value instead of the direct name reference. After googling to no success I found out that the copy and paste from the website was also pasting invisible controls. When I found this out I had 1,300+ shapes when I only expected 1 (the button I use to trigger the program). It was actually only apparent when a glitch - presumably due to so much memory being used to store these controls - displayed for a few seconds.
I ran the following code independently and then appended it to the end of my program when I do the cleanup of the data. The code goes through the sheet and deletes any shape that isn't the same type as my button. It would have to be adapted if the shapes you want to delete are the same type as the shapes you want to keep. It also becomes simpler if you don't have any shapes to keep.
Dim wsh As Worksheet
Set wsh = ActiveSheet
Dim i As Integer
For i = wsh.Shapes.Count To 1 Step -1
If wsh.Shapes(i).Type <> wsh.Shapes("UpdateDataButton").Type Then
wsh.Shapes(i).Delete
End If
Next i
I'm not sure this would solve this problem, but hopefully this can help others and prevent loss of time figuring out what may be causing this relatively vague error message.