Multiple checkboxes in dropdown list for multiple cells - vba

I have a column K that is headed with "Downloads". I want to be able to click a cell in column K, then a listbox with checkboxes appears and I select from a list of 7 (which is stored in another sheet) the names of the files that have been downloaded by that user. These are then added to the cell, separated by commas.
The issue I'm having is that each cell in column K needs to be different, so for example, if my list of downloads is "Item A, Item B, Item C" etc. and then in K3 I check Item A, then it should display just Item A. However, then if I click K29 and select Item A, B and C, then it should display "Item A, Item B, Item C" in that cell.
Here's an example of something I was testing which didn't work as it filled EVERY cell in column K with what I checked. Also, the dropdown was always visible and I only want it visible when a cell is clicked:
Private Sub ListBox1_Change()
Dim lngCurrentItem As Long
Dim strCurrentItem As String
Dim strAllSelectedItems As String
Dim rngOutput As Range
Set rngOutput = [K1:K999]
strAllSelectedItems = ""
For i = 0 To ListBox1.ListCount - 1
strCurrentItem = ListBox1.List(i)
If ListBox1.Selected(i) Then
If strAllSelectedItems = "" Then
strAllSelectedItems = strCurrentItem
Else
strAllSelectedItems = strAllSelectedItems & " - " & strCurrentItem
End If
End If
Next i
If strAllSelectedItems = "" Then
rngOutput = "No Items Selected"
ElseIf InStr(1, strAllSelectedItems, " - ", vbTextCompare) > 0 Then
rngOutput = strAllSelectedItems & " Are Selected"
Else
rngOutput = strAllSelectedItems & " Is Selected"
End If
End Sub

I think I'd use a Userform if I were doing this.
You can insert one in your editor and make it look like this:
I've added a Label and changed its properties as follows:
Name = lblPrompt
Autosize = true
Wordwrap = false
I've added a Listbox and changed its properties as follows:
Name = lboxItems
MultiSelect = 1 - fmMultiSelectMulti
ListStyle = 1 - fmListStyleOption
List item = Sheet2!A1:A7 ~> use the range of your own items.
I've added 2 CommandButtons and named them btnOk and btnCanx (and changed their captions to 'OK' and 'Cancel'.
Then in the code for the Userform, I've used:
Option Explicit
Private mCell As Range
Public Sub PopUp(user As String, cell As Range)
Dim i As Integer
Set mCell = cell
lblPrompt = "Downloads by " & user
For i = 0 To lboxItems.ListCount - 1
lboxItems.Selected(i) = False
Next
Me.Show
End Sub
Private Sub btnCanx_Click()
Me.Hide
End Sub
Private Sub btnOk_Click()
Dim i As Integer
Dim itemText As String
For i = 0 To lboxItems.ListCount - 1
If lboxItems.Selected(i) Then
If Len(itemText) > 0 Then
itemText = itemText & ", "
End If
itemText = itemText & lboxItems.List(i)
End If
Next
mCell.Value = itemText
Me.Hide
End Sub
And, finally, on the Worksheet code behind. I've put:
Option Explicit
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
Dim cell As Range
Dim user As String
For Each cell In Target.Cells
If Not Intersect(cell, Columns("K")) Is Nothing Then
user = CStr(cell.Offset(, -10).Value2)
UserForm1.PopUp user, cell
End If
Next
End Sub

Related

How to make buttons run code on correct row after sorting the rows?

