User form data is overwriting itself rather than entering row by row.
I have tried different combinations of ActiveCell, Cell, Set, and Range. Pulling code from the internet for somewhat similar purposes and tweaking was unsuccessful.
Private Sub CheckOut_Click()
Dim xCell As Range
For Each xCell In ActiveSheet.Columns(1).Cells
If Len(xCell) = 0 Then
xCell.Select
Exit For
End If
Next
Range("B2").Value = TextBox1.Text
Range("C2").Value = TextBox2.Text
Range("D2").Value = ("OUT")
TextBox1 = ""
TextBox2 = ""
End Sub
I want each submission in the user form to populate a new row creating a list. What is actually happening is everything writes to row 2.
Please give feed back with down votes and flags.
Dim ws as Worksheet
Dim freeRow as long
Set ws = ActiveSheet 'Is it really necessary to use the active sheet?
freeRow = ws.Cells(ws.Rows.Count, 1).End(xlUp).row + 1 'End(xlUp) jumps to the next free cell
ws.Cells(freeRow, 2) = TextBox1.Text
ws.Cells(freeRow, 3) = TextBox2.Text
ws.Cells(freeRow, 4) = "OUT"
TextBox1.Text = ""
TextBox2.Text = ""
It is usually considered that ".select" is bad practice since it can lead to weird/nasty errors - rather use variables (this makes your code more reusable and less error prone!)
Your code
Private Sub CheckOut_Click()
Dim xCell As Range
' Loop through cells of first column. You can also use "A" instead of 1.
' Since you haven't used ActiveSheet with the ranges, it is also not
' needed here. It would be better to specify the worksheet e.g. "Sheet1".
For Each xCell In ActiveSheet.Columns(1).Cells
' Check if length of value of current cell is 0.
' Usually 'If xCell = "" Then' is used.
If Len(xCell) = 0 Then
' Select (Go to) current cell. What for?
xCell.Select
' Exit the For Next loop. Will jump to 'Range("B2") ...'
Exit For
End If
Next
' Write certain values to cells of 2nd row.
Range("B2").Value = TextBox1.Text
Range("C2").Value = TextBox2.Text
Range("D2").Value = ("OUT")
' Clear the Text boxes.
TextBox1 = ""
TextBox2 = ""
End Sub
In a nutshell, the code will check for an empty cell in column 1, will select the found cell (for an unknown reason) and will write some data to certain cells in the 2nd row and clear the values of the text boxes.
Questions
You loop through column 1. When an empty cell is found, do you want to write the values to columns B-D in the first found empty row or to columns B-D in the same row where the empty cell in column 1 was found?
Empty or Same?
Do you want this to happen only once, when an empty cell was found or for all found empty cells in the used range of column 1?
Once or All?
The used range of column 1 would be from e.g. A1 or which cell you choose to the last used cell.
You can manually determine the last used cell by selecting the last cell of column 1 ("A") and holding RIGHT CTRL and pressing UP. This will be done in the code, but it is just for you to have a visual of what will be checked for empty cells if you want to find more of them.
A1 or ...?
You should address these questions in your question which you can modify by using the edit button below it.
Possible Solution
Private Sub CheckOut_Click()
Dim xCell As Range ' Current Cell in Column "A"
Dim FER As Long ' First Empty Row
' Loop through cells of Column "A".
For Each xCell In Columns("A")
' Check if value of Current Cell is "".
If xCell.Value = "" Then
' Select Current Cell. If necessary.
xCell.Select
' Calculate First Empty Row using column "B".
FER = Range("B" & Rows.Count).End(xlUp).Row + 1
' Write values to Target Cells in First Empty Row.
Range("B" & FER).Value = TextBox1.Text
Range("C" & FER).Value = TextBox2.Text
Range("D" & FER).Value = ("OUT")
' Clear the Text boxes.
TextBox1 = ""
TextBox2 = ""
Exit For ' Stop looping.
End If
Next
End Sub
Remarks
How would this make any sense?
What if OP didn't tell us that xCell.Select triggers a Selection Change event which will write values to xCell and the text boxes and will restrict this to the used range of column A?
Related
I am attempting to create a macro button that does one thing in two steps. This is for a progress tracker, if a task is marked completed in column G, then I need the row hidden.
That command I have completed below, however step two of this is if the value in column c "Name" is hidden (based on the first command) then I need all other values in column C, equal to the values of the hidden rows, hidden as well. The goal of this is to return all items actively in progress by eliminating any names in row C that have a "completed" task under them.
'Step 1: (Works to hide completed rows)
Sub HideCompletes()
For Each cell In ActiveSheet.Range("G5:G200") 'would love to have this work for all cells after G5, but not sure how to acomplish that either
If cell.Value = "Completed" Or cell.Value = "" Then
cell.EntireRow.Hidden = True
End If
Next cell
'Step 2: (non functional idea)
For Each cell In ActiveSheet.Range("G5:G200")
If cell.RowHeight = 0 And cell.Value In ActiveSheet.Range("C5:C200")
cell.EntireRow.Hidden = True
End If
Next cell
End Sub
Try this:
Sub HideCompletes()
' first find the last row in the spreadsheet that has data
Dim lastrow As Long
lastrow = ActiveSheet.Cells.SpecialCells(xlLastCell).Row
' now loop through the cells in G and hide them if they are completed
For Each cell In ActiveSheet.Range("G5:G" & lastrow)
If cell.Value = "Completed" Or cell.Value = "" Then
cell.EntireRow.Hidden = True
' get the value from column C for that row
Dim hiddenvalue As Variant
hiddenvalue = ActiveSheet.Range("C" & cell.Row)
' now loop through the cells in C and hide them if they match our hidden value
' the value 0 will match an empty cell so we need to check both conditions
For Each othercell In ActiveSheet.Range("C5:C" & lastrow)
If othercell.Value <> "" And othercell.Value = hiddenvalue Then
othercell.EntireRow.Hidden = True
End If
Next othercell
End If
Next cell
End Sub
I think it does what you want. If cell in G is "Completed" or "" then it hides that row. Then after that it loops through all the rows and hides any that have the same value in column C as the row that was hidden originally.
I am a VBA newbie here. Ideally, I would like to put together a macro that will scan a specific column for certain Chinese phrases and translate them per a list of translations.
I've started with kind of a primitive find and replace via an Activecell.value loop per my friend's suggestion, but it won't work because VBA doesn't allow for Chinese characters.
sub Translate()
ActiveCell.Select ("A2")
Dim r As Integer ' Number of rows
' ****************************** Input ******************************
' Count rows "r" & Indent
' Use Loop
Do
r = r + 1
If ActiveCell.Value = "??" Then
ActiveCell.Value = "Apple"
Else
If ActiveCell.Value = "??" Then
ActiveCell.Value = "Banana"
End If
' Move Cursor
ActiveCell.Offset(0, 1).Select
' End Loop
Loop Until ActiveCell.Value = ""
End Sub
Here's the logic I would want the macro to follow:
select a specific column as range
check value of cell
if value of cell = specific Chinese phrase (likely from another sheet or index)
replace value with specified translation phrase
continue down the column until blank cell is reached, then end macro
For example,
A
1 **Fruit**
2 赛伍
3 香蕉
gets checked against reference sheet or index:
A B
1 赛伍 apple
2 香蕉 banana
so that the end result is:
A
1 **Fruit**
2 apple
3 banana
Any help you could provide would be greatly appreciated. Thank you!
Edit: I do not think my question is a duplicate to "declaring a unicode string in vba in excel" because ideally the macro would function based on reading cell values outside of the code
ex:
' if Sheet0!A2 matches Sheet1!A2, replace Sheet0!A2 with Sheet1!B2
Let's assume the two sheets are Sheet1 and Sheet2. You may use a for loop to iterate the cells of the first column on Sheet1 and then use the Range.Find method to look for a match in Sheet2.
Try something like this:
Option Explicit
Sub Test()
Dim lastRow As Long, i As Long
lastRow = Sheet1.Range("A" & Sheet1.Rows.Count).End(xlUp).Row
For i = 2 To lastRow
Dim currentCell As Range, foundChineseCell As Range, foundEnglishCell As Range
Set currentCell = Sheet1.Range("A" & i)
Set foundChineseCell = Sheet2.Range("A:A").Find(currentCell.Value)
If Not foundChineseCell Is Nothing Then
Set foundEnglishCell = foundChineseCell.Offset(0, 1)
currentCell.Value = foundEnglishCell.Value
End If
Next
End Sub
Result:
I have an excel where I have a column called roles with text like:
Then I have another column where I have name and reference this first column like:
My question is, there is a way to assign first column to second one, I.E: if I click on GetSalesOrderItems = 1,2,4,5 cell, autoclick cells 1,2,4 and 5? is that possible? How can I do a reference of second column to first column? Regards
Here's a quick example of doing something like this in VBA.
Assuming you have a sheet like:
You can add code to the sheet (open your VBE, double click the worksheet in the Project pane and paste in this code):
Private Sub Worksheet_BeforeDoubleClick(ByVal Target As Range, Cancel As Boolean)
'Worksheet_BeforeDoubleClick() fires whenever a double click is detected on this worksheet.
'Our thing being double clicked is in B1, so lets make sure the double click came from there by testing `Target`
If Not Intersect(Target, Range("B1")) Is Nothing Then
'Must be B1... so let's load the numbers into an array
Dim numArray As Variant
numArray = Split(Split(Target, "=")(1), ",")
'We are going to assume we already have some highlighted cells. Unhighlight this first
i = 1
Do Until Cells(i, 1).Value = ""
Cells(i, 1).Font.Bold = False
'increment for the next loop
i = i + 1
Loop
'Now we can loop this array and search for it in Column A
For Each num In numArray
'Loop through column A
i = 1
Do Until Cells(i, 1).Value = ""
'test if it shares a value
If num = Split(Cells(i, 1).Value, "=")(1) Then
'Make the cell bold or something
Cells(i, 1).Font.Bold = True
End If
'increment for the next loop
i = i + 1
Loop
Next num
End If
End Sub
That's going to bold any cells in Column A that share a value of the cell in Column B (When you double click on that cell).
No doubt you will need to edit this to get what you need, but this should get you in the ballpark.
I'm trying to paste info to the first blank cell in colum A of a sheet? How can I do this?
This is what I have done but it paste the info 1000 times. What do I need to change?
Thanks in advance.
Range("B2:E2").Select 'Selet info to copy
Selection.Copy 'Copy
Sheets(Range("A2").Value).Select 'Goto Sheet Listed in cell A2
Dim i 'define i
For i = 3 To 1000 'Set up loop size
If Range("A" & CStr(i)).Value = "" Then 'If Cell Ai is blank
Range("A" & i).Select
ActiveSheet.Paste 'Paste info
End If
Next i
End If
While modifying the loop with an Exit For will work, there is a much better approach - finding the last cell in a column can be achieved with
Set lastCell = Range("A1").End(xlDown)
set freeCell = lastCell.Offset(1,0)
This assumes that there is at least one cell below A1. If you know (as in your example) that there will never be more than 1000 rows occupied, you can do this in the other direction:
Function freeCell(r As Range) As Range
' returns first free cell below r
Dim lc As Range ' last used cell on sheet
Set lc = r.Offset(1000, 0).End(xlUp).Offset(1, 0)
Set freeCell = lc
End Function
Sub testIt()
Dim p As Range
Set p = freeCell(Range("A3"))
MsgBox "the address of p is " & p.Address
End Sub
The function freeCell returns the cell you are after; the sub testIt shows that it works (and how it is called). In your case, you can greatly simplify your code to
Sub doIt()
Dim sh As Worksheet, tCell As Range
Sheets("Sheet1").Range("B2:E2").Copy
Set sh = Sheets(Range("A2").Value)
Set tCell = freeCell(sh.Range("A3"))
sh.Paste tCell
End Sub
Note - when you record a macro, you get lots of Activate, Select etc commands sneaking in. These can usually be avoided - and there are plenty of excellent articles online (and on this site) explaining why you would want to avoid them. The above snipped shows how to copy from one sheet to another without any of these.
If you are never sure that there is anything on your target sheet (no header row in row 2, for example) you could modify your code so the target cell is never above row 3:
If tCell.Row < 3 Then Set tCell = tCell.Offset(3 - tCell.Row)
Your FOR LOOP will run from cell A3 until A1000 and for every empty cell it will paste the value. You want to exit your loop as soon as the condition is matched. You want to add an Exit For condition.
If Range("A" & CStr(i)).Value = "" Then
Range("A" & i).Select
ActiveSheet.Paste
Exit For
End If
Source
So, I have three very large columns of data. I want these to match, but there are lots of mismatching rows between the columns.
What I want to do is write a looping macro to delete the contents in cell F2 if they are not equal to the contents in either A2 or K2. However, I can only find details on writing looping macros for ranges. Is it possible to have a command carried out on the same cell over and over? So far I have:
Sub ArrayMatch()
Application.ScreenUpdating = True
Dim F As Range
For Each F In Range("F2:F2043").Cells
F.Select
If ActiveCell <> ActiveCell.Offset([0], [-5]) And ActiveCell <> ActiveCell.Offset([0], [5]) Then
Selection.Delete Shift:=xlUp
Else: Stop
End If
Next
At the moment, I just want the code to stop if any of these are equal. However, the way I have the range defined here, the code is only applied to every other cell in the range. Can I rephrase this range to have the rest of the code applied to cell F2 over and over again?
Thanks! I'll keep experimenting with what I have while eagerly awaiting a response!
Assuming your input:
Can I rephrase this range to have the rest of the code applied to cell
F2 over and over again?
that's NOT exactly what you expect. The clue is you should check every cell in range, and move to the NEXT only in case it does NOT meet the criteria. Otherwise the row is deleted, and you should stay on the same spot, i.e. DON'T move down, since if A1 is removed, A2 now becomes A1, and you should check it again.
The below code will do the job (perhaps you should modify the criteria, but the idea is that):
Sub RemoveRows()
Dim i As Long
Dim ActiveCell As Range
i = 2
Do While i <= 2043
Set ActiveCell = Range("F" & i)
If ActiveCell <> ActiveCell.Offset([0], [-5]) And ActiveCell <> ActiveCell.Offset([0], [5]) Then
Selection.Delete Shift:=xlUp
Else
i = i + 1
End If
Loop
End Sub
This is the sample for quite similar task: https://www.dropbox.com/s/yp2cwphhhdn3l98/RemoweRows210.xlsm
Try using something like this:
Sub checkF()
RowCount = WorksheetFunction.CountA(Range("F2").EntireColumn)
While RowCount >= 1
If Range("F2").Value = Range("A2").Value Or Range("F2").Value = Range("K2").Value Then
Stop
Else
Range("F2").Delete Shift:=xlUp
End If
RowCount = RowCount - 1
Wend
End Sub
This will loop through the until there is 1 value left in column F and will stop when any of the values match.
Here is a simple loop that will do the following:
Retrieve all cell values for row 2 of columns A, F and K
Check if the value in F2 equals A2 or K2
If equal, do nothing and exit macro
If not equal, delete the value in F2, shift the cells up, retrieve new F2 value, then start over from step 1
Here's the code:
Public Sub MatchFirstRow()
Dim fCellValue As String
Dim aCellValue As String
Dim kCellValue As String
Dim shouldCheckAgain As Boolean
'get values of each cell in question
fCellValue = Cells(2, 6).Value
aCellValue = Cells(2, 1).Value
kCellValue = Cells(2, 11).Value
shouldCheckAgain = True
'loop through while the cell in "F" has a value AND the previous value wasn't a match
While Not IsEmpty(fCellValue) And Not fCellValue = "" And shouldCheckAgain
shouldCheckAgain = False
'If row values don't match, delete cell in F, shift up, then
'reinitialize the F cell value for next pass
If Not StrComp(fCellValue, aCellValue, vbTextCompare) _
And Not StrComp(fCellValue, kCellValue, vbTextCompare) Then
Cells(2, 6).Select
Selection.Delete Shift:=xlUp
fCellValue = Cells(2, 6).Value
shouldCheckAgain = True
End If
Wend
End Sub
Simply paste this code into the VB Editor for the sheet that contains the columns in question. For example, if Sheet1 has the columns, then open the Visual Basic Editor, double click Sheet1, then paste the code there.
Once the code is pasted you can run this as a regular macro by choosing the Macros button.
You should do this without loops, either with
Inserting a working column that uses an =OR(F2=K2,F2=A2) to return True or False results, then use AutoFilter either manually or with vba to delete the False results
Get funky and do (1) directly in a variant array like below, then dump the variant array back over the original range
code
Sub GetEm()
X = Filter(Application.Transpose(Application.Evaluate("=IF(--(F2:F2043=A2:A2043)+--(F2:F2043=K2:K2043),F2:F2043,""x"")")), "x", False)
Range("F2:F2043").Value = vbNullString
[f2].Resize(UBound(X), 1).Value = Application.Transpose(X)
End Sub
The Worksheet_Change sub of the sheet should work here. That sub gets called whenever a cell in that sheet changes.
'This sub placed in one of the "Sheet1"/"Sheet2"/... objects in the list of
'Microsoft Excel Object in the VBA Editor will be called everytime you change
'a cell value in the corresponding sheet.
'"Target" is the effected cell.
Private Sub Worksheet_Change(ByVal Target As Range)
'Check that Target is cell F2 (6th column, 2nd row)
If Target.Row = 2 And Target.Column = 6 Then
'If this is the cell we are looking for call the sub ValidateF2
ValidateF2
End If
End Sub
And:
Sub ValidateF2()
'Check that the value of F2 is not equal to A2 or K2
If Not (Range("F2").Value = Range("A2").Value Or Range("K2").Value = Range("K2").Value) Then
'Set the value of F2 to "" (empty)
Range("F2").Value = ""
End If
End Sub