Trying to update an excel table using a multiselect form - excel

I'm creating a simple log that will update a table of devices to show when the last firmware update was and who updated it. I have a form that will update a single device entry correctly, but I can't get it to work with multiselect. It will only update the last item in the list.
How can I get it so that a that someone can update multiple entries with their name and date in a single use of the form? I think I need to loop through the selected index values (for loop?), but I'm just not seeing it.
Private Sub UpdateButton_Click()
EditIndex = Me.UpdateDevice.ListIndex
If EditIndex = -1 Then
MsgBox "No device was selected", vbExclamation, "Update Log"
Else
EditIndex = EditIndex + 2
Devices.Range("F" & EditIndex) = Me.DateUpdated
Devices.Range("G" & EditIndex) = Me.UpdatedBy
Unload Me
End If
MsgBox "Log has been successfully updated", vbExclamation, "Update Log"
End Sub
EditIndex is a public variable I have saved in a module to use across various forms in this file.

Private Sub UpdateButton_Click()
EditIndex = Me.UpdateDevice.ListIndex
Dim i As Integer
Dim rmaster As Long
If EditIndex = -1 Then
MsgBox "No device was selected", vbExclamation, "Update Log"
Exit Sub
Else
For i = 0 To Me.UpdateDevice.ListCount - 1
If Me.UpdateDevice.Selected(i) Then
rmaster = i + 2
Devices.Range("F" & rmaster) = Me.DateUpdated.Value
Devices.Range("G" & rmaster) = Me.UpdatedBy.Value
Debug.Print (Me.UpdateDevice.List(i))
Debug.Print rmaster
Else
End If
Next i
Unload Me
End If
MsgBox "Log has been successfully updated", vbExclamation, "Update Log"
End Sub
I kept the debug.print to see if it was returning correctly. Only returns the first selected item if I try to update the columns.

ListBox to Update Worksheet
ListIndex will return -1 only if the list box is empty (not populated).
Objects
Command Button - UpdateButton
List Box - UpdateDevice
Text Box - DateUpdated
Text Box - UpdatedBy
Worksheet - Devices
All controls are on a user form.
Devices is the code name of the worksheet.
The Code
Option Explicit
Private Sub UpdateButton_Click()
Dim ItemsCount As Long
Dim i As Long
With Me.UpdateDevice
For i = 0 To .ListCount - 1
If .Selected(i) Then
ItemsCount = ItemsCount + 1
EditIndex = i + 2 ' EditIndex is maybe not needed!?
Devices.Range("F" & EditIndex) = Me.DateUpdated
Devices.Range("G" & EditIndex) = Me.UpdatedBy
End If
Next i
End With
' I don't know why, but I needed the following line to see the complete
' change in worksheet 'Devices' (CodeName) before the MsgBox:
'Application.ScreenUpdating = True
Select Case ItemsCount
Case 0
MsgBox "No device was selected", vbExclamation, "Update Log"
Case 1
MsgBox "Log has been successfully updated with 1" _
& " entry.", vbInformation, "Update Log"
Case Else
MsgBox "Log has been successfully updated with " & ItemsCount _
& " entries.", vbInformation, "Update Log"
End Select
Unload Me
End Sub

The .ListIndex property only returns the index of the last selected item from a multiselect enabled listbox control. You'll have to iterate though all the items in the list and check to see if they have been selected. Note that .ListCount returns the number of items in the listbox control starting with 1 while the .Selected(i) references the list index values which start at 0. (i.e. if the listbox has one item in it, .ListCount returns 1 while .ListIndex returns 0 because there is 1 item in the list, but it is the item at the 0th index).
For i = 0 To Me.lsBox.ListCount - 1
If Me.lsBox.Selected(i) Then
'record was selected
'do something
Debug.Print (Me.lsBox.List(i))
Else
'record was not selected
'do nothing
End If
Next i
Edit 1 - In action
Edit 2 - OPs updated code exactly

Related

VBA Excel - looping through ListView Controls