I have a spreadsheet where the rows are individual projects and the columns are the information about of that project.
The columns I am dealing with are for a technician to make a service call so I have: Tech Name, Site Contact, Date, Time and duration.
In the next column I have a button that once clicked, will run my VBA code to generate a meeting request that is sent to that technician which also placed the event on my outlook calendar. This code has been proven and is fine.
I generated buttons for about 300 rows. Upon a click, the code SHOULD check the button's location with the Application.Caller and get row and column numbers which I use to pull info for the meeting request.
Initially the button press works.
The issue is that I have the sheet set to auto sort with AutoFilter.ApplyFilter. So when I enter a job a row 92 with associated button 92 and the row auto sorts to say 30, the button 30 now tries to schedule 31 and button 92 is now scheduling row 30 (not sure where the button that schedules row 30 goes).
When clicked, the button should be reporting the cell directly under it.
Code to create buttons:
Option Explicit
Public Sub CreateButtons()
Application.ScreenUpdating = False
Dim wb As Workbook
Set wb = ThisWorkbook
Dim ws As Worksheet
Set ws = wb.Sheets("Projects")
Dim BTN As Button
Dim btn1 As Range
Dim btn2 As Range
Dim btn3 As Range
Dim i As Long
For i = 2 To 95
Set btn1 = ws.Cells(i, 22)
Set BTN = ws.Buttons.Add(btn1.Left, btn1.Top, btn1.Width, btn1.Height)
With BTN
.Caption = "Schedule" & i
.OnAction = "TASKSCHEDULER"
End With
Set btn2 = ws.Cells(i, 31)
Set BTN = ws.Buttons.Add(btn2.Left, btn2.Top, btn2.Width, btn2.Height)
With BTN
.Caption = "Schedule"
.OnAction = "TASKSCHEDULER"
End With
Set btn3 = ws.Cells(i, 40)
Set BTN = ws.Buttons.Add(btn3.Left, btn3.Top, btn3.Width, btn3.Height)
With BTN
.Caption = "Schedule"
.OnAction = "TASKSCHEDULER"
End With
Next i
Application.ScreenUpdating = True
End Sub
Code for Button Click:
Option Explicit
Public Sub TASKSCHEDULER()
Dim wb As Workbook
Set wb = ThisWorkbook
Dim ws As Worksheet
Set ws = wb.Sheets("Projects")
Dim b As Object
Dim r As Long
Dim c As Long
Set b = ws.Buttons(Application.Caller)
With b.TopLeftCell
r = .Row
c = .Column
End With
Dim TECH As String
Dim sitecon As String
Dim connum As String
Dim schdate As String
Dim schtime As String
Dim schdur As String
If IsEmpty(ws.Cells(r, c - 8)) Then 'VerIfy data has been entered into all fields needed - works
TECH = "Technician" & vbCrLf
Else
TECH = vbNullString
End If
If IsEmpty(ws.Cells(r, c - 5)) Then
sitecon = "Site Contact" & vbCrLf
Else
sitecon = vbNullString
End If
If IsEmpty(ws.Cells(r, c - 4)) Then
connum = "Site Contact Phone #" & vbCrLf
Else
connum = vbNullString
End If
If IsEmpty(ws.Cells(r, c - 3)) Then
schdate = "Date" & vbCrLf
Else
schdate = vbNullString
End If
If IsEmpty(ws.Cells(r, c - 2)) Then
schtime = "Start Time" & vbCrLf
Else
schtime = vbNullString
End If
If IsEmpty(ws.Cells(r, c - 1)) Then
schdur = "Duration" & vbCrLf
Else
schdur = vbNullString
End If 'End field verify
If IsEmpty(ws.Cells(r, c - 7)) Or IsEmpty(ws.Cells(r, c - 5)) Or IsEmpty(ws.Cells(r, c - 4)) Or IsEmpty(ws.Cells(r, c - 3)) Or IsEmpty(ws.Cells(r, c - 2)) Or IsEmpty(ws.Cells(r, c - 1)) Then 'Call out missing fields If present
MsgBox "Missing Fields: " & vbCrLf & vbCrLf & TECH & sitecon & connum & schdate & schtime & schdur
Else
SCHMTG 'Schedule Meeting
End If
'Else
'CNCLMTG 'Cancel Meeting
End Sub
Maybe try shrinking your button a bit so it fits more accurately within the underlying cell space:
Set BTN = ws.Buttons.Add(btn1.Left+2, btn1.Top+2, btn1.Width-4, btn1.Height-4)

Array insertion of Duplicated and not duplicated data to different column in VBA

Good day! in my worksheet i have (1) textbox as TextBox1 and 1 button for submit button. I have here sample code that gives splitted text as an output. I just want that if there's duplicated word in textbox1 and the user enters the submit button it will saves to worksheet(DatabaseStorage) and categorize the output from No Duplicated Word and With duplicated Word. Because this two different fields will be needed for some function of the system.
Private Sub CommandButton1_Click()
Call SplitText
End Sub
Sub SplitText()
Dim WArray As Variant
Dim TextString As String
TextString = TextBox1
WArray = Split(TextBox1, " ")
If (TextString = "") Then
MsgBox ("Error: Pls Enter your data")
Else
With Sheets("DatabaseStorage")
.Cells(.Rows.Count, 1).End(xlUp).Offset(1, 0).Resize(UBound(WArray) + IIf(LBound(WArray) = 0, 1, 0)) = Application.Transpose(WArray)
End With
MsgBox ("Successfully inserted")
End If
End Sub
This should accomplish what you need. I loop through the array to check if the given value exists in the "No Duplicates" column. If not, don't print it there.
Any time I encounter a situation where I need to check a single value against a list (ex. check for duplicates, GT/LT, etc.), I consider looping.
Sub SplitText()
Dim WArray As Variant
Dim TextString As String
Dim col_no_dup As Long
Dim col_dup As Long
Dim counter As Integer
Dim sht_database As Worksheet
With ThisWorkbook
Set sht_database = .Sheets("DatabaseStorage")
TextString = LCase(.Sheets("Sheet1").Shapes("Textbox1").DrawingObject.Text)
End With
WArray = Split(TextString, " ") 'load array
If (TextString = "") Then
MsgBox ("Error: Pls Enter your data")
End
Else: End If
'set column locations for duplicates/no duplicates
col_no_dup = 1
col_dup = 2
With sht_database
.Range("A2:B10000").ClearContents 'clear existing data. Change this as needed
'Print whole array into duplicates column
.Cells(Cells.Rows.Count, col_dup).End(xlUp).Offset(1, 0).Resize(UBound(WArray) + IIf(LBound(WArray) = 0, 1, 0)) = Application.Transpose(WArray)
'Loop through array
For i = LBound(WArray) To UBound(WArray)
counter = 0
lrow_no_dup = .Cells(Cells.Rows.Count, col_no_dup).End(xlUp).Row
For n = 1 To lrow_no_dup 'loop through and check each existing value in the no dup column
If .Cells(n, col_no_dup).Value = WArray(i) Then
counter = counter + 1 'account for each occurence
Else: End If
Next n
If counter = 0 Then 'counter = 0 implies the value doesn't exist in the "No Duplicates" column
.Cells(lrow_no_dup + 1, col_no_dup).Value = WArray(i)
Else: End If
Next i
End With
MsgBox ("Successfully inserted")
End Sub

