using checkboxes with userform - vba

I have an user form designed with three listboxes.
The 3 listboxes are populated by the location from three different sheets.
By selecting the listbox, the user can filter the data in the sheet "Data".
if the user is selecting the "BBE Bebra" from the Listbox1. then he could find the filtered result of Bebra in the sheet.
Similary, if the user is selecting from the Listbox2, the same procedure is followed and if the user is selecting from listbox3, the same procedure is followed.
The user can also, select all the three checkbox and looks for the filtered result in the sheet.
I have a issues with the working code.
If I am selecting the checkboxes and click "Filter" then I always see the filtered result. The next time I click on the Filter Button I would like to see the whole data sheet with filters clear and checkboxes cleared.
Can someone tell how I can do it ?
Below is the code, I am using in the filter button
Sub DoFilter()
Dim strCriteria() As String
Dim strCriteria2() As String
Dim strcriteria3() As String
Dim arrIdx As Integer
Dim arrIdx2 As Integer
Dim arrIdx3 As Integer
Dim xRow As Integer
Dim arrCounter As Integer
Dim lo As ListObject
arrIdx = 0
arrIdx2 = 0
arrIdx3 = 0
For xRow = 2 To Last(1, List.Cells)
If List.Cells(xRow, 2) = True Then
ReDim Preserve strCriteria(0 To arrIdx)
strCriteria(arrIdx) = List.Cells(xRow, 3)
arrIdx = arrIdx + 1
End If
Next xRow
For xRow = 2 To Last(1, List.Cells)
If List_Man.Cells(xRow, 2) = True Then
ReDim Preserve strCriteria2(0 To arrIdx2)
strCriteria2(arrIdx2) = List_Man.Cells(xRow, 3)
arrIdx2 = arrIdx2 + 1
End If
Next xRow
For xRow = 2 To Last(1, List.Cells)
If List_S.Cells(xRow, 2) = True Then
ReDim Preserve strcriteria3(0 To arrIdx3)
strcriteria3(arrIdx3) = List_S.Cells(xRow, 3)
arrIdx3 = arrIdx3 + 1
End If
Next xRow
Set Ws = ThisWorkbook.Sheets("Data")
Set lo = Ws.ListObjects("Table7")
If arrIdx = 0 And arrIdx2 = 0 And arrIdx3 = 0 Then
'Ws.UsedRange.AutoFilter
Else
With Ws
With lo
'.AutoFilterMode = True
' .UsedRange.AutoFilter
If arrIdx <> 0 Then
.Range.AutoFilter field:=13, Criteria1:=Array(strCriteria), Operator:=xlFilterValues
End If
If arrIdx2 <> 0 Then
.Range.AutoFilter field:=14, Criteria1:=Array(strCriteria2), Operator:=xlFilterValues
End If
If arrIdx3 <> 0 Then
.Range.AutoFilter field:=15, Criteria1:=Array(strcriteria3), Operator:=xlFilterValues
End If
If .AutoFilter.Range.Columns(1).SpecialCells(xlCellTypeVisible).Cells.Count = 1 Then
MsgBox " Your filter has no result"
End If
End With
End With
Dim i As Long
On Error Resume Next
With ThisWorkbook.Worksheets("Dev").PivotTables("PivotTable1").PivotFields("Lo.")
.ClearAllFilters
For i = 1 To .PivotItems.Count
.PivotItems(i).Visible = False
Next
For arrCounter = LBound(strCriteria) To UBound(strCriteria)
.PivotItems(strCriteria(arrCounter)).Visible = True
Next arrCounter
End With
End If
End Sub
I call the function do filter in my button "Filter".
with the button "exit" I always have the
following code
Private Sub CBExit_Click()
If ActiveSheet.FilterMode Then
ActiveSheet.ShowAllData
End If
Sheets("Dev").Select
Sheets("Dev").PivotTables("PivotTable1").PivotFields("Development Loc.").ClearAllFilters
Unload Me
End Sub

You will need to keep track of your current state using some sort of flag. I would do something like the following:
Private Sub Filter_Click()
If Filter.Caption = "Filter" Then
DoFilter
Filter.Caption = "Unfilter"
Else
'do logic to clear
Filter.Caption = "Filter"
End If
End Sub
This has the added benefit of telling the user what the next click of the button will do.

Related

ComboBox display wrongly