I have 4 ListViews on the UserForm. Is it possible to check which ListView is active/selected as on the code below?
Private Sub CommandButton8_Click()
For i = 1 To 4
If me."ListView" & i) is selected Then
MsgBox me("ListView" & i ).Name
End If
Next i
End Sub
It is not working with ListView.SelectedItem. I don't actually understand why? Even if ListView is not selected, MsgBox pops up first ListView item as SelectedItem.
For i = 1 To 4
If Me("ListView" & i).SelectedItem > 0 Then
MsgBox "listview" & i & " selected item is " & Me("ListView" & i).SelectedItem
End If
Next i
First, when the data is loaded onto a listview control, the first item is automatically selected. So, to avoid this from happening, set the Selected property for the first item to False after you've added the data. For example...
Me.ListView1.ListItems(1).Selected = False
or
Me.Controls("ListView" & i).ListItems(1).Selected = False
Then you can use the following code to loop through each listview control, and then for each one loop through each item to check which one is selected...
Private Sub CommandButton1_Click()
Dim i As Long
For i = 1 To 4
Dim lv As ListView
Set lv = Me.Controls("ListView" & i)
With lv
Dim j As Long
For j = 1 To .ListItems.Count
If .ListItems(j).Selected Then
MsgBox lv.Name & " - " & .ListItems(j).Text
Exit Sub 'optional
End If
Next j
End With
Next i
End Sub
If you can have more than one item selected, and you want to display the name of each one, remove Exit Sub from the code.

How to click out of Combobox?

