Excel-VBA get number from letter equivalent entry in a textbox - vba

I have a user form that asks for a column reference to be entered into a TextBox. I am trying to make it so that the number replaces the letter in the code. I am using the Cells(a,b) format to do this. Which is why I need the number to replace the letter.
Worksheets("AIO").Cells(X, TextBox3).Value = Worksheets("FDSA").Cells(Y, TextBox4).Value
Hence in the previous code when: x=2, TextBox3.Value=A, y=4, and TextBox4.Value=AA
The code will work as
Worksheets("AIO").Cells(2, 1).Value = Worksheets("FDSA").Cells(4, 27).Value
The only thing I can think of making is a huge if statement were I code something similar like this:
If textbox3.value ="A" then
textbox3.value=1
elseif textbox3.value=E then
textbox3.value=5
.......
.......
textbox3.value=AD then
textbox3.value=30
End If

If you want to keep it uncomplicated, .Cells can use the column string instead of number
Sub test()
'From sheet module
Debug.Print Me.Cells(1, 1).Address 'prints $A$1
Debug.Print Me.Cells(1, "A").Address 'also prints $A$1
End Sub
You might have to validate that it's a valid column ID but you probably need to do that even converting it to a number.

On way to get a column number from a character string:
Sub ColumnNumber()
Dim s As String
Dim L As Long
s = "AB"
L = Cells(1, s).Column
MsgBox L
End Sub

Related

Assign value to a range with a variable column refreence

The following code gives me a compile error:expected: separator or ).
Public Sub test1()
Dim first_column As String,a_tab as string
a_tab="Sheet1"
first_column = "A"
ThisWorkbook.Sheets(a_tab).Range(first_column&"10").value="hello"
End Sub
I know we can do it when the row reference is a variable, i.e.
Public Sub test1()
dim fist_row as integer, a_tab as string
a_tab="Sheet1"
first_row=10
ThisWorkbook.Sheets(a_tab).Range("A"&first_row).value="hello"
End Sub
Could someone help? Many thanks.
Get out of the habit of using a letter for the column designation.
Your first column is column 1:
Columns(1).Value = "Hello" will place "Hello" in every cell in column 1 - Range(A1:A1048576).
The second cell in column 1:
Cells(2, 1) = "Hello" will place "Hello" in row 2, column 1 - Range(A2).
A range of cells designated by a start and end cell:
Range(Cells(2, 1), Cells(4, 2)) = "Hello" will place "Hello" in every cell between row 2, column 1 and row 4, column 2 - Range("A2:B4")
The first, second, third & fourth columns:
Range(Cells(1,1),Cells(1,4)).EntireColumn - Range("A:D").
But, saying that the only thing that caused your code to fail was spacing. You'll notice with the row variable it keeps putting the spaces back in - doesn't seem to do that with the column variable:
ThisWorkbook.Sheets(a_tab).Range(first_column & "10").Value = "hello"
- add a space either side of the ampersand.
Edit:
Consider placing values in columns CB:CL using a loop. Using numbers you'd just write:
Sub Test()
Dim x As Long
For x = 80 To 90
Cells(1, x) = "Hello"
Next x
End Sub
Using letters you'd have to use something like:
Sub Test()
Dim col_Letter As String
col_Letter = "CB"
Do
Range(col_Letter & "10") = "Hello"
'Get the next column letter by finding the address, splitting it and extracting just the column letter.
col_Letter = Split(Range(col_Letter & "10").Offset(, 1).Address(True, False), "$")(0)
Loop While col_Letter <> "CL"
End Sub
Are you missing spaces when concatenating strings in your argument to Range? ThisWorkbook.Sheets(a_tab).Range(first_column & "10").value="hello" Works for me if I add the spaces.

Excel cell content validation with use of VBA code

