VBA help copy/paste in same sheet in next available row - excel

I want to create a command button which copies a range of cells and pastes them into the next empty range.
I have found a code online which I tweaked to perform the function, but it does not work when I add conditional formatting.
The conditional formating being, blank cells = yellow.
The VBA im currently using is:
Private Sub CommandButton1_Click()
Application.ScreenUpdating = False
Dim copySheet As Worksheet
Dim pasteSheet As Worksheet
Set copySheet = Worksheets("Sheet1")
Set pasteSheet = Worksheets("Sheet1")
copySheet.Range("B11:J11").Copy
pasteSheet.Cells(Rows.Count, 2).End(xlUp).Offset(1, 0).PasteSpecial xlPasteAll
Application.CutCopyMode = False
Application.ScreenUpdating = True
End Sub
If I enter a value into the blank cell the above VBA works fine, however if I leave the cell blank it does not paste into the next cell.
The aim was for the user to paste in as many rows as needed, and the yellow shading to indicate which cells to add a value in.
I hope this makes sense. I'm not particularly used to these functions in excel.

Try this code:
Private Sub CommandButton1_Click()
'Macro to copy in a new row.
'Turning off screen updating.
Application.ScreenUpdating = False
'Declarations.
Dim copySheet As Worksheet
Dim pasteSheet As Worksheet
Dim targetRange As Range
'Setting variables.
Set copySheet = Worksheets("Sheet1")
Set pasteSheet = Worksheets("Sheet1")
'Setting targetRange as the last cell in column B with value.
Set targetRange = pasteSheet.Cells(Rows.Count, 2).End(xlUp).Offset(1, 0)
'Setting targetRange as the first cell in column B with no conditional formatting under the last cell in column B with no value.
Do Until targetRange.FormatConditions.Count = 0
Set targetRange = targetRange.Offset(1, 0)
Loop
'Copying range B11:J11.
copySheet.Range("B11:J11").Copy
'Pasting the copied range in targetRange.
targetRange.PasteSpecial xlPasteAll
'Turning off the cut-copy mode.
Application.CutCopyMode = False
'Turning on the screen updating.
Application.ScreenUpdating = True
End Sub
I've taken your code and added the variable targetRange. Said variable is then set as the last cell with value in column B (similar to what you have already done) and then i use a Do Loop cycle to set targetRange as the first cell with no conditional formatting under the last cell with value in column B. I've also added the proper comments to the whole code.
Extra code as requested in comments.
You can obtain a sum of the values of a range while counting any "outgoing" value as a 7 with this formula:
=SUM(B11:B15,COUNTIF(B11:B15,"ongoing")*7)
You can use the same formula in a macro like this:
Sub Macro1()
'A example of macro to return a range sum with any "ongoing" switched with 7.
'Declaration.
Dim rng As Range
'Setting the seed range.
Set rng = Range("B11")
'Expanding rng to the last cell with value of its column.
Set rng = Range(rng, Cells(Rows.Count, rng.Column).End(xlUp))
'Reporting in the immediate window the result.
Debug.Print Excel.WorksheetFunction.Sum(rng, Excel.WorksheetFunction.CountIf(rng, "ongoing") * 7)
'Reporting in the immediate window the result, this time using a With End With statement to make it more readable.
With Excel.WorksheetFunction
Debug.Print .Sum(rng, .CountIf(rng, "ongoing") * 7)
End With
End Sub

Related

Create Summary of tabs with conditional formatting