I have a combobox with the properties MatchEntry 1-fmMatchEntryCompleteand MatchRequired True.
I need it true to prevent any invalid entry in the combobox. I dont want to make this a Style 2-fmStyleDropDownList but rather keep it a Style 0-fmStyleDropDownCombo because I have about 1000 items to choose from.
This setup works, except if you accidentally click in the combobox, and try to click out of it. You keep getting
Invalid Property Value
Is there anyway I could code the invalid entries so I don't have to assign the property to True?
Figured it out if anyone has this problem in the future. All I did was keep the properties above, and add this code to my userform for the combobox1.
Private Sub ComboBox1_Change()
If Me.ComboBox1.Value = "" Then
'Match not required if zero lenght string
Me.ComboBox1.MatchRequired = False
Else
'Match is required if other than zero length string
Me.ComboBox1.MatchRequired = True
End If
End Sub
You can use the combo LostFocus event. It will check if the value matches one of the combo entries, send a message in case of not, and delete the combo value. Or it can do something else, if my suggestion is not good enough:
Private Sub ComboBox1_LostFocus()
If ComboBox1.Value = "" Then Exit Sub
Dim cbVal As Variant, boolFound As Boolean, i As Long
cbVal = ComboBox1.Value
For i = 0 To ComboBox1.ListCount - 1
If cbVal = ComboBox1.list(i) Then boolFound = True: Exit For
Next i
If Not boolFound Then _
MsgBox "The value """ & cbVal & """ does not exist between the combo items" & vbCrLf & _
"It will be deleted", vbInformation, "Illegal entry": ComboBox1.Value = ""
End Sub
MatchRequired should remain False (default)...

Find & Delete subroutine are not working in Excel

User enters the Waypoint id and then press delete record it, so data of that particular waypoint id should be delete from observations table.
Written a subroutine where my vba code first find the waypoint id in the observation worksheet, get the row number and then delete the row number and move the cell up. If it doesnot find the waypoint id then message should appear Waypoint id not found and cannot be deleted.
My vba code is not working. Can anyone help me to fix this issue? Attach File with name Problem.xlsm
Sub FindRecord(WyPt)
Dim Value As String
WyPtRow = 0
ReadRow = 2
Value = Cells(ReadRow, 2).Select 'Observation Sheet-WayPointID
While Value <> ""
If WyPt = Value Then
WyPtRow = ReadRow
Exit Sub
End If
ReadRow = ReadRow + 1
Value = Cells(ReadRow, 2)
Wend
End Sub
Sub DeleteRecord()
Set DEFrm = Sheets("DataEntryForm")
Set ObsData = Sheets("Observations")
WyPt = Trim(DEFrm.Cells(6, 2)) 'DataEntryForm worksheet-WayPointID
Call FindRecord(WyPt)
If WyPtRow > 0 Then
Worksheets("Observations").Rows(WyPtRow).Delete Shift:=xlShiftUp
MsgBox "WaypointID found", vbOKOnly + vbCritical, "Deleted Succesfully"
End If
If WyPtRow = 0 Then
MsgBox "WaypointID Not found", vbOKOnly + vbCritical, "We can't delete the record"
Exit Sub
End If
End Sub
I suggest you use application.match to find the row to delete.
I have not downloaded your file so this may need to adjustments.
Sub FindRecord()
Set DEFrm = Sheets("DataEntryForm")
WyPt = Trim(DEFrm.Cells(6, 2).value)
WyPtRow = application.match(WyPt, range("B:B"),0)
if not iserror(WyPtRow) then
DeleteRecord(WyPtRow)
else
msgbox "No waypoint found"
end if
End sub
Sub DeleteRecord(WyPtRow)
Worksheets("Observations").Rows(WyPtRow).EntireRow.Delete
End sub
Edit sorry I see now that I made the code in reverse.
My idea was to call FindRecord and it calls delete, I see now that you called Delete and it called find.
Try this code.
Sub DelRow(WyPt As String)
Dim i As Long
For i = 2 To 65536
If Cells(i, 2).Text = WyPt Then
Worksheets("Observations").Rows(i).Delete Shift:=xlShiftUp
MsgBox "WaypointID found", vbOKOnly + vbCritical, "Deleted Succesfully"
Exit Sub
End If
If Cells(i, 2).Text = "" Then 'stop on first empty row
Exit For
End If
Next
MsgBox "WaypointID Not found", vbOKOnly + vbCritical, "We can't delete the record"
End Sub

Using VBA/VlookUp to use data from one table to match data in another table and use that to calculate quantity

So I am working on an inventory spreadsheet and it basically has two large tables in it. One of the tables has the part number/description/location/lot number/quantity/etc (called "Inventory List") and the other one just has part number/description/vendor/total quantity (called "Ordering List"). The first table is mainly for tracking lot numbers of each item so it has multiple instances of one SKU/part number, while the second table is more used to track total quantity of each item for reordering purposes so it will just have one instance of each part number. The tables are locked to the user and the user edits the table by using a User Form to "Pick and Place" items into the table. Currently the pick button is set so they choose from the Lot number table and it will subtract the number they are taking out of or adding to inventory from that row, my question is, how do I match that part number selected in the first table to also subtract/add from/to the total quantity in the second table? I am very new to VBA, and I am not sure if this is even possible. The item that both tables have in common is the first column of each lists the part number. I can post the current code written for the pick/place buttons below.
Private Sub btnPick_Click()
Dim pickValue As Integer
Dim updateQTY As Integer
Dim invQTY As Integer
Dim findMe As Long
Dim sh As Worksheet
Set sh = ThisWorkbook.Sheets("Inventory List")
If Selected_List = 0 Then
MsgBox "You must select an Inventory Item Prior to Pick!", vbOKOnly + vbInformation, "Edit"
Exit Sub
End If
If Me.txtPPQty.Value = "" Then
MsgBox "Please enter a quantity to pick.", vbOKOnly + vbInformation, "Edit"
Exit Sub
End If
pickValue = Me.txtPPQty.Value
invQTY = Me.lstInventory.List(Me.lstInventory.ListIndex, 7)
findMe = Selected_List + 4
If pickValue > invQTY Then
MsgBox "The pick quantity is too high! Please select a lower Value.", vbOKOnly + vbInformation, "Edit"
Exit Sub
End If
If pickValue <= invQTY Then
updateQTY = invQTY - pickValue
End If
ThisWorkbook.Sheets("Inventory List").Cells(findMe, 9) = updateQTY
MsgBox "You have removed " + CStr(pickValue) + " units from the selected item.", vbOKOnly + vbInformation, "Edit"
Dim pickValue As Integer
Dim updateQTY As Integer
Dim invQTY As Integer
Dim findMe As Long
Dim sh As Worksheet
Set sh = ThisWorkbook.Sheets("Inventory List")
If Selected_List = 0 Then
MsgBox "You must select an Inventory Item to Return!", vbOKOnly + vbInformation, "Edit"
Exit Sub
End If
If Me.txtPPQty.Value = "" Then
MsgBox "Please enter a quantity to Return.", vbOKOnly + vbInformation, "Edit"
Exit Sub
End If
pickValue = Me.txtPPQty.Value
invQTY = Me.lstInventory.List(Me.lstInventory.ListIndex, 7)
findMe = Selected_List + 4
If pickValue > invQTY Then
MsgBox "The pick quantity is too high! Please use Inventory Edit functions.", vbOKOnly + vbInformation, "Edit"
Exit Sub
End If
If pickValue <= invQTY Then
updateQTY = invQTY + pickValue
End If
ThisWorkbook.Sheets("Inventory List").Cells(findMe, 9) = updateQTY
MsgBox "You have added " + CStr(pickValue) + " Units to the selected Item.", vbOKOnly + vbInformation, "Edit"
End Sub
Okay, so I have tried to create a general routine to demonstrate my suggested solution. It is by no means the most efficient, but it should complete the task you are after.
First, some clarifications. The routine takes two arguments, part_number and order_qty. The order_qty is the new quantity of the part number you want to set in the other table.
Second, I have used general declarations for demonstrative purposes, so you can adjust these where necessary for your case.
Third, quantity_offset is the column offset from the Part Number column to the Total Quantity column.
Here is the code:
Option Explicit
Sub Update_Quantity(part_number As String, order_qty As Long)
Dim ws1 As Worksheet, update_table_name As String, column_header As String
Dim rng_part_number As Range
Dim quantity_offset As Long
Set ws1 = ThisWorkbook.Sheets("Update_Sheet")
update_table_name = "myTable"
column_header = "Part Number"
quantity_offset = 10
'find part number
'assuming table object and column header Part Number
Set rng_part_number = ws1.Range(update_table_name & "[" & column_header & "]").Find(What:=part_number, LookAt:=xlWhole)
'assign new qty
rng_part_number.Offset(0, quantity_offset).Value = order_qty
End Sub

How can I find the shape that is selected in group box in Excel?

I have a group box with option buttons in it and I need to find out which one of them is selected in VBA. I have been browsing MSDN for hours now and I can't find a solution.
There has to be a way to find the selected option button. Possibly find the group by name and for-each through each option button?
Here's what seems to be a working solution.
(Nod to KazJaw for Dim ... As OptionButton. this seems to be the key to get .GroupBox to work)
Function WhichOption(shpGroupBox As Shape) As OptionButton
Dim shp As OptionButton
Dim shpOptionGB As GroupBox
Dim gb As GroupBox
If shpGroupBox.FormControlType <> xlGroupBox Then Exit Function
Set gb = shpGroupBox.DrawingObject
For Each shp In shpGroupBox.Parent.OptionButtons
Set shpOptionGB = shp.GroupBox
If Not shpOptionGB Is Nothing Then
If shpOptionGB.Name = gb.Name Then
If shp.Value = 1 Then
Set WhichOption = shp
Exit Function
End If
End If
End If
Next
End Function
Use it like this
Sub test()
Dim shpOpt As OptionButton
Set shpOpt = WhichOption(Worksheets("Sheet1").Shapes("Group Box 1"))
Debug.Print shpOpt.Name
End Sub
If you really need to check OptionButton which are grouped (Grouped in the way we group any type of shape) you could go with this code:
Sub Grouped_into_UnitType()
Dim i!
'grouped into 'UnitType' Shape
For i = 1 To ActiveSheet.Shapes("UnitType").GroupItems.Count
With ActiveSheet.Shapes("UnitType").GroupItems(i).ControlFormat
If .Value = 1 Then
MsgBox "Chosen item: " & i
End If
End With
Next i
End Sub
Edit having in mind the following picture the code above will solve the problem if we have Option Buttons which are group in the way we group any Shapes placed in the sheet.
The code under the picture will find which option button is selected if they are located within GroupBox. Code check the name of the group in which OptionButton is located.
Important Note! the code below didn't work until I switched Excel off and run it again.
Sub Grouped_into_GroupBox_UnitType()
Dim OB As OptionButton
For Each OB In ActiveSheet.OptionButtons
'check if grouped into 'UnitType' Shape
If OB.GroupBox.Name = "UnitType" Then
If OB.Value = 1 Then
MsgBox "Chosen item: " & OB.Name & _
vbNewLine & _
"Alt text: " & OB.ShapeRange.AlternativeText
End If
End If
Next
End Sub
Lets say you have two standard option buttons:
To check if its "on" use:
Dim opt As Shape
Set opt = Worksheets("Sheet1").Shapes("Option Button 1")
If opt.ControlFormat.Value = xlOn Then
Debug.Print "option is ""on"" value of 1"
Else
Debug.Print "option is ""off"" value of -4146"
End If
To get its alternat text use:
Debug.Print "Alternate Text is: " & opt.AlternativeText
For a large amount of options the "FormControlType" property can be used:
Dim s as Shape
For Each s In Worksheets("Sheet1").Shapes
If s.FormControlType = xlOptionButton Then
If s.ControlFormat.Value = xlOn Then
Debug.Print "option is ""on"" value of 1"
Else
Debug.Print "option is ""off"" value of -4146"
End If
Debug.Print "Alternate Text is: " & s.AlternativeText
End If
Next
If you wanted a particular group:
Dim s As Shape, o
For Each s In Worksheets("Sheet1").Shapes
If s.FormControlType = xlOptionButton Then
Set o = s.OLEFormat.Object
If o.GroupBox.Name = "Group Box 3" Then
If s.ControlFormat.Value = xlOn Then
Debug.Print "Option is ""on"" value of 1"
Else
Debug.Print "Option is ""off"" value of -4146"
End If
Debug.Print "Alternate Text is: " & s.AlternativeText
Debug.Print "Group: " & o.GroupBox.Name
End If
Set o = Nothing
End If
Next

Resources