I am looking for a solution to validate and highlight my cell in case false.
I tried the most promising solution: Regex. But still can not find the pattern I need.
My latest attempt was this pattern: "[A-Z-0-9_.]" This works only if the cell contains only a symbol and nothing else, if the symbol is part of a string it does not work.
Problem is that it does not catch cells that have an odd character in a string of text: Example C4UNIT| or B$GROUP.
Specification Cell can contain only capital characters and two allowed symbols Dash - and Underbar _
This is my complete code:
Function ValidateCellContent()
Sheets("MTO DATA").Select
Dim RangeToCheck As Range
Dim CellinRangeToCheck As Range
Dim CollNumberFirst As Integer
Dim CollNumberLast As Integer
Dim RowNumberFirst As Integer
Dim RowNumberLast As Integer
'--Start on Column "1" and Row "3"
CollNumberFirst = 1
RowNumberFirst = 3
'--Find last Column used on row "2" (Write OMI Headings)
CollNumberLast = Cells(2, Columns.count).End(xlToLeft).Column
RowNumberLast = Cells(Rows.count, 1).End(xlUp).Row
'--Set value of the used range of cell addresses like: "A3:K85"
Set RangeToCheck = Range(Chr(64 + CollNumberFirst) & RowNumberFirst & ":" & Chr(64 + CollNumberLast) & RowNumberLast)
Debug.Print "Cells used in active Range = " & (Chr(64 + CollNumberFirst) & RowNumberFirst & ":" & Chr(64 + CollNumberLast) & RowNumberLast)
For Each CellinRangeToCheck In RangeToCheck
Debug.Print "CellinRangeToCheck value = " & CellinRangeToCheck
If Len(CellinRangeToCheck.Text) > 0 Then
'--Non Printables (Space,Line Feed,Carriage Return)
If InStr(CellinRangeToCheck, " ") _
Or InStr(CellinRangeToCheck, Chr(10)) > 0 _
Or InStr(CellinRangeToCheck, Chr(13)) > 0 Then
CellinRangeToCheck.Font.Color = vbRed
CellinRangeToCheck.Font.Bold = True
'--Allowed Characters
ElseIf Not CellinRangeToCheck.Text Like "*[A-Z-0-9_.]*" Then
CellinRangeToCheck.Font.Color = vbRed
CellinRangeToCheck.Font.Bold = True
Else
CellinRangeToCheck.Font.Color = vbBlack
CellinRangeToCheck.Font.Bold = False
End If
End If
Next CellinRangeToCheck
End Function
Try this:
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
'we want only validate when cell content changed, if whole range is involved (i.e. more than 1 cell) then exit sub
If Target.Cells.Count > 1 Then Exit Sub
'if there is error in a cell, also color it red
If IsError(Target) Then
Target.Interior.ColorIndex = 3
Exit Sub
End If
'validate cell with our function, if cell content is valid, it'll return True
'if it i s not valid, then color cell red
If Not ValidateText(Target.Value) Then
Target.Interior.ColorIndex = 3
End If
End Sub
Function ValidateText(ByVal txt As String) As Boolean
Dim i As Long, char As String
'loop through all characters in string
For i = 1 To Len(txt)
char = Mid(txt, i, 1)
If Not ((Asc(char) >= 65 And Asc(char) <= 90) Or char = "-" Or char = "_") Then
'once we come upon invalid character, we can finish the function with False result
ValidateText = False
Exit Function
End If
Next
ValidateText = True
End Function
I've originally assumed you wanted to use RegEx to solve your problem. As per your comment you instead seem to be using the Like operator.
Like operator
While Like accepts character ranges that may resemble regular expressions, there are many differences and few similarities between the two:
Like uses ! to negate a character range instead of the ^ used in RegEx.
Like does not allow/know quantifiers after the closing bracket ] and thus always matches a single character per pair of brackets []. To match multiple characters you need to add multiple copies of your character range brackets.
Like does not understand advanced concepts like capturing groups or lookahead / lookbehind
probably more differences...
The unavailability of quantifiers leaves Like in a really bad spot for your problem. You always need to have one character range to compare to for each character in your cell's text. As such the only way I can see to make use of the Like operator would be as follows:
Private Function IsTextValid(ByVal stringToValidate As String) As Boolean
Dim CharValidationPattern As String
CharValidationPattern = "[A-Z0-9._-]"
Dim StringValidationPattern As String
StringValidationPattern = RepeatString(CharValidationPattern, Len(stringToValidate))
IsTextValid = stringToValidate Like StringValidationPattern
End Function
Private Function RepeatString(ByVal stringToRepeat As String, ByVal repetitions As Long) As String
Dim Result As String
Dim i As Long
For i = 1 To repetitions
Result = Result & stringToRepeat
Next i
RepeatString = Result
End Function
You can then pass the text you want to check to IsTextValid like that:
If IsTextValid("A.ASDZ-054_93") Then Debug.Print "Hurray, it's valid!"
As per your comment, a small Worksheet_Change event to place into the worksheet module of your respective worksheet. (You will also need to place the above two functions there. Alternatively you can make them public and place them in a standard module.):
Private Sub Worksheet_Change(ByVal Target As Range)
Dim ValidationRange As Range
Set ValidationRange = Me.Range("A2:D5")
Dim TargetCell As Range
For Each TargetCell In Target.Cells
' Only work on cells falling into the ValidationRange
If Not Intersect(TargetCell, ValidationRange) Is Nothing Then
If IsTextValid(TargetCell.Text) Then
TargetCell.Font.Color = vbBlack
TargetCell.Font.Bold = False
Else
TargetCell.Font.Color = vbRed
TargetCell.Font.Bold = True
End If
End If
Next TargetCell
End Sub
Regular Expressions
If you want to continue down the RegEx road, try this expression:
[^A-Z0-9_-]+
It will generate a match, whenever a passed-in string contains one or more characters you don't want. All cells with only valid characters should not return a match.
Explanation:
A-Z will match all capital letters,
0-9 will match all numbers,
_- will match underscore and dash symbols.
The preceding ^ will negate the whole character set, meaning the RegEx only matches characters not in the set.
The following + tells the RegEx engine to match one or more characters of the aforementioned set. You only want to match your input, if there is at least one illegal char in there. And if there are more than one, it should still match.
Once in place, adapting the system to changing requirements (different chars considered legal) is as easy as switching out a few characters between the [brackets].
See a live example online.

