Find method has issues with small width columns? - excel

I was working in a Function that gives me the Column in wich it finds one value.
I was having trouble getting it done...But I made it work!!
The ERROR, believe it or not, was that the Find method has issues with finding values in cells which width is too small...
Could that be so dumb?
This is the call..
Private Sub CommandButton3_Click()
Direccion = BuscarCol(2)
MsgBox "the cell address is " & Direccion
End Sub
And this is the function...
Function BuscarCol(Fecha As Integer) As String
Dim RangoFech As Range
With Sheets("REGISTRO").Range("A1:IN1")
Set RangoFech = .Find(What:=Fecha, LookIn:=xlValues, LookAt:=xlWhole, SearchDirection:=xlNext, MatchCase:=False)
If Not RangoFech Is Nothing Then
BuscarCol = ConvertToLetter(RangoFech.Column)
End If
End With
End Function
Oh, and I have one more for converting Column numbers to letters, but this never was the problem..
Function ConvertToLetter(iCol As Integer) As String
Dim iAlpha As Integer
Dim iRemainder As Integer
iAlpha = Int(iCol / 27)
iRemainder = iCol - (iAlpha * 26)
If iAlpha > 0 Then
ConvertToLetter = Chr(iAlpha + 64)
End If
If iRemainder > 0 Then
ConvertToLetter = ConvertToLetter & Chr(iRemainder + 64)
End If
End Function
So...can you tell me if that is right? The Find method has that problem?

If you choose Look in: Values in the Find box, it will only find values that are visible. If the column is hidden, it won't find it. If the column is too narrow to display the value and it displays ### instead, it won't find it. Even if you format the cell as ;;; to effectively hide the value, it won't find it.
If you choose Look in: Formulas, it will find it in all those cases.
But if you have a formula that produces a value, and that value doesn't exist in the text of the formula, it won't find it. So =200+22 is in a cell and you search for 222
In Values: Only will find it if it's visible
In Formulas: Will not find it
It seems like an odd design decision. My theory is that the algorithm uses the Range.Text property. That property returns what is visible in the cells, such as ### for narrow columns, rather than .Value or .Value2.

Related

Excel: strange #VALUE error behaviour when using UDF

I know the topic "Excel formulas not updating" has been discussed a lot on many forums but I haven't found a useful solution to my problem.
In a worksheet, I am using built-in Excel formulas as well as own functions written with VBA in the module of the worksheet and I am referencing them within the worksheet.
There is a binary code which gets generated from a hexadecimal code in cell A1. The binary code gets calculated in cell B1.
Let's take following code as an example: 100001101110
Cell C1 contains following:
=DecodeVal(B1;0;20)
If I now paste a hex code into A1 and the binary code gets created in B1, cell C1 is displaying an #VALUE! error.
If I go back to cell A1, click in the textbox and press enter again, the correct value (= 2158) gets displayed.
Why is there a Value error at first, but not if I press enter one more time?
If I paste the binary code directly as text, there is no error at all.
This is the function I'm referring to:
Public Function DecodeVal(value, start As Integer, length As Integer) As Long
Dim abschnitt As String
Dim i As Integer
Dim valueText As String
valueText = value.Text
If (Len(valueText) - start - length + 1 > 0) Then
abschnitt = Mid(valueText, Len(valueText) - start - length + 1, length)
Else
If (Len(valueText) > start) Then
abschnitt = Left(valueText, Len(valueText) - start)
length = Len(valueText) - start
End If
End If
Do
If (Int(Left(abschnitt, 1)) = 1) Then
DecodeVal = DecodeVal * 2 + 1
Else
DecodeVal = DecodeVal * 2
End If
abschnitt = Right(abschnitt, length - 1)
length = length - 1
Loop While length > 0
End Function
Yes, calculation options are set to automatic.
Any suggestions?
Thanks
Using Range.Text is not recommended practice. This will particularly cause errors when the input column has less width than data and cell is displaying ######. If the formula is calculated then it will return #VALUE error. See the snapshot below.
If you adjust the column width and recalculate it will then show the correct result.
To get around this, use either valueText = value.Value2 or valueText = value.Value instead of valueText = value.Text.
Also, I'd suggest using something like RngValue as a declared variable/argument instead of value which is a Range property as well (as it may result in conflicts).
The next two things would solve your problem:
Change
Public Function DecodeVal(value, start As Integer, length As Integer) As Long
with
Public Function DecodeVal(val As Range, start As Integer, length As Integer) As Long
and use valueText = val.value
Be also sure that B1 is formatted as Text. The best way of formatting would be TextToColumns. Manually (from Data Tab) or in code:
Dim sh As Worksheet, rng As Range
Set sh = ActiveSheet
Set rng = sh.Range("B1:B10")
rng.TextToColumns Destination:=rng, fieldInfo:=Array(1, 2)
Otherwise, Excel guess can be a scientific format...
Within your Do loop, you are using DecodeVal in calculations, but never assigned it an initial value.
(there may be other errors)

