I've created an InputBox which asks the user for the letter of the last column containing entries. I'd like the title to be sheet name, according to an index. Here's the code I've written:
Dim LastEntryCol As String
Dim ShtName As Variant
Set ShtName = ThisWorkbook.Sheets(2) '****The number 2 will need to be changed to an index. For now it's hard-entered.
LastEntryCol = Application.InputBox("What is the letter of the last column containing entry labels?", ShtName)`
When I run it, I get error 1004 "Method 'InputBox' of object '_Application' failed". I suspect it has something to do with how I set ShtName, as the code runs properly if I replace the title argument with something like "hooray coding!"
Can anyone explain to me what's going wrong and how I can fix it? Thanks!
You are passing the whole WorkSheet object, instead of just its name. Try this:
Dim LastEntryCol As String
Dim ShtName As String
ShtName = ThisWorkbook.Sheets(2).Name '****The number 2 will need to be changed to an index. For now it's hard-entered.
LastEntryCol = Application.InputBox("What is the letter of the last column containing entry labels?", ShtName)
Sheets is a Collection so to get the name you need to use
ShtName = ThisWorkbook.Sheets.Item(2).Name
Also pretty sure this will always be a string so you could use Dim ShtName As String and avoid Set.
Related
I'm trying to enter formulas into tables.
Sometimes I get "Subscript out of range". It doesn't matter how I write the formula, it never works consistently.
You'll see a different formula commented out which doesn't work either.
Sub UpdateAccountTable()
'PURPOSE: Update table data with current data from CW Data Table
'Erik 2022
'
Dim tbl As ListObject
Dim tName As String
Dim warnCol As Long
Dim limitCol As Long
Range("L4").Select
tName = ActiveCell.ListObject.Name 'gets table name
Set tbl = ActiveSheet.ListObjects(tName)
warnCol = tbl.HeaderRowRange.Cells.Find("Current Warn").Column
limitCol = tbl.HeaderRowRange.Cells.Find("Current Limit").Column
' warn and limitcol gets column number because the columns are not always in the same place
StopExcelActions 'function to stop calculate, screen updating ect
With tbl
.ListColumns("warnCol").DataBodyRange.Formula = "=INDEX(CWdata[Warn Value],MATCH([#Helper],CWdata[Helper],0))"
' "=SUMIFS(CWdata[Warn Value], CWdata[Policy Name],[#[Policy Name]],CWdata[Rule Name],[#[Evaluator Description]])"
.ListColumns("limitCol").DataBodyRange.Formula = "=INDEX(CWdata[limit Value],MATCH([#Helper],CWdata[Helper],0))"
' "=SUMIFS(CWdata[Limit Value], CWdata[Policy Name],[#[Policy Name]],CWdata[Rule Name],[#[Evaluator Description]])"
End With
'Range("M4:N4").Select
With tbl.ListColumns("warnCol")
.EntireColumn.Copy
.EntireColumn.xlpastespecial Paste:=xlPasteValues
End With
With tbl.ListColumns("limitCol")
.EntireColumn.Copy
.EntireColumn.xlpastespecial Paste:=xlPasteValues
End With
StartExcelActions
Set tbl = Nothing
FormatData
End Sub
The error:
Consider how your use of `tbl.ListColumns(....) is one of those times where VBA is defaulting to the "Item Property" of the ListColumns object.
So:
ListColumns(StringName) or listColumns(IndexNumber)
are coding variations that point to the "Item" property: ListColumns.Item(variant)
Then notice how you must use the stringName for the column you have, not the String which is the name of the variable you used to store the string. Similarly, if you're using the "indexNumber" version of the object property, you use the value stored in the variable, not the string name of your indexNumber variable.
I give myself a heads up, as I code, and explicitly name all string variables as str_someName, and all indexes as j_someIndexName -- therefore:
Dim str_someName as string
Dim j_someIndexingName as Long
' you might have written Dim jLong_warnCol as Long
If I wrote ListColumns("str_someName") I would see right off that I'm using the string of my variable name, and not the value stored within the string variable. Similarly, if you wrote ListColumns("j_someIndexName"), you might notice that was weird.
Using the naming convention for Long or Integers becomes useful in Loops, so your variables have some expected range of values: Dim long_someName as Long or Dim j_someName' as Integer. You could extend this habit by using "t_..." for table variables, "obj_..." for objects, and on and on. Forced name conventions also helped me learn to avoid coding problems when crafting SQL statements, themselves stored into a str_sql string variable.
The use of OPTION EXPLICIT is an additional check.
I want to compare two strings from two different worksheets with vba in excel. Already wrote the following code:
Public Sub Vergleich_Arbeitsmappen()
Dim i As Long
Dim projectCounter As Integer
Dim strAngNr As String
Dim strCodename As String
Dim wks As Workbook
strAngNr = Range("C3").Value
strCodename = Range("C4").Value
projectCounter = 200
Set wks = Workbooks.Open("filename")
For i = 2 To projectCounter
If CStr(Workbooks(wks).Worksheets("Tabelle2").Cells(i, 2).Value) = strAngNr Then
MsgBox "FEHLER"
End If
Next i
End Sub
But while debugging, excel always show the error "types incompatible" even if both values are strings, as defined.
Your problem doesn't come from the 2 strings you are comparing, it comes from the invalid parameter into the Workbooks-collection.
As you have Workbook object already stored in wks, you simply can write
wks.Worksheets("Tabelle2").Cells(i, 2).Value
You use the Workbooks-Collection to access an open workbook either by name or by index so the parameter into Workbooks is either a String or a Number (In theory you could write Workbooks(wks.Name), but that would be completely useless).
You are passing an object of type Workbook as Parameter, and that fails and give you the "types incompatible"-error.
I am new to vba and totally lost in writing the above mentioned function in vba. Actually, I want to do the same thing I would do with the usual excel formula.
Update:
Based on the answer of Scott I have adjusted my code. Now I have a Type mismatch error. The Type of Mname by definition is a string. The values in the lookup Range (B18:B38) are (not exclusive) integer. Should I tell Excel to take them as a string? If yes, how?
Summary:
I have a range (D18:D38) where I want to chose a value from based on the row number determined by a match between a string Variable (Mname) and another range (B18:B38). The string Variable is determined by the name of a file in a folder.
My Problem is that I get the error message: 'Unable to get the match property of the worksheetfunction class'
Thanks for your help!
Sub Test()
Application.ScreenUpdating = False
Dim Mname As String
Set WSCockpit = ThisWorkbook.ActiveSheet
Dim strFileName As String
Dim strFolder As String: strFolder = WSCockpit.Range("D9").Value
Dim strFileSpec As String: strFileSpec = strFolder & "*.xls*"
strFileName = Dir(strFileSpec)
Do While Len(strFileName) > 0
Dim strFilePath As String: strFilePath = strFolder & strFileName
Mname = Mid(strFileName, 13, Len(strFileName) - 17)
Dim rw As Long
rw = Application.Match(Mname, WSCockpit.Range("B18:B38"), 0)
Dim VarImp As Boolean
VarImp = Application.WorksheetFunction.Index(WSCockpit.Range("D18:D38"), rw)
'some other task'
Loop
Application.DisplayAlerts = True
End Sub
Backup:
Sorry for the code being messy. I have no clue about the general rules for writing vba. Like mentioned before, my goal is to get the lookup running. The looked up value will be "TRUE" or "FALSE". Afterwards I will use this in order to determine whether the file found in the folder needs to be imported or not. If you have some other suggestions for my coding or for the task I want to perform, I would be glad to hear.
Break it into steps and also ensure the data you expect to find in the lookup is in indeed there. Meaning, check the value of Mname at run-time (via debugging code) and verify you can find it manually.
Lastly, use Application.Match instead.
Dim rw as Long
rw = Application.Match(Mname, WSCockpit.Range("B18:B38"),0)
Dim import as Boolean
import = Application.WorksheetFunction.Index(WSCockpit.Range("D18:D38"),rw)
Background
Recently I answered a question which involved looking at a file's properties. Eventually the code I put up worked fine, but there is one thing about it that got me puzzled.
Problem
There are two specific lines where I wanted to replace a (to me what looks like) a string, with a variable, more specifically, try the following:
Sub TestForSO()
Dim oDir As Object: Set oDir = CreateObject("Shell.Application").Namespace("C:\Users\...\")
Debug.Print oDir.GetDetailsOf(oDir.Items, 1)
End Sub
Replace the pathname to a directory which includes an excel file, and it should return the property value just fine.
Now when I try to replace the full path with a variable the following throws an "Runtime Error 91: Object variable or with block variable not set" on the debug.print line:
Sub TestForSO()
Dim MainPath As String: MainPath = "C:\Users\...\"
Dim oDir As Object: Set oDir = CreateObject("Shell.Application").Namespace(MainPath)
Debug.Print oDir.GetDetailsOf(oDir.Items, 1)
End Sub
Solution
A bit peculiar to me that the following did work:
Sub TestForSO()
Dim MainPath As String: MainPath = "C:\Users\...\"
Dim oDir As Object: Set oDir = CreateObject("Shell.Application").Namespace(CStr(MainPath))
Debug.Print oDir.GetDetailsOf(oDir.Items, 1)
End Sub
I do not understand the difference per se as the code below will give the same result through "Watches":
Sub test()
Dim check1 As String, check2 As String
check1 = "Hello"
check2 = CStr("Hello")
End Sub
Question
Does somebody understand why the string variable on itself was not enough and would throw an error? Why would adding Cstr() make the code work when seemingly it's the same data type?
According to documentation about Namespace, it needs a parameter that must be a Variant or can be a string that specifies the path of the folder.
That explains why these 2 methods work with no problems:
Set oDir = CreateObject("Shell.Application").Namespace("C:\Users\...\ 'string path
Or defining a Variant variable:
Dim MainPath As Variant: MainPath = "C:\Users\...\"
Dim oDir As Object: Set oDir = CreateObject("Shell.Application").Namespace(CStr(MainPath))
But defining MainPath as string causes error Runtime Error 91: Object variable or with block variable not set
OP found a solution. If MainPath declared as string, and combined with Cstr, the code works.
It's just a theory, but some unnoficial sources (not directly related to VBA) mention that Cstr converts the value to a variant with a subtype.
http://www.csidata.com/custserv/onlinehelp/vbsdocs/vbs89.htm
https://docs.oracle.com/cd/E57185_01/HFMAD/ch10s06s04s03.html
Actually, the official documentation it's kind of confusing, because at first lines it says:
Each function coerces an expression to a specific data type.
and later on it says
The function name determines the return type
But if we read carefully, there is also some important information like this:
"...In general, you can document your code using the data-type
conversion functions to show that the result of some operation
should be expressed as a particular data type rather than the
default data type..."
And also:
"...This technique is consistent with the conversion of all other
intrinsic types to their equivalent Variant subtypes..."
So after doing some research and thinking about it in the last 24 hours, and reading a lot of times the previous paragraphs I've posted, I would dare to say that all conversion functions returns a Variant with a subtype. In this case, CStr does return a Variant that is being coerced to be expressed as string being string the subtype, but the data is Variant.
That would explain why doing Cstr(MainPath) makes the code works.
Dim sampleRange as Range
Set sampleRange = Worksheet.Range(Cells(1,1),Cells(1,4)
sampleRange.Name = "Range1"
MsgBox sampleRange.Name
The above code will show the actual address of the range, not the name. Why?
How do I get a named range to return its name?
For a Range, Name isn't a string it's a Name object, that you then take the Name property of to get the string:
MsgBox sampleRange.Name.Name