Excel VBA Userform, Update and delete database, - excel

I'm very new to Excel VBA and I have found solutions to most my problem through Stackoverflow.com But still, there is a problem I've couldn't solve.
I am working on a multidimensional Userform to maintain our database. The Userform I'm working on containing option boxes, checkboxes, textboxes and combo boxes.
After long search and work, I fixed the search bottoms and they all are working. But I can not get the Update bottom and the Delete bottom to work.
I have uploaded the file, I would be grateful if anyone can help me out with this issue.
Private Sub bt2_Click() 'Update shipment
Dim sonsat As Long, sor As String
If ListBox1.ListIndex = -1 Then
MsgBox "Choose an item", vbExclamation, ""
Exit Sub
End If
sor = MsgBox("Are your sure?", vbYesNo, "")
If sor = vbNo Then Exit Sub
lastrow = Sheets("logbook").Cells(Rows.count, 1).End(xlUp).Row
Sheets("logbook").Range("A1:A" & lastrow).Find(What:=ListBox1.Value,
LookIn:=xlValues, LookAt:=xlWhole).Activate
sonsat = ActiveCell.Row
Cells(sonsat, 1) = op1
Cells(sonsat, 2) = op2
Cells(sonsat, 3) = chb1
Cells(sonsat, 4) = chb2
Cells(sonsat, 5) = tb14
Cells(sonsat, 6) = tb1
Cells(sonsat, 7) = tb2
Cells(sonsat, 8) = tb3
Cells(sonsat, 9) = tb4
Cells(sonsat, 10) = tb5
Cells(sonsat, 11) = cb1
Cells(sonsat, 12) = tb6
Cells(sonsat, 13) = tb7
Cells(sonsat, 14) = tb8
Cells(sonsat, 15) = tb9
Cells(sonsat, 16) = cb2
Cells(sonsat, 17) = tb10
Cells(sonsat, 18) = tb11
Cells(sonsat, 19) = tb12
Cells(sonsat, 20) = cb3
Cells(sonsat, 21) = cb4
Cells(sonsat, 22) = tb13
MsgBox "Item Has Been Changed", vbInformation, ""
ListBox1.list = Sheets("logbook").Range("A1:V" &
Sheets("logbook").Cells(Rows.count, 1).End(xlUp).Row).Value
If Me.op1.Value = True Then
Cells(sonsat, 1).Value = "X"
Else
Cells(sonsat, 1).Value = "-"
End If
If Me.op2.Value = True Then
Cells(sonsat, 2).Value = "X"
Else
Cells(sonsat, 2).Value = "-"
End If
If Me.chb1.Value = True Then
Cells(sonsat, 3).Value = "X"
Else
Cells(sonsat, 3).Value = "-"
End If
If Me.chb2.Value = True Then
Cells(sonsat, 4) = "X"
Else
Cells(sonsat, 4) = "-"
End If
End Sub
Private Sub bt3_Click() 'delete shipmet
Dim sil As Long
Dim e, b, c, d As Integer
If ListBox1.ListIndex = -1 Then
MsgBox "Choose an entry", vbExclamation, ""
Exit Sub
End If
If ListBox1.ListIndex >= 0 Then
cevap = MsgBox("Entry will be deleted. ... Are you sure ?", vbYesNo, "")
If cevap = vbYes Then
Sheets("logbook").Range("A:A").Find(What:=ListBox1.Value).Activate
sil = ActiveCell.Row
Sheets("logbook").Rows(sil).Delete
End If
End If
For d = 1 To 2
Controls("op" & d) = False
Next
For c = 1 To 4
Controls("cb" & c) = "-"
Next
For b = 1 To 2
Controls("chb" & b) = False
Next
For e = 1 To 14
Controls("tb" & e) = ""
Next
ListBox1.list = Sheets("logbook").Range("A1:V" &
Sheets("logbook").Cells(Rows.count, 1).End(xlUp).Row).Value
End Sub