Any ideas why VBA isn't being case-sensitive in a VLookup?

I've created a VBA Macro to look at a string of input text in the cell E3, split it into individual characters and then VLookup those characters against a table of individual character pixel widths, which is added to the code using a named range, "pw_Table".
The pixel-widths for each letter are then summed and displayed in a cell below the text input box - "Cells(4,5)". Hitting return is meant to show the combined pixel-width total for the complete string.
The problem is that it is not being case sensitive and is using the same VLookup value for both upper and lower case characters.
All the manuals I've seen say VBA is case sensitive on VLookup, and all I can find are ways to get around this.
For my issue, however, the VLookup must be case sensitive to make sure I get the correct pixel width for each letter, for example, "c" is 9 pixels wide, "C" is 13.
I have tried reordering the upper and lower case characters in the table to see if that made a difference, but it only uses the first values it encounters for each letter of the alphabet, whether they be upper- or lower-case.
I thought that I might use INDEX, MATCH, and EXACT, but couldn't see how to implement that in VBA.
This is the Macro code ...
Private Sub ReadCharacter()
cell_value = ThisWorkbook.Sheets("Pixel-widths").Range("E3")
Character_Value = 0
For rep = 1 To Len(cell_value)
Character = Mid(cell_value, rep, 1)
On Error GoTo MyErrorHandler
Character_Value = Application.WorksheetFunction.VLookup(Character, [pw_Table], 2, 0)
Pixel_Width = Pixel_Width + Character_Value
MyErrorHandler:
Character_Value = 10
Resume Next
Next rep
Cells(4, 5) = Pixel_Width
End Sub
I had some issues with numbers, with VBA reporting Run-time Error 1004, but I bodged this by adding an error trap because all the numerals from 0-9 are 10 pixels wide.
I simply can't see why VBA is breaking its own rules.
Vlookup isnt case sensitive.
ive found this function that "simulates" a vlookup case sensitive.
Function CaseVLook(FindValue, TableArray As Range, Optional ColumnID As Integer = 1) As Variant
Dim xCell As Range
Application.Volatile
CaseVLook = "Not Found"
For Each xCell In TableArray.Columns(1).Cells
If xCell = FindValue Then
CaseVLook = xCell.Offset(0, ColumnID - 1)
Exit For
End If
Next
End Function
to use it just call it CaseVLook(F1,A1:C7,3)
more information in here
https://www.extendoffice.com/documents/excel/3449-excel-vlookup-case-sensitive-insensitive.html
good luck
Here's another way...
Character_Value = Evaluate("INDEX(" & Range("pw_Table").Address(, , , True) & _
",MATCH(TRUE,EXACT(INDEX(" & Range("pw_Table").Address(, , , True) & ",0,1),""" & Character & """),0),2)")
Hope this helps!

Search from Excel combobox, returing results to userform

I'd like search from a combobox on a userform, returning 2 items from 2 different rows. So far I am using a predetermined location set to return the alternate rows.
My question is about this section:
Private Sub ComboBox1_Change()
If ComboBox1.Text = Sheet1.Cells(3, 1) Then
oHousing.Text = Sheet1.Cells(3, 2)
oMeal.Text = Sheet1.Cells(3, 3)
End If
End Sub
Here is what the pseudocode would do:
User selects item in combobox
combobox will search A1:A99 for item
then once item is found it will output B# and C# (# is based on location of A#)
B# is outputted to oHousing (textbox)
C# is outputted to oMeal (textbox)
On my sheet I have:
A2:A28 with random text (I used ABC's)
B2:B28 are random 3 digit numbers (numeric, eg: 001-999)
C2:C28 is Random 3 numbers (numeric, eg: 001-999)
Here's the rest of my code:
'Finds the difference in 2 known dates (returns whole number in textbox)
Private Sub CommandButton1_Click()
Dim firstDate As Date, secondDate As Date, n As Integer
firstDate = DateValue(sDate.Text)
secondDate = DateValue(EDate.Text)
n = DateDiff("d", firstDate, secondDate) - 0.5
dTotal.Text = n
End Sub
Private Sub CommandButton2_Click() 'Exit the userform (PerDiem)
Unload PerDiem
End Sub
Thanks to all in advance!
You can use the Find function.
If a value is found, you can return the Row Number with Found.Row and Column Index with Count.Column
Private Sub ComboBox1_Change()
Dim Found As Range
Set Found = Sheet1.Range("A1:A99").Find(ComboBox1.Text, , xlValues, xlWhole)
If Found Is Nothing Then
'What do you want to do if your value in CommboBox is not found in the range?
Else
oHousing.Text = Sheet1.Cells(Found.Row, 2)
oMeal.Text = Sheet1.Cells(Found.Row, 3)
End If
End Sub
If you are sure that your ComboBox value will always exist in your range (maybe you systematically programmed your ComboBox values this way) you can skip the check and simply use:
Dim Found As Range
Set Found = Sheet1.Range("A1:A99").Find(ComboBox1.Text, , xlValues, xlWhole)
oHousing.Text = Sheet1.Cells(Found.Row, 2)
oMeal.Text = Sheet1.Cells(Found.Row, 3)
You can find properties of the Find method here. If you are looking for text, you may need to distinguish between case sensitivity (for your needs, does THIS = this?). The properties that are currently applied means the function is looking for values (xlValues), specifically, looking at the whole value of the cell (xlWhole). I.E. (this value will not match with this)

Excel - How do programmatically convert 'number stored as Text' to Number?

I'm looking for a simple Excel VBA or formula that can convert an entire row in Excel from 'number stored as Text' to an actual Number for vlookup reasons.
Can anyone point me in the right direction?
Better Approach
You should use INDEX(MATCH) instead of VLOOKUP because VLOOKUP behaves in an unpredictable manner which causes errors, such as the one you're presumably experiencing.
INDEX ( <return array> , MATCH ( <lookup value> , <lookup array> , 0) )
Using 0 as the last argument to MATCH means the match must be exact
Here is some more in-depth information on INDEX(MATCH)-ing
Further
Add zero +0 to convert a value to a number.
This can be (dangerously) extended with IFERROR() to turn non-numeric text into a zero:
=A2+0
=IFERROR(A2+0,0)
For the inverse, you can catenate an empty string &"" to force the value to be a string.
Notes
If 0 is not used as the last argument to MATCH, it will find all sorts of unexpected "matches" .. and worse, it may find a different value even when an exact match is present.
It often makes sense to do some extra work to determine if there are duplicates in the MATCH lookup column, otherwise the first value found will be returned (see example).
Help with MATCH comes from here, notably the matching logic the 3rd argument controls.
This should work if you add it before your vlookup or index/match lines:
Sheets("Sheet1").UsedRange.Value = Sheets("Sheet1").UsedRange.Value
I did find this, but does anyone have a formula as well?
Sub macro()
Range("F:F").Select 'specify the range which suits your purpose
With Selection
Selection.NumberFormat = "General"
.Value = .Value
End With
End Sub
http://www.ozgrid.com/forum/showthread.php?t=64027
Try this:
Sub ConvertToNumber()
Application.ScreenUpdating = False
Dim cl As Range
For Each cl In Selection.Cells
cl.Value = CInt(cl.Value)
Next cl
Application.ScreenUpdating = True
End Sub
To use it, simply select the relevant block of cells with the mouse, and then run the macro (Alt+F8 to bring up the dialogue box). It will go through each cell in the selected range and convert whatever value it holds into a number.
I wrote a custom vlookup function that doesn't care about data formats. Put this into a module in VBA and use = VLOOK instead of = VLOOKUP
Public Function VLook(sValue As String, rDest As Range, iColNo As Integer)
' custom vlookup that's insensitive to data formats
Dim iLastRow As Long
Dim wsDest As Worksheet
Set wsDest = Sheets(rDest.Parent.Name)
iLastRow = wsDest.Range(wsDest.Cells(100000, rDest.Column).Address).End(xlUp).Row
If iLastRow < rDest.Row + rDest.Rows.Count Then
For X = rDest.Column To rDest.Column + rDest.Columns.Count
If wsDest.Cells(100000, X).End(xlUp).Row > iLastRow Then iLastRow = wsDest.Cells(100000, X).End(xlUp).Row
Next X
End If
sValue = UCase(Application.Clean(Trim(sValue)))
For X = rDest.Row To iLastRow
If UCase(Application.Clean(Trim(wsDest.Cells(X, rDest.Column)))) = sValue Then
VLookDM = wsDest.Cells(X, rDest.Column + iColNo - 1)
Exit For
End If
Next X
End Function
The easiest way I can think of is using the built-in function =VALUE(TEXT_TO_CONVERT_TO_STRING).

Excel VBA How to select variable range of cells

I tried to search this problem but found no similar issue.
I am still newbie in VBA and I'm trying to create macro which chooses range of cells depending on the user's input and then creates an outlined grid out of those selected cells.
I have two ActiveX buttons in my Excel workbook which let the user to input how big the grid is they want to use (Width & Height). I am struggling to include the above mentioned width and height to my code. Here is the code for the buttons (nothing unclear about them):
Private Sub Height_Click()
Dim Height As Integer
Height = InputBox("Syötä ruudukon korkeus", "Ruudukon korkeus", "Syötä tähän")
Range("E5") = Height
End Sub
And width button:
Private Sub Width_Click()
Dim Width As Integer
Width = InputBox("Syötä ruudukon leveys", "Ruudukon leveys", "Syötä tähän")
Range("E2") = Width
End Sub
I want my grid to start from cell "G2" and expand right&down from there and change the size of the selected cells. However the code I have written isn't working at all (as I thought). Here is the code:
Private Sub CreateGrid_Click()
Columns("G:G+E2").Select
Selection.ColumnWidth = 1
Rows("2:2+E5").Select
Selection.RowHeight = 1
End Sub
Cells "E2" and "E5" have the values of width and height printed, respectively. Nothing happens when I click the CreateGrid-button. Any ideas how I can make this code work? Thanks a lot for all answers.
-Teemu
The trick is use the record macro button.
This function will record all instruction that you are doing with the excel book while is recording
Example:
1.- Start the record macro and type a name for your macro.
2.- Select any cell and type a value
3.- select a range of cells that you want
4.- Press the stop macro recording.
5.- Press Alt +F11 and you will see that excel generate a code of what you did
in excel while the macro recording was turned on, even you can know how to type a value inside a cell or select a range of it.
EDIT:
Private Sub CreateGrid_Click()
Range("G2:" & Range("G2").Offset(Range("E5").Value,Range("E2").Value).Addresslocal).Select
End Sub
If this doesn't do what you expect, please let me know and I will try to help correct it.
the command you're looking for is Range().Select but you'll need to create the string that goes into the parenthesis. So if I understand correct you have stored in variables the number of rows and number of columns you want to offset from G2 right ?
In order to get the column letter you can use the function supplied by microsoft here
Function ConvertToLetter(iCol As Integer) As String
Dim iAlpha As Integer
Dim iRemainder As Integer
iAlpha = Int(iCol / 27)
iRemainder = iCol - (iAlpha * 26)
If iAlpha > 0 Then
ConvertToLetter = Chr(iAlpha + 64)
End If
If iRemainder > 0 Then
ConvertToLetter = ConvertToLetter & Chr(iRemainder + 64)
End If
End Function
but since you're starting from G you'll have to call the function like this:
ConvertToLetter(7+numerColumns)
your final code will look like
Range("G" & 2 + numberLines & ":" & ConvertToLetter(7+numberCols) & numberLines).Select
where numberLines is the number of lines to offset and numberCols the number of columns.
EDIT:
A shorter way, as pointed out by #Kyle, would be to use:
Range("G2").Offset(numberLines,numberCols).Select

Resources