Reputation: 99
I'm trying to copy the values and conditional formatting from a column in the sheet wsHR
and paste them into wsHH
.
With the code below the values are pasted, but the formatting is not.
I added formatting into wsHR
that isn't conditional, and it works fine copying that over.
Is there a way to paste conditional formatting?
Private Sub CommandButton1_Click()
'Set variables
Dim LastRow As Long
Dim wsHR As Worksheet
Dim wsHH As Worksheet
Dim y As Integer
'Set row value
y = 4
'Set heavy chain raw data worksheet
Set wsHR = ThisWorkbook.Worksheets(4)
'Set heavy chain hits worksheet
Set wsHH = ThisWorkbook.Worksheets(6)
'Optimizes Speed
Application.ScreenUpdating = False
Application.EnableEvents = False
Application.Calculation = xlCalculationManual
'Finds last row
With wsHR
LastRow = .Cells(.Rows.Count, "A").End(xlUp).Row
End With
'Iterates through rows in column A, and copies the row into proper sheet depending on "X" in PBS/KREBS
For i = 4 To LastRow
'Checks for "X" in PBS
If VarType(wsHR.Range("AD" & i)) = 8 Then
If wsHR.Range("AD" & i).Value = "X" Or wsHR.Range("AE" & i).Value = "X" Then
With wsHH
wsHR.Range("A" & i).Copy
.Range("A" & y).PasteSpecial Paste:=xlPasteFormats
.Range("A" & y).PasteSpecial Paste:=xlPasteValues
'Range before PBS/KREBS
.Range("B" & y & ":AC" & y).Value = wsHR.Range("B" & i & ":AC" & i).Value
'Adds space to keep formulas for PBS/KREBS
'Range after PBS/KREBS
.Range("AG" & y & ":AW" & y).Value = wsHR.Range("AG" & i & ":AW" & i).Value
End With
y = y + 1
End If
End If
Next i
'Message Box when tasks are completed
MsgBox "Complete"
'Reset Macro Optimization Settings
Application.EnableEvents = True
Application.Calculation = xlCalculationAutomatic
Application.ScreenUpdating = True
End Sub
I cannot use the same conditional formatting rules in the second sheet, wsHH
, because not all of the values from wsHR
are pasted. The conditional formatting is based on duplicates.
Upvotes: 1
Views: 8253
Reputation: 4765
I wrote some more complete and customizable/parameterized copy subs to complete this task in a quite performant way. So one can decide if things like the following should be copied or not:
XlPasteType
and XlPasteSpecialOperation
params
e.g. the following call:
EventsDisable
PasteWithDisplayFormat Range("B40"), Range("A1:Z30")
EventsEnable
in the OP example it should be something like this:
With wsHH
PasteWithDisplayFormat .Range("A" & y), wsHR.Range("A" & i)
'...
End With
instead of:
With wsHH
wsHR.Range("A" & i).Copy
.Range("A" & y).PasteSpecial Paste:=xlPasteFormats
.Range("A" & y).PasteSpecial Paste:=xlPasteValues
'...
End With
(please feel free to enhance/extend it here for others)
'including conditional formatting as fixed styles (DisplayFormat)
'based on Range.PasteSpecial
Public Sub PasteWithDisplayFormat( _
dst As Range, _
Optional src As Range, _
Optional pasteSpecialBefore As Boolean = True, _
Optional paste As XlPasteType = xlPasteValuesAndNumberFormats, _
Optional Operation As XlPasteSpecialOperation = xlNone, _
Optional SkipBlanks As Boolean = False, _
Optional Transpose As Boolean = False, _
Optional Borders As Boolean = True, _
Optional Font As Boolean = True, _
Optional InteriorColor As Boolean = True, _
Optional WrapText As Boolean = True, _
Optional HorizontalAlignment As Boolean = True, _
Optional VerticalAlignment As Boolean = True _
)
If src Is Nothing Then Set src = Selection
If pasteSpecialBefore Then dst.PasteSpecial paste:=paste, Operation:=Operation, SkipBlanks:=False, Transpose:=False
Dim x As Integer: For x = 1 To src.Rows.Count
For y = 1 To src.Columns.Count
Dim sf As DisplayFormat: Set sf = src.Cells(x, y).DisplayFormat 'source cells DisplayFormat
With dst.Cells(x, y)
If Borders Then CopyBorders .Borders, sf.Borders
If Font Then
.Font.ColorIndex = sf.Font.ColorIndex
.Font.Color = sf.Font.Color
.Font.Background = sf.Font.Background
.Font.FontStyle = sf.Font.FontStyle '=> bold + italic
'.Font.Bold = sf.Font.Bold
'.Font.Italic = sf.Font.Italic
.Font.Size = sf.Font.Size
.Font.Name = sf.Font.Name
End If
If InteriorColor Then .Interior.Color = sf.Interior.Color
If WrapText Then .WrapText = sf.WrapText
If HorizontalAlignment Then .HorizontalAlignment = sf.HorizontalAlignment
If VerticalAlignment Then .VerticalAlignment = sf.VerticalAlignment
End With
Next y
Next x
End Sub
Sub CopyBorders(dst As Borders, src As Borders)
If src.LineStyle <> xlLineStyleNone Then
dst.ColorIndex = src.ColorIndex
If src.ColorIndex <> 0 Then dst.Color = src.Color
dst.Weight = src.Weight
dst.LineStyle = src.LineStyle
dst.TintAndShade = src.TintAndShade
End If
Dim bi As Integer: For bi = 1 To src.Count 'border index
CopyBorder dst(bi), src(bi)
Next bi
End Sub
Sub CopyBorder(dst As Border, src As Border)
If src.LineStyle <> xlLineStyleNone Then
dst.ColorIndex = src.ColorIndex
If src.ColorIndex <> 0 Then dst.Color = src.Color
dst.Weight = src.Weight
dst.LineStyle = src.LineStyle
dst.TintAndShade = src.TintAndShade
End If
End Sub
'used with EventsEnable()
Sub EventsDisable()
With Application: .EnableEvents = False: .ScreenUpdating = False: .Calculation = xlCalculationManual: End With
End Sub
'used with EventsDisable()
Sub EventsEnable()
With Application: .EnableEvents = True: .ScreenUpdating = True: .Calculation = xlCalculationAutomatic: End With
End Sub
here is one example based on copying to a temp word file and pasting back, but (at least on more complex tables) results in the pasting of some OLE embedded object that is not really usable in excel anymore, but could suffice for other uses:
using xlPasteAllMergingConditionalFormats
as the XlPasteType
seems to produce the same result like the temp MS Word doc approach above
Upvotes: 1
Reputation: 99
Found a work-around to get the formatting. Previously, you were not able to access the interior color from conditional formatting in VBA without going through a lot of extra work (see here). However, I discovered as of Excel 2010, this was changed (see here). Since I'm using Excel 2013, I am able to use .DisplayFormat
to find the interior color regardless of formatting (see here).
Using this, I changed:
With wsHH
wsHR.Range("A" & i).Copy
.Range("A" & y).PasteSpecial Paste:=xlPasteFormats
.Range("A" & y).PasteSpecial Paste:=xlPasteValues
'Range before PBS/KREBS
.Range("B" & y & ":AC" & y).Value = wsHR.Range("B" & i & ":AC" & i).Value
'Adds space to keep formulas for PBS/KREBS
'Range after PBS/KREBS
.Range("AG" & y & ":AW" & y).Value = wsHR.Range("AG" & i & ":AW" & i).Value
End With
to this:
With wsHH
'Range before PBS/KREBS
.Range("A" & y & ":AC" & y).Value = wsHR.Range("A" & i & ":AC" & i).Value
'Adds space to keep formulas for PBS/KREBS
'Applying background CF color to new sheet
If wsHR.Range("A" & i).DisplayFormat.Interior.ColorIndex > 0 Then
.Range("A" & y).Interior.ColorIndex = 3
End If
'Range after PBS/KREBS
.Range("AG" & y & ":AW" & y).Value = wsHR.Range("AG" & i & ":AW" & i).Value
End With
I am no longer copying and pasting values. Instead, I set the values using .Value
like I had been for the other cells in the row, and then use the outcome of If wsHR.Range("A" & i).DisplayFormat.Interior.ColorIndex > 0 Then
to determine if the second sheet's cell should be formatted.
Upvotes: 2