I have a code which display the text of the cell underneath it. However, it seems that the Combobox just refuse to display the correct text. As you can see in the screenshot
The Text property is different from the displaying text. It's the previous value.
ScreenUpdating is True
The combobox is enabled
There is only 1 combobox, no other objects/shapes/buttons/forms. And a single table in this sheet.
Other information:
Problematic ComboBox is in sheet LinhKien, other comboboxes work fine. I don't know how to upload file here, so it's a 7 days link valid begin from 20220712 (YYYYMMDD)
The combobox is hidden when user is not selecting column 1 or select more than 1 cell. It becomes visible when a cell in column 1 is selected.
I have 2 other sheets with Comboboxes behave the exact same way (hidden when not in certain column, text comes from underneath cell) but they don't have this problem.
If the code is of relevant, here it is.
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
DoEvents
If Selection.Count > 1 Then Exit Sub
If Application.CutCopyMode Then
searchBoxAccessories.Visible = False
Exit Sub
End If
If searchBoxAccessories Is Nothing Then
Set searchBoxAccessories = ActiveSheet.OLEObjects("SearchCombBoxAccessories")
End If
If Target.Column = 1 And Target.Row > 3 Then
Dim isect As Range
Set isect = Application.Intersect(Target, ListObjects(1).Range)
If isect Is Nothing Then GoTo DoNothing
isInitializingComboBox = True
GetSearchAccessoriesData
searchBoxAccessories.Activate
isInitializingComboBox = True 'This prevent "_Change" fires up when something changes
searchBoxAccessories.Top = Target.Top
searchBoxAccessories.Left = Target.Left
searchBoxAccessories.Width = Target.Width + 15
searchBoxAccessories.Height = Target.Height + 2
Application.EnableEvents = False 'Another attemp to prevent "_Change" fires up when something changes
searchBoxAccessories.Object.text = Target.text
Application.EnableEvents = True
searchBoxAccessories.Object.SelStart = 0
searchBoxAccessories.Object.SelLength = Len(Target.text)
searchBoxAccessories.Visible = True
isInitializingComboBox = False 'Screenshot is taken here
Set workingCell = Target
Else
DoNothing:
If searchBoxAccessories Is Nothing Then
Set searchBoxAccessories = ActiveSheet.OLEObjects("SearchCombBoxAccessories")
End If
If searchBoxAccessories.Visible Then searchBoxAccessories.Visible = False
End If
End Sub
_____________________
Public Sub GetSearchAccessoriesData()
Dim col2Get As String: col2Get = "3;4;5;6"
Dim dataSourceRg As Range: Set dataSourceRg = GetTableRange("PhuKienTbl")
If Not IsEmptyArray(searchAccessoriesArr) Then Erase searchAccessoriesArr
searchAccessoriesArr = GetSearchData(col2Get, dataSourceRg, Sheet22.SearchCombBoxAccessories)
End Sub
_____________________
Public Function GetSearchData(col2Get As String, dataSourceRg As Range, searchComboBox As ComboBox, _
Optional filterMat As String = "") As Variant
Dim filterStr As String: filterStr = IIf(filterMat = "", ";", "1;" & filterMat)
Dim colVisible As Integer: colVisible = 1
Dim colsWidth As String: colsWidth = "200"
Dim isHeader As Boolean
Dim colCount As Integer: colCount = Len(col2Get) - Len(Replace(col2Get, ";", "")) + 1
GetSearchData = GetArrFromRange(dataSourceRg, col2Get, False, filterStr)
With searchComboBox
.ColumnCount = colVisible
.ColumnWidths = colsWidth
.ColumnHeads = False
End With
Set dataSourceRg = Nothing
End Function
_____________________
Public Function GetArrFromRange(rg As Range, cols2GetStr As String, isHeader As Boolean, Optional colCriFilterStr As String = ";") As Variant
Dim col2Get As Variant: col2Get = Split(cols2GetStr, ";")
Dim arrRowsCount As Integer
Dim arrColsCount As Integer: arrColsCount = UBound(col2Get) + 1
Dim resultArr() As Variant
Dim iRow As Integer
Dim iCol As Integer
Dim criCol As Integer
If Len(colCriFilterStr) = 1 Then
criCol = 0
Else: criCol = CInt(Left(colCriFilterStr, InStr(colCriFilterStr, ";") - 1))
End If
Dim criStr As String: criStr = IIf(isHeader, "", Mid(colCriFilterStr, InStr(colCriFilterStr, ";") + 1))
If isHeader Then
arrRowsCount = 1
Else
If criCol <> 0 Then
arrRowsCount = WorksheetFunction.CountIf(rg.Columns(criCol), criStr)
Else
arrRowsCount = rg.Rows.Count
End If
End If
If arrRowsCount = 0 Then GoTo EndOfFunction
ReDim resultArr(1 To arrRowsCount, 1 To arrColsCount)
Dim wkCell As Range
Dim arrRow As Integer: arrRow = 1
For iRow = IIf(isHeader, 1, 2) To IIf(isHeader, 1, rg.Rows.Count)
If criStr = "" Then
For iCol = 1 To arrColsCount
resultArr(arrRow, iCol) = rg.Cells(iRow, CDbl(col2Get(iCol - 1))).Value
Next iCol
arrRow = arrRow + 1
Else
If rg.Cells(iRow, criCol).Value = criStr Then
For iCol = 1 To arrColsCount
resultArr(arrRow, iCol) = rg.Cells(iRow, CDbl(col2Get(iCol - 1))).Value
Next iCol
arrRow = arrRow + 1
End If
End If
Next iRow
EndOfFunction:
GetArrFromRange = resultArr
Erase resultArr
End Function
After weeks of frustration, I am please to announce that I found out the cause. It was the Freeze Panes that affects the display of combobox. Particularly, ComboBox placed in freezed column is not refreshed as frequently as in other cell. In that area, combobox almost act as it's disabled (visually). No text changes update even when you type, no selection/highlighting. I changed to only freeze upper rows and the combobox works just as expected. That's why my other comboboxes in other sheets behaved correctly.
I suspect that Excel tries to save resources by making the freezed part not as responsive. That behavior override Application.ScreenUpdating and not exposed to user.
Since this "feature" could be version specific, my system is Win 10 pro, Excel 16 pro plus.

