Using .range property on string that includes sheet name - vba

I have a string inside a cell in a workbook that I am using to define the address of a range that a lookup should be done upon.
As an example, let's say the string is called LookupRange and has the value:
''Rate Sheet'!Y111:AA126
My problem is that in my code, when I set the range I have to use:
Set yRange = ThisWorkbook.Worksheets("Rate Sheet").Range(LookupRange)
Is there a way to use the .Range() property without using the .Worksheets() property?
For instance, maybe a way to do something like:
Set yRange = ThisWorkbook.Range(LookupRange)
If not, I guess I might have to write some code to extract the sheetname from the sheet range?

Assuming LookupRange is a String, you can extract the Sheet and Range from the string using Mid() and InStr():
Sub TestIt()
Dim LookupRange As String
LookupRange = "'Rate Sheet'!Y111:AA126"
SheetL = Mid(LookupRange, 2, InStr(2, LookupRange, "'") - 2)
RangeL = Mid(LookupRange, InStr(1, LookupRange, "!") + 1, Len(LookupRange))
Set yRange = ThisWorkbook.Sheets(SheetL).Range(RangeL)
End Sub

I don't know exactly what sort of look up you are doing, but this should work..(parse it as a string)
Sub range_set()
Dim rr As Range
Set rr = Range(CStr(Range("LookupRange")))
Debug.Print Application.WorksheetFunction.VLookup(1, rr, 2, False)
End Sub
Where the named range "LookupRange" is a single cell that contains the sheet address "Sheet2!Y111:AA126" (or whatever) to be used in a "lookup".

Set yRange = Application.Range("'Rate Sheet'!Y111:AA126")

Related

formula leaving whitespace