The following is based on the file you uploaded to Google Drive (as at 2017-06-08, 09:01 UK Time).
I lost a few controls when trying to open the workbook, perhaps our versions of Excel are too different for mine to cope with them. These were your date controls dtp2 and dtp3. I commented out code relating to these whenever they caused me trouble. Hopefully that doesn't negatively affect what follows ...
Main Suggestions
To get things to run at all I had to declare the lastrow variable and the cevap variable.
Your listbox1 is allowing multi-select. If you want to update just one row, you need to ensure that only one row is selected. Within the "Behaviour" section of the control properties, I'd change MultiSelect to 0 - fmMultiSelectSingle.
Because you were allowing multi-select, listbox1.value wasn't working. You have to do it differently when you allow multi-select (see here). But assuming you're okay with single-select, you don't need to worry about that.
When you use your Find ... Activate you'll then get a different error. Excel can't Activate the spreadsheet because Userform1 retains focus. You might be able to change that by making the form "non-modal", but I wouldn't. Instead, rather than, for example:
Sheets("logbook").Range("A1:A" & lastrow).Find(What:=ListBox1.Value, _
LookIn:=xlValues, LookAt:=xlWhole).Activate
sonsat = ActiveCell.Row
I'd do
sonsat = Sheets("logbook").Range("A1:A" &
lastrow).Find(What:=ListBox1.Value, _
LookIn:=xlValues, LookAt:=xlWhole).Row
Which avoid's the need to Activate. After that the code should run without complaining.
However, it still doesn't do what you want. The value of the listbox is based on your bound column, which you've set to the be first column. That value doesn't uniquely identify the row. As a result, when you run the update/delete the code updates/deletes the first matching row.
Minor Matters
There is currently nothing preventing the user selecting and updating/deleting the header row. Personally, I'd take them out of the listbox (start at A2 instead of A1) and add them as "column headings" in the form.
I'm guessing the title of the form should be "Data Entry Application" not "Data Entery Application".

Related

Excel VBA Listbox displays more times than expected

My macro goes through all data rows on a specific sheet. Currently there are 6 rows. The first row is a negative number and the 2nd row is a positive number (debit and credit).
The macro reviews each row and displays a list box for the user to make a selection. Then it goes through the next row and does the same thing. I'm expecting the listbox to display 6 times, once for each row of data.
The problem I'm having is that the listbox is displaying 7 times. 3 times for the first pair or records and twice for the remaining pair of records. I can't figure out why the listbox is displaying the extra time.
Here is the code for the list box:
Private Sub ContinueButton_Click()
If IsNull(ListBox1.Value) Then
MsgBox " Please select the appropriate balance to continue. "
Exit Sub
Else
MyIndex = 0
MyIndex = ListBox1.ListIndex
MyIndex = MyIndex + 1
MyBal = ""
MyBal = APIARArray(MyIndex, 4)
Unload UserForm1
UserForm1.Hide
Sleep 750
End If
End Sub
Private Sub UserForm_Initialize()
UserForm1.Label1.Caption = "Please select the appropriate balance for Unit: " & vUnit
ListBox1.ColumnCount = 4
ListBox1.ColumnWidths = "50;50;75;50"
Dim i As Integer
With ListBox1
w = 1
i = 0
For w = 1 To UBound(APIARArray)
DoEvents
.AddItem
.List(i, 0) = APIARArray(w, 1)
.List(i, 1) = APIARArray(w, 2)
.List(i, 2) = APIARArray(w, 3)
.List(i, 3) = format(APIARArray(w, 4), "#,##0.00;[Red](#,##0.00)")
i = i + 1
Next
End With
UserForm1.Height = 215
UserForm1.Width = 348
ListBox1.SetFocus
End Sub
This is the code that calls the ListBox:
Sub LookForBalance()
Dim r As Integer
Dim APIUnit As String
r = 2
Do Until Len(Trim(Cells(r, 1))) + Len(Trim(Cells(r, 7))) + Len(Trim(Cells(r, 9))) + Len(Trim(Cells(r, 10))) + Len(Trim(Cells(r, 11))) = 0
DoEvents
If Trim(Cells(r, 27)) = "A199" Then
If Cells(r, 29) > 90 Then
APIUnit = ""
vUnit = ""
vUnit = Trim(Cells(r, 11))
If MyCntry = "A1" Then APIUnit = clsAPI.APIARSearch("WWW11", Trim(Cells(r, 11)))
If MyCntry = "A2" Then APIUnit = clsAPI.APIARSearch("WWW12", Trim(Cells(r, 11)))
If InStr(1, APIUnit, "ERROR") > 0 Then
Cells(r, 30) = "Unit Not Found"
Else
If UBound(APIARArray) > 1 Then
Load UserForm1
UserForm1.Show
Cells(r, 30) = MyBal
Else
Cells(r, 30) = APIARArray(1, 4)
End If
End If
End If
End If
r = r + 1
Loop
End Sub
There isn't much code here but I'm not sure what is going on. Any help or suggestions to resolve this issue would be greatly appreciated. Thanks in advance for your help.....

