I have a VBA class that I call to fetch column numbers for the required columns in a worksheet (15 of them). Users are allowed to move columns around and the match functionality works well. However if a user deletes a column, I get a runtime error. How do I trap an error and let the user know that 'X' column name has been deleted but still continue checking the rest of the columns.
Option Explicit
Public EmpName As Long, EmpID As Long, EmpDepartment As Long, EmpAddress As Long
Private Sub Class_Initialize()
Dim ws As Worksheet, r As Range, tStr As String, wsname As String
Set ws = ActiveSheet: Set r = ws.Range("1:1")
EmpName = Application.WorksheetFunction.Match("EmpName", r.value, 0)
EmpID = Application.WorksheetFunction.Match("EmpID", r.value, 0)
EmpDepartment = Application.WorksheetFunction.Match("EmpDepartment", r.value, 0)
EmpAddress = Application.WorksheetFunction.Match("EmpAddress", r.value, 0)
Set r = Nothing: Set ws = Nothing
End Sub
Original code updated
To avoid the run-time error you could use Application.Match instead of Application.WorksheetFunction.Match.
Option Explicit
Public EmpName As Long, EmpID As Long, EmpDepartment As Long, EmpAddress As Long
Private Sub Class_Initialize()
Dim ws As Worksheet, r As Range, tStr As String, wsname As String
Dim Res As Variant
Set ws = ActiveSheet
Set r = ws.Range("1:1")
Res = Application.Match("EmpName", r.Value, 0)
If Not IsError(Res) Then
EmpName = Res
Else
MsgBox "EmpName column not found!", vbInformation, "Missing Column"
End If
Res = Application.Match("EmpID", r.Value, 0)
If Not IsError(Res) Then
EmpID = Res
Else
MsgBox "EmpID column not found!", vbInformation, "Missing Column"
End If
Res = Application.Match("EmpDepartment", r.Value, 0)
If Not IsError(Res) Then
EmpName = Res
Else
MsgBox "EmpDepartment column not found!", vbInformation, "Missing Column"
End If
Res = Application.Match("EmpAddress", r.Value, 0)
If Not IsError(Res) Then
EmpAddress = Res
Else
MsgBox "EmpAddress column not found!", vbInformation, "Missing Column"
End If
End Sub
Using a dictionary
If you don't want all the repetition in the code you might want to look at using a dictionary to store the column names/numbers.
Option Explicit
Private Sub Class_Initialize()
Dim ws As Worksheet, r As Range, tStr As String, wsname As String
Dim dicCols As Object
Dim arrCols As Variant
Dim Res As Variant
Dim idx As Long
arrCols = Array("EmpName", "EmpID", "EmpDepartmen", "EmpAddress")
Set dicCols = CreateObject("Scripting.Dictionary")
Set ws = ActiveSheet
Set r = ws.Range("1:1")
For idx = LBound(arrCols) To UBound(arrCols)
Res = Application.Match(arrCols(idx), r.Value, 0)
If Not IsError(Res) Then
dicCols(arrCols(idx)) = Res
Else
dicCols(arrCols(idx)) = "Not Found"
MsgBox arrCols(idx) & " column not found!", vbInformation, "Missing Column"
End If
Next idx
End Sub
Once this code is executed you can use dicCols(ColumnName) to get the column number.
For example, wherever you refer to the variable EmpName in the rest of the code you can use dicCols("EmpName").
Using a dictionary populated from a function
Another refinement might be to use a function to create the dictionary.
This would allow you to pass different sets of column names when required.
Option Explicit
Public dicCols As Object
Private Sub Class_Initialize()
Dim ws As Worksheet, r As Range, tStr As String, wsname As String
Dim arrColNames As Variant
Dim arrNotFound() As Variant
Dim ky As Variant
Dim cnt As Long
arrColNames = Array("EmpName", "EmpID", "EmpDepartment", "EmpAddress")
Set ws = ActiveSheet
Set r = ws.Range("1:1")
Set dicCols = GetColNos(arrColNames, r)
For Each ky In dicCols.keys
If dicCols(ky) = "Not Found" Then
cnt = cnt + 1
ReDim Preserve arrNotFound(1 To cnt)
arrNotFound(cnt) = ky
End If
Next ky
If cnt > 0 Then
MsgBox "The following columns were not found:" & vbCrLf & vbCrLf & Join(arrNotFound, vbCrLf), vbInformation, "Missing Columna"
End If
End Sub
Function GetColNos(arrColNames, rngHdr As Range) As Object
Dim dic As Object
Dim idx As Long
Dim Res As Variant
Set dic = CreateObject("Scripting.Dictionary")
For idx = LBound(arrColNames) To UBound(arrColNames)
Res = Application.Match(arrColNames(idx), rngHdr.Value, 0)
If Not IsError(Res) Then
dic(arrColNames(idx)) = Res
Else
dic(arrColNames(idx)) = "Not Found"
End If
Next idx
Set GetColNos = dic
End Function
Related
I have two global variables ErrorMsg and SectionName. What I want my macro to do is run through the code and if ErrorMsg is assigned a value, I want it to list the SectionName and then the ErrorMsg that was generated within that section. There are cases where ErrorMsg could appear in multiple different SectionNames thats why I want it to be labeled which Section generated the ErrorMsg.
There will be cases where there are more than two values for ErrorMsg so I need the macro to recognize all the values of ErrorMsg and SectionName list them.
So if errors are generated in lines wavelength_col = GetColumnIndex(ws, "Wavelength (nm)") and power_value = Getdata(ws, sysrow, power_col)
Then the output in With logsht should look like this with each new Section font bolded.
Complete with Error - Section: Wavelength - Wavelength column index could not be found, Section: Power - data could not be found
Here are the functions I mentioned above.
Global ErrorMsg As String, SectionName As String
Sub Main
Dim cell As Range, ws As Worksheet, sysnum As String, sysrow As Integer, wb As Workbook, logsht As Worksheet
Set wb = ActiveWorkbook
Set ws = ActiveWorksheet
Set logsht = wb.Worksheets("Log Sheet")
For Each cell In ws.Range("E2", ws.cells(ws.Rows.Count, "E").End(xlUp)).cells
sysnum = cell.Value
sysrow = cell.row
power_col = GetColumnIndex(ws, "Power (mW)")
power_value = GetJiraData(ws, sysrow, power_col)
Dim begincell As Long
With logsht
begincell = .cells(Rows.Count, 1).End(xlUp).row
.cells(begincell + 1, 2).Value = sysnum
.cells(begincell + 1, 2).Font.Bold = True
If Not ErrorMsg = "" Then
.cells(begincell + 1, 3).Value = "Complete with Erorr - " & ErrorMsg
.cells(begincell + 1, 3).Font.Bold = True
.cells(begincell + 1, 3).Interior.Color = vbRed
Else
.cells(begincell + 1, 3).Value = "Completed without Errors"
.cells(begincell + 1, 3).Font.Bold = True
.cells(begincell + 1, 3).Interior.Color = vbGreen
End If
End With
Next cell
End Sub
Sub Wavelength()
Dim wavelength_col As Long, wavelength_value As Double
SectionName = "Wavelength"
On Error GoTo errormessage
wavelength_col = GetColumnIndex(ws, "Wavelength (nm)")
wavelength_value = Getdata(ws, sysrow, wavelength_col)
Exit Sub
errormessage:
ErrorMsg = ErrorMsg
End Sub
Sub Power()
Dim power_col As Long, power_value As Double
SectionName = "Power"
On Error GoTo errormessage
power_col = GetColumnIndex(ws, "Average Power (mW)")
power_value = Getdata(ws, sysrow, power_col)
Exit Sub
errormessage:
ErrorMsg = ErrorMsg
End Sub
Function GetColumnIndex(sht As Worksheet, colname As String) As Double
Dim paramname As Range
Set paramname = sht.Range("A1", sht.cells(2, sht.Columns.Count).End(xlToLeft)).cells.Find(What:=colname, LookAt:=xlWhole, LookIn:=xlFormulas, searchorder:=xlByColumns, searchdirection:=xlPrevious, MatchCase:=True)
If Not paramname Is Nothing Then
GetColumnIndex = paramname.column
ElseIf paramname Is Nothing Then '
ErrorMsg = ErrorMsg & IIf(ErrorMsg = "", "", ", ") & colname & " column index could not be found"
End If
End Function
Function Getdata(sht As Worksheet, WDrow As Long, parametercol As Long) As Variant
Getdata = sht.cells(WDrow, parametercol)
If Getdata = -999 Then
ElseIf Getdata = Empty Then
ErrorMsg = ErrorMsg & IIf(ErrorMsg = "", "", ", ") & "data could not be found"
End If
End Function
first of all, there are several things wrong in your code.
Just to name a few;
your Power() sub uses ws as a WorkSheet object yet they are not declared as Global under the Main method nor are they used as parameters for the sub and hence will not be available? Same applies for Wavelength.
Power() and Wavelenght() both produce a variable yet you do not seem to do anything with those values?
But alas, for the solution;
What you can do is add a ClassModule to your project and give it below fields and name it 'ErrorState'
Option Explicit
Public ErrMsg As String
Public ErrNumber As Long
Public SectionName As String 'suggest to use 'MethodName' but your pick
Then in your CodeModule declare a new Collection as a a Global collection
Global Errors As New Collection
Then add a Method (a Sub if you wish) that adds the error to the collection.
Private Sub AddError(message As String, number As Long, method As String)
Dim error As New ErrorState
error.ErrMsg = message
error.SectionName = method
error.ErrNumber = number
Errors.Add error
End Sub
Add the above correctly to your ErrorHandling as per below example
Sub Power(sht As Worksheet, sysrow As Long)
On Error GoTo ErrorExit
Err.Raise (13) 'you can remove this, this is just to trigger an Error
Dim power_col As Long, power_value As Double
power_col = GetColumnIndex(sht, "Average Power (mW)")
power_value = Getdata(sht, sysrow, power_col)
Exit Sub
ErrorExit:
AddError Err.Description, Err.number, "Power"
End Sub
So your complete code would look like the below (I have simplified the Main method, but I'm sure you get the picture)
Global Errors As New Collection
Private Sub AddError(message As String, number As Long, method As String)
Dim error As New ErrorState
error.ErrMsg = message
error.SectionName = method
error.ErrNumber = number
Errors.Add error
End Sub
Sub Main()
Set Errors = New Collection
Dim wb As Workbook
Dim ws As Worksheet
Set wb = ThisWorkbook
Set ws = ActiveSheet
Wavelength ws, 1
Power ws, 1
Index = GetColumnIndex(ws, "SomeColum")
Data = Getdata(ws, 1, 1)
For Each e In Errors
Debug.Print e.SectionName, e.ErrMsg, e.ErrNumber
Next
End Sub
Sub Wavelength(sht As Worksheet, sysrow As Long)
On Error GoTo ErrorExit
Dim wavelength_col As Long, wavelength_value As Double
wavelength_col = GetColumnIndex(sht, "Wavelength (nm)")
wavelength_value = Getdata(sht, sysrow, wavelength_col) 'do you need to do anything with this value?
Exit Sub
ErrorExit:
AddError Err.Description, Err.number, "Wavelength"
End Sub
Sub Power(sht As Worksheet, sysrow As Long)
On Error GoTo ErrorExit
Dim power_col As Long, power_value As Double
power_col = GetColumnIndex(sht, "Average Power (mW)")
power_value = Getdata(sht, sysrow, power_col) 'do you need to do anything with this value?
Exit Sub
ErrorExit:
AddError Err.Description, Err.number, "Power"
End Sub
Function GetColumnIndex(sht As Worksheet, colname As String) As Double
Dim paramname As Range
Set paramname = sht.Range("A1", sht.Cells(2, sht.Columns.Count).End(xlToLeft)).Cells.Find(What:=colname, LookAt:=xlWhole, LookIn:=xlFormulas, searchorder:=xlByColumns, searchdirection:=xlPrevious, MatchCase:=True)
If Not paramname Is Nothing Then
GetColumnIndex = paramname.Column
Else
AddError Trim(colname & " column index could not be found"), 0, "GetColumnIndex"
End If
End Function
Function Getdata(sht As Worksheet, WDrow As Long, parametercol As Long) As Variant
Getdata = sht.Cells(WDrow, parametercol)
If Getdata = -999 Then
'do something
ElseIf IsEmpty(Getdata) Then
AddError "data could not be found", 0, "Getdata"
End If
End Function
Why is it not working?
Prints only the first word and I don't know how I can change "10" in "For" on something like "For each word in sentence"
Sub Change()
Dim S As String
Dim i As Integer
Dim x As String
S = InputBox("Sentence")
x = Split(S, " ")
For i = 1 To x
Cells(1, i).Value = Split(S, " ")
Next i
End Sub
Try this:
Public Sub Change()
Dim sentence As String: sentence = InputBox("Sentence")
Dim col As Long: col = 1
Dim word As Variant: For Each word In Split(sentence, " ")
ThisWorkbook.Worksheets("Sheet1").Cells(1, col).Value = word
col = col + 1
Next
End Sub
Split Sentence to Worksheet
Option Explicit
Sub SentenceToRow()
Const ProcTitle As String = "Sentence to Row"
Const First As String = "A1"
Dim S As Variant: S = InputBox("Input a Sentence", ProcTitle)
If Len(S) = 0 Then
MsgBox "You canceled.", vbExclamation, ProcTitle
Exit Sub
End If
Dim Strings() As String: Strings = Split(S)
Dim cCount As Long: cCount = UBound(Strings) + 1
Dim ws As Worksheet: Set ws = ActiveSheet
Dim rg As Range: Set rg = ws.Range(First).Resize(, cCount)
rg.Value = Strings
MsgBox "Sentence split to a row.", vbInformation, ProcTitle
End Sub
Sub SentenceToColumn()
Const ProcTitle As String = "Sentence to Column"
Const First As String = "A1"
Dim S As Variant: S = InputBox("Input a Sentence", ProcTitle)
If Len(S) = 0 Then
MsgBox "You canceled.", vbExclamation, ProcTitle
Exit Sub
End If
Dim Strings() As String: Strings = Split(S)
Dim rCount As Long: rCount = UBound(Strings) + 1
Dim ws As Worksheet: Set ws = ActiveSheet
Dim rg As Range: Set rg = ws.Range(First).Resize(rCount)
rg.Value = Application.Transpose(Strings)
MsgBox "Sentence split to a column.", vbInformation, ProcTitle
End Sub
this is fast and eficient:
Sub testSplit2Row()
Dim frase As String
frase = "las palabras de amor"
Dim ary As Variant
ary = Split(frase, " ")
Dim dest As Range
Dim start As Range
Set start = Range("B1")
Set dest = start.Resize(UBound(ary) + 1)
dest.Value = Application.Transpose(ary)
start.Resize(, UBound(ary) + 1).Value = ary
End Sub
If you dispose of the dynamic array functions of MSExcel 365, you might profit from the following function, usable as well as udf or via code.
The function words() accepts range values, array values or explicit string inputs as first argument s; the second argument IsVertical is optional and indicates that results will be returned as vertical array by default (instead of a "flat" array).
Public Function words(ByVal s As Variant, Optional IsVertical As Boolean = True)
'Debug.Print VarType(s)
If VarType(s) >= vbArray Then
s = Replace(Application.WorksheetFunction.ArrayToText(s), ",", "")
End If
words = Split(s)
If IsVertical Then
words = Application.WorksheetFunction.Transpose(Split(s))
End If
End Function
a) Example using a multi-row range input in B2
=words(A2:A4)
b) Example call via code
Option Explicit ' module head of code module
Sub ExampleCall
With Sheet1
Dim wds As Variant
wds = words(.Range("A2:A4"))
.Range("A10").Resize(UBound(wds), UBound(wds, 2)) = wds
End With
End Sub
If you intend, however to display results horizontally, just code as follows (note the dimension change!):
'...
wds = words(.Range("a2:a4"), False) ' False returns "flat" 1-dim array
.Range("A10").Resize(1, UBound(wds)) = wds
I need my loop to check for existing part numbers and only if there is no existing part number to add it to my table. If the part number already exists, to have a message box stating that it already exists. Its adding it to my table just fine, but will not give me the message box if there is already an existing part number.
Private Sub Add_Click()
Dim ws As Worksheet
Set ws = Sheet4
Dim X As Integer
Dim lastrow As Long
Dim PartColumnIndex As Integer
Dim DescriptionColumnIndex As Integer
Const Part = "CM ECP"
Const Description = "Material Description"
Dim PartNum As String
Dim MaterailDescription As String
Dim tbl As ListObject
Set tbl = ws.ListObjects("Master")
Dim newrow As ListRow
Set newrow = tbl.ListRows.Add
With ws
On Error Resume Next
Let PartColumnIndex = WorksheetFunction.Match(PartNum, .Rows(2), 0)
Let DescriptionColumnIndex = WorksheetFunction.Match(MaterialDecription, .Rows(2), 0)
Let lastrow = .Cells(.Rows.Count, PartColumnIndex).End(xlUp).Row
X = 3
Do
Let PartValue = .Cells(X, PartColumnIndex).Value
Let DecriptionColumnIndex = .Cells(X, DecriptionColumnIndex).Value
If TextBox1.Value = PartValue Then
MsgBox "Part Number " + TextBox1.Value + " already exists. Please try again or return to main screen."
ElseIf TextBox1.Value <> PartValue Then
With newrow
.Range(1) = TextBox1.Value
.Range(2) = TextBox2.Value
End With
ElseIf X < lastrow Then
X = X + 1
End If
Loop Until X > lastrow
End With
Scan all the rows in the table before deciding to add a new row or not, and always add Use Option Explicit to top of code to catch errors like DecriptionColumnIndex (no s).
Option Explicit
Sub Add_Click()
Const PART = "CM ECP"
Const DESCRIPTION = "Material Description"
Dim ws As Worksheet
Dim X As Integer, lastrow As Long
Dim PartColumnIndex As Integer, DescrColumnIndex As Integer
Dim PartNum As String, MaterialDescription As String
Dim tbl As ListObject, bExists As Boolean
Set ws = Sheet1
Set tbl = ws.ListObjects("Master")
With tbl
PartColumnIndex = .ListColumns(PART).Index
DescrColumnIndex = .ListColumns(DESCRIPTION).Index
PartNum = Trim(TextBox1.Value)
MaterialDescription = Trim(TextBox2.Value)
' search
With .DataBodyRange
lastrow = .Rows.Count
For X = 1 To lastrow
If .Cells(X, PartColumnIndex).Value = PartNum Then
bExists = True
Exit For
End If
Next
End With
' result
If bExists = True Then
MsgBox "Part Number `" & PartNum & "` already exists on Row " & X & vbLf & _
"Please try again or return to main screen.", vbExclamation
Else
With .ListRows.Add
.Range(, PartColumnIndex) = PartNum
.Range(, DescrColumnIndex) = MaterialDescription
End With
MsgBox "Part Number `" & PartNum & "` added", vbInformation
End If
End With
End Sub
Long time listener, first time caller.
Anyway, I could use a bit of help. I have a macro that adds Text Boxes, and names them "Fig Num " & ActiveSheet.Shapes.count.
Once all of these text boxes are spread through out the Workbook, I would like to rename all shapes with the name "Fig Num*", or at least the text inside them, to go in order from first page to last, top to bottom, and left to right.
Currently, my code will rename the the text boxes based on seniority. In other words, if I added a text box and it was labeled "Fig Num 3", it would still be named "Fig Num 3" whether it was on the first page or last page.
enter code here
Sub Loop_Shape_Name()
Dim sht As Worksheet
Dim shp As Shape
Dim i As Integer
Dim Str As String
i = 1
For Each sht In ActiveWorkbook.Worksheets
For Each shp In sht.Shapes
If InStr(shp.Name, "Fig Num ") > 0 Then
sht.Activate
shp.Select
shp.Name = "Fig Num"
End If
Next shp
For Each shp In sht.Shapes
If InStr(shp.Name, "Fig Num") > 0 Then
sht.Activate
shp.Select
shp.Name = "Fig Num " & i
Selection.ShapeRange(1).TextFrame2.TextRange.Characters.Text = _
"FIG " & i
i = i + 1
End If
Next shp
Next sht
End Sub
---
I have a workbook example, but I'm not sure how to load it up, this being my first time and all.
Edit:
I have found a code that will do what I'm looking for, however it's a bit clunky. I also need a good way to find the last row on the sheet that contains a shape. Since the shape names are based on creation, if I insert a shape in row 35 and use the shape.count. featured below, it will skip all shapes after row 35 unless I add additional rows that bog down the code.
Most Recent Code (loops through grouped shapes):
Private Sub Rename_FigNum2()
'Dimension variables and data types
Dim sht As Worksheet
Dim shp As Shape
Dim subshp As Shape
Dim i As Integer
Dim str As String
Dim row As Long
Dim col As Long
Dim NextRow As Long
Dim NextRow1 As Long
Dim NextCol As Long
Dim rangex As Range
Dim LR As Long
i = 1
'Iterate through all worksheets in active workbook
For Each sht In ActiveWorkbook.Worksheets
If sht.Visible = xlSheetVisible Then
LR = Range("A1").SpecialCells(xlCellTypeLastCell).row + 200
If sht.Shapes.Count > 0 Then
With sht
NextRow1 = .Shapes(.Shapes.Count).BottomRightCell.row + 200
'NextCol = .Shapes(.Shapes.Count).BottomRightCell.Column + 10
End With
If LR > NextRow1 Then
NextRow = LR
Else
NextRow = NextRow1
End If
End If
NextCol = 15
Set rangex = sht.Range("A1", sht.Cells(NextRow, NextCol))
For row = 1 To rangex.Rows.Count
For col = 1 To rangex.Columns.Count
For Each shp In sht.Shapes
If shp.Type = msoGroup Then
For Each subshp In shp.GroupItems
If Not Intersect(sht.Cells(row, col), subshp.TopLeftCell) Is Nothing Then
If InStr(subshp.Name, "Fig Num") > 0 Then
subshp.Name = "Fig Num " & i
subshp.TextFrame2.TextRange.Characters.Text = _
"FIG " & i
i = i + 1
End If
End If
Next subshp
Else
If Not Intersect(sht.Cells(row, col), shp.TopLeftCell) Is Nothing Then
If InStr(shp.Name, "Fig Num ") > 0 Then
shp.Name = "Fig Num " & i
shp.TextFrame2.TextRange.Characters.Text = _
"FIG " & i
i = i + 1
End If
End If
End If
Next shp
Next col
Next row
End If
Next sht
End Sub
Example of Workbook:
Rename Text Boxes
To use the ArrayList, you have to have .NET Framework 3.5 SP1 installed, even if you already have a later version (e.g. 4.7) installed.
It is assumed that each text box is an ActiveX control (not a Form control) and has a (per worksheet) unique top-left cell.
Option Explicit
Sub RenameTextBoxes()
Const oTypeName As String = "TextBox" ' OLEObject Type Name
Const fPattern As String = "Fig Num " ' Find Pattern (Unsorted)
Const tPattern As String = "Dummy" ' Temporary Pattern
Const nPattern As String = "Fig Num " ' New Pattern (Sorted)
Const ByRows As Boolean = False
Dim wb As Workbook: Set wb = ThisWorkbook ' workbook containing this code
Dim arl As Object: Set arl = CreateObject("System.Collections.ArrayList")
Dim dict As Object: Set dict = CreateObject("Scripting.Dictionary")
Dim ws As Worksheet
Dim ole As OLEObject
Dim Key As Variant
Dim n As Long
Dim r As Long
Dim Coord As Double
Dim tName As String
For Each ws In wb.Worksheets
arl.Clear
dict.RemoveAll
For Each ole In ws.OLEObjects
If TypeName(ole.Object) = oTypeName Then
If InStr(1, ole.Name, fPattern, vbTextCompare) = 1 Then
n = n + 1
If ByRows Then
Coord = GetNumericByRows(ole.TopLeftCell)
Else
Coord = GetNumericByColumns(ole.TopLeftCell)
End If
arl.Add Coord
tName = tPattern & n
ole.Name = tName
dict(Coord) = tName
End If
End If
Next ole
arl.Sort
For Each Key In arl
r = r + 1
ws.OLEObjects(dict(Key)).Name = nPattern & r
'Debug.Print nPattern & r, Key, dict(Key)
Next Key
Next ws
End Sub
Function GetNumericByColumns( _
ByVal OneCellRange As Range) _
As Double
If OneCellRange Is Nothing Then Exit Function
With OneCellRange.Cells(1)
GetNumericByColumns = Val(.Column & "." & Format(.Row, "000000#"))
End With
End Function
Function GetNumericByRows( _
ByVal OneCellRange As Range) _
As Double
If OneCellRange Is Nothing Then Exit Function
With OneCellRange.Cells(1)
GetNumericByRows = Val(.Row & "." & Format(.Column, "0000#"))
End With
End Function
' Modify the range address to see what the 'GetNumeric' functions are all about.
Sub GetNumericTEST()
Dim cCell As Range: Set cCell = Sheet1.Range("XFD1048576")
Debug.Print GetNumericByColumns(cCell)
Debug.Print GetNumericByRows(cCell)
End Sub
I would like to create the table based on the "Header" name and it's last row of the table.
I could found the Header start address and Length of the table also using some formulas.
For Example:
FindHeaderValue as 14 i.e, $B$14
TableLength as 65, i.e, $V$65
Hence, I would like to create the Table with the range for
$B$FindHeaderValue:$V$TableLength .
Because the FindHeaderValue and TableLength will vary Excel to Excel.
Please help to figure out the solution for the same. Thank you so much in advance.
Sub Test()
Dim sFindHeader As String
Dim oRangeFindHeader As Range, FirstRange As String, LastRange As String
Dim FindHeaderValue As Integer, FindLength As Integer, TableLength As Integer
Dim Ws As Worksheet
Set Ws = ThisWorkbook.Sheets("Sheet1")
Set oRangeFindHeader = Worksheets("8A52").Range("B1:V5000").Find("BBBB", lookat:=xlPart)
sFindHeader = oRangeFindHeader.Address(ReferenceStyle:=xlR1C1)
FindHeaderValue = GetNumber(sFindHeader)
FirstRange = oRangeFindHeader.Address
MsgBox FindHeaderValue
MsgBox FirstRange
FindLength = FindHeaderValue + 2
TableLength = Cells(FindLength, 13).End(xlDown).Row
MsgBox TableLength
Ws.ListObjects.Add(xlSrcRange, Ws.Range("$B$FindHeaderValue:$V$TableLength"), , xlYes).Name = "DefinitionTable"
Ws.ListObjects("DefinitionTable").TableStyle = "TableStyleLight1"
End Sub
Public Function GetNumber(s As String) As Long
Dim b As Boolean, i As Long, t As String
b = False
t = ""
For i = 1 To Len(s)
If IsNumeric(Mid(s, i, 1)) Then
b = True
t = t & Mid(s, i, 1)
Else
If b Then
GetNumber = CLng(t)
Exit Function
End If
End If
Next i
End Function
Variables don't belong inside quotes. Use & to concatenate them into the range address (which doesn't need $ by the way):
Ws.Range("B" & FindHeaderValue & ":V" & TableLength)