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)
Related
I have a combobox with different currency items: "PEN, USD, etc"
I have a textbox with an amount that I need it to have the corresponding currency symbol based on the selection of the combobox.
Not a solution:
If I use:
TextBox1.Value = Format(TextBox1.Value, "$#,##0.00") it shows the dollar symbol.
TextBox1.Value = Format(TextBox1.Value, "[$S/-es-PE] #,##0.00") it doesnt show the S/ symbol (corresponding to PEN) I coppied this format from when custom formating a cell in a sheet.
TextBox1.Value = Format(TextBox1.Value, "currency") it shows the regional configuration currency symbol.
I don't want to change my regional settings since this doesnt solve the problem. I want to be able to show different symbol according to the currency selected.
thanks!
Please, try the next way. I tried to create a function to extract the value from the text. You can use it in order to make arithmetical operations with the text box value. Having a combo ("ComboBox1") and a text box ("TextBox1"), please paste the following code the combo box Click event:
Private Sub ComboBox1_Change()
Dim arrCur, arrEch, mtch
arrC = Split("USD,PEN,EURO", ",") 'the string representation from combo, separated by comma (not by ", ")
arrEch = Split("$,S/.,€ ", ",") 'the desired corresponding format string
If Me.ComboBox1.ListIndex <> -1 Then 'if a selection exists (in combo):
If Me.TextBox1.Value <> "" Then 'if text box is not empty:
mtch = Application.match(Me.ComboBox1.Value, arrC, 0)
Me.TextBox1.Value = arrEch(mtch - 1) & Format(numberPart(Me.TextBox1.Value), "#,##0.00")
End If
End If
End Sub
You can add as many currencies as you need, as comma separated in arrCur array. And then the corresponding sign to appear as suffix, in arrEch array.
The next function is necessary to extract the numeric part and eliminate when change the format. It can be also used if you need to use the numeric part for other operations:
Private Function numberPart(strVal As String) As Currency
Dim i As Long
For i = 1 To Len(strVal)
If IsNumeric(Mid(strVal, i, 1)) Then numberPart = CCur(Right(strVal, Len(strVal) - i + 1)): Exit Function
Next i
End Function
You can use the same (first) array to load the combo, pasting the next code in the form 'Initializeevent. In such a case, it should be good to declarearrCuras aPrivatevariable on top of the form module (in the declarations area) and just using it in the comboChange` event:
Private Sub UserForm_Initialize()
Dim arrCur, El
arrC = Split("USD,PEN,EURO", ",")
For Each El In arrC
Me.ComboBox1.AddItem El
Next
End Sub
Please, test it and send some feedback.
I'm new to VBA and I'm trying to set up a customizable sheet that allows the user to filter certain columns based on the checkboxes that I have set up. So far, I understand how checkboxes work and how I can integrate them into the code, but I think I have an issue with the autofilter function. Specifically, I think that I'm putting the wrong value for Criteria1.
I've been looking around for similar coding problems, but none of them seem to work with what I'm trying to do.
TL;DR I think my issue lies with how I format the array to put in Criteria1 of the AutoFilter()
Sub Auto_filter()
'variables are for checkboxes'
Dim VC1500 As Shape
Dim VC7500 As Shape
Dim VC144024 As Shape
'initiates to check for the checkboxes'
Set VC1500 = Sheets("Sheet7").Shapes("Check Box 4")
Set VC7500 = Sheets("Sheet7").Shapes("Check Box 5")
Set VC144024 = Sheets("Sheet7").Shapes("Check Box 6")
'if statement that will add a string to strCriteria if checkbox is true'
If VC1500.OLEFormat.Object.Value = 1 Then
strCriteria = strCriteria & ", VC1500"
End If
If VC7500.OLEFormat.Object.Value = 1 Then
strCriteria = strCriteria & ", VC7500"
End If
If VC144024.OLEFormat.Object.Value = 1 Then
strCriteria = strCriteria & ", 144024"
End If
'with statement that finds for column vendor then filter it based on
strCriteria, I think this is where my issue is'
With Worksheets("Open Purchase Orders")
With .Range("A1", .Cells(1, Columns.Count).End(xlToLeft))
Set vendorfind = .Rows(1).Find("Vendor")
If Not vendorfind Is Nothing Then
.AutoFilter Field:=vendorfind.Column,
Criteria1:=Split(strCriteria, ", "), Operator:=xlFilterValues
End If
End With
.AutoFilterMode = False
End With
End Sub
I expect to have the sheet filtered based on the checkboxes.
I get a runtime error 9 error:subscript out of range
Have you tried using Slices?
Its easy and should do simple filters without Macros.
Select your data > Insert Table.
Once the table is done, from the Design tab you can select "Insert Slicer".
Try if this solves your problem.
Some parts of that code look to me like scratching your left ear with your right hand going over your head. But I'm not entirely clear on how it actually looks (a sample would be helpful) - does each vendor have some separate indication column? If so, what are you filtering there? A vendor tag, by the looks of it?
This for example is a solution for a single vendor column (D) which may contain the 3 names. It basically applies an autofilter of a list of values. (I'm using activex checkboxes below as their properties can be accessed directly.)
Private Sub VC1500_Click()
Update_Filter
End Sub
Private Sub VC7500_Click()
Update_Filter
End Sub
Private Sub VC144024_Click()
Update_Filter
End Sub
Private Sub Update_Filter()
Dim varr_filter(3) As String
Dim indshow As Boolean
indshow = True
If VC1500 Then
varr_filter(0) = VC1500.Caption
indshow = False
End If
If VC7500 Then
varr_filter(1) = VC7500.Caption
indshow = False
End If
If VC144024 Then
varr_filter(2) = VC144024.Caption
indshow = False
End If
If indshow Then
Range("$A:$D").AutoFilter
Else
Range("$A:$D").AutoFilter field:=4, Criteria1:=varr_filter, Operator:=xlFilterValues
End If
End Sub
Note: Pick the correct column for filtering as the "field" value, and if you wish to separate the checkboxes from the form for some reason, then add """sheets("sheetname").{each checkbox}""".
Alternatively, if each of the vcs possesses a separate column, and seeking rows which literally say "vendor", I'd merge them in the sheet like so:
E2=if(cond1)*checkbox1 + if(cond2)*checkbox2 + if(cond3)*checkbox3 ; E > 0.
Cond1 could be b2="Vendor", for example.
To make the sheet display all cols when no ticks are selected,
I've added another value: 1 - max(checkboxes).
E6=1-MAX($H$4:$H$6) + IF(AND(B2="Vendor"),1,0)*$H$4 +
IF(AND(C2="Vendor"),1,0)*$H$5 + IF(AND(D2="Vendor"),1,0)*$H$6
That's one example where a hidden sheet value helps, since you can actually define such a column without vb. And then, the code itself is simplified a bit.
Private Sub VC1500_Click()
If VC1500.Value Then
Range("$H$4").Value = 1
Else
Range("$H$4").Value = 0
End If
Update_Filter
End Sub
Private Sub VC7500_Click()
If VC7500.Value Then
Range("$H$5").Value = 1
Else
Range("$H$5").Value = 0
End If
Update_Filter
End Sub
Private Sub VC144024_Click()
If VC144024.Value Then
Range("$H$6").Value = 1
Else
Range("$H$6").Value = 0
End If
Update_Filter
End Sub
Private Sub Update_Filter()
Range("$A:$E").AutoFilter field:=5, Criteria1:=">0", Operator:=xlFilterValues
End Sub
It's also easier to transition to a form control, by checking the range value during click instead of the checkbox, and hiding column H. Not entirely bulletproof yet sufficient for the average user. Either that or read the shape as you wrote.
Edit: Added tested code above for both cases (single col, multicol), including displaying all rows when no tickboxes are checked rather than none. Here are the demo shots.
Single col code
Single col sample sheet
Single col filtered
Multicol code
Multicol sample
Multicol filtered
The code returning an error is the first line of the following:
While StrComp(selectedRecipe, dataSheet.Cells(i, 1)) <> 0
recipeRow = recipeRow + 1
i = i + 1
Wend
The debug I'm getting has issues with the While statement line itself. This code is contained under an OK Button click event on a userform, with selectedRecipe defined as a public string variable in the main worksheet sub. "i" is defined as an integer in this private sub. Basically the code is to find which row of the sheet holds the string value contained in selectedRecipe after selectedRecipe is selected from a drop-down combo box (selectedRecipe returns correctly and has no issues associated with it). I assume I need to have some sort of "converting" command in front of "dataSheet.Cells(i,1)" to reinforce the cell value as a string, but am not sure. Thanks!
1) Make sure dataSheet is actually set to a valid sheet. 2) as Comintern said, you need to begin at 1 as Excel is 1 based not zero based. 3) You need to make sure you don't overflow the number of rows:
Public Sub CheckRecipe()
Dim selectedRecipe As String
Dim i As Long
selectedRecipe = "Test"
i = 1
While StrComp(selectedRecipe, ThisWorkbook.ActiveSheet.Cells(i, 1).Value) <> 0 _
And i < ThisWorkbook.ActiveSheet.UsedRange.Rows.Count
i = i + 1
Wend
End Sub
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.
I have a problem. I spent hours designing a form which works just great with all your feedback. Today, everything went wrong. The reason for this is simple. A few new columns got added and, obviously, the data my form is reading in is now wrong.
Thus I was thinking of trying the following...
Rather than using the column number as below
TK = Cells(ActiveCell.Row, "S").Value 'everything in the form refers to the active row
I could possibly use the column headings in Row 1.
Is that possible ? This way the spreadsheet can have columns added up to as many as a user would like and the form would dynamically scan for the right heading and get the column number that way.
My thought is, on opening the form, read in all the headings, pick out the ones I need and assign them to a variable. Then I use my normal code and substitute the variable into the column section.
It sounds easy, but I have no idea how to do this.
Use the versatile Find to give you a quick method of detecting where your header is - or if it is missing
Find details here
In the code below I have specified that the search must return
an exact match (xlWhole)
a case sensitive match (False)
The match can be a partial match (xlPart) if you were looking to match say Game out of Game X
code
Const strFind = "Game"
Sub GetEm()
Dim rng1 As Range
Set rng1 = ActiveSheet.Rows(1).Find(strFind, , xlValues, xlWhole, , , False)
If Not rng1 Is Nothing Then
MsgBox "Your column is " & rng1.Column
Else
MsgBox strFind & " not found", vbCritical
End If
End Sub
Why use a loop? There's no need to.
Dim col as variant
Col = application.match("my header", rows(1), 0)
If iserror(col) then
'not found
Else
TK = cells(activecell.row, col)
End if
For this purpose I usually use a function which runs through the headers (in the first row of a sheet) and returns the number of the column which contains the value I have searched for.
Public Function FindColumn(HeaderName As String, Sht As String) As Long
Dim ColFound As Boolean
Dim StartingPoint As Range
ColFound = False
Set StartingPoint = Sheets(Sht).Range("A1")
Do While StartingPoint.Value <> ""
If UCase(Trim(StartingPoint.Value)) = UCase(Trim(HeaderName)) Then
FindColumn = StartingPoint.Column
ColFound = True
Exit Do
Else
Set StartingPoint = StartingPoint.Offset(0, 1)
End If
Loop
If Not ColFound Then FindColumn = 0
End Function
Example:
If the first row of your sheet named "Timeline" contains headers like e.g. "Date" (A1), "Time" (B1), "Value" (C1) then calling FindColumn("Time", "Timeline") returns 2, since "Time" is the second column in sheet "Timeline"
Hope this may help you a little.
Your thought is a good one. Reading in column headers to calculate addresses is one way to avoid hard coding - e.g.
Sub Test()
Dim R As Range
Set R = ActiveSheet.[A1]
Debug.Print ColNo(R, "Col1Hdr")
End Sub
Function ColNo(HdrRange As Range, ColName As String) As Integer
' 1st column with empty header is returned if string not found
ColNo = 1
Do While HdrRange(1, ColNo) <> ""
If HdrRange(1, ColNo) = ColName Then Exit Do
ColNo = ColNo + 1
Loop
End Function
Another way I frequently use - and I must admit I prefer it over the above, is to define Enum's for all my tables in a seperate "definition" module, e.g.
Public Enum T_VPN ' sheet VPN
NofHRows = 3 ' number of header rows
NofCols = 35 ' number of columns
MaxData = 203 ' last row validated
GroupNo = 1
CtyCode = 2
Country = 3
MRegion = 4
PRegion = 5
City = 6
SiteType = 7
' ....
End Enum
and use it like
Sub Test1()
Debug.Print ActiveSheet(T_VPN.NofHRows, T_VPN.Country)
End Sub
As you can see, the usage is simpler. Allthough this is again "some kind" of hardcoding, having all definition in one place reduces maintenance significantly.