Add codes for dynamically created Active x-check boxes using vba - vba

Dim t As Long
Dim u As Long
Dim v As Long
Dim q As Long
Dim p As Long
t = 1
u = 1
Do
If Sheet2.Range("D" & t).Value = "" Then
If Sheet2.Range("D" & t + 1).Value = "" Then
If Sheet2.Range("D" & t + 2).Value = "" Then
If Sheet2.Range("D" & t + 3).Value = "" Then
If Sheet2.Range("D" & t + 4).Value = "" Then
If Sheet2.Range("C" & t).Value = "" Then
Exit Do
End If
End If
End If
End If
End If
End If
If Not Sheet2.Range("D" & t).Value = "" Then
If Not Sheet2.Range("D" & t).Value = "Description" Then
v = Sheet2.Range("A" & 1 & ":" & "A" & t - 1).Height
q = Sheet2.Range("A" & t).Height
p = v + (q / 2) - 5
Set obj = Sheet2.OLEObjects.Add("Forms.checkbox.1")
With obj
.Width = 10
.Top = p
.Left = 875
.Height = 10
End With
u = u + 1
End If
End If
t = t + 1
Loop
This Code will help me to create many active-x check boxes as per my requirement as u can see in the image.
check the image,after i click the necessary check boxes,and then the command button "export the nfr", the row corresponding to the selected check box should be copied to another sheet, is there any way to add codes for that manipulation
sorry for editing the question
https://i.stack.imgur.com/YF2U2.png

Use a "custom" check box, by creating an event sunk class, such as this, clsCustomCheckBox
Option Explicit
Public WithEvents cb As msforms.CheckBox
Public Sub init(cbInit As msforms.CheckBox)
Set cb = cbInit
End Sub
Private Sub cb_Click() ' or the _Change event....
' Your code here
End Sub
You could then add your new ones, afterwards doing something similar to the below
Private c As Collection
Sub testcb()
Dim o As Object
Dim cb As New clsCustomCheckBox
Set o = ActiveSheet.OLEObjects(1)
cb.init o.Object
Set c = New Collection
c.Add cb
End Sub

you could switch to a Form Control instead of an ActiveX one and take advantage of its OnAction property and assign the same sub to all checkboxes
as follows:
Sub Macro2()
Dim t As Long, u As Long, v As Long, q As Long, p As Long
t = 2 '<--| start from 2 otherwise subsequent "A" & (t - 1) would return "A0"!
u = 1
With Sheet2
Do
If WorksheetFunction.CountA(.Cells(t, "D").Resize(5), .Cells(t, "C")) < 6 Then Exit Do
If Not .Cells(t, "D").Value = "Description" Then
v = .Range("A1", "A" & (t - 1)).Height
q = .Cells(t, "A").Height
p = v + (q / 2) - 5
With .CheckBoxes.Add(875, p, 10, 10) '<--| add a 'Form' checkbox
.OnAction = "CheckBoxClick" '<--| current checkbox will "react" calling 'CheckBoxClick()' sub
End With
u = u + 1 '<--| what is this for?
End If
t = t + 1
Loop
End With
End Sub
then you only have to type your CheckBoxClick() sub, for instance:
Sub CheckBoxClick()
With ActiveSheet.CheckBoxes(Application.Caller) '<--| reference caller checkbox
MsgBox "hello from " & .Name & " place at cell " & .TopLeftCell.Address
End With
End Sub

Related

implementing a priority list in recursive tree parsing with VBA

