VBA - Index SumProduct with mis - vba

I am new to VBA and am working on a userform at the moment that has 3 ComboBoxes that a user picks 1 item from each. The intent is for the code to look up the corresponding 4th value from the spreadsheet and return it to a textbox on the userform. Right now I'm getting a "Type Mismatch (Error 13):"
I have been fiddling with this for going on 3 days now. Some websites say the SumProduct function doesn't work in VBA, some say it does as long as you specify "WorkSheetFunction", and still some say you should instead use 'evaluate'.
Like in this post:
SUMPRODUCT Formula in VBA
(I didn't have much luck using 'evaluate' but my syntax might have been off)
Anyway, I created a quick example to show what I am trying to do. If anyone can help it would be tremendously appreciated.
worksheetdata
this is the code I have been trying:
Private Sub TestButton_Click()
textboxTesting.Text = Application.WorkSheetFucntion.Index(Range("Thickness"), _
Application.WorkSheetFucntion.SumProduct((Range("Wood") = "Oak") _
* (Range("Metal") = "Copper") * (Range("Box") = "Red")), 0)
End Sub

A better approach is to write your own function, I believe the below is much more understandable:
Sub Test()
Dim thickness
thickness = FindThickness("oak", "copper", "red")
MsgBox (thickness)
End Sub
Function FindThickness(wood As String, metal As String, box As String) As String
Dim rng As Range
Set rng = Range("Wood")
For Each cell In rng
If cell.Value = wood _
And cell.Offset(0, 1).Value = metal _
And cell.Offset(0, 3).Value = box Then
FindThickness = cell.Offset(0, 2).Value
Exit Function
End If
Next cell
End Function

Related

VBA - Adding to an existing formula

I have various formulas in a spreadhseet that I need to convert to a different unit of measure.
Some are as simple a value such as 889 and others are a formula such as the below;
=Incision_Point_1x+(Arm_Depth_1-Graphic_Radius)
I'd like to use VBA to quickly take the existing formula / value and convert it to;
=(889/Unit_of_Measure_Multiplier)
=(Incision_Point_1x+(Arm_Depth_1-Graphic_Radius)/Unit_of_Measure_Multiplier)
How can I do this?
I used the following code;
Range("B3") = "=(" & Range("B3") & "/" & "Unit_Of_Measure_Multiplier)"
Which works perfectly when you have a whole number but deletes the formula and replaces it with a value for my second example, which defeats the point.
Additionally, how do I then apply this to a large data range? i.e. apply it to range B3:D100?
Try this code:
Sub test1()
For Each cl In Range("B3:D100")
If cl.HasFormula Then
v = Mid(cl.Formula, 2) 'remove leading =
Else
v = cl.Value
End If
frm = "=(" & v & "/Unit_Of_Measure_Multiplier)"
Debug.Print frm 'check that this is what you want
cl.Formula = frm
Next
End Sub
Please, try the next way:
Sub adaptFormula()
Dim rngFormula As Range, cel As Range
On Error Resume Next 'for the case of no formula in the range...
Set rngFormula = Range("B3:D100").SpecialCells(xlCellTypeFormulas)
On Error GoTo 0
If rngFormula Is Nothing Then Exit Sub
For Each cel In rngFormula.cells 'iterate only between cells having a formula
If InStr(cel.Formula, "=(Inc") > 0 Then
cel.Formula = Replace(cel.Formula, "Incision_Point_1x+(Arm_Depth_1-Graphic_Radius)", "889")
End If
Next
End Sub
Please, check if "Incision_Point_1x+(Arm_Depth_1-Graphic_Radius)" as you show us, is not "Incision_Point_1x + (Arm_Depth_1-Graphic_Radius" (spaces in front and after "+"), as it looks to me more probably. If so, please adapt the string to be replaced according to your real formula string...

Number stored as text to number with VBA

I have some columns that have cells that are "Number stored as text", which is causing problems with other code that is trying to copy one range to another
rng1.Copy Destination:=rng2
The destination range (rng2) is blank. Not had this issue with any other data, just when these "Number stored as text" are there, so I need to, via VBA, be able to convert them to number.
Looking around there seems to be two methods for this, but neither are working for me...
TextToColumnns:
rng1.Select
Selection.TextToColumns Destination:=Range(rng1), DataType:=xlDelimited
Value = value:
Range(rng1).Select
With Selection
.NumberFormat = "General"
.Value = .Value
End With
Other ways I have discovered are 100+ lines of code long which surely cannot be right??
What is the best way to achieve this?
What is wrong with something like this:
Public Sub TestMe()
With Selection
.NumberFormat = "0.00"
.Value = .Value
End With
End Sub
You can convert them with this:
Function text_to_number(txt As String) As Double
text_to_number = txt * 1.0
End Function
So, first of all, you need to convert them, and after this, copy to another place.
Something like this:
Sub copy_and_paste()
Dim numbers(30) As Double
'Copping from range A1:A30
For i = 1 To 30
numbers(i) = text_to_number(Cells(i, 1).Value)
Next i
'Pasting tn B1:B30
For i = i To 30
Cells(i, 2).Value = numbers(i)
Next i
End Sub

Convert sub to function to use it as a formula

The below code is working fine with me. I need your help and support to make it a function so I can for example write in any cell
=adj() or =adj(A1) and the formula will apply,
Sub adj()
Dim i, j As Integer
Sheet1.Select
With Sheet1
j = Range(ActiveCell.Offset(0, -2), ActiveCell.Offset(0, -2)).Value
For i = 1 To j
ActiveCell.Formula = "=" & Range(ActiveCell.Offset(0, -1), ActiveCell.Offset(0, -1)) & i & "))" & "&char(10)"
Next i
End With
End Sub
It's hard for me to definitively understand what you're trying to do here. I think you're trying to concatenate x number of cells with a separator field.
So, I would do the following changes... obviously you can change accordingly.
Declare the Inputs as variants. If you don't and get a type mismatch the function wont call in debug. This also gives you the opportunity to deal with the Inputs.
Put in an error handler to prevent unwanted debug w.r.t. a failure.
You can't use Evaluate that way. I think you're trying to get an Evaluation of cells like A1 etc.
The function has to be called from a Cell on a sheet since it uses Application.Caller. You shouldn't really need this for the function to work, but I put in in there in case you are calling via F9 calculation.
You can also put in the line if you want the calculation to occur every time you recalculate. However this should be used with caution since you can get some unwanted calculation side effects with some spreadsheets when using this.
Application.Volatile
Public Function Adj(ByVal x As Variant, ByVal y As Variant) As String
On Error GoTo ErrHandler
Dim sSeparator As String, sCol As String
Dim i As Integer
'Get the column reference.
sCol = Split(Columns(y).Address(False, False), ":")(1)
'Activate the sheet.
Application.Caller.Parent.Select
sSeparator = Chr(10)
For i = 1 To x
Adj = Adj & Evaluate(sCol & i) & sSeparator
Next
'Remove the last seperator...
Adj = Left(Adj, Len(Adj) - 1)
Exit Function
ErrHandler:
'Maybe do something with the error return value message here..
'Although this is a string, Excel will implicitly convert to an error.
Adj = "#VALUE!"
End Function
If you wanted to pass change to a formula, and pass in the range, you would use something like:
Public Function Func(Byval MyRange as range) as variant
In this case, you're not specifying a return value so it will be ignored.
Public Function Func(Byval MyRange as range) as variant
Dim i, j As Integer
With MyRange.parent
j = .Range(MyRange.Offset(0, -2), MyRange.Offset(0, -2)).Value
For i = 1 To j
MyRange.Formula = "=" & .Range(MyRange.Offset(0, -1), MyRange.Offset(0, -1)) & i & "))" & "&char(10)"
Next i
End With
End Sub
It would be something like that..

How to change range to run only when there information

I have an excel sheet where I am doing a VlookUP using VBA. The problem is that I extract information, and the amount is always different. I want to find a way to add to the code that will add information until there is no more information to add.
Here is the code that works but only for the cells I put in:
Sub vLook()
With ThisWorkbook.Worksheets("EODComponents").Range("f5:F200")
.Formula = "=VLOOKUP(C5,($H$5:$i$34),2,FALSE)"
.Value = .Value
End With
End Sub
You can set a lastRow:
Sub vLook()
Dim lastRow as Long
With ThisWorkbook.Worksheets("EODComponents")
lastRow = .Cells(.Rows.Count,6).End(xlUp).Row
With .Range("f5:F" & lastRow)
.Formula = "=VLOOKUP(C5,($H$5:$i$34),2,FALSE)"
.Value = .Value
End With
End With
End Sub
Maybe you can try to use a Do while-loop?
If you put the while statement right, this will continue until the statement becomes false, in your case; there is no more information to add.
You can use the Len()-function to check the length of the text/value inside a cell, when this is zero you can assume the cell is empty.
More information about this item can be found here.
Example:
Public Sub Something()
Dim i As Integer
i = 1
Do While (Len(Cells(i, 1).Text) > 0)
i = i + 1
Loop
MsgBox "The next row of column 'A' is empty: A" & i
End Sub
Hope this helps.

Excel VBA changing color on cell at the time

Maybe due to my poor English some of you may misunderstood what I wanted to do. Anyways, here is the code that I wanted. After many trial and errors I made it but I doubt its the best way but it works =). If anyone know how to make the code better please tell me =).
I previous post is also below this new code.
Private Sub Worksheet_Change(ByVal Target As Range)
Dim row As Integer
For row = 1 To 1000
If Cells(row, "A").Value = "Yes" Then
Range("B" & row).Interior.ColorIndex = 4
End If
If Cells(row, "A").Value = "yes" Then
Range("B" & row).Interior.ColorIndex = 4
End If
Next row
End Sub
Previous post
I have written a VBA code in excel where I want to change a cell color everytime I write "yes". In this case I write "yes" in column E and column A should change color. I have used a for loop but it does not run as I want. I have a feeling I am thinking a bit wrong...
Private Sub Worksheet_Change(ByVal Target As Range)
Dim cellNr As Long
For cellNr = 1 To 5
If Range("E" & cellNr).Value = "yes" Then
Range("A" & cellNr).Interior.ColorIndex = 5
Else
ActiveCell(0, -2).Interior.ColorIndex = 4
End If
Next cellNr
End Sub
Use conditional formatting with a formula. Starting in row 1 the formula required is
=$E1="yes"
If I understand what you are trying to do with the following line:
ActiveCell(0, -2).Interior.ColorIndex = 4
Replace it with:
ActiveCell.Offset(0, -2).Interior.ColorIndex = 4
As far as I know, the line I told you to remove will always throw an error. It doesn't make any sense syntactically. You should use the Offset function to get positions relative to the Active Cell. But also, this offset function will throw an error if your active cell is in column A or B because there are less than 2 columns to the left of the active cell.
Consider:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim rOfInterest As Range
Set rOfInterest = Range("E1:E5")
If Intersect(Target, rOfInterest) Is Nothing Then Exit Sub
v = Target.Value
If v = "yes" Then
Target.Offset(0, -4).Interior.ColorIndex = 5
Else
Target.Offset(0, -4).Interior.ColorIndex = 4
End If
End Sub
and make sure the macro is in the worksheet code area.