How to get the MS Word Form Fields Check box associated text and their value using VBA?

How to get the MS word document checkbox form element associated text value. I am able to extract the value of the checkbox. I tried with bookmark and name properties and found that there is no value associated with bookmark filed of the checkbox. I got the following output. Any thoughts?
Form Fields:
Code:
Sub Test()
Dim strCheckBoxName As String
Dim strCheckBoxValue As String
For i = 1 To ActiveDocument.FormFields.Count
If ActiveDocument.FormFields(i).CheckBox Then
strCheckBoxName = ActiveDocument.FormFields(i).Name
strCheckBoxValue = ActiveDocument.FormFields(i).CheckBox.Value
Debug.Print strCheckBoxName & " = " & strCheckBoxValue
End If
Next
End Sub
Output:
Check1 = True
Check1 = True
Check1 = True
Check1 = False
Check1 = False
Check1 = False
Solution looking for:
A = True
B = True
C = True
D = False
E = False
F = False
EDIT:
By default, when a FormField Check Box is added, it has a Bookmark (name) of Check# where # is sequential starting at 1 until n. Copy and Paste are your friends with FormFields, so one of two things will occur if you go that route to get, say your 1000 FormFields:
1: If you do not alter the value of Bookmark (e.g. default to Check1) and copy and paste that say 1000 times, you end up with 1000 FormFields of Bookmark Check1.
2: If you alter the value of Bookmark (e.g. to A) and copy and past that say 1000 times, only the first FormField retains the Bookmark of A while the rest have a Bookmark that is empty.
You can alter the Check Box default bookmark value (in this case Check1 as a result from copy and paste over and over) to a sequential value such as A1, A2, A3, A4 or Check1, Check2, Check3, etc... by using the following:
Sub Test()
Dim strCheckBoxName As String
Dim strCheckBoxValue As String
For i = 1 To ActiveDocument.formFields.Count
If ActiveDocument.formFields(i).CheckBox Then
strCheckBoxName = ActiveDocument.formFields(i).Name
strCheckBoxValue = ActiveDocument.formFields(i).CheckBox.Value
Debug.Print strCheckBoxName & " = " & strCheckBoxValue
End If
Next
End Sub
Sub RenameCheckBox()
Dim oFields As formFields
Dim oVar As Variant
Dim i As Long
Dim x As Long
x = 0
i = 0
If ActiveDocument.ProtectionType <> wdNoProtection Then
ActiveDocument.Unprotect
End If
Set oFields = ActiveDocument.formFields
For x = 1 To oFields.Count
oFields(x).Select
Select Case oFields(x).Type
Case wdFieldFormCheckBox
oVar = oFields(x).CheckBox.Value
i = i + 1
With Dialogs(wdDialogFormFieldOptions)
.Name = "Check" & i
.Execute
End With
oFields(x).CheckBox.Value = oVar
Case Else
'Do Nothing
End Select
Next x
ActiveDocument.Protect Type:=wdAllowOnlyFormFields, NoReset:=True
Call Test
End Sub

VBA loop through column, replace using drop down box