I need to create a summary page that will report ONLY tabs that contain conditional formatting that's true. So Tab1 contains a comparison of Before and After; the After will highlight any cells that are different than the Before; then the macro loops to do this with a new tab for every .jbi file in a folder. So each .jbi will have a copy of Tab1 named differently. I'm not sure which method would be better to identify tabs with highlighted changes on a summary page nor really how to go about searching each tab for them.
So my questions are - Should I 1.) make it part of the .jbi import loop where it creates a new copy of Tab1, pastes the before and after data, then resets the template 2.) have it look for changes once it has completed creating new tabs?
3.) How do I get it to search for true conditional formats either way?
Edit: Using the suggestion in the first comment, this is what I came up with, but it doesn't work. It never copies the values
Sub Create_summary()
Dim inputarea As Range
Set inputarea = Sheets("PGM Copy Template").Range("AF2:BA1000")
If inputarea.DisplayFormat.Interior.ColorIndex = 49407 Then
Sheets("Change Summary").Select
Rows("3:3").Select
Selection.Insert Shift:=xlDown, CopyOrigin:=xlFormatFromLeftOrAbove
If Sheets("PGM Copy Template").Range("F4").Value = "#N/A" Then
Sheets("Change Summary").Range("B3").Text = Sheets("PGM Copy Template").Range("AI5").Text
Sheets("Change Summary").Range("C3").Text = Sheets("PGM Copy Template").Range("AI4").Text
Else
Sheets("Change Summary").Range("B3").Text = Sheets("PGM Copy Template").Range("F5").Text
Sheets("Change Summary").Range("B3").Text = Sheets("PGM Copy Template").Range("F4").Text
End If
Else
Exit Sub
End If
End Sub
I guess I need help understanding how I can make the If/then function with the search.
A bit easier to split out the check for the CF color:
Sub Create_summary()
Const CHECK_COLOR As Long = 49407 'use Const for fixed values
Dim inputarea As Range, wb As Workbook, wsInput As Worksheet, c As Range
Dim wsSummary As Worksheet, isNA As Boolean
Set wb = ThisWorkbook 'ActiveWorkbook? 'use a workbook variable
Set wsInput = wb.Worksheets("PGM Copy Template") 'use worksheet variables
Set wsSummary = wb.Worksheets("Change Summary")
If HasCfColor(wsInput.Range("AF2:BA1000"), CHECK_COLOR) Then
isNA = wsInput.Range("F4").Value = "#N/A"
With Sheets("Change Summary")
.Rows(3).Insert Shift:=xlDown, CopyOrigin:=xlFormatFromLeftOrAbove
.Range("B3").Text = wsInput.Range(IIf(isNA, "AI5", "F5")).Text
.Range("C3").Text = wsInput.Range(IIf(isNA, "AI4", "F4")).Text
End With
End If
End Sub
'Does range `rngToCheck` contain a cell with CF coloring of `cfColor` ?
Function HasCfColor(rngToCheck As Range, cfColor As Long)
Dim rng As Range, c As Range
On Error Resume Next 'ignore error if no CF in this range
Set rng = rngToCheck.SpecialCells(xlCellTypeAllFormatConditions) 'only cells with CF
On Error GoTo 0 'stop ignoring errors
If Not rng Is Nothing Then 'True if have any cells with CF
For Each c In rng.Cells
If c.DisplayFormat.Interior.Color = cfColor Then
HasCfColor = True
Exit Function 'done checking
End If
Next c
End If
HasCfColor = False
End Function

How do I copy and paste a specific range to the next blank value of that range? EG: Copy A4:A12 and paste at F4:F12

I'm trying to automate a copy/paste macro. I am trying to copy the values in the range from C4:C12 and paste them at the next blank column in the same range of rows. This is the code I have currently:
Sub CopyPaste()
Dim range_to_copy As Range
Dim range_to_paste As Range
Set range_to_copy = Application.Range("C4:C12")
Set range_to_paste = 1 + Cells(4, Columns.Count).End(xlToLeft).column
range_to_copy.Copy
range_to_paste.PasteSpecial xlPasteValues
Application.CutCopyMode = False
Application.ScreenUpdating = True
End Sub
I keep getting an object error and I don't understand where I'm going wrong.

How to run an For Loop where if cell is true (has text), the row is copied to a different ss

So i want to make a loop where it checks the data in every cell in a column and if the cell has any type of data, it copy's the entire row to a different ss. If the cell is blank i need it to move onto the next cell below and not copy the row.
I have added some code below, im trying to copy all the rows in report1 in column H:H that have any input to Report3.
Sub GenerateReport3_Click()
Dim rep1 As Worksheet
Dim rep3 As Worksheet
Set rep1 = ThisWorkbook.Worksheets("Report1")
Set rep3 = ThisWorkbook.Worksheets("Report3")
Dim rngA As Range
Dim cell As Range
rep1.Range("A1:J1").Copy Destination:=rep3.Range("A1")
Set rngA = Sheets("Report1").Range("H:H")
For Each cell In rngA
If cell.Value = True Then
cell.EntireRow.Copy Destination:=rep2.Range("A" & Rows.Count).End(xlUp)(2)
End If
Next cell
End Sub
Every row in column in report 1 H:H that has any input needs to be copied to Report3.
Test for Not IsEmpty(...) rather than =TRUE.
Also, a few details around geting Range references need work (eg avoiding implicit references to ActiveSheet).
And don't loop over the entire 1,000,000+ rows in a column (That's so slow!)
Something like this
Sub GenerateReport3_Click()
Dim rep1 As Worksheet
Dim rep3 As Worksheet
Set rep1 = ThisWorkbook.Worksheets("Report1")
Set rep3 = ThisWorkbook.Worksheets("Report3")
Dim rngA As Range
Dim cell As Range
rep1.Range("A1:J1").Copy Destination:=rep3.Cells(1, 1)
With rep1
Set rngA = .Range(.Cells(1, "H"), .Cells(.Rows.Count, "H").End(xlUp))
For Each cell In rngA
If Not IsEmpty(cell) Then
cell.EntireRow.Copy Destination:=rep3.Cells(rep3.Rows.Count, 1).End(xlUp).Offset(1, 0)
End If
Next cell
End With
End Sub
Note that if this is still too slow, there a are more ways to speed it up