How can I refer to a data in a different row?

I've got an Excel file with N rows and M columns. Usually data are organized one per row, but it can happens that a data occupy more than a row. In this case how can I express that the second (or next) row has to refer to the first row?
In this example, AP.01 has got 5 rows of description, so how can I say that the other 4 rows refer also to the first code?
EDIT once that I did the association I have to export my Excel file into an Access DB. So I want to see the tables with the correct data.
If I have only one row for the description I wrote this code and it works:
If grid(r, 3).Text.Length > 255 Then
code.Description = grid(r, 3).Text.ToString.Substring(0, 252) + "..."
Else
code.Description = grid(r, 3).Text.ToString
End If
Instead if I have more than one row for the description I wrote this code and it doesn't work:
Do While grid(r, 1).ToString = ""
If grid(r, 1).ToString = "" And grid(r, 3).ToString IsNot Nothing Then
Dim s As String
s = grid(r, 3).ToString
code.Description = grid((r - 1), 3).ToString & s
End If
Loop
If it is a one-off, try the below. This will basically put a formula in every cell that refers to the cell immediately above it:
Select column A (from top until bottom of list (row N)
Press ctrl + g to open the GoTo dialogue
Press Special
Select Blanks from the radio buttons
The above will select all the blank cells in column A. Now enter = and press up arrow. Enter the formula by holding down ctrl while pressing enter. That will enter the same formula in every cell.
Try
Sub Demo()
Dim ws As Worksheet
Set ws = ThisWorkbook.Sheets("Sheet3") 'change Sheet3 to your data sheet
With .Range("A:A").SpecialCells(xlCellTypeBlanks)
.FormulaR1C1 = "=R[-1]C"
.Value = .Value
End With
End Sub
From your question I Guess that, you must be define a variable for last column Value. and check the value in respective column, if it is empty then use column value if not empty then take current value as last value.
'Dim LastValue as string
LastValue = sheet("SheetName").cells(i,"Column Name").value
for i = 2 to LastRow '>>>> here i am assume you run code in for loop from row to
'to last count row(LastRow as variable)
'Put your sheet name at "SheetName" and column index (like "A","B","C"...) at "Column Name"
if sheet("SheetName").cells(i,"Column Name").value <>"" then
LastValue = sheet("SheetName").cells(i,"Column Name").value
end if
'(Do your stuff using LastValue , you may generate lastvalue 1, lastvalue2 ..etc)
next'for loop end here

Excel VBA, Null textbox, and CInt

What I'm trying to do is take the values from 4 textboxes and put them into 4 different sheets, but they need to be Integers so the Average and Sum functions work. But if the value is Null to clear the textbox so that value isn't calculated into the Monthly Sums or Averages. I keep getting a Type Mismatch Error with the Else clause, and when I mouse over it, it shows me frmDataEntry.tbBloodDraws = "". I thought that the else clause would just take the value and change it to an Int as long as it wasn't empty or Null? What am I missing?
Private Sub btnOK_Click()
' Get currently selected Cell of the Data Entry Sheet
Dim DataEntryCell As String
DataEntryCell = ActiveCell.Address
'Copy values from the dialog box into the correct sheets
Worksheets("Blood Draws").Activate
Range(DataEntryCell).Select
If (IsNull(frmDataEntry.tbBloodDraws)) Then
ActiveCell.Value = ActiveCell.Clear
Else
ActiveCell.Value = CInt(frmDataEntry.tbBloodDraws)
End If
End Sub
Use ClearContents to remove only the content of the cell and then check with IsNumeric if the string can be interpreted as number.
If tbBloodDraws.Text = "" Then
ActiveCell.ClearContents
ElseIf IsNumeric(tbBloodDraws.Text) Then
ActiveCell.value = CInt(tbBloodDraws.Text)
End If

VBA Excel: Show visible cells in listbox only

I have the below mentioned code, I am trying to load filtered cells only into the listbox but I don't know why the below mentioned code is not functional.
Legend:
PatternSearchButton is a button
PatternTextBox is a textbox by which the user enters a value Which the Sheet will filter.
WsLookup is a function which selects the sheet (completely functional)
Private Sub PatternSearchButton_Click()
Dim PatternInput As String, PatternCounter As Double, WsSelector As Worksheet
PatternInput = PatternTextBox.Value
Set WsSelector = WsLookup(GSMListType.Value)
WsSelector.Range("F:F").AutoFilter Field:=1, Criteria1:=PatternInput
PatternCounter = Application.WorksheetFunction.Subtotal(4, WsSelector.Range("F:F"))
With AvailableNumberList
.Clear
For k = 2 To PatternCounter + 1
.AddItem WsSelector.Range("A" & k).SpecialCells(xlCellTypeVisible).Value
Next k
End With
End Sub
You're are using PatternCounter as the upper limit in your For .. Next but this is being set using the MAX (e.g. 4) subfunction of SUBTOTAL. This might work on sequential numbers in an unfiltered list but it is unlikely to be accurate in a filtered list. Using the COUNT (2/102) or COUNTA (3/103) subfunction might be more appropriate.
You were using SUBTOTAL(4, ...) so I would assume that you are dealing with numbers. Use a straight count on numbers on visible cells in column F and modify the remainder of the code to resemble this.
PatternCounter = Application.WorksheetFunction.Subtotal(2, WsSelector.Range("F:F"))
With WsSelector.cells(1,1).currentregion.offset(1,0).SpecialCells(xlCellTypeVisible)
AvailableNumberList.Clear
For k = 1 To PatternCounter
AvailableNumberList.AddItem .cells(k, 1).Value
Next k
End With
The problem might stem from the fact that you add to the list box the value of a special cell that might not exist if the cell is hidden.
Try for the body of the For loop:
' ... previous code '
If Not WsSelector.Rows(k).EntireRow.Hidden Then
.AddItem WsSelector.Cells(k, 1).Value
End If
' rest of the code ... '
Also, make sure that AvailableNumberList points to the correct object in your code.