Very new at VBA, I need something that sounds simple but I lack the knowledge or terminology to correctly research how to do this.
I need a way to loop through a column (we'll say D) to find value (X) and prompt a dropdown box from range (T2:T160) to replace value X for each individual occurance of X in rows rows 1 to 10000.
At the same for each time X is found, the value in that row for column B needs to be displayed (the user will query an external application to determine which of the values from the range needs to be set for that unique column B value)
1 b
2 y
3 x
4 t
5 x
and end like this
1 b
2 y
3 q
4 t
5 p
I setup my data like this:
Main code:
Sub findReplace()
Dim iReply As Integer
Dim strName As String
strName = InputBox(Prompt:="Enter Text to Search in Column D", Title:="Search Text", Default:="Enter value to find")
If strName = "Enter value to find" Or strName = vbNullString Then
Exit Sub
Else
For Each cell In Range("D1:D5")
If cell.Value = Trim(strName) Then
'Prompt to see if new value is required
iReply = MsgBox(Prompt:="Found " & strName & vbCrLf & "Value in column B is: " & cell.Offset(0, -2).Value & vbCrLf & "Do you wish to replace it?", _
Buttons:=vbYesNoCancel, Title:="UPDATE MACRO")
'Test response
If strName = "Your Name here" Or _
strName = vbNullString Then
Exit Sub
ElseIf iReply = vbYes Then
'Get new value
UserForm1.Show
ValueSelected = UserForm1.ComboBox1.Value
Unload UserForm1
If ValueSelected = vbNullString Or ValueSelected = "" Then
Exit Sub
Else
'Replace value
cell.Value = ValueSelected
End If
ElseIf iReplay = vbCancel Then
Exit Sub
End If
End If
Next cell
End If
End Sub
Setup a UserForm1 to display a drop down list to provide the user a selection option. Code behind form looks like this: (buttons have to be named the same to work correctly)
Private Sub bnt_Cancel_Click()
Unload Me
End Sub
Private Sub btn_Okay_Click()
Me.Hide
End Sub
Private Sub UserForm_Initialize()
'Populate dropdown list in userform
Dim rng As Range
Dim ws As Worksheet
Set ws = Worksheets("Sheet1")
For Each rng In ws.Range("T1:T10")
Me.ComboBox1.AddItem rng.Value
Next rng
End Sub
When you run it you'll get this sequence of popups:
I said no to the second replacement value so now my spread sheet looks like this:

How to display Values from a multiselect listbox

I have a form in Excel macro. This form will capture the values inserted in textboxes, listbox and store in Sheet2.
There are 2 buttons in the form applet named "Next" and "Previous". These button will be used for navigating between the saved records. I am able to navigate between records and the values display fine in textboxes. However, I am not sure how can I display the Values from listboxes. My list box is a multiselect list box.
I have provided snippet of my code on how the records are saved in sheet2 and how the navigation happens when clicked on Next button.
Private Sub Save_Click()
Dim ctl As Control
Dim S As String
Dim i As Integer
RowCount = Worksheets("Sheet2").Range("A1").CurrentRegion.Rows.Count
With Worksheets("Sheet2").Range("A1")
.Offset(RowCount, 0).Value = Me.Name1.Value ' capture value from list box
'below code is for capturing value from multiselect listbox
With AOI
For i = 0 To .ListCount - 1
If .Selected(i) = True Then S = S & ", " & .List(i)
Next i
Range("A1").Offset(RowCount, 10).Value = S
End With
End Sub
Below code is for navigating between saved records..
Private Sub Next1_Click()
strCurrentSetofRows = Worksheets("Sheet2").Range("A1").CurrentRegion.Rows.Count
i = i + 1: j = 0
If i > (strCurrentSetofRows - 1) Then
MsgBox "No More Records"
Exit Sub
End If
Set sRange = Worksheets("Sheet2").Range("A1")
Name1.Text = sRange.Offset(i, j).Value: j = j + 1
End Sub
Any thoughts on how can I display saved values of AOI (my field).
Since you are storing the values using , as a separator, you can use the same to split the values and upload it to the ListBox. BTW, I hope you are generating the ListBox with the complete list in the UserForm's Initialize event?
Here is a very basic example. Please amend it to suit your needs.
Let's say Cell A1 has Blah1,Blah2,Blah6. Then try this code
Option Explicit
Dim i As Long, j As Long
Private Sub UserForm_Initialize()
ListBox1.MultiSelect = fmMultiSelectMulti
For i = 1 To 10
ListBox1.AddItem "Blah" & i
Next
End Sub
Private Sub CommandButton1_Click()
Dim ArValues As Variant
Dim sValue As String
Dim multivalues As Boolean
If InStr(1, Range("A1").Value, ",") Then
ArValues = Split(Range("A1").Value, ",")
multivalues = True
Else
sValue = Range("A1").Value
multivalues = False
End If
If multivalues = True Then
For i = 0 To UBound(ArValues)
For j = 0 To ListBox1.ListCount - 1
If ListBox1.List(j) = ArValues(i) Then
ListBox1.Selected(j) = True
Exit For
End If
Next j
Next i
Else
For j = 0 To ListBox1.ListCount - 1
If ListBox1.List(j) = sValue Then
ListBox1.Selected(j) = True
Exit For
End If
Next j
End If
End Sub
Screenshot