Next buttons userform Excel VBA

I have an admin sheet that has a column containing a list of True and False. I am building a userform UI so users can click next (for now - building previous button after making next work), the userform will show the next False item in admin sheet and its corresponding data in Sheet1 will be displayed in Textbox1.
Reason for this is the row id in admin sheet correlates with Sheet1. So if data in Sheet1 row(31) has something wrong, column(13) in Admin sheet row(31) will be False.
Code:
Dim n As Long
Private Sub CommandButton1_Click()
Dim LR As Long
LR = Sheets("Sheet1").Cells(Rows.count, "B").End(xlUp).row
n = 7
With Worksheets("Admin")
For i = n To LR
If .Cells(i, 13).Value = "False" Then
With Worksheets("Sheet1")
Me.TextBox1 = .Cells(i, 2).Value
Exit For
End With
End If
Next i
End With
n = i + 1
End Sub
This successfully goes to the next False item and displays it correctly in Textbox1. However, it does not iterate to the next one..
Whatever logic we use to set up Next, I am going to assume Previous will be the same?
Thanks guys.
You can do something like this:
Sub cmdNext_Click()
FindRow True
End Sub
Sub cmdPrev_Click()
FindRow False
End Sub
Private Sub FindRow(bForward As Boolean)
Const RW_START As Long = 7
Dim LR As Long, t As Long, dir As Long, i As Long
LR = Sheets("Sheet1").Cells(Rows.Count, "B").End(xlUp).Row
'going forwards, or back?
If bForward Then
n = IIf(n = 0, RW_START, n + 1) '<< Start at top
t = LR '<< towards here
dir = 1 '<< increasing
Else
n = IIf(n = 0, LR, n - 1) '<< Start at bottom
t = RW_START '<< towards here
dir = -1 '<< decreasing
End If
For i = n To t Step dir
If Worksheets("Admin").Cells(i, 13).Value = "False" Then
Me.TextBox1 = Worksheets("Sheet1").Cells(i, 2).Value
n = i
Exit For
End If
Next i
End Sub

interlinking two listbox with commandbutton