I have the following formula designed to flag rows in a ListObject:
=IF( [#[Is Closed]]="Y", "", "Y")
I have some vba code that looks for these value via StrCmp, and was surprised to find that the Text property of the cell was " Y " (as opposed to "Y").
There are some obvious easy work arounds but can someone explain why the formula is leaving whitespace and how to force it not to?
Cheers,
UPDATE
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' FindAllInColumn
' To find a value regardless of hidden rows and autofulter settings that can make
' other methods unreliable
'
' aSearchRange : the range of data to search, which MUST be a single column
' aLookUpVal : the value
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Function FindAllInColumn(aSearchRange As Range, aLookUpVal As Variant) As Excel.Range
Debug.Assert aSearchRange.Columns.Count = 1
Dim rngEach As Range
Dim rngResult As Excel.Range
For Each rngEach In aSearchRange
' Debug.Print rngEach.Address & ": Value " & rngEach.Text
' If IsValued(rngEach.Text) Then Stop
If (StrComp(rngEach.Text, aLookUpVal) = 0) Then
If rngResult Is Nothing Then
Set rngResult = rngEach
Else
Set rngResult = Application.Union(rngResult, rngEach)
End If
End If
Next rngEach
Set FindAllInColumn = rngResult
End Function
The FIX
StrComp(rngEach.Value2, aLookUpVal, vbTextCompare)
Changing .Text to .Value2 instead. Odd, but at least it works now
In general empty spaces in Excel sometimes cause a lot of problems. As the OP has found out himself, .Value2 seems like a universal problem-solver of many strange cases.
Try to select the cell and check the following code, it will print possible "hidden" empty spaces:
Option Explicit
Public Sub TestMe()
Dim rng As Range
Dim cnt As Long
Set rng = Selection
For cnt = 1 To Len(rng)
Debug.Print Asc(Mid(rng, cnt, 1))
Next cnt
End Sub

Excel VBA find address and assign to variable then reuse value

I'm trying to find if there's a given title on a cell, pass the address of that cell to a variable and use such location to adjust the size of the column. The reason I'm doing this is because I'm writing several functions which will shift the position of the columns. I'd appreciate it if someone could take a look and tell me what I'm doing wrong.
Option Explicit
Sub adjustColumns()
Dim PONumberCell As String
Dim PONumberAddress As Range
Dim TopLabelinColumn As Range
For Each TopLabelinColumn In Range("A1:Z1").Cells
If TopLabelinColumn Like "PO_NUMBER" Then TopLabelinColumn.Value = "PO"
PONumberCell = TopLabelinColumn.Address
Set PONumberAddress = PONumberCell
PONumberAddress.ColumnWidth = 70
Next TopLabelinColumn
End Sub
edited after OP's further request:
you are confusing a Range object (such as PONumberCell is meant to be) with a String variable one (like PONumberAddress), so
Set PONumberAddress = PONumberCell
doesn't work because you are trying to assign an object variable to a String one
but you can be more effective avoiding the loop and using the Find() method
Option Explicit
Sub adjustColumns()
Dim PONumberAddress As String
Dim PONumberCell As Range
Set PONumberCell = Range("A1:Z1").Find(what:="PO_NUMBER", LookIn:=xlValues, lookat:=xlPart, MatchCase:=False)
If Not PONumberCell Is Nothing Then
With PONumberCell
.value = "PO"
PONumberAddress = .Address
.EntireColumn.ColumnWidth = 70
End With
Else
Set PONumberCell = Range("A1:Z1").Find(what:="PO", LookIn:=xlValues, lookat:=xlWhole, MatchCase:=False) '<--| if it didn't find "PO_NUMBER" then it seaches for a complete match of "PO"
If Not PONumberCell Is Nothing Then PONumberCell.EntireColumn.ColumnWidth = 70
End If
End Sub
Following the comments above, there are a few erros in your code:
Setting the PONumberAddress Range, you need to use the syntax : Set PONumberAddress = Range(PONumberCell) using the address string found in brackets.
To set the column width, use : PONumberAddress.Columns.ColumnWidth = 70.
According to your post, I think you want to do this only for columns where the header text is "PO_NUMBER", therefore you need all the code below inisde your If : If TopLabelinColumn.Value Like "PO_NUMBER" Then.
Code
Option Explicit
Sub adjustColumns()
Dim PONumberCell As String
Dim PONumberAddress As Range
Dim TopLabelinColumn As Range
For Each TopLabelinColumn In Range("A1:Z1").Cells
If TopLabelinColumn.Value Like "PO_NUMBER" Then
TopLabelinColumn.Value = "PO"
PONumberCell = TopLabelinColumn.Address
Set PONumberAddress = Range(PONumberCell)
PONumberAddress.Columns.ColumnWidth = 70
End If
Next TopLabelinColumn
End Sub

someExcel VBA: Cannot create a range object successfully

This is my first question here, so bear with me. I'm a security consultant working on a huge firewall migration, for which I got my VBA skill from under a thick layer of dust. So far I have managed to get all my issues resolved by searching, but this issue: I get errors when doing exactly how I find it everywhere.
What I want to do:
I have an array that contains (among other things), strings formatted like this: "A3:P59", representing a cell range.
Now, this are ranges within a table. When I get the address of a certain cell in the table, I want to test if it's in that range.
I wrote a test function:
Function TestCellRange() As Boolean
Dim tbl As ListObject
Dim cell, rng, test As range
Dim range As range
Dim bRow, eRow As Integer
Set tbl = shRulebase.ListObjects("tblBFFirewallRules")
shRulebase.Activate
With shRulebase
cell = tbl.DataBodyRange(5, 1).Address(False, False) 'it's this command that gives me issues
Set range = .range(.Cells(bRow, 1), .Cells(eRow, 16))
Debug.Print cell
'Set rng = shRulebase.range(range)
Debug.Print rng
Set test = Application.Intersect(cell, range(range(A3), range(P59)))
If test Is Nothing Then
MsgBox ("oops")
TestCellRange = False
Else
MsgBox ("yup yup")
TestCellRange = True
End If
End With
End Function
Now whatever I try, I keep getting blocked on the set range:
set range = .Range("A3:P59") -> will return "object required", on the "set test" line (if i use intersect (cell, range))
Set range = range("A3:P59") -> will return object variable or with block variale not set on the same line
Set range = .range(.Cells(bRow, 1), .Cells(eRow, 16)) -> will step through, but debug.print returns a type mismatch and "Set test = Application.Intersect(cell, range)" returns a "object required"
Any help would be really appreciated...I'm all to familiar with networks ip's and the bits and bytes of it, but here I am a bit out of my comfort zone and I need to finish this by tomorrow :(
Greetings,
Kraganov
EDIT Some More tries:
rng and cell as variant:
cell = tbl.DataBodyRange(5, 1).Address(False, False)
rng = .range("A3:P59").Address(False, False)
Set test = Application.Intersect(cell, rng)
==>I would get objects required
just using rng as range and trying to set it without "set"
rng = .range("A3:P59")
EDIT 2 : I found a way around using the range.
So what I was trying to do, was the following:
I had a table that contains information about firewall rules. However, not every line describes a rule. There are also lines that described the context in which the rules below that line were to be placed.
Outside of the table, aside of those lines there would be a cell with the range of cells for that context. I wanted to use that to describe the context for those rules, if I pulled them.
I ended up looping through the table rows and identifying those specific rows and setting a "context" variable when, a row like that was met.
Try setting the cell as well as following:
set cell = tbl.DataBodyRange(5, 1).Address(False, False)
What is cell? A Range?
You do not need to add 'set' to the range value assignment.
Try just
range = .Range("A3:P59")
Function TestCellRange() As Boolean
Dim tbl As ListObject
Dim cellToTest As Range
Dim testResult As Range
Set tbl = shRulebase.ListObjects("tblBFFirewallRules")
Set cellToTest = tbl.DataBodyRange.Cells(5, 1)
'or with one more level of indirection
'Set cellToTest = shRulebase.range(tbl.DataBodyRange.Cells(5, 1).Value)
Set testResult = Application.Intersect(cellToTest, [A3:P59])
If testResult Is Nothing Then
MsgBox ("oops")
TestCellRange = False
Else
MsgBox ("yup yup")
TestCellRange = True
End If
End Function
Thanks to the post of VincentG I found the working solution. Thanks for that.
Function TestCellRange() As Boolean
Dim tbl As ListObject
Dim cellToTest As range
Dim testResult As range
Set tbl = shRulebase.ListObjects("tblBFFirewallRules")
shRulebase.Activate
Set cellToTest = tbl.DataBodyRange.Cells(5, 1)
'or with one more level of indirection
'Set cellToTest = shRulebase.range(tbl.DataBodyRange.Cells(5, 1).Value)
Set testResult = Application.Intersect(cellToTest, range("A3:P59"))
If testResult Is Nothing Then
MsgBox ("oops")
TestCellRange = False
Else
MsgBox ("yup yup")
TestCellRange = True
End If
End Function

how to use variable in range using vba

Hello I have written code for generating graph using vba. everything working correctly ,but problem is i want to use variable for selecting particular column
the code is :
Set x = Range("$CF$2", Range("$CF$2").End(xlDown))
Set y = Range("$CG$2", Range("$CG$2").End(xlDown))
Dim c As Chart
Set c = ActiveWorkbook.Charts.Add
Set c = c.Location(Where:=xlLocationAsObject, Name:=assume)
With c
.ChartType = xlXYScatterLines
' set other chart properties
With .Parent
.Top = Range("cl1").Top
.Left = Range("cl12").Left
.Name = "c"
End With
End With
Dim s As Series
Set s = c.SeriesCollection(1)
With s
.Values = y
.XValues = x
' set other series properties
End With
I want to use variable COLs in first to line they are
Set x = Range("$CF$2", Range("$CF$2").End(xlDown))
Set y = Range("$CG$2", Range("$CG$2").End(xlDown))
COLs is variable of string
I'm not sure I understand, but if you want a Range object based on a string, why not try this:
Option Explicit
Sub TestRange()
'***** Declare variables
Dim oX As Range
Dim sCOLs As String
'***** Select column
sCOLs = "A"
'***** Set Range based on column from sCOLs
Set oX = Range(sCOLs & "2", Range(sCOLs & "2").End(xlDown))
'***** Do something with oX
Debug.Print TypeName(oX)
'***** Clean up
Set oX = Nothing
End Sub
You could also try and have the whole range as a string, maybe a bit cleaner code?
Dim sRange as String
sRange = "A2"
Set oX = Range(sRange, Range(sRange).End(xlDown))
You could also use Inputbox to have the user click on a certain cell. This then creates a variable "UserRange" which contains the cell reference you can use.
Sub test()
Dim UserRange As Range
Set UserRange = Application.InputBox(Prompt:="Please Select Range", Title:="Range Select", Type:=8)
UserRange.Value = "Test"
End Sub

Storing Range attributes as an object?

I'm having trouble with the way I designed this little report I'm making. Is it possible to create a variable for a Range object in Excel VBA, for the purposes of applying the formatting to another Range? Here is my example:
I'm creating a dictionary from the Microsoft Scripting Runtime library:
Dim d as Scripting.Dictionary
With this I'm adding labels, values, and (trying to add) Ranges.
Dim rng as Range
rng.Font.Bold = True
d.Add 1, Field("test1", 12345, rng)
rng.Font.Bold = False
d.Add 2, Field("TestTwo", "Testing field", rng)
rng.HorizontalAlignment = xlCenter
d.Add 3, Field("threeeee", 128937912, rng)
Dim key As Variant
For Each key In d.keys
Range("A" & key).value = d(key).Label
Set Range("B" & key).value = d(key).rng
Next key
Here is my Field function:
Private Function Field(Label As String, val As Variant, rng As Range) As cField
Dim f As New cField
f.Label = Label
f.val = val
Set f.rng = rng
Set Field = f
End Function
And here is my cField class:
Option Explicit
Dim mVarValue As Variant
Dim mStrLabel As String
Dim mRng As Range
Property Let val(ByVal val As Variant)
mVarValue = val
End Property
Property Get val() As Variant
val = mVarValue
End Property
Property Let Label(ByVal val As String)
mStrLabel = val
End Property
Property Get Label() As String
Label = mStrLabel
End Property
Property Let rng(ByVal val As Range)
Set mRng = val
End Property
Property Get rng() As Range
Dim a As Range
a.value = mVarValue
Set rng = a
End Property
The idea is that the key in the dictionary is going to be the row location for the field. This way if changes need to be made to the report I'm making, the only thing that needs to be changed is the key for that particular value in the dictionary. I have been successful storing the label for the value, and the value itself, but I also want to store the formatting for that Range (bold, justification, borders, etc...).
I get a 'Run-time error '91': Object variable or With block variable not set' error on the line immediately following the rng declaration. I'm wondering if its not possible to have a generic Range that doesn't have a location on a sheet, or if somehow my syntax is off.
Any help would be greatly appreciated! :)
Is it possible to create a variable for a Range object in Excel VBA, for
the purposes of applying the
formatting to another Range?
I'm wondering if its not possible to have a generic Range that doesn't have
a location on a sheet...
The short answer is no.
The quick answer is...I suggest creating a "format" worksheet, which can be hidden or very hidden, that contains ranges, or Named Ranges, with the formatting you need. This allows you to range.Copy the "formatted" range then use range.PasteSpecial xlPasteFormats.
I dislike overwriting the user's clipboard, but it is difficult to programmatically copy the formatting of one range to another. I use this method in numerous solutions because it is flexible, maintainable, reusable, and does not rely on complex code. Moreover, I can visually change formatting without touching code.
Good question! Unfortunately, I don't think you can store a range that hasn't been initialized to an existing range of cells on your worksheet. I can think of a couple of options:
Use a hidden worksheet to store the range information
Store the range information manually, in a handful of member variables
Option 1 could be the easiest, despite the fact that it sounds like overkill to have an extra sheet kicking around. I'm picturing one hidden worksheet, defined specifically for this purpose.
Option 2 might be simplified if you only need to keep track of a couple of range properties (borders and color, for example).
You are correct - it is not possible to have a generic Range object. You have to 'Set' your range variable to some actual range to be able to read and write its properties.
But if you're "Letting" your rng property, then it seems you should already have a reference to a range. Why do you have a Property Let rng if you're not going to use that property in the Get statement.
How about this solution?
Create a class with
the range address as text, ie."$A$3:$A$11,$A$18:$A$24,$D$29".
The value
Save the formatting of the range as a format-text.
Then you could create the range by Range(RangeAdressAsText) and use something like the following
Private Sub ApplyFormatting(r As Range, ByVal f As String)
On Error GoTo ErrHandler:
f = UCase$(f)
Dim IterateRange As Range
Dim Formatarray() As String
Formatarray = Split(f, " ")
Dim i As Integer
With r
For i = LBound(Formatarray) To UBound(Formatarray)
Select Case Formatarray(i)
Case "BOLD"
.Font.Bold = True
Case "ITALIC"
.Font.Italic = True
Case "TOP"
.VerticalAlignment = xlTop
Case "BOTTOM"
.VerticalAlignment = xlBottom
Case "UNDERLINE"
.Font.Underline = True
End Select
Next i
End With
Erase Formatarray
Exit Sub
ErrHandler:
LogInformation Format(Now, "yyyy-mm-dd hh:mm:ss") & " - " & ": # ApplyFormatting in xlPrinter " & " - " & Err.Number & " - " & Err.Description & " - " & Err.Source & " - " & Err.LastDllError
End Sub