I’m a total newbie at this. I’ve got a worksheet with a list of jobs. One of the columns relate to the location eg, London, Manchester. When London is selected, I want that row copied to the London worksheet, and so on.
Also, I’ve got a column to show when the job is completed. So when I select completed, I want that row cut and pasted into the completed worksheet.
Now, after searching, I’ve found the code for both these actions and individually they work. But I’m trying to get them to work together. I’ve tried multiple things from searches I’ve done on here and google but nothing is working.
These are the codes I’ve got that work individually:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim wsUse As Worksheet
Dim wsDc As Worksheet
Dim strdc As String
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
If Target.Cells.Count > 1 Then Exit Sub
If Target.Column <> 9 Then Exit Sub ' change 2 to the correct column number
Set wsUse = ThisWorkbook.Sheets("Workload Overview")
Set wsDc = ThisWorkbook.Sheets("Completed")
With wsUse
strdc = Target.Value
If strdc = "Completed" Then
n = .Rows.Count
Target.EntireRow.Copy
wsDc.Range("A" & n).End(xlUp).Offset(1, 0).PasteSpecial xlValues
wsDc.Range("A" & n).End(xlUp).EntireRow.PasteSpecial xlPasteFormats
Application.CutCopyMode = False
Target.EntireRow.Delete
End If
End With
Application.ScreenUpdating = True
Application.Calculation = xlCalculationAutomatic
End Sub
Private Sub Worksheet_Change(ByVal Target As Range)
Dim wsUse As Worksheet
Dim wsDc As Worksheet
Dim strdc As String
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
If Target.Cells.Count > 1 Then Exit Sub
If Target.Column <> 6 Then Exit Sub ' change 2 to the correct column number
Set wsUse = ThisWorkbook.Sheets("Workload Overview")
Set wsDc = ThisWorkbook.Sheets("London")
With wsUse
strdc = Target.Value
If strdc = "London" Then
n = .Rows.Count
Target.EntireRow.Copy
wsDc.Range("A" & n).End(xlUp).Offset(1, 0).PasteSpecial xlValues
wsDc.Range("A" & n).End(xlUp).EntireRow.PasteSpecial xlPasteFormats
Application.CutCopyMode = False
Target.EntireRow.Copy
End If
End With
Application.ScreenUpdating = True
Application.Calculation = xlCalculationAutomatic
End Sub
Worksheet_Change is an event that Excel looks out for and the code should be in a worksheet module (rather than ThisWorkbook or a normal module).
You can only have one Worksheet_Change change code in a module - shouldn't compile with it twice as you have.
So you need to combine the two procedures into one.
I've made a couple of assumptions - you set wsDC to London. You were then going to add similar code for Manchester and any other city. If you can guarantee your selected cities will be the same as the sheet name then use that to find your sheet to paste to.
If column 9 isn't Completed (could be Cancelled, In Progress) then can exit the sub as well.
The only difference between a Completed record and a City record are that the completed ones are deleted, so that can be treated the same way as cities except the last IF block that checks whether it needs deleting or not.
Private Sub Worksheet_Change(ByVal Target As Range)
On Error GoTo ErrorHandler 'Turn on error handling.
'You may not need to turn off calculation or screenupdating.
'Always polite to return it to the setting it was, rather than assuming
'so remember the setting so can be put back later.
Dim CalcMethod As Long
CalcMethod = Application.Calculation
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
'This is needed if the row is deleted.
'Deleting a row is a Change event which will cause this code to fire a second time.
Application.EnableEvents = False
If Target.Cells.Count > 1 Then Exit Sub
If Target.Column <> 9 And Target.Column <> 6 Then Exit Sub
If Target.Column = 9 And Target.Value <> "Completed" Then Exit Sub
'Assuming Target value will be the same as the sheet name if column 6,
'or a "Completed" if it's column 9.
'e.g. London, Manchester, New York, Completed.
Dim wsDc As Worksheet
Set wsDc = ThisWorkbook.Worksheets(Target.Value)
Target.EntireRow.Copy
wsDc.Cells(Rows.Count, 1).End(xlUp).Offset(1).PasteSpecial xlValues
wsDc.Cells(Rows.Count, 1).End(xlUp).Offset(1).PasteSpecial xlPasteFormats
If Target.Column = 9 And Target.Value = "Completed" Then
Application.CutCopyMode = False
Target.EntireRow.Delete xlShiftUp
End If
TidyExit:
'Turn everything back on.
Application.EnableEvents = True
Application.Calculation = CalcMethod
Application.ScreenUpdating = True
Exit Sub
'If an error occurs, skip to this section (which is outside the main body),
'deal with the error and jump back into the code so everything can be
'turned back on before exiting.
ErrorHandler:
MsgBox Err.Number & vbCr & Err.Description, vbOKOnly + vbCritical
Resume TidyExit
End Sub
Related
Any chance of getting help combining the two below codes?
I'll try to educate myself on combining these things as I'm sure it's not that complicated, but for now I'd appreciate any assistance.
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
If Application.CutCopyMode = False Then
Application.Calculate
End If
End Sub
Private Sub Worksheet_Change(ByVal Target As Range)
Dim UndoList As String
With Application
.EnableEvents = False
.ScreenUpdating = False
End With
On Error GoTo ErrExit
UndoList = Application.CommandBars("Standard").Controls("&Undo").List(1)
If Left(UndoList, 5) = "Paste" Or UndoList = "Auto Fill" Then
MsgBox "Copy / paste is not permitted" & vbCr & _
"- Creator"
With Application
.Undo
.CutCopyMode = False
End With
Target.Select
End If
'The UperCase part______________________________________________
If Not (Application.Intersect(Target, Range("E8:OF57")) _
Is Nothing) Then
With Target
If Not .HasFormula Then
Application.EnableEvents = False
.Value = UCase(.Value)
Application.EnableEvents = True
End If
End With
End If
'_______________________________________________________________
ErrExit:
With Application
.ScreenUpdating = True
.EnableEvents = True
End With
End Sub
I'm trying to make my workbook as easy to use as possible, and to avoid user mistakes that mess upp formulas and so forth.
Private Sub Worksheet_SelectionChange(ByVal Target As Excel.Range)
Dim MyPicture As Object
Dim MyTop As Double
Dim MyLeft As Double
Dim TopRightCell As Range
'-----------------------------------------------------------
'- top right cell
With ActiveWindow.VisibleRange
r = 1
c = .Columns.Count
Set TopRightCell = .Cells(r, c)
End With
'------------------------------------------------------------
'- position picture
Set MyPicture = ActiveSheet.Pictures(1)
MyLeft = TopRightCell.Left - MyPicture.Width - 200
With MyPicture
.Left = MyLeft
End With
End Sub
The line starting with Private Sub or Sub begins the macro, and the line End Sub is the end of the macro.
Of the two code blocks you've pasted, the top contains two macros (one Worksheet_SelectionChange and one Worksheet_Change), and the second block only contains a SelectionChange one.
Depending which of those you wish to merge, just cut-paste the code from the inside of one sub (i.e. not including the start and end lines Private Sub and End Sub) into another, to make an amalgamated sub containing both sets of code. You may wish to amalgamate all three, but I'd guess it's just the two SelectionChange subs you want to merge.
I want the user's name and the date to be entered into a specified column when any change is made.
I also have a snippet of code that forces any data that is pasted into the sheet to be pasted as values so the sheet's formatting is maintained.
I was able to write code that functioned properly, but the event was also being triggered even when the user double clicked in a cell and clicked out of the cell (i.e., no change was made). A user could accidentally click into a cell and leave it without making changes, but their name would be left behind as having made an edit.
I tried to incorporate this solution. Here is a simplified version of my code:
Private Sub Worksheet_Change(ByVal Target as Range)
Dim DesiredRange as Range
Dim TOld, TNew as String
Set DesiredRange as 'Whatever range I'm using
If Not Intersect(Target, DesiredRange) is Nothing Then
TNew = Target.Value
With Application
.EnableEvents = False
.Undo
End With
TOld = Target.Value
Target.Value = TNew
If Application.CutCopyMode = xlCopy Then
Application.EnableEvents = False
Application.Undo
Target.PasteSpecial Paste:=xlPasteValues
Application.EnableEvents = True
End if
If TOld <> TNew Then
Target.Offset(0, 23 - Target.Column) = Application.Username & vbNewLine & Date
End If
Application.EnableEvents = True
End if
End Sub
I am encountering the following issue:
When a user double clicks into a cell and clicks into another cell, the event is not triggered (i.e., the user's name and date is not left in the cell) but the active cell is reverted into the original cell, rather than the one they clicked into after double-clicking.
So a user would double click into a cell, do nothing, then click into another cell, and the active cell would revert to the first cell they were in.
This is also happening after the user inputs their change into the cell and presses enter.
I also encounter an error when something is pasted into the sheet, causing the code to not execute properly.
Prevent Worksheet Change When No Change
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
On Error GoTo ClearError
Dim srg As Range: Set srg = Range("B5:E10")
Dim irg As Range: Set irg = Intersect(srg, Target)
If irg Is Nothing Then Exit Sub
Dim coll As Collection: Set coll = New Collection
Dim iCell As Range
For Each iCell In irg.Cells
coll.Add iCell.Value
Next iCell
With Application
.EnableEvents = False
.Undo
End With
Dim drg As Range
Dim n As Long
For Each iCell In irg.Cells
n = n + 1
If iCell.Value <> coll(n) Then
iCell.Value = coll(n) ' write different value
If drg Is Nothing Then ' combine the cells for user and date
Set drg = iCell
Else
Set drg = Union(drg, iCell)
End If
End If
Next iCell
If Not drg Is Nothing Then
' Use 'Now' while testing or you will see no difference.
' Later switch to 'Date'.
Intersect(drg.EntireRow, Columns("W")).Value = Application.UserName _
& vbNewLine & Format(Now, "mm/dd/yyyy hh:mm:ss") ' Date
End If
SafeExit:
If Not Application.EnableEvents Then Application.EnableEvents = True
Exit Sub
ClearError:
Debug.Print "Run-time error '" & Err.Number & "': " & Err.Description
Resume SafeExit
End Sub
Following advice from here, Loop through named range list, I have tried to make the following code more efficient with a loop.
Sub Worksheet_Calculate()
Application.EnableEvents = False
Range("in1.1").Rows.EntireRow.Hidden = (Range("in1.1").Cells(1, 1).Value = "No")
Range("in1.2").Rows.EntireRow.Hidden = (Range("in1.2").Cells(1, 1).Value = "No")
Application.EnableEvents = True
End Sub
However, I still get a runtime error of various flavors, and I don't really understand how VBA properties work.
Sub Worksheet_Calculate()
Application.EnableEvents = False
Dim TargetSheetName As String
TargetSheetName = "Input data"
For Each nmdrange In ThisWorkbook.Names
If Range(nmdrange.RefersTo).Parent.Name = TargetSheetName Then
'Loop over benefits
Range(nmdrange).Rows.EntireRow.Hidden = (Range(nmdrange).Cells(1, 1).Value = "No")
End If
Next nmdrange
Application.EnableEvents = True
End Sub
This worked for me:
Sub Worksheet_Calculate()
Dim nmdrange As Name, rng As Range
On Error GoTo haveError
Application.EnableEvents = False
For Each nmdrange In ThisWorkbook.Names
Set rng = Range(nmdrange.RefersTo) '<< set a variable to simplify subsequent code
'you can use Me to refer to the sheet where this code is running
If rng.Parent.Name = Me.Name Then
'Loop over benefits
rng.Rows.EntireRow.Hidden = (rng.Cells(1, 1).Value = "No")
End If
Next nmdrange
haveError:
'## alert if error
If Err.Number <> 0 Then MsgBox "Error" & Err.Description
Application.EnableEvents = True
End Sub
I am brand new to coding.
I am trying to use the code to move rows to different sheets and to move completed rows to a different work.
I am having trouble that the Sub Worksheet_Change is being seen as ambiguous name and doesn't work when I try to change the name to something like Worksheet_ChangeCOMPLETE or WorkSheet_Change3.
Below is the codes that I am trying to use.
What my plan is that I want completed orders (rows) to move to a new workbook in which I have named "COMPLETED" when a command button is pushed which triggers a Macro to insert the word "COMPLETE" in column 13 (M).
This new workbook was formerly my sheet 2 but I made it a new workbook following instruction from another forum. I also need rows to move to sheet 3 when "PARTIAL HOLD" inserted in column 13 via a different command button and then returned to sheet one when the command button on sheet 3 "RESUME" is clicked.
All workbooks and worksheets have all the same columns and spacing, I just can't get the codes to work when I rename them.
The first set of codes I am posting are for moving rows from sheet 1 to sheet 3 when the command button is pressed, followed by the code to move rows to the new workbook these codes are in Sheet 1 under VBA project, not a module.
The third is on sheet 3 to move rows back to sheet 1 once HOLD is complete.
Thank you in advance for your help.
SHEET 1
Private Sub Worksheet_Change(ByVal Target As Range)
Dim rngDest As Range
Set rngDest = Sheet3.Range("A5:R5")
If Not Intersect(Target, Sheet1.Range("M5:M290")) Is Nothing Then
If UCase(Target) = "PARTIAL HOLD" Then
Application.EnableEvents = False
Target.EntireRow.Select
Selection.Cut
rngDest.Insert Shift:=xlDown
Selection.Delete
Application.EnableEvents = True
End If
End If
End Sub
Private Sub Worksheet_ChangeCOMPLETE(ByVal Target As Range)
Dim destWbk As String
Dim wbk As Workbook
Dim rngDestCOMPLETE As Range
destWbk = ThisWorkbook.Names("Completed.xlsx").RefersTo
destWbk = Replace(destWbk, "=" & Chr(34), "")
destWbk = Replace(destWbk, Chr(34), "")
Set wbk = Application.Workbooks(destWbk)
Set rngDest = wbk.Names("A1:S1").RefersToRange
If Not Intersect(Target, Sheet1.Range("rngTrigger")) Is Nothing Then
If UCase(Target) = "COMPLETED" Then
Application.EnableEvents = False
Target.EntireRow.Select
Selection.Cut
rngDest.Insert Shift:=xlDown
Selection.Delete
Application.EnableEvents = True
End If
End If
End Sub
SHEET 3
Private Sub Worksheet_Change3(ByVal Target As Range)
Dim rngDest3 As Range
Set rngDest3 = Sheet1.Range("A5:S5")
If Not Intersect(Target, Sheet3.Range("M5:M290")) Is Nothing Then
If UCase(Target) = "IN PROGRESS" Then
Application.EnableEvents = False
Target.EntireRow.Select
Selection.Cut
rngDest.Insert Shift:=xlDown
Selection.Delete
Application.EnableEvents = True
End If
End If
End Sub
As I mentioned on the comment you cannot rename these Subs, but you can do something like below:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim rngDest As Range, rngDest2 As Range, rngDest3 As Range
Dim destWbk As String
Dim wbk As Workbook
If UCase(Target.Value) = "PARTIAL HOLD" Then
Set rngDest = Sheet3.Range("A5:R5")
If Not Intersect(Target, Sheet1.Range("M5:M290")) Is Nothing Then
Application.EnableEvents = False
Target.EntireRow.Cut
rngDest.Insert Shift:=xlDown
Target.EntireRow.Delete
Application.EnableEvents = True
End If
ElseIf UCase(Target.Value) = "IN PROGRESS" Then
Set rngDest3 = Sheet1.Range("A5:S5")
If Not Intersect(Target, Sheet3.Range("M5:M290")) Is Nothing Then
Application.EnableEvents = False
Target.EntireRow.Cut
rngDest3.Insert Shift:=xlDown
Target.EntireRow.Delete
Application.EnableEvents = True
End If
ElseIf UCase(Target.Value) = "COMPLETED" Then
destWbk = ThisWorkbook.Names("Completed.xlsx").RefersTo
destWbk = Replace(destWbk, "=" & Chr(34), "")
destWbk = Replace(destWbk, Chr(34), "")
Set wbk = Application.Workbooks(destWbk)
Set rngDest2 = wbk.Range("A1:S1")
If Not Intersect(Target, Sheet1.Range("rngTrigger")) Is Nothing Then
Application.EnableEvents = False
Target.EntireRow.Cut
rngDest2.Insert Shift:=xlDown
Target.EntireRow.Delete
Application.EnableEvents = True
End If
End If
End Sub
I need users to be able to fill in one row to generate a P.O., and when the P.O. is generated the row below would be unhidden. The P.O. depends on column C, E and G to be filled in.
This code only unhides a row if one of the requirements are met. It also makes the workbook lag.
Private Sub Worksheet_Change(ByVal Target As Range)
Application.EnableEvents = False
If Target.Row < 14 Or Target.Row > 5000 Or Target.Column < 3 Or Target.Column < 5 Or Target.Column <> 7 Then GoTo ExitMe
Rows(Target.Row + 1).Hidden = False
ExitMe:
Application.EnableEvents = True
End Sub
I need one row to be filled in at a time so the P.O. can be generated properly. If there is a better way please let me know.
This macro also conflicts with my macro for protecting changed cells when the worksheet is saved. This is the error that appears: Run-time error '1004': Unable to set hidden property of the Range class.
It is placed in ThisWorkbook
Option Explicit
Private bRangeEdited As Boolean
Private WithEvents ws As Worksheet
Private Sub Workbook_Open()
Set ws = Range("A14:Y3000").Parent
End Sub
Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
Dim sMSG As String
sMSG = "saving the workbook will lock the cells you have entered data into." & vbLf
sMSG = sMSG & "Do you want to go ahead ?"
If Not bRangeEdited Then GoTo Xit
If Not Me.ReadOnly Then
With Range("A14:Y3000")
If MsgBox(sMSG, vbExclamation + vbYesNo) = vbNo Then
Cancel = True
GoTo Xit
End If
.Parent.Unprotect "password"
If .SpecialCells(xlCellTypeBlanks).Address <> .Address Then
.SpecialCells(xlCellTypeConstants).Locked = True
bRangeEdited = False
End If
.Parent.Protect "password"
End With
End If
Xit:
End Sub
Private Sub ws_Change(ByVal Target As Range)
If Not Intersect(Range("A14:Y3000"), Target) Is Nothing Then
bRangeEdited = True
End If
End Sub