I've been using the following code for quite a while and it works just perfectly to filter a listbox based on a Textbox value (code by Ralph).
Private Sub Textbox1_Change()
Dim i As Long
Dim arrList As Variant
Me.ListBox1.Clear
If TMP.Range("A" & TMP.Rows.Count).End(xlUp).Row > 1 And Trim(Me.TextBox1.Value) <> vbNullString Then
arrList = TMP.Range("A1:A" & TMP.Range("A" & TMP.Rows.Count).End(xlUp).Row).Value2
For i = LBound(arrList) To UBound(arrList)
If InStr(1, arrList(i, 1), Trim(Me.TextBox1.Value), vbTextCompare) Then
Me.ListBox1.AddItem arrList(i, 1)
End If
Next i
End If
If Me.ListBox1.ListCount = 1 Then Me.ListBox1.Selected(0) = True
End Sub
I would like to use it with multicolumn Listbox (4 to be accurate A->D). One of the hints in the original post (titled "How to filter listbox values based on a Textbox value") was to replace :
Me.ListBox1.AddItem arrList(i, 1)
with
Me.Listbox.AddItem
Listbox.List(0, 0) = arrList(i, 1)
Listbox.List(0, 1) = arrList(i, 2)
but i can't make it work. I've been stuck on this for days, could you help me get it to work?
Thank you...
Related
I have two combo-boxes, the first one you pick to select what shows in the second one. And what ever you pick in the first one, the second one should show two columns.
I had it running with one column in the second combo-box with
Private Sub cbo_area_Change()
'Populate Equipment combo box.
Dim strRange As String
If cbo_area.ListIndex > -1 Then
strRange = cbo_area
Label2.Caption = strRange
strRange = Replace(strRange, " ", "_")
With cbo_asset
.RowSource = vbNullString
.RowSource = strRange
.ListIndex = 0
End With
End If
End Sub
and now after much research and trying various things, I have tried the following to get two columns.
Private Sub cbo_area_Change()
'Populate Equipment combo box.
Dim strRange As String
Dim strRange2 As String
If cbo_area.ListIndex > -1 Then
strRange = cbo_area
Label2.Caption = strRange
strRange = Replace(strRange, " ", "_")
strRange2 = strRange & "2"
With cbo_asset
.RowSource = vbNullString
.List(.ListCount - 1, 1) = strRange
.List(.ListCount - 1, 2) = strRange2
.ListIndex = 0
End With
End If
End Sub
But I get an invalid property array index at the List(.ListCount - 1, 1) = strRange line.
Like I said, I tried many things but I do not get further than this.
You need to add an item to the list before you assign a value to it. The added item become column 0.
With cbo_asset
.ColumnCount = 2
.ColumnWidths = "60pt;75pt;"
.RowSource = vbNullString
.AddItem strRange
.list(.ListCount - 1, 1) = strRange2
.ListIndex = 0
End With
I am trying to input multiple rows in a textbox and display each value in a different row of a single column in excel, My code inputs all values in different rows of the column. Code is as follows
Private Sub CommandButton1_Click()
Dim i As Variant
For Each i In Split(TextBox1.Text, vbCrLf)
With Range("A1")
lastrow = ThisWorkbook.Worksheets("sheet1").Range("A" & Rows.Count).End(xlUp).Row + 1
ThisWorkbook.Worksheets("sheet1").Range("A" & lastrow).Value = TextBox1.Value
End With
Next
TextBox1.Text = ""
End Sub
Any suggestions please? your response will be highly appreciated
if I understand it correctly you want to have each line in the text box in its own row so this would work
Private Sub CommandButton1_Click()
Dim i As Variant
Dim rowCounter As Long
rowCounter = 1
For Each i In Split(TextBox1.Text, vbCrLf)
'start at row 1 column A
Cells(rowCounter, 1).Value = i
rowCounter = rowCounter + 1
Next
TextBox1.Text = ""
End Sub
There is no need to iterate. Split returns an array that you can use to fill all the rows at once.
Private Sub CommandButton1_Click()
Dim Target As Range
Dim Data As Variant
If TextBox1.Text = "" Then Exit Sub
Data = Split(TextBox1.Text, vbCrLf)
With Worksheets("sheet1")
Set Target = .Range("A" & .Rows.Count).End(xlUp)
If Target.Value <> "" Then Set Target = Target.Offset(1)
Target.Resize(UBound(Data) + 1).Value = Application.Transpose(Data)
End With
TextBox1.Text = ""
End Sub
I have a multicolumn listbox in my userform and I would like to get all the values of the elements which are in the selected row in the listbox.Here is my userform:
Just like in the photo, I want to select one line then I will click button Associer and I could get the information of this row. I can just get the first column which is CAN20168301436 I want to get the information from the whole line. How can I do it? Here is my button clicked event:
Private Sub CommandButton3_Click()
a = ListBoxResultatFind.Text
End Sub
you can use this code
Private Sub CommandButton3_Click()
Dim strng As String
Dim lCol As Long, lRow As Long
With Me.ListBox1 '<--| refer to your listbox: change "ListBox1" with your actual listbox name
For lRow = 0 To .ListCount - 1 '<--| loop through listbox rows
If .selected(lRow) Then '<--| if current row selected
For lCol = 0 To .ColumnCount - 1 '<--| loop through listbox columns
strng = strng & .List(lRow, lCol) & " | " '<--| build your output string
Next lCol
MsgBox "you selected" & vbCrLf & Left(strng, (Len(strng) - 1)) '<--| show output string (after removing its last character ("|"))
Exit For '<-_| exit loop
End If
Next lRow
End With
End Sub
No need to loop the entire list - in order to get the selected item row you can use the ListIndex property. Then you can use the List(Row, Column) property to retreive the data, as in the examples by #DragonSamu and #user3598756:
'***** Verify that a row is selected first
If ListBoxResultatFind.ListIndex > -1 And ListBoxResultatFind.Selected(ListBoxResultatFind.ListIndex) Then
'***** Use the data - in my example only columns 2 & 3 are used
MsgBox ListBoxResultatFind.List(ListBoxResultatFind.ListIndex, 1) & ":" & ListBoxResultatFind.List(ListBoxResultatFind.ListIndex, 2)
End If
With a single column you can retrieve the value as below:
Dim str as String
str = me.ListBox1.Value
With a multicolumn you can retrieve the value like this:
Dim strCol1 as String
Dim strCol2 as String
Dim strCol3 as String
strCol1 = ListBox1.List(0, 1)
strCol2 = ListBox1.List(0, 2)
strCol3 = ListBox1.List(0, 3)
or you can add all the data into 1 String:
Dim strColumns as String
strColumns = ListBox1.List(0, 1) + " " + ListBox1.List(0, 2) + " " + ListBox1.List(0, 3)
It's a 6column list box and the 3rd column would be the multiplier hence the "(x)". You may also rearrange the list to how you like it.
Private Function selList() As String
Dim i As Long
For i =LBound(lstListBox1.List) To UBound(lstListBox1.List)
If lstListBox1.Selected(i) Then
selList = selList & lstListBox1.List(i) & " " & lstListBox1.List(i, 1) _
& "(x" & lstListBox1.List(i, 3) & ")" & " " & lstListBox1.List(i, 2) & " " & lstListBox1.List(i, 4) & ", "
End If
Next i
If selList= "" Then
selList= ""
Else
selList= Left(selList, Len(selList) - 2)
End If
MsgBox selList
End Function
I have a bunch of subroutines for a worksheet that all start and end exactly the same way. They all basically loop through every row in the table and perform some unique operation to each individual row. I do not want them all to run every time, instead I want to be able to call them individually.
Here's what the actual code looks like:
Sub randomSub()
Dim finalRow As Long
Dim i As Long
finalRow = Sheet.Cells(Rows.count, Column).End(xlUp).row
With Sheet2
For i = 3 To finalRow
' Do some random operations here
Next i
End With
End Sub
Setting the code up to loop through every row is not hard but after repeating it across 4 or 5 different subs I imagine there is a better way.
So I guess my question is this: Is there a best practice for avoiding writing a loop set-up like this over and over for every new sub I make?
EDIT: Here's some examples of the type of operations I'm doing, and would normally replace the ' Do random operations here
Sub moveToFront()
Dim stringHolder() As String
stringHolder = Split(Sheet2.Cells(i, 11), "; ")
If stringHolder(1) = "" Then
.Cells(i, 11) = stringHolder(0)
Else
.Cells(i, 11) = stringHolder(1) & "; " & stringHolder(0)
End If
End Sub
And another
Sub fillInTotals()
If .Cells(i, 3) <> "" Then
.Cells(i, 1) = "='EUS Graph'!$C$" & _
Application.WorksheetFunction.Match(.Cells(i, 3), Sheet4.Range("$A:$A"), 0)
Else
.Cells(i, 1) = "='EUS Graph'!$C$"
End If
End Sub
Consider using a generalized user-defined function and place it where all macros have access to it, either the ThisWorkbook section or a standard module:
Public Function randomSub(SheetName As String, ColumnLetter As String, _
OperationType As String)
Dim wsh As Worksheet
Dim i As Long, finalRow As Long
Dim stringHolder() As String
Set wsh = ThisWorkbook.Worksheets(SheetName)
With wsh
finalRow = wsh.Cells(wsh.Rows.Count, ColumnLetter).End(xlUp).Row
For i = 3 To finalRow
Select Case OperationType
Case "MoveToFront"
stringHolder = Split(Sheet2.Cells(i, 11), "; ")
If stringHolder(1) = "" Then
.Cells(i, 11) = stringHolder(0)
Else
.Cells(i, 11) = stringHolder(1) & "; " & stringHolder(0)
End If
Case "fillInTotals"
If .Cells(i, 3) <> "" Then
.Cells(i, 1) = "='EUS Graph'!$C$" & _
Application.WorksheetFunction.Match(.Cells(i, 3), _
Sheet4.Range("$A:$A"), 0)
Else
.Cells(i, 1) = "='EUS Graph'!$C$"
End If
End Select
Next i
End With
End Function
Then, call the function as needed, passing required parameters:
Call randomSub(ActiveSheet.Name, "A", "MoveToFront")
I have a table with three columns,
ID, Name and Date
then I create a userform with textbox ID and Name.
how could I display the Name of similar ID from the table with latest Date when I key in the ID in the userform? (similar ID will have different names, but I want to display the one with latest date in the table)
thanks in advance for all the help
coding for the textbox1
Private Sub TextBox1_Change()
getdata
End Sub
coding for the getdata module
Sub getdata()
If IsNumeric(UserForm1.TextBox1.Value) Then
flag = False
i = 0
id = UserForm1.TextBox1.Value
Do While Cells(i + 1, 1).Value <> ""
If Cells(i + 1, 1).Value = id Then
flag = True
For j = 2 To 3
UserForm1.Controls("textbox" & j).Value = Cells(i + 1, j).Value
Next j
End If
i = i + 1
Loop
If flag = False Then
For j = 2 To 3
UserForm1.Controls("TextBox" & j).Value = ""
Next j
End If
Else
ClearForm
End If
End Sub
This should do it for you. This routine goes in your userform code module:
Private Sub TextBox1_AfterUpdate()
TextBox2 = Evaluate("=INDEX(B2:B999,MATCH(MAX((IF(A2:A999=" & TextBox1 & _
",1)*(C2:C999)),1),IF(A2:A999=" & TextBox1 & _
",1)*(C2:C999),))")
End Sub
It assumes your data are in columns A, B, and C. It also assumes your data do not extend past row 999; if they do, then increase the 999's in the formula to what is appropriate.
TextBox1 is for the ID.
TextBox2 is for the Name.
Note that this code is placed in the AfterUpdate event procedure. This is different than your sample code. You used the Change event procedure. The difference is that Change fires on each keystroke while AfterUpdate fires only after the full text is confirmed for the textbox.
Note that you should still add error checking for the case where the ID is not numeric and also for the case where the numeric ID does not match. The code above is simply for demonstrating the technique to display the looked-up value. If you wish for me to flesh it out more, please let me know.
UPDATE
I went ahead and fleshed it out with the error checking:
Private Sub TextBox1_AfterUpdate()
GetData
End Sub
Public Sub GetData()
Dim v, w
On Error Resume Next
v = Evaluate("=INDEX(B2:B999,MATCH(MAX((IF(A2:A999=" & TextBox1 & _
",1)*(C2:C999)),1),IF(A2:A999=" & TextBox1 & _
",1)*(C2:C999),))")
w = Evaluate("MAX((IF(A2:A999=" & TextBox1 & ",1)*(C2:C999)))")
If IsArray(v) Or IsError(v) Then v = "ID not found.": w = ""
TextBox2 = v
TextBox3 = "": TextBox3 = CDate(w)
End Sub
UPDATE 2
In the fleshed out version directly above, I added support for the associated date in TextBox3.
You could read the whole range in when the userform opens, sort it, then find the first ID.
Private mvaData As Variant
Private Sub TextBox1_AfterUpdate()
Me.TextBox2.Text = vbNullString
Me.TextBox3.Text = vbNullString
GetData
End Sub
Public Sub GetData()
Dim i As Long
For i = LBound(mvaData, 1) To UBound(mvaData, 1)
If mvaData(i, 1) = Val(Me.TextBox1.Text) Then
Me.TextBox2.Text = mvaData(i, 2)
Me.TextBox3.Text = mvaData(i, 3)
Exit For 'stop after the first one - largest date
End If
Next i
End Sub
Private Sub UserForm_Initialize()
Dim i As Long, j As Long
Dim lId As Long, sDesc As String, dtDate As Date
'store the data in a variable when the forms opens
mvaData = Sheet1.Range("A1:C5")
'sort with larger dates on top
For i = LBound(mvaData, 1) To UBound(mvaData, 1) - 1
For j = i To UBound(mvaData, 1)
If mvaData(i, 3) < mvaData(j, 3) Then
lId = mvaData(j, 1)
sDesc = mvaData(j, 2)
dtDate = mvaData(j, 3)
mvaData(j, 1) = mvaData(i, 1)
mvaData(j, 2) = mvaData(i, 2)
mvaData(j, 3) = mvaData(i, 3)
mvaData(i, 1) = lId
mvaData(i, 2) = sDesc
mvaData(i, 3) = dtDate
End If
Next j
Next i
End Sub