I have the following sheet of data (called "WeightsDB", and below line 30 is my formatting sheet with my priority values, named "Formatting":
https://ethercalc.org/zeacfw3jskc3
I have code that recursively parses this data using a scripting dictionary, and generates the following tree:
[
However, I want my output to be sorted by looking up some priority in the formatting sheet:
I'm stuck on adjusting my code to handle priority; recursion is already difficult for me. Something to note is that "Cash" entity's should always be at the bottom of every sub-tree. Meaning that if I have an entity that isn't on my formatting sheet, it's priority does not matter AS LONG AS it shows up before cash.
What would the most efficient way of implementing this be, perhaps even nonrecursively?
The code:
Sub weightsSheet(wbk, USESTALE, realTimeDataVersion, closeDataVersion)
' Write to "Weights" sheet
Dim w1 As Worksheet, w2 As Worksheet
Dim num_rows
Dim parent As Range, parentName As String
Dim parentRange As Range, childrenRange As Range
Dim childCount As Long
Dim p As Variant
Dim f1 As Range, f2 As Range
currRow = 8
Dim dict As Object
Set dict = CreateObject("Scripting.Dictionary")
' Real time and close dates
wbk.Sheets("Weights").Range("D5").Value = "Real-Time (" & realTimeDataVersion & ")"
realTimeDate = getMaxColumn("WeightsDB", "dataTime", 0)
wbk.Sheets("Weights").Range("D6").Value = realTimeDate
If Not IsEmpty(USESTALE) And Not USESTALE = "NULL" Then
If USESTALE Then
closeType = "Stale"
End If
Else
closeType = "Close"
End If
wbk.Sheets("Weights").Range("E5").Value = closeType & " (" & closeDataVersion & ")"
closeDate = getMaxColumn("WeightsDB", "dataTime", 1)
wbk.Sheets("Weights").Range("E6").Value = closeDate
wbk.Sheets("Weights").Range("K5").Value = closeType & " Exposures"
Set w1 = wbk.Sheets("WeightsDB")
Set w2 = wbk.Sheets("Weights")
num_rows = w1.Cells(Rows.Count, 1).End(xlUp).row
'If there's no parentName column, we can't continue.
If w1.Rows(1).Find("portfolioName") Is Nothing Then Exit Sub
'find first instance
Set f1 = w1.Rows(1).Find("portfolioName", lookat:=xlWhole)
If Not f1 Is Nothing Then
'find second instance
Set f2 = f1.Offset(0, 1).Resize(1, w1.Columns.Count - f1.Column).Find("portfolioName", lookat:=xlWhole)
If Not f2 Is Nothing Then
'set range based on f2
Set parentRange = w1.Range(f2.Offset(1, 0), _
w1.Cells(Rows.Count, f2.Column).End(xlUp))
End If
End If
'If there's no Root level, how do we know where to start?
If parentRange.Find("Main") Is Nothing Then Exit Sub
For Each parent In parentRange
If Not dict.Exists(parent.Value) Then
childCount = Application.WorksheetFunction.CountIf(parentRange, parent.Value)
Set childrenRange = parent.Offset(, 2).Resize(childCount, 1)
dict.Add parent.Value, Application.Transpose(Application.Transpose(childrenRange.Value))
End If
Next
' Recursive method to traverse our dictionary, beginning at Root element.
Call WeightsProcessItem("", "Main", dict, w2, 7)
wbk.Sheets("Weights").Columns("A:F").AutoFit
Application.CalculateFull 'calculate exposures
End Sub
Private Sub WeightsProcessItem(parentName As String, name As String, dict As Object, ws As Worksheet, row_num As Long, Optional indent As Long = 0)
Dim output As String, v
Dim w2 As Worksheet
'Debug.Print WorksheetFunction.Rept(" ", indent) & name
Debug.Print parentName & name
'Formatting
Dim i As Integer
For i = 3 To 6
ws.Cells(row_num, i).ClearFormats
ws.Cells(row_num, i).Interior.Color = RGB(255, 255, 255)
ws.Cells(row_num, i).Font.name = "Calibri"
ws.Cells(row_num, i).Font.Size = 10
If i <> 6 Then
ws.Cells(row_num, i).NumberFormat = "0.0%"
If parentName = "Main" Or parentName = "Lima" Or name = Papa" Or name = "Main" Then
ws.Cells(row_num, i).Font.Bold = True
End If
End If
If parentName = "Main" Then
ws.Cells(row_num, i).Borders(xlEdgeBottom).LineStyle = xlContinuous
ws.Cells(row_num, i).Borders(xlEdgeBottom).LineStyle = xlContinuous
End If
If i = 6 Then
ws.Cells(row_num, i).Borders(xlEdgeLeft).LineStyle = xlDash
ws.Cells(row_num, i).Borders(xlEdgeRight).LineStyle = xlDash
End If
If indent <> 0 Then
ws.Cells(row_num, i).InsertIndent indent / 1
End If
Next
ws.Cells(row_num, 3).Value = name 'Lets worry about output mapping later
row_num = row_num + 1
If Not dict.Exists(name) Then
'we're at a terminal element, a child with no children.
Exit Sub
Else
On Error GoTo ErrHandler:
For Each v In dict(name)
' ## RECURSION ##
Call WeightsProcessItem(name, CStr(v), dict, ws, row_num, indent + 2)
Next
ErrHandler:
Exit Sub
Resume Next
End If
End Sub
Any help would be appreciated!
Since VBA collections and for that matter Scripting Dictionaries lack a public "Next" method, I would not use recursion. Collections are really a modern implementation of the C struct and pointer combination.
I would move the formatting code into a separate sub routine that is called from the For Each v In dict(name) loop. This will also provide you with the ability to add "Cash" at the end of any list.
Private Sub WeightsProcessItem(parentName As String, name As String, dict As Object, ws As Worksheet, row_num As Long, Optional indent As Long = 0)
Dim output As String
Dim v As Variant
'Debug.Print WorksheetFunction.Rept(" ", indent) & name
Debug.Print parentName & name
On Error GoTo ErrHandler:
For Each v In dict(name)
DoFormating name, CStr(v), ws, row_num, indent + 2
row_num = row_num + 1
Next
Exit Sub
ErrHandler:
On Error GoTo 0
End Sub
Private Sub DoFormating(parentName As String, name As String, ws As Worksheet, row_num As Long, Optional indent As Long = 0)
'Formatting
Dim i As Integer
For i = 3 To 6
ws.Cells(row_num, i).ClearFormats
ws.Cells(row_num, i).Interior.Color = RGB(255, 255, 255)
ws.Cells(row_num, i).Font.name = "Calibri"
ws.Cells(row_num, i).Font.Size = 10
If i <> 6 Then
ws.Cells(row_num, i).NumberFormat = "0.0%"
If (parentName = "Main") Or (parentName = "Lima") _
Or (name = "Papa") Or (name = "Main") Then
ws.Cells(row_num, i).Font.Bold = True
End If
End If
If parentName = "Main" Then
ws.Cells(row_num, i).Borders(xlEdgeBottom).LineStyle = xlContinuous
ws.Cells(row_num, i).Borders(xlEdgeBottom).LineStyle = xlContinuous
End If
If i = 6 Then
ws.Cells(row_num, i).Borders(xlEdgeLeft).LineStyle = xlDash
ws.Cells(row_num, i).Borders(xlEdgeRight).LineStyle = xlDash
End If
If indent <> 0 Then
ws.Cells(row_num, i).InsertIndent indent / 1
End If
Next
ws.Cells(row_num, 3).Value = name 'Lets worry about output mapping later
End Sub

Instead of row number use the first cell number(Excel VBA)

I have made a userform which automatically adds Textboxes & Labels depending on how many rows/Columns there are in the Sheet.
Now I have a problem, for example if I had "Steve" with number like 4, it would not show the exact number in the cell Instead it will show the Row number.
Excel Data Sheet Screenshot
So what I want is to fix the Number : Label and also make the TextBox for example now if i type 1 it will show the data for the Row number 1 i want to make it work with "Steve" writing a "4" instead of a "2" Which is the row number.
Here is the Userform code:
Private Sub CommandButton1_Click()
'Exit Form
Unload Me
End Sub
Private Sub CommandButton2_Click()
'Edit
k = ScrollBar1.Value
lcol = Sheet1.Range("DX2").End(xlToLeft).Column
For j = 1 To lcol
Sheet1.Cells(k + 1, j) = Me.Controls("textbox" & j)
Next j
End Sub
Private Sub CommandButton3_Click()
'Delete
k = ScrollBar1.Value
Sheet1.Cells(k + 1, 1).EntireRow.Delete
End Sub
Private Sub ScrollBar1_Change()
Dim Rng As Range
lcol = Sheet1.Range("DX2").End(xlToLeft).Column
k = ScrollBar1.Value
k2 = TextBox1000.Value
label1000.Caption = "Number : " & k
If k <> 0 And k2 <> 0 Then
TextBox1000.Value = k
For j = 1 To lcol
Me.Controls("textbox" & j).Text = Sheet1.Cells(k, j).Offset(1, 0).Value
Next j
End If
End Sub
Private Sub TextBox1000_Change()
lcol = Sheet1.Range("DX2").End(xlToLeft).Column
k = ScrollBar1.Value
k2 = TextBox1000.Value
label1000.Caption = "Number : " & k2
If k2 <> "" Then
ScrollBar1.Value = k2
For j = 1 To lcol
Me.Controls("textbox" & j).Text = Sheet1.Cells(k2, j).Offset(1, 0).Value
Next j
End If
End Sub
Private Sub UserForm_Initialize()
Dim myLabel As Control
Dim txtbox As Control
k = ScrollBar1.Value
label1000.Caption = "Number : " & k
lcol = Sheet1.Range("DX2").End(xlToLeft).Column
For i = 1 To lcol
Set myLabel = Frame1.Controls.Add("Forms.label.1", "label" & i, True)
myLabel.Left = 250
myLabel.Top = 12 + (i * 20)
myLabel.Width = 150
myLabel.Height = 15
Set txtbox = Frame1.Controls.Add("Forms.TextBox.1", "TextBox" & i, True)
txtbox.Left = 50
txtbox.Top = 10 + (i * 20)
txtbox.Width = 180
txtbox.Height = 60
Next i
For j = 1 To lcol
With Frame1.Controls("label" & j)'Formating Labels
.Caption = Sheet1.Cells(1, j).Value
.TextAlign = fmTextAlignCenter
.Font.Bold = True
.Font.Size = 11
.FontName = "Times New Roman"
.ForeColor = vbRed
End With
With Frame1.Controls("TextBox" & j) 'Formating TextBoxes
.Text = Sheet1.Cells(1, j).Offset(1, 0).Value
.TextAlign = fmTextAlignRight
.Font.Bold = True
.Font.Size = 11
.FontName = "Times New Roman"
End With
With Frame1.Controls("TextBox1")'Make textbox1 not editable
.Enabled = False
End With
With Frame1.Controls("TextBox3")'Make textbox3 not editable
.Enabled = False
End With
Next j
End Sub
I'd say
Label1000.Caption = "Number : " & Sheet1.Cells(k + 1, 1).Value

Find Roll and Column of Name with latest Date

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

Unable to run the 2 sets of codes in one sheet

I need help for VBA as I'm new to this programming language. Is it possible to have 2 different sets of codes in one sheet in the workbook?
I want to make the Excel sheet more interactive like clicking on certain cell then highlighting the entire row that the cell is selected. But the sheet that im trying to make it interactive has a set of codes already.
Here is the codes that I want to make the excel sheet interactive
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
initializeWorksheets
Dim ws As Worksheet
For Each ws In Worksheets
ws.Activate
' Clear the color of all the cells
Cells.Interior.ColorIndex = 0
If IsEmpty(Target) Or Target.Cells.Count > 1 Then Exit Sub
Application.ScreenUpdating = False
With ActiveCell
' Highlight the row and column that contain the active cell, within the current region
Range(Cells(.Row, .CurrentRegion.Column), Cells(.Row, .CurrentRegion.Columns.Count + .CurrentRegion.Column - 1)).Interior.ColorIndex = 6
End With
Next ws
Application.ScreenUpdating = True
End Sub
Private Sub Worksheet_BeforeDoubleClick(ByVal Target As Range, Cancel As Boolean)
'filtering
Dim ws As Worksheet
ws.Activate
Dim ccolumn As Integer
Dim vvalue As String
ccolumn = ActiveCell.Column
vvalue = ActiveCell.Value
For Each ws In Worksheets
If IsEmpty(Target) Or Target.Cells.Count > 1 Then Exit Sub
Application.ScreenUpdating = False
With ActiveCell
Range(Cells(.Row, .CurrentRegion.Column), Cells(.Row, .CurrentRegion.Columns.Count + .CurrentRegion.Column - 1)).AutoFilter Field:=ccolumn, Criteria1:=vvalue
Cancel = True
End With
Next ws
End Sub
Here is the codes that it is used for the same sheet:
Private Sub Workbook_SheetFollowHyperlink(ByVal Sh As Object, ByVal Target As Hyperlink)
initializeWorksheets
Application.ScreenUpdating = False
If (ActiveSheet.Name = "Student Viewer") Then
searchKey = Trim(Target.Range.Value)
If (Right(searchKey, 1) = ")") Then
searchKey = Right(searchKey, Len(searchKey) - InStrRev(searchKey, "(", -1))
searchKey = Left(searchKey, Len(searchKey) - 1)
End If
temp = 2
Do While (mainSheet.Range(findColumn(mainSheet, "IC Number") & temp) <> searchKey & "")
temp = temp + 1
If (temp > 65535) Then
MsgBox ("Error in Finding xxxx Details")
End
End If
Loop
viewerSheet.Unprotect
' Set details
For i = 2 To 10
viewerSheet.Range("C" & i) = mainSheet.Range(findColumn(mainSheet, Left(viewerSheet.Range("B" & i), Len(viewerSheet.Range("B" & i)) - 1)) & temp)
viewerSheet.Range("F" & i) = mainSheet.Range(findColumn(mainSheet, Left(viewerSheet.Range("E" & i), Len(viewerSheet.Range("E" & i)) - 1)) & temp)
Next i
For i = 2 To 3
viewerSheet.Range("I" & i) = mainSheet.Range(findColumn(mainSheet, Left(viewerSheet.Range("H" & i), Len(viewerSheet.Range("H" & i)) - 1)) & temp)
Next i
loadSummary
viewerSheet.Protect
ElseIf (ActiveSheet.Name = "xxxx Viewer") Then
searchKey = Trim(Target.Range.Value)
viewerSheet2.Unprotect
' Set details
temp = 2
Do While (DetailsSheet.Range(findColumn(DetailsSheet, "Policy Num") & temp) <> searchKey & "")
temp = temp + 1
If (temp > 65535) Then
MsgBox ("Error in Finding Details")
End
End If
Loop
For i = 2 To 11
viewerSheet2.Range("C" & i) = DetailsSheet.Range(findColumn(DetailsSheet, Left(viewerSheet2.Range("B" & i), Len(viewerSheet2.Range("B" & i)) - 1)) & temp)
Next i
For i = 2 To 6
viewerSheet2.Range("I" & i) = ValuesSheet.Range(findColumn(ValuesSheet, Left(viewerSheet2.Range("H" & i), Len(viewerSheet2.Range("H" & i)) - 1)) & temp)
Next i
For i = 7 To 12
viewerSheet2.Range("I" & i) = DetailsSheet.Range(findColumn(DetailsSheet, Left(viewerSheet2.Range("H" & i), Len(viewerSheet2.Range("H" & i)) - 1)) & temp)
Next i
viewerSheet2.Hyperlinks.Add Anchor:=Range("C2"), Address:="", SubAddress:="'Client Viewer'!A1"
loadDetail
viewerSheet2.Protect
End If
Application.ScreenUpdating = True
End Sub
As commented, you can try this approach:
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
On Error GoTo halt
Application.EnableEvents = False
With Me ' Me refers to the worksheet where you put this code
.Cells.Interior.ColorIndex = -4142 ' xlNone
If Not CBool(-Target.Hyperlinks.Count) Then ' Check if there is hyperlink
Target.EntireRow.Interior.ColorIndex = 6 ' or you can use RGB(255, 255, 0)
Else
Target.Hyperlinks(1).Follow ' follow hyperlink if there is
CodeFromYourFollowHyperlinkEvent ' call a routine
End If
End With
moveon:
Application.EnableEvents = True
Exit Sub
halt:
MsgBox Err.Description
Resume moveon
End Sub
As you can see above, CodeFromYourFollowHyperlinkEvent should be a sub that contains what you want done in your FollowHyperlink event as shown below.
Private Sub CodeFromYourFollowHyperlinkEvent()
' Put your code in FollowHyperlink here
initializeWorksheets
Application.ScreenUpdating = False
If (ActiveSheet.Name = "Student Viewer") Then
.
.
.
End Sub
Now take note that you need to exercise explicitly working on your objects.
To know more about that, check this cool post out.

VBA realtime filter Listbox through Textbox

I would like to filter a Listbox created from a list of values stored in a worksheet depending on text written in a textbox contained in the same userform.
My Listbox has 4 or 5 columns (depending on OptionField selection) and I would like to search all the columns for the text written.
Example: I write "aaa" in TextField and the Listbox should return a list based on all the lines whose column 1 or 2 or 3 or 4 or 5 contain "aaa".
Below my code to refresh the list on OptionField selection (this code does not produce any error, it is just to show how I create my list):
Sub RefreshList()
Dim selcell, firstcell As String
Dim k, i As Integer
Dim r as long
i = 0
k = 0
' reads parameters from hidden worksheet
If Me.new_schl = True Then
firstcell = Cells(3, 4).Address
selcell = firstcell
Do Until IsEmpty(Range("" & selcell & "")) And i = 2
If IsEmpty(Range("" & selcell & "")) Then i = i + 1
k = k + 1
selcell = Cells(1 + k, 7).Address(0, 0)
Loop
k = k - 1
selcell = Cells(1 + k, 7).Address(0, 0)
With Me.ListBox1
.ColumnCount = 4
.ColumnWidths = "50; 80; 160; 40"
.RowSource = ""
Set MyData = Range("" & firstcell & ":" & selcell & "")
.List = MyData.Cells.Value
For r = .ListCount - 1 To 0 Step -1
If .List(r, 3) = "" Or .List(r, 3) = "0" Then
.RemoveItem r
End If
Next r
End With
Else
firstcell = Cells(3, 11).Address
selcell = firstcell
Do Until IsEmpty(Range("" & selcell & "")) And i = 11
If IsEmpty(Range("" & selcell & "")) Then i = i + 1
k = k + 1
selcell = Cells(1 + k, 15).Address(0, 0)
Loop
k = k - 1
selcell = Cells(1 + k, 15).Address(0, 0)
With Me.ListBox1
.ColumnCount = 5
.ColumnWidths = "40; 40; 160; 40; 40"
.RowSource = ""
Set MyData = Range("" & firstcell & ":" & selcell & "")
.List = MyData.Cells.Value
For r = .ListCount - 1 To 0 Step -1
If .List(r, 3) = "" Or .List(r, 3) = "0" Then
.RemoveItem r
End If
Next r
End With
End If
End Sub
Finally I could come out with something!
Sub Filter_Change()
Dim i As Long
Dim Str As String
Str = Me.Filter.Text
Me.RefreshList
If Not Str = "" Then
With Me.ListBox1
For i = .ListCount - 1 To 0 Step -1
If InStr(1, LCase(.List(i, 0)), LCase(Str)) = 0 And InStr(1, LCase(.List(i, 1)), LCase(Str)) = 0 And _
InStr(1, LCase(.List(i, 2)), LCase(Str)) = 0 And InStr(1, LCase(.List(i, 3)), LCase(Str)) = 0 Then
.RemoveItem i
End If
Next i
End With
End If
End Sub
I know, the answer is couple of years old...
But I thought I'd share solution that works the best for me, because the filter is blazing fast even when there are thousands of items in the list. It is not without a "catch", though:
it uses a Dictionary object
Option Explicit
Dim myDictionary As Scripting.Dictionary
Private Sub fillListbox()
Dim iii As Integer
Set myDictionary = New Scripting.Dictionary
' this, here, is just a "draft" of a possible loop
' for filling in the dictionary
For iii = 1 To RANGE_END
If Not myDictionary.Exists(UNIQUE_VALUE) Then
myDictionary.Add INDEX, VALUE
End If
Next
myListbox.List = myDictionary .Items
End Sub
Private Sub textboxSearch_Change()
Dim Keys As Variant
Keys = myDictionary .Items
myListbox.List = Filter(Keys, textboxSearch.Text, True, vbTextCompare)
End Sub
Private Sub UserForm_Initialize()
Call fillListbox
End Sub