I have developed an userform, with two Listbox multiple option.
I have populated the listbox1 with "locations" eg:Germany, USA, UK ; from sheet list.
I have populated listbox2, with the "locations"eg:Germany, USA, UK from sheet list_Man.
My objective is to filter the rows in my sheet "result", depending upon the locations selection. The location are available in column L and M of my sheet "result"
I have an function Do filter for this.
Sub DoFilter()
Dim Ws As Worksheet
Dim strCriteria() As String
Dim arrIdx As Integer
Dim xRow As Integer
arrIdx = 0
For xRow = 2 To Last(1, List.Cells)
If List.Cells(xRow, 2) = True Then
ReDim Preserve strCriteria(0 To arrIdx)
strCriteria(arrIdx) = List.Cells(xRow, 3)
arrIdx = arrIdx + 1
End If
Next xRow
Set Ws = ThisWorkbook.Sheets("Result")
If arrIdx = 0 Then
Ws.UsedRange.AutoFilter
Else
Ws.Range("A:R").AutoFilter Field:=12, Criteria1:=Array(strCriteria), Operator:=xlFilterValues
End If
End Sub
![this is the user form that have been designed. The Listbox1 has the locations from the list sheet and the listbox2 has the locations from the List_Man sheet.
The filter option, according to the selection in the listbox, filters the column L and M of the sheet "Result". exit buton, unloads and returns to the original sheet clearing the filter option.]1
Now the userform works in such a way that, if I select both the listbox, then I get the option filtered.
I would like to have an code in my command button, in such a way that
[![If I am selecting more than one option in listbox1,"USA and UK" and in listbox2, I am selecting "Germany", then I need the filtered rows in result sheet for these option".
also the case in viceversa should be possible. If I select only location2 in listbox2, I should be able to see the filtered rows in the sheet"result".
if I am selecting more than one option in listbox2, and one option in listbox1, then I should be able to see the result accordingly.
I would like to have a code in my command button "Filter" for such condition.
Any lead would be helpful.
this is the code, I am using in my listbox
Private Sub ListBox2_Change()
Dim listboxCounter As Integer
For listboxCounter = 0 To ListBox2.ListCount - 1
If ListBox2.Selected(listboxCounter) = True Then
List_Man.Cells(listboxCounter + 2, 2) = True
Else
List_Man.Cells(listboxCounter + 2, 2) = False
End If
Next
End Sub
this is the code for my userform
Private Sub UserForm_activate()
Dim xRow As Integer
Dim yows As Integer
For xRow = 2 To Last(1, List.Range("A:A"))
With ListBox1
.AddItem List.Cells(xRow, 3).Value
If List.Cells(xRow, 2) = True Then
.Selected(xRow - 2) = True
Else
.Selected(xRow - 2) = False
End If
End With
Next xRow
ListBox1.Height = (xRow - 1) * 15
For yrow = 2 To Last(1, List_Man.Range("A:A"))
With ListBox2
.AddItem List_Man.Cells(yrow, 3).Value
If List_Man.Cells(yrow, 2) = True Then
.Selected(yrow - 2) = True
Else
.Selected(yrow - 2) = False
End If
End With
Next yrow
ListBox2.Height = (xRow - 1) * 15
End Sub

VBA to display results on multiple checkbox with "True" condition

I have designed an useform with listbox having multiple Options.
The listbox are populated with Locations. eg: Germany, USA etc.
If Checkbox "Germany" is true, then it should filter the results of Germany in my sheet "Result" in the column "L". If the Checkbox "GErmany and USA are checked" then I would like to have the results filtered for both the Locations in my sheet.
Surfing through Internet, I found a code like this: This works with Checkbox, how should i modify this for Listbox with multiple Option ?
Private Sub Filter()
Dim Ws As Worksheet
Dim strCriteria() As String
Dim arrIdx As Integer
Dim cBox As Control
arrIdx = 0
For Each cBox In Me.Controls
If TypeName(cBox) = "CheckBox" Then
If cBox.Value = True Then
ReDim Preserve strCriteria(0 To arrIdx)
strCriteria(arrIdx) = cBox.Caption
arrIdx = arrIdx + 1
End If
End If
Next cBox
Set Ws = ThisWorkbook.Sheets("Result")
If arrIdx = 0 Then
Ws.UsedRange.AutoFilter
Else
Ws.Range("A:R").AutoFilter Field:=12, Criteria1:=Array(strCriteria), Operator:=xlFilterValues
End If
End Sub
This works with Checkbox, how should I modify this for listbox with multiple Option like Image below
any lead would be helpful
This might be helpful for you
With ListBox1
For x = 0 To .ListCount - 1
If .Selected(x) Then
temp = temp & Chr(10) & .List(x)
End If
Next
End With
MsgBox temp & " is selected"
Try
Dim strCriteria() As String, i As Integer, arrIdx As Integer
ReDim strCriteria(0 To Me.listBoxCountries.ListCount-1)
For i = 0 To Me.listBoxCountries.ListCount - 1
If Me.listBoxCountries.Selected(i) Then
strCriteria(arrIdx) = Me.listBoxCountries.List(i)
arrIdx = arrIdx + 1
End If
Next i
If arrIdx = 0 Then
Ws.UsedRange.AutoFilter
Else
ReDim preserve strCriteria(arrIdx - 1)
Ws.Range("A:R").AutoFilter Field:=12, Criteria1:=Array(strCriteria), Operator:=xlFilterValues
End If
With the help of Fun Thomas, I edited few lines of his code and it works for my requirement.
Here is the code.
Private Sub DoFilter34()
Dim ws As Worksheet
Dim strCriteria() As String, i As Integer, arrIdx As Integer
ReDim Preserve strCriteria(0 To arrIdx)
arrIdx = 0
For i = 0 To Me.ListBox1.ListCount - 1
If Me.ListBox1.Selected(i) Then
ReDim Preserve strCriteria(0 To arrIdx)
strCriteria(arrIdx) = Me.ListBox1.List(i)
arrIdx = arrIdx + 1
End If
Next i
Set ws = Sheets("Result")
If arrIdx = 0 Then
ws.UsedRange.AutoFilter
Else
ws.Range("A:R").AutoFilter Field:=12, Criteria1:=Array(strCriteria), Operator:=xlFilterValues
End If
End Sub

Loop Through Userform & Paste to Offset Cells

It's me again!
I am trying to input data into a database with a userform by looping through each control and pasting it into a cell via an offset with a counter. I am getting an error on the line which actually inputs the data to the cell and cannot figure out how to do this via a loop. It would be easy to do it field by field but I do not want to write that many lines of code.
Here is my most recent attempt:
Option Explicit
Sub cbSubmit_Click()
' Set worksheet
Dim dbFood As Worksheet
Set dbFood = Sheets("dbFood")
'Set last row and column
Dim lRow As Long
lRow = Cells(Rows.Count, 1).End(xlUp).Row
Dim lCol As Long
lCol = Cells(1, Columns.Count).End(xlLeft).Row
'Define idCell as Range type
Dim idCell As Range
' If no records exit, add first record
If Cells(lRow, 1).Value = "ID" Then
Set idCell = dbFood.Range("A2")
idCell.Value = 1
' Add Data
Dim ufControl As Control
Dim Counter As Long
Counter = 1
For Each ufControl In Me.Controls
If TypeOf ufControl Is MSForms.ComboBox Or MSForms.TextBox Then
idCell.Offset(0, Counter).Value = ufField.Value
Counter = Counter + 1
End If
Next ufControl
MsgBox "Added to database!"
' Else add next record
ElseIf Cells(lRow, 1).Value >= 0.1 Then
Dim lastID As Long
lastID = Cells(lRow, 1).Value
Set idCell = dbFood.Cells(lRow + 1, 1)
idCell.Value = lastID + 1
' Add Data
' If none of the above display ERROR and exit sub
Else: MsgBox ("ERROR - Cannot Create Record")
Exit Sub
End If
End Sub
If anyone could help me figure out how to solve this one then great!
I managed to solve this by using the method Kathara suggested to me but edited it to avoid the 438 error. Below is the small adjustment I made to make it work:
For Each ufControl In Me.Controls
If TypeOf ufControl Is MSForms.TextBox Then
idCell.Offset(0, Counter).Value = ufControl.Text
Counter = Counter + 1
ElseIf TypeOf ufControl Is MSForms.ComboBox Then
idCell.Offset(0, Counter).Value = ufControl.Text
Counter = Counter + 1
End If
Next ufControl
Many thanks for your help :)
I saw some things that I have adapted down below. May I ask you to test that bit of code?
Option Explicit
Sub cbSubmit_Click()
Dim dbFood As Worksheet
Set dbFood = ActiveWorkbook.Sheets("dbFood")
Dim lRow As Long
lRow = dbFood.Cells(dbFood.Rows.Count, 1).End(xlUp).Row
Dim lCol As Long
lCol = dbFood.Cells(1, dbFood.Columns.Count).End(xlLeft).Row
Dim idCell As Range
If dbFood.Cells(lRow, 1).Value = "ID" Then
Set idCell = dbFood.Range("A2")
idCell.Value = 1
Dim ufControl As Control
Dim Counter As Long
Counter = 1
For Each ufControl In Me.Controls
If TypeOf ufControl Is MSForms.TextBox Then
idCell.Offset(0, Counter).Value = ufControl.Result
Counter = Counter + 1
ElseIF TypeOf ufControl Is MSForms.ComboBox
idCell.Offset(0, Counter).Value = ufControl.SeletedItem.Value
End If
Next ufControl
MsgBox "Added to database!"
ElseIf dbFood.Cells(lRow, 1).Value >= 0.1 Then
Dim lastID As Long
lastID = dbFood.Cells(lRow, 1).Value
Set idCell = dbFood.Cells(lRow + 1, 1)
idCell.Value = lastID + 1
Else
MsgBox ("ERROR - Cannot Create Record")
Exit Sub
End If
End Sub
As you can see I have divided the types of the ufcontrol as I am not sure that with a combobox you can directly say .Value so you'll have to add .SelectedItem. You can at least try it once :)