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:
Related
I have a Cell range Sheets("INVOICE MAKER").Range("D18:D37") (Total 20 Cells), and a little UserForm with name Add Items.
In UserForm there are one Textbox and one Submit Button.
So if I write something in that Textbox and click on Submit Button, Data should be write to next available empty cell in range Sheets("INVOICE MAKER").Range("D18:D37"). And if all 20 cells are filled with data then show a message like "No more rows are available to write data".
Below code don't start writing data from Cell D18, its start writing data from D1.
and doesn't stop after cell D37.
Option Explicit
Dim lRow As Long
Dim ws As Worksheet
Set ws = Worksheets("INVOICE MAKER")
lRow = ws.Cells.Find(What:="*", SearchOrder:=xlRows, _
SearchDirection:=xlPrevious, LookIn:=xlValues).Row + 1
'check for a part number
If Trim(Me.Textbox.Value) = "" Then
Me.Textbox.SetFocus
MsgBox "Please Type Item Name"
Exit Sub
End If
With ws
.Cells(lRow, 5).Value = Me.Textbox.Value
End With
End Sub
Hope below code will help you:
Public Working_Sheet As Worksheet
Public All_Cell_Value As Boolean
Public Write_Cell_No As Integer
Public Content As String
'When button in the form is clicked
Sub Button1_Click()
Write_Content
End Sub
'validation and content writing function
Public Function Write_Content()
All_Cell_Value = True
Set Working_Sheet = Worksheets("Sheet1")
For i = 18 To 37
If Trim(Working_Sheet.Cells(i, "D")) = "" Then
All_Cell_Value = False
Write_Cell_No = i
Exit For
End If
Next i
If All_Cell_Value = False Then
Content = InputBox("Enter the value")
If Content = "" Then
MsgBox ("No Data")
Else
Working_Sheet.Cells(i, "D").Value = Content
End If
Else
MsgBox ("Sorry content is full")
End If
End Function
Maybe this will help!
EDIT #1
Fix some errors, and the code must to be inside a Form, with the TextBox and the Button
EDIT #2
Added a closing statement for the userform or the macro
Option Explicit
Private Sub CommandButton1_Click()
Dim lRow As Long
Dim ws As Worksheet
Set ws = ThisWorkbook.Worksheets("INVOICE MAKER") 'Set from Thisworkbook
ws.Activate 'activate the Invoice Maker
'lRow = ws.Cells.Find(What:="*", SearchOrder:=xlRows, SearchDirection:=xlPrevious, LookIn:=xlValues).Row + 1
Dim iniCell As Integer: iniCell = 18
Dim endCell As Integer: endCell = 37
Dim setCol As Integer: setCol = ws.Range("D1").Column
'As you said, the range is D18:D37, then you can manipulate from this 3 vars
Dim iRange As Range
Dim i As Range
Dim isTheRangeFull As Boolean: isTheRangeFull = False
Dim iMsgbox As Integer
If Trim(Me.TextBox.Value) = "" Then
Me.TextBox.SetFocus
'Ask the user to retry or quit.
iMsgbox = MsgBox("Please Type Item Name" & Chr(10) & "Do you want to retry?", vbYesNo + vbDefaultButton1)
If iMsgbox = 6 Then
GoTo InsertData
'if the user say YES
'do it again
ElseIf iMsgbox = 7 Then
End
'if the user say NO
End If
End If
Set iRange = ws.Range(Cells(iniCell, setCol), Cells(endCell, setCol))
'set your working Range
'This Loop do the job!
For Each i In iRange
isTheRangeFull = True
'if there is no empty cell, won't enter the if, and
'the var continue TRUE, so there is no empty cells...
If i.Value = Empty Then
i.Value = Me.TextBox.Value
isTheRangeFull = False
'the Next line (End) Will close the Form and terminate the macro
'End
'The next line just close the userform
'Unload Me
'Decide which one to uncomment.
Exit For
End If
Next i
If isTheRangeFull Then
MsgBox "No more rows are available to write data"
End
End If
'With ws
' .Cells(lRow, 5).Value = Me.TextBox.Value
'End With
InsertData:
End Sub
I'm setting up a button to check a range for a value if the value don't exist then copy value to next available row
Private Sub CommandButton2_Click()
Dim LrowCompleted As String
If TextBox1.Text = "" Then
MsgBox "DON'T DO THAT"
Else
LrowCompleted = Sheets("Budget").range("N4").End(xlDown).Row
Sheets("Budget").range("N" & LrowCompleted + 1) = TextBox1.Text
Unload Me
MechanicalEquipment.Show
End If
End Sub
First. LrowCompleted should be a Long not a String.
Second. You need to build the Find portion. Are you only going to find this value in a single column? Example below. Not tested but it should work.
Private Sub CommandButton2_Click()
Dim LrowCompleted As Long, fText as String, Dim findValue As Range
fText = TextBox1.Text
'You probably dont need to check all 3 below but I'm not on excel to check the best one to use.
If fText = "" Or fText = Nothing Or fText = Null Then
MsgBox "Provide what to look for"
Else
Set findValue = Sheets("Budget").Columns("N:N").Find(fText, Range("N1"), xlValues, xlPart, xlByColumns, xlNext)
If findValue Is Nothing Then
'Nothing found lets place it at the end
LrowCompleted = Sheets("Budget").Range("N4").End(xlUp).Row + 1
Sheets("Budget").Range("N" & LrowCompleted) = fText
Unload Me
MechanicalEquipment.Show
Else
'I found something, do nothing i guess
End If
End If
End Sub
I'm not sure why, but when my if statement is false and my msgbox is called I have to click okay 4 times for it to go away. How do I correct this?
My code:
Option Explicit
Private tskCol As String
Private unitCol As String
Private Sub txtTask_Change()
End Sub
Public Sub UserForm_Initialize()
tskCol = Application.InputBox("Enter Column Letter for Task Names", Type:=2)
unitCol = Application.InputBox("Enter Column Letter for Number of Units", Type:=2)
End Sub
Private Sub cmdAdd_Click()
Dim LastRow As Long, i As Long
LastRow = ActiveSheet.Range(tskCol & Rows.Count).End(xlUp).Row
'Copy input values to sheet
For i = 2 To LastRow
If CStr(ActiveSheet.Range(tskCol & i).Value) = CStr(Me.txtTask.Value) Then
ActiveSheet.Range(unitCol & i).Value = Me.txtQuantity.Value
Else
MsgBox "Task Not Found!"
End If
Next i
'Clear input controls
Me.txtTask.Value = ""
Me.txtQuantity.Value = ""
End Sub
To answer your specific question, try changing this line on the Else statement:
Msgbox "Task Not Found"
to
If i = LastRow Then Msgbox "Task Not Found"
You might also want to put Exit For if the task is found. Refactoring IF statement:
If CStr(ActiveSheet.Range(tskCol & i).Value) = CStr(Me.txtTask.Value) Then
ActiveSheet.Range(unitCol & i).Value = Me.txtQuantity.Value
Exit For '/* no need to continue the loop, task is found */
Else
'/* only call msgbox if all rows are processed */
If i = LastRow Then Msgbox "Task Not Found"
End If
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
new to VBA here. I've been stuck on this problem for a while now:
Essentially, I need to create a macro that copies over specific data from one sheet to another, that is up to the user to specify. The catch is that while all the data is in one column (B), not all rows of the column have relevant entries; some are blank and some have other data that I don't want.
Only entries that begin with 4 numbers are wanted. I can't seem to get how the iterated copy-pasting works; what I've come up with is as follows:
'defining input
Dim dater As Date
dater = Range("B2")
If dater = False Then
MsgBox "Date not specified"
Exit Sub
End If
Dim sheetin As String
sheetin = Range("B5")
If sheetin = "" Then
MsgBox "Input Sheet not specified"
Exit Sub
End If
Dim wbin As String
wbin = Range("B4")
If wbin = "" Then
MsgBox "Input workbook not specified"
Exit Sub
End If
Dim sheetout As String
sheetout = Range("B9")
If sheetout = "" Then
MsgBox "Output Sheet not specified"
Exit Sub
End If
Dim wbout As String
wbout = Range("B8")
If wbout = "" Then
MsgBox "Output Workbook not specified"
Exit Sub
End If
Windows(wbout).Activate
Dim sh As Worksheet, existx As Boolean
For Each sh In Worksheets
If sh.Name Like sheetout Then existx = True: Exit For
Next
If existx = True Then
If Sheets(sheetout).Visible = False Then Sheets(sheetout).Visible = True
Else
Sheets.Add.Name = CStr(sheetout)
End If
'copy pasting values
Windows(wbin).Activate
Sheets(sheetin).Select
'specify maximum row
iMaxRow = 500
For iRow = 1 To iMaxRow
With Worksheets(sheetin).Cells(iRow, 2)
'Check that cell is not empty.
If .Value = "####*" Then
.Copy Destination:=Workbooks(wbout).Worksheets(sheetout).Range("A" & i)
'Else do nothing.
End If
End With
Next iRow
End Sub
Subsequently i'll have to match data to these entries that have been copied over but I figure once i get the hang of how to do iterated stuff it shouldn't be too much of a problem. But right now i'm really stuck... Please help!
It looks like it should work, except for that part :
With Worksheets(sheetin).Cells(iRow, 2)
If .Value = "####*" Then
.Copy Destination:=Workbooks(wbout).Worksheets(sheetout).Range("A" & i)
End If
End With
The third line contains an unknown variable : i.
You need to define it to contain the number of the line to which you're copying. For example, if you want to copy to the first available line, try this :
Set wsOut = Workbooks(wbout).Worksheets(sheetout)
With Worksheets(sheetin).Cells(iRow, 2)
If .Value = "####*" Then
i = wsOut.Cells(wsOut.Rows.Count, 1).End(xlUp).Row + 1
.Copy Destination:=wsOut.Range("A" & i)
End If
End With