User form (Updating,Adding, Deleting and Resetting)

Hi Im having a problem on Updating and Deleting the data on my Worksheet. Using VBA Excel user form I always got a problem on Application defined object defined error.
I tried Rows select method but I cant get the output that I needed.
Private Sub cmdUpdate_Click()
If Me.cmbAssetTag.Value = "" Then
MsgBox "Asset Tag Can Not be Blank!!!", vbExclamation, "Asset Tag"
Exit Sub
End If
AssetTag = Me.cmbAssetTag.Value
Sheets("Assets").Select
Dim r As Single
Dim msg As String
Dim ans As String
r = Me.cmbAssetTag.Value
Rows(r, Cells).Select
Cells(r, 2) = Me.txtName.Text
Cells(r, 3) = Me.txtManager.Text
Cells(r, 4) = Me.txtDepartment.Text
Cells(r, 5) = Me.txtAction.Text
Cells(r, 6) = Me.txtTemplate.Text
Cells(r, 7) = Me.txtModel.Text
Cells(r, 8) = Me.txtReason.Text
Cells(r, 9) = Me.txtDate.Text
Cells(r, 10) = Me.txtUpdatedBy.Text
msg = "Asset Tag" & rowselect & " Successfully Updated...Continue?"
Unload Me
ans = MsgBox(msg, vbYesNo, "Update")
If ans = vbYes Then
UserForm1.Show
Else
Sheets("Assets").Select
End If
End Sub
The actual result should replaced the data on the sheet with the replaced input

How to change the 'Sheet1' name to a custom spreadsheet name like "AAA BBB"?

I'm very new to vba that's why I rely so much on internet search. What I'm trying to do now is I want to make an Advanced Filter using a ComboBox where a user will type a keyword and it will be automatically be displayed on the ListBox (Extracting data as the user type).
Since I don't don't know to do it, I searched for tutorials online and I found this code from https://www.razakmcr.in/2017/10/ms-excell-listbox-search-by-textbox-vba.html. <- that's what I'm trying to do exactly. But I noticed that his sheet is named to default 'Sheet1'. I have a sheet named "DATA STOCK" and I've tried to change Sheet1 to "DATA STOCK" but I got an error. I want to try his code because it may be a huge help.
Here is his code:
Private Sub TextBox1_Change()
Me.TextBox1.Text = StrConv(Me.TextBox1.Text, vbProperCase)
Dim i As Long
Me.ListBox1.Clear
On Error Resume Next
For i = 1 To Application.WorksheetFunction.CountA(Sheet1.Range("A:A"))
a = Len(Me.TextBox1.Text)
If Left(Sheet1.Cells(i, 1).Text, a) = Left(Me.TextBox1.Text, a) Then
Me.ListBox1.AddItem Sheet1.Cells(i, 1).Value
Me.ListBox1.List(ListBox1.ListCount - 1, 1) = Sheet1.Cells(i, 2).Value
End If
Next i
End Sub
What I did is for example: For i = 1 To Application.WorksheetFunction.CountA(Sheet1.Range("A:A")) to For i = 1 To Application.WorksheetFunction.CountA(("DATA STOCK").Range("A:A"))
Anyway, here is my code for the WHOLE ComboBox that serves as an Advanced Filter:
Private Sub cmbSearch_Change()
Me.cmbSearch.Text = StrConv(Me.cmbSearch.Text, vbProperCase)
Dim i As Long
Me.listHeader.Clear
On Error Resume Next
For i = 1 To x
a = Len(Me.cmbSearch.Text)
If Left("DATA STOCK").Cells(i, 1).Text, a) = Left(Me.cmbSearch.Text, a) Then
Me.cmbSearch.AddItem Sheet1.Cells(i, 1).Value
Me.cmbSearch.List(listHeader.ListCount - 1, 1) = Sheet1.Cells(i, 2).Value
End If
Next i
'THE FF CODE WILL DISPLAY THE VALUE ON THE LISTBOX FROM THE COMBOBOX SELECTION
x = Sheets("DATA STOCK").Range("A" & Rows.Count).End(xlUp).Row
For y = 2 To x
If Sheets("DATA STOCK").Cells(y, 1).Text = cmbSearch.Value Then
cmbSchema.Text = Sheets("DATA STOCK").Cells(y, 1)
cmbEnvironment.Text = Sheets("DATA STOCK").Cells(y, 2)
cmbHost.Text = Sheets("DATA STOCK").Cells(y, 3)
cmbIP.Text = Sheets("DATA STOCK").Cells(y, 4)
cmbAccessible.Text = Sheets("DATA STOCK").Cells(y, 5)
cmbLast.Text = Sheets("DATA STOCK").Cells(y, 6)
cmbConfirmation.Text = Sheets("DATA STOCK").Cells(y, 7)
cmbProjects.Text = Sheets("DATA STOCK").Cells(y, 8)
UserForm1.listHeader.RowSource = "A" + CStr(y) + ": H" + CStr(y)
Exit For
End If
Next y
End Sub
Can you help me how to create an Advanced Filter?
Sheet1 in this example is the code name of the sheet.
Your DATA STOCK sheet also has a code name, and most likely it's not DATA STOCK. Look it up in the project tree and use instead of Sheet1.
Alternatively, use Worksheets("DATA STOCK") in place of Sheet1, but then your code will rely on users not renaming the sheet.

Search and edit records using userform

i'm relatively new to VBA and have muddled my way through to almost achieving the system i set out to produce.
I have now reached a brick wall and have been smashing my head against it for some time, help with my paradigm (tome only i'm sure) would be very much appreciated!!
So i am able to search for records and populate my user form from that, what i would like to do is update the found record through the same form when clicking the update button which is present on said user form.
Private Sub btsearch_Click()
Dim totrows As Long
totrows = Worksheets("Report").Range("A1").CurrentRegion.Rows.Count
If Txtforename.Text = "" Then
MsgBox "Please enter guest name!!"
End If
For i = 2 To totrows
If Trim(Report.Cells(i, 1)) <> Trim(Txtforename.Text) And i = totrows Then
MsgBox "Guest Not Found"
End If
If Trim(Report.Cells(i, 1)) = Trim(Txtforename.Text) Then
Txtforename.Text = Report.Cells(i, 1)
Txtsurename.Text = Report.Cells(i, 2)
Cboidtype.Text = Report.Cells(i, 3)
txtidnumber.Text = Report.Cells(i, 4)
Cboroomno.Text = Report.Cells(i, 5)
txtcheckin.Text = Report.Cells(i, 6)
txtcheckout.Text = Report.Cells(i, 7)
Cbopaymenttype.Text = Report.Cells(i, 9)
Txttotalpayment.Text = Report.Cells(i, 10)
cmbouser.Text = Report.Cells(i, 11)
Exit For
End If
Next i
End Sub
Private Sub btnupdate_Click()
answer = MsgBox("Would you like to update guest details?", vbYesNo +
vbQuestion, "Update Record")
If answer = vbYes Then
Cells(currentrow, 1) = Txtforename.Text
Cells(currentrow, 2) = Txtsurename.Text
Cells(currentrow, 3) = Cboidtype.Text
Cells(currentrow, 4) = txtidnumber.Text
Cells(currentrow, 5) = Cboroomno.Text
Cells(currentrow, 6) = txtcheckin.Text
Cells(currentrow, 7) = txtcheckout.Text
Cells(currentrow, 9) = Cbopaymenttype.Text
Cells(currentrow, 10) = Txttotalpayment.Text
Cells(currentrow, 11) = cmbouser.Text
End If
End Sub
Something like this should work (untested). The matched row is stored in a global variable so you can update it when you're finished editing
Dim CurrentRow As Range 'to store the matched row
Private Sub btsearch_Click()
Dim totrows As Long, i As Long, fName
fName = Trim(Txtforename.Text)
If Len(fName) = 0 Then
MsgBox "Please enter guest name!!"
Exit Sub
End If
totrows = Report.Range("A1").CurrentRegion.Rows.Count
Set CurrentRow = Nothing 'clear any previous row
For i = 2 To totrows
If Trim(Report.Cells(i, 1)) = fName Then
Set CurrentRow = Report.Rows(i)
LoadRow CurrentRow '<< save the matched row
Exit For
End If
Next i
If CurrentRow Is Nothing Then
MsgBox "not found!"
End If
End Sub
Private Sub btnupdate_Click()
If MsgBox("Would you like to update guest details?", _
vbYesNo + vbQuestion, "Update Record") = vbYes Then
SaveRow CurrentRow
End If
End Sub
'load a row of data into the userform
Sub LoadRow(rw As Range)
With rw
Txtforename.Text = .Cells(1).Value
Txtsurename.Text = .Cells(2).Value
Cboidtype.Text = .Cells(3).Value
'etc etc
End With
End Sub
'save the userform data back to the sheet
Sub SaveRow(rw As Range)
With rw
.Cells(1).Value = Txtforename.Text
.Cells(2).Value = Txtsurename.Text
.Cells(3).Value = Cboidtype.Text
'etc etc
End With
End Sub
First thing I would check is the result value of the MsgBox. MsgBox always returns an integer, and answer is a variant.
Secondly I would declare answer as an integer. Together it could become this : . . .
Dim answer As Integer
answer = Msgbox("Would you ... ecord")
Debug.Print "' answer := " & answer ' display result in immediate-window
MsgBox "' answer := " & answer ' or display the result with a msgbox
If answer = vbYes Then
Debug.Print "' then"
' while you are busy debugging, display this value too
Debug.Print "' currentrow := " & currentrow
. . .
Else
Debug.Print "' else"
End If
. . .

Error 13: type mismatch for a textbox on userform where similar vba statement works

One of our spreadsheets requires a userform. When trying to paste the user's values to the sheet housing the data, I get error code 13: type mismatch.
All the fields are textboxes. One line of code identical except the address of where we're posting the information works.
Here's what I have:
Public Sub btnSubmit_Click()
Dim TableSht As Worksheet
Dim NextRow As Long
Set TableSht = ThisWorkbook.Sheets("Table")
TableSht.Visible = True
'https://www.mrexcel.com/forum/excel-questions/1017033-making-all-fields-userform-mandatory.html#post4880848
'determine if any fields were left blank
For Each Control In Me.Controls '
Select Case TypeName(Control)
Case "TextBox"
If Control.Value = vbNullString Then
MsgBox "empty field in " & Control.Name
Exit For
End If
Case Else
End Select
Next Control
'data is housed in E3:J3, E5:J5, E7:J7, E9:J9. if statement determines what row information
'should be entered on.
If TableSht.Range("E3") = "" Then
NextRow = 3
ElseIf TableSht.Range("E5") = "" Then
NextRow = 5
ElseIf TableSht.Range("E7") = "" Then
NextRow = 7
ElseIf TableSht.Range("E9") = "" Then
NextRow = 9
Else
MsgBox ("There are no more available rows. Contact Craig for additional assistance.")
End If
'paste the user's data entry into the appropriate cells
With TableSht
.Cells(NextRow, 5) = Me.tbOwner
.Cells(NextRow, 6) = CDate(Me.tbDate)
.Cells(NextRow, 7) = Me.tbChange
'Me.tbChange.Value = CDec(Me.tbChange) 'no longer use this but one of my attempts
.Cells(NextRow, 8) = Me.tbAmount
.Cells(NextRow, 9) = Me.tbOriginal
.Cells(NextRow, 10) = Me.tbReason
.Cells(NextRow, 7).Value = Format(Range("G" & NextRow) / 100, "0.00%")
.Cells(NextRow, 8).Value = Format(Range("H" & NextRow), "$##.##")
.Cells(NextRow, 9).Value = Format(Range("I" & NextRow) / 100, "0.00%")
End With
Sheets("Rate Calculator v8").Select
TableSht.Visible = xlVeryHidden
Unload Me
End
End Sub
The error occurs on
.Cells(NextRow, 7).Value = Format(Range("G" & NextRow) / 100, "0.00%")
There's no error if I remove the line and cycle through the two after it, even though the last line before "end with" is essentially the same statement.
I've tried swapping the two lines of code that are similar. "Cells(NextRow, 7)..." and ".Cells(NextRow, 9)..." but the error still shows up on the "Cells(NextRow, 7)..." line.
I've confirmed the cells the data is pasted in columns G and I are both formatted as "percentage".
Qualify your Range usage with a sheet. If the sheet is also TableSht, the below should work. If the Range is from a different sheet, qualify that sheet
= Format(.Range("G" & NextRow) / 100, "0.00%")
= Format(.Range("H" & NextRow), "$##.##")
= Format(.Range("I" & NextRow) / 100, "0.00%")

Resources