Copy and Paste special without selecting cell

The code I have runs but it does not do what I intend in the last line. The line at the end pastes the formula but it does not adjust the formula for the new cell.
As an example If the formula im copying is is A3 and the formula is A3=A1+A2, when it is pasted into A10 the formula is still A1+A2 instead of A9+A8.
I tried using paste special but I cannot get that to work. I do not want to select a new active cell as I will have to return back to the original active cell and reference it again.
Sub Macro1()
'
' Macro1 Macro
'
' Keyboard Shortcut: Ctrl+Shift+Z
'
Dim StartCell As Range
Dim copyRance As Range
Dim dataSheet As Worksheet
Dim destSheet As Worksheet
Set dataSheet = Sheets("Macro (insert data)")
Set destSheet = Sheets("Jun-2019")
Set StartCell = ActiveCell
Set copyRange = dataSheet.Range("G4:Q4")
ActiveCell.Resize(copyRange.Rows.Count, copyRange.Columns.Count).Value = copyRange.Value
Set copyRange = dataSheet.Range("W4:AG5")
destSheet.Range("C42").Resize(copyRange.Rows.Count, copyRange.Columns.Count).Value = copyRange.Value
Set copyRange = destSheet.Range("N10:X10")
StartCell.Offset(0, 11).Resize(copyRange.Rows.Count, copyRange.Columns.Count).Value = copyRange.Formula
End Sub
From comments, it seems that you want to copy the Formula, and then convert it to values. This needs to be done in 2 stages, optionally with an explicit .Calculate in case Calculation is set to Manual:
Set copyRange = dataSheet.Range("G4:Q4")
'Copy formulas to ActiveCell
copyRange.Copy Destination:=ActiveCell
With ActiveCell.Resize(copyRange.Rows.Count, copyRange.Columns.Count)
'Force the calculation
.Calculate
'Keep just the values
.Value = .Value
End With

Clear Contents of Visible Cells in Filtered Column

I'm filtering on a helper cell to locate cells in column B that need the contents cleared. Once I filter on the helper cell that has identified cells in column B that need contents cleared, I am having issues clearing the contents in that cell.
I got the general idea down except I cannot figure out how to clear the visible cells only starting from the first visible cell down to the last visible cell. My issue is identifying where is the start of the first visible cell after the filter is applied and where is the last visible cell.
Sub Macro1()
'
' Macro1 Macro
Dim wb As Workbook
Dim ws As Worksheet
Dim FoundCell1 As Range
Set wb = ActiveWorkbook
Set ws = ActiveSheet
'This identifying the row of the last cell to filter on
Const WHAT_TO_FIND1 As String = "Tango"
Set FoundCell1 = ws.Range("AX:AX").Find(What:=WHAT_TO_FIND1)
'This is filtering on the helper cell to determine what cells need to be cleared.
ws.Range("$BA$8:$BA$" & FoundCell1.Row).AutoFilter Field:=1, Criteria1:= _
"Delete"
'This is where I'm having issues. I would like to replace B2 with a more dynamic code
'that finds the first visible cell after the filter is applied and start there.
'I think the xlUp solves the issue of finding the last visible cell but I am not sure
'if that is the best or correct method.
ws.Range("B2:B" & Rows.Count).End(xlUp).SpecialCells(xlCellTypeVisible).ClearContents
End Sub
Here's how I'd do it:
Sub tgr()
Dim wb As Workbook
Dim ws As Worksheet
Dim FoundCell1 As Range
Set wb = ActiveWorkbook
Set ws = wb.ActiveSheet
'This identifying the row of the last cell to filter on
Const WHAT_TO_FIND1 As String = "Tango"
Set FoundCell1 = ws.Range("AX:AX").Find(What:=WHAT_TO_FIND1)
If FoundCell1 Is Nothing Then Exit Sub 'WHAT_TO_FIND1 not found
'This is filtering on the helper cell to determine what cells need to be cleared.
With ws.Range("$BA$8:$BA$" & FoundCell1.Row)
If .Row < 8 Or .Rows.Count = 1 Then Exit Sub 'No data
.AutoFilter Field:=1, Criteria1:="Delete"
On Error Resume Next 'Suppress error in case there are no visible cells
Intersect(.Worksheet.Columns("B"), .Offset(1).Resize(.Rows.Count - 1).EntireRow).SpecialCells(xlCellTypeVisible).ClearContents
On Error GoTo 0 'Remove "On Error Resume Next" condition
.AutoFilter
End With
End Sub

Resources