The following code seems to be skipping my second for loop. It does not give an error.
I have 20 sheets in my workbook which contains data about different products.
Each sheet contains a column by the name of "selling date" and it is on a different index number on each sheet.
On the dashboard sheet I made two text boxes and one command button.
In the first text box you enter the product number e.g. ssn-45.
In second box you enter the date on which it was sold.
When you click the command button it is supposed to find that product in whichever sheet it may be and then go to its respective selling date column and write the provided date of selling which will be in textbox2.
In each sheet the column in which the selling date has to be entered is different so I will need to write code as the for loop selects different sheets. I will tell it by if statements that if sheet is this then go to column that and etc.
The following code contains location of selling column of one sheet named SSN. I have not written code for locations of selling column from other sheets.
Private Sub CommandButton1_Click()
Dim rw As Long
Dim x As Long
Dim sh As Worksheet
Dim y As Long
Dim msgvalue As VbMsgBoxResult
For y = 1 To ThisWorkbook.Worksheets.Count
set sh = ThisWorkbook.Worksheets(y)
rw = sh.Cells(Rows.Count, 1).End(xlUp).row
For x = 1 To rw
If sh.Cells(x, 1).Value = Me.TextBox1.Value Then
If sh.Name = "SSN" And sh.Cells(x, 12).Value = "" Then
sh.Cells(x, 12).Value = Me.TextBox2.Value
msgvalue = msgbox(Me.TextBox1.Value & "was marked as sold on date:" & Me.TextBox2.Value, vbOKOnly + vbInformation, "Confirmation")
Exit For
Exit For
End If
End If
Next x
Next y
End Sub
You don't need to loop over worksheets if you know the name of the worksheet, and Match is faster than checking row-by-row:
Private Sub CommandButton1_Click()
Dim sh As Worksheet, m
Set sh = ThisWorkbook.Worksheets("SSN")
m = Application.Match(Me.TextBox1.Value, sh.Columns("A"), 0) 'find matching row
If Not IsError(m) Then 'got a match if m is not an error value
If sh.Cells(m, 12).Value = "" Then 'check the matched row
sh.Cells(m, 12).Value = Me.TextBox2.Value
MsgBox Me.TextBox1.Value & " was marked as sold on date: " & Me.TextBox2.Value, _
vbOKOnly + vbInformation, "Confirmation"
End If
End If
End Sub
Also you don't need the result of the MsgBox call if you're not doing anything with it.
Can someone modify my code so that the message box will only show once?
I've been at it for a while now without succes.
The file I'm working on is a register. Whenever the sum of AD13:AJ13 exceed 4 the msg should show,
Prompting action from the user. However as of now, once a cell within the range have exceeded 4 the msgbox shows on all changes within the range, even sums below 4. That's is not intended, i only want the user to be notified once for each cell within the range (AD13:AJ13)
Code:
Private Sub Worksheet_Calculate()
Dim myCell As Range
For Each myCell In Range("AD13:AJ13")
If myCell > 4 Then
MsgBox "Management approval is required once the value exceed 4"
Exit Sub
End If
Next myCell
End Sub
I kind of agree with the comments below the question as Worksheet_Change seems like a more natural trigger. However, the problem could be that this range is not changed directly (i.e. cells have formulae which could depend on cells from other sheets or even other workbooks).
You basically need to somehow save the current state of these cells. Please try this code and see if it helps or opens up a new window of ideas for you.
Private Sub Worksheet_Calculate()
Dim rngSavedState As Range
Dim j As Integer
Dim bMsgBoxShown As Boolean
Set rngSavedState = Range("AD14:AJ14")
Application.EnableEvents = False
With Range("AD13:AJ13")
bMsgBoxShown = False
For j = 1 To .Columns.Count
If .Cells(1, j).Value <> rngSavedState.Cells(1, j).Value Then
rngSavedState.Cells(1, j).Value = .Cells(1, j).Value
If .Cells(1, j) > 4 And Not bMsgBoxShown Then
MsgBox "Management approval is required once the value exceed 4"
bMsgBoxShown = True
End If
End If
Next j
End With
Application.EnableEvents = True
End Sub
You obviously need to change the address of rngSaveState to suit your application.
All the best
I've a Listbox1 and users select items to move into Listbox2. I need to move everything from Listbox2 into Excel.
The Userform should then close Me and another Userform should be displayed (either UF1, UF2 or UF3; a formula in G3 calculates which new form should be displayed).
Private Sub CommandButton2_Click()
Dim i as integer
Dim LastRow As Long
LastRow = Sheets("EnteredData").Range("F" & Rows.Count).End(xlUp).Row
If Me.ListBox2.ListCount = 0 Then
MsgBox ("Please select at least one role")
Else
For i = 0 To ListBox2.ListCount - 1
Sheets("EnteredData").Range("F" & LastRow).Offset(1, 0).Value = ListBox2.List(i)
Me.ListBox2.RemoveItem i
Next i
End If
Unload Me
Sheets("EnteredData").Range("G3").Show
End Sub
The issues:
If Listbox2 contains at least two items, Run-time error 381: Could not get the List property. Invalid property array index on line Sheets("EnteredData").Range("F" & LastRow).Offset(1, 0).Value = ListBox2.List(i)
The 'next' Userform called in Sheets("EnteredData").Range("G3").Show does not display the required form. Unload Me works, but the new form (e.g. UF1) isn't shown.
Try this.
Because you are removing items as you go your loop breaks - whenever you delete anything you need to loop backwards.
That said, that would result in your items being transferred backwards.
To get round that we don't loop backwards (!), but remove all the items in one go at the end using Clear.
Lastly, but by no means least, you need to update your LastRow variable in the loop to avoid overwriting (though you could dispense with it altogether).
Private Sub CommandButton1_Click()
Dim i As Long
Dim LastRow As Long
For i = 0 To ListBox2.ListCount - 1
LastRow = Sheets("EnteredData").Range("F" & Rows.Count).End(xlUp).Row
Sheets("EnteredData").Range("F" & LastRow).Offset(1, 0).Value = ListBox2.List(i)
Next i
Me.ListBox2.Clear
End Sub
I am facing a little problem, I have a userform which contains two comboboxes, a combobox1 for "company name" and another combobox2 for "specialty"
I really want that when I choose for example like in the photo, I choose in combobox1 "teter", I want to display in combobox2 a list which contains only MP and PDP
and if I choose teterss in combobox1, I would like to display in combobox2 only PDP, I tried this in combobox2 which allows you to search only in column H compared to the choice I chose in combobox1 but it does not work
Dim i As Long
Dim isearch As Long
isearch = Worksheets("FRS").Range("A" & Rows.Count).End(xlUp).Row
For i = 2 To isearch
If Trim(sheets7.Cells(i, 1)) = Trim(Combobox1.Value) Then
Combobox2.Value = sheets7.Cells(i, 8).Value
Exit For
End If
Next i
Thanks
Change sheets7 to Sheet7 That way intellisense will pick up the range object.
Dim i As Long
Dim isearch As Long
isearch = Worksheets("FRS").Range("A" & Rows.Count).End(xlUp).Row
For i = 2 To isearch
If Trim(Sheet7.Cells(i, 1)) = Trim(Combobox1.Value) Then
Combobox2.Value = Sheet7.Cells(i, 8).Value
Exit For
End If
Next i
The combo box value can be set in that way but it is not wise. It is good to check if the string of that cell exists between that combo items collection. I try this answer supposing that you know some VBA and your code wants to do something. Otherwise, your explanation does not match the code you presented...
Dim i As Long, isearch As Long, cbIt as Long
isearch = Worksheets("FRS").Range("A" & Rows.Count).End(xlUp).Row
For i = 2 To isearch
If Trim(sheets7.Cells(i, 1)) = Trim(Combobox1.Value) Then
cbIt = ComboIt(Me.ComboBox2, sheets7.Cells(i, 8).Value)
If cbIt = -1 Then
Me.ComboBox2.AddItem sheets7.Cells(i, 8).Value
Me.ComboBox2.Value = sheets7.Cells(i, 8).Value
Else
Me.ComboBox2.ListIndex = cbIt
End If
Exit For
End If
Next i
You need a way to find the combo listIndex for that specific string. Which MUST BE PART OF THE COMBO ITEMS COLLECTION.
I just suppose that sheets7 has been previously correctly set...
Function ComboIt(cb As ComboBox, strIt As String) As Long
Dim i As Long
If cb.ListCount > 0 Then
For i = 0 To cb.ListCount - 1
If cb.List(i) = strIt Then ComboIt = i: Exit Function
Next i
End If
ComboIt = -1
End Function
If your code does not count, based on your explanation, you should clear the combo and add one or two items according to the combobox1 value, not with the checked range...
Something like that:
Private Sub ComboBox1_Change()
If Me.ComboBox1.value = "teter" Then
Me.ComboBox2.Clear
Me.ComboBox2.AddItem "MP"
Me.ComboBox2.AddItem "PDP"
ElseIf Me.ComboBox1.value = "teterss" Then
Me.ComboBox2.Clear
Me.ComboBox2.AddItem "MP"
End If
End Sub
EDIT: I am unable to comment as I am not logged in. Please see edits below.
Here's a suggestion of a smarter way to fill out your comboboxes. You may use Dictionary object (Scripting.Dictionary) to avoid repeated values on your dropdown.
Dictionary is similar to Collection which has a set of Keys (unique) with its corresponding values. You may read on this link to learn more about Dictionary.
Variables used:
companyNamesRange = range of your Company Names
dict = Scripting.Dictionary object
cboCompanyName = ComboBox1
specialty = value of specialty
cboSpecialty = ComboBox2
And now for the code...
Add this to your userform's code -- UserForm_Initialize() event:
Private Sub UserForm_Initialize()
totalRows = Sheet1.Range("A" & Rows.Count).End(xlUp).Row 'get total rows
Set companyNamesRange = Sheet1.Range("A2:A" & totalRows) 'range of company values
Call GetCompanyNameList 'this method will fill add unique items on your Combobox1 (Company Name)
End Sub
For Combobox1 (Company Name), you may use this edit and use the code below to get unique values
Private Sub GetCompanyNameList()
'create dictionary object
Set dict = CreateObject("Scripting.Dictionary")
'loop through each Company Name
For Each cellRange In companyNamesRange
'test if Company Name exists on the dictionary Keys
If Not dict.Exists(cellRange.Value) Then
'since we confirmed that the value is unique, add the value as a dictionary key so that we can collect unique values for testing later on
dict.Add cellRange.Value, ""
'add value to cboCompanyName(Combobox1)
cboCompanyName.AddItem cellRange.Value
End If
Next
'dispose object
Set dict = Nothing
End Sub
Added method here for cboCompany_Change event
Private Sub cboCompanyName_Change()
cboSpecialty.Value = ""
cboSpecialty.Clear
Call GetSpecialtyList
End Sub
For Combobox2 (Specialty), you may edit and use this as well to get unique values of specialty based on the Company Name selected**
Private Sub GetSpecialtyList()
Set dict = CreateObject("Scripting.Dictionary")
For Each companyRange In companyNamesRange
If cboCompanyName.Value = companyRange.Value Then
specialty = Sheet1.Range("B" & companyRange.Row).Value
If Not dict.Exists(specialty) Then
dict.Add specialty, ""
cboSpecialty.AddItem specialty
End If
End If
Next
Set dict = Nothing
End Sub
So, here is my whole [UserForm(Code)] module. I hope I understood everything correct.
Read comments, ask if you have questions.
Option Explicit
Dim dataSheet As Worksheet
Private Sub UserForm_Initialize() ' update UserForm name if needed
Dim companyRange As Range, cr As Range
Dim startRow As Long, columnNo As Long
Set dataSheet = ActiveSheet ' replace ActiveSheet with your data sheet name, don't use ActiveSheet
startRow = 2 ' as I suppose - values start from 2d row, 1st one - is the header, update if needed
columnNo = 1 ' as I suppose - starting column is 1, update if needed
With dataSheet
Set companyRange = Range(.Cells(startRow, columnNo), .Cells(Rows.Count, columnNo).End(xlUp)) ' assign companies range
End With
With ComboBox1 ' this is a combobox with company's names
For Each cr In companyRange
.AddItem cr.Value ' add companies to combobox one by one
' so if the cell row is 2, it will have a 0 ListIndex in combobox
Next
End With
End Sub
'-------------------------------------------------------------------------------------------------------
Private Sub ComboBox1_Change()
Dim item1 As Range, item2 As Range
Set item1 = dataSheet.Cells(ComboBox1.ListIndex + 2, 8) ' see the explanation below this part of code
Set item1 = dataSheet.Cells(ComboBox1.ListIndex + 3, 8)
'when we were adding items to combobox1, the cell on the sartRow=2 has row number 2 and a 0 ListIndex in combobox1 (cell on the row 3 has ListIndex 1, and so on)
'so in order to get the row of selected item - we need to add 2 to item's ListIndex
With ComboBox2
.Clear ' clear the combobox2 upon each change, consider it if you have something in your ComboBox2_Change() event
' 'cos if there is some selected value the .Clear statement will trigger that event
' This point is still not clear to me, so there are 2 options based on original post
' uncomment if needed
' Option 1
If Not item1 = item2 Then ' as I understood, if ites are different we add two of them
.AddItem item1.Value
.AddItem item2.Value
Else
.AddItem item1.Value ' if they are the same - we add only one
End If
' Option 2
' If ComboBox1.Value = "teter" Then
' .AddItem "MP"
' .AddItem "PDP"
' ElseIf ComboBox1.Value = "teterss" Then
' .AddItem "MP"
' End If
End With
End Sub
Adding items to a second combobox
Assuming you want rebuild your list by entering one or several "row" items each time you choose another value in ComboBox1 and assuming your sheet's CodeName actually is sheets7, I'd suggest the following steps:
just clear contents in combobox2,
use the .AddItem method to add comboitems in a list,
omit the Exit For and
set the .ListIndex to the first item in the list if only one item to choose
Private Sub ComboBox1_Change()
Dim isearch As Long
isearch = Worksheets("FRS").Range("A" & Rows.Count).End(xlUp).Row
With Me.ComboBox2
.Clear
Dim i As Long
For i = 2 To isearch
If Trim(sheets7.Cells(i, 1)) = Trim(ComboBox1.Value) Then
.AddItem sheets7.Cells(i, 8).Value
End If
Next i
If .ListCount > 1 Then ' several items
.ListIndex = -1 ' no concrete display, let open for choice
Else
.ListIndex = 0 ' display single item
End If
End With
End Sub
Further hint: instead of using AddItem you could also populate an array and assign it to the .List property via one code line, but the above approach should show you the way :-)
Further assumption: "specialty" items seem to be unique per chosen identifying name.
Edit due to comment
Your issue seems to be caused by adding the ".RowSource` property to you comboboxes.
I added a simple UserForm_Initialize event procedure removing this property by code as first step, so you can control it.
Remove or outcomment a Combobox2_Change (Combospe_Change) event procedure overwriting prior results!
Seems that you named the data worksheet "FRS" sheets7 equalling the sheets Codename feuil7 (Excel worksheet name "FRS") - change that to your needs. Furthermore I sticked to ComboBox1 (Combofrs) and ComboBox2 (Combospe) ... Bonne chance :-)
Private Sub UserForm_Initialize()
With Me.ComboBox1 ' << (Me.Combofrs)
.RowSource = "" ' << remove existing row source !
Dim frs As Collection
Set frs = New Collection
' get unique elements of suppliers/fournisseurs (e.g. teter, teterss, test)
Dim fr
On Error Resume Next
For Each fr In sheets7.Range("listefrs") ' << feuil7.
frs.Add fr, fr
If Trim(fr) = vbNullString Then Exit For
Next
' populate supplier/fournisseurs combo with unique elements
Dim i As Long
For i = 1 To frs.Count
.AddItem frs(i) & ""
Next
End With
'(Combospe)
ComboBox2.RowSource = "" ' << remove existing row source !
End Sub
So I have a table with conditional formatting already setup (attached).
The values are being highlighted in red when greater than +/-35mm for each constituent separately (dE, dN, dH).
what I'm looking for is to create a userform so the user don't have to navigate to manage rules, instead the threshold for each constituent can be changed directly from the userform.
attached is also a photo of what I need Needed
All help greatly appreciated.
conditional_formatting
not sure what you are asking for but my understanding is you want to click on that record and edit it on a user form and you have your spread sheet already formatted.Use this code to achieve that.
place this code behind your sheet in VBA editor(the one with the data to be manipulated)
Private Sub Worksheet_BeforeDoubleClick(ByVal Target As Range, Cancel As Boolean)
'##################################################
'# Intercept a double click in the record area #
'# and open the edit form 36 #
'##################################################
If Target.Column > 65 Or Target.Row < 1 Then
Exit Sub
End If
Cancel = True
EditRecord
End Sub
and place this one on a module
Sub EditRecord()
Dim CurRow As Integer, CurCol As Integer, intCount1 As Long
Dim RecordEntry
Dim iRow As Long
CurRow = ActiveCell.Row
Range("A" & CurRow).Select
' check if empty row - if so call new record
With ActiveCell
If ActiveCell.Value = "" Then
' check empty rows and create new record goto_empty_row
UserForm1.Show
Exit Sub
End If
End With
' edit existing record - populate form
With UserForm1
.TextBox1.Value = ActiveCell.Offset(0, 0)
.TextBox2.Value = ActiveCell.Offset(0, 1)
.TextBox3.Value = ActiveCell.Offset(0, 2)
.Show
End With
End Sub
and then this on your user form
Private Sub CommandButton1_Click()
Dim iRow As Long
Dim ws As Worksheet
Set ws = Worksheets("Sheet2") 'name of the Sheet
'copy the data to the spread sheet
ws.Cells(ActiveCell.Row, 1).Value = Me.TextBox1.Value
ws.Cells(ActiveCell.Row, 2).Value = Me.TextBox2.Value
ws.Cells(ActiveCell.Row, 3).Value = Me.TextBox3.Value
End Sub