I have the following macro that will search for three different column headings, select the data under those headings and change the data from a currency format to a number format. The data is stored in Sheet 2 of my workbook and the macro works fine when I run it on it's own in this Sheet.
Sub ProjectFundingFormat()
'
Dim WS As Worksheet
Dim lastCol As Long, lastRow As Long, srcRow As Range
Dim found1 As Range, found2 As Range
Set WS = Workbooks("Workbook1.xlsm").Worksheets("Sheet2") 'Needs to be open
With WS
lastCol = .Cells(1, Columns.count).End(xlToLeft).Column
Set srcRow = .Range("A1", .Cells(1, lastCol))
Set found1 = srcRow.Find(What:="2018FundingLabor", LookAt:=xlWhole, MatchCase:=False)
If Not found1 Is Nothing Then
lastRow = .Cells(Rows.count, found1.Column).End(xlUp).Row
.Range(.Cells(2, found1.Column), .Cells(lastRow, found1.Column)).Select
Selection.NumberFormat = "0.00"
End If
End With
With WS
lastCol = .Cells(1, Columns.count).End(xlToLeft).Column
Set srcRow = .Range("A1", .Cells(1, lastCol))
Set found1 = srcRow.Find(What:="2018FundingNonlabor", LookAt:=xlWhole, MatchCase:=False)
If Not found1 Is Nothing Then
lastRow = .Cells(Rows.count, found1.Column).End(xlUp).Row
.Range(.Cells(2, found1.Column), .Cells(lastRow, found1.Column)).Select
Selection.NumberFormat = "0.00"
End If
End With
With WS
lastCol = .Cells(1, Columns.count).End(xlToLeft).Column
Set srcRow = .Range("A1", .Cells(1, lastCol))
Set found1 = srcRow.Find(What:="2018 Total Funding", LookAt:=xlWhole, MatchCase:=False)
If Not found1 Is Nothing Then
lastRow = .Cells(Rows.count, found1.Column).End(xlUp).Row
.Range(.Cells(2, found1.Column), .Cells(lastRow, found1.Column)).Select
Selection.NumberFormat = "0.00"
End If
End With
End Sub
I am wanting to combine this macro with another two so that I can go into Sheet 1, click a "run" button I have inserted and all my macros will run together to update my data. However, I am getting the error
Run time error 1004 - select method of range class failed
at the line
.Range(.Cells(2, found1.Column), .Cells(lastRow, found1.Column)).Select
Does anyone know what might be wrong with my code? I am confused since it works fine on its own, but won't run when combined with my other macros.
I am using the following macro to combine my two existing macros:
Sub ProjectUpdate()
Call ProjectName
Call ProjectFunding
Call ProjectFundingFormat
MsgBox "Done"
End Sub
You should really avoid to use .Select and .Activate at all! This slows down your code a lot and leads into many issues. It is a very bad practice. If you are interested in writing stable and good quality code I really recommend to read and follow: How to avoid using Select in Excel VBA
Your code can be reduced to the following:
Option Explicit
Public Sub ProjectFundingFormat()
Dim Ws As Worksheet
Set Ws = Workbooks("Workbook1.xlsm").Worksheets("Sheet2") 'Needs to be open
With Ws
Dim srcRow As Range
Set srcRow = .Range("A1", .Cells(1, .Columns.Count).End(xlToLeft))
Dim lastRow As Long
Dim found1 As Range
Set found1 = srcRow.Find(What:="2018FundingLabor", LookAt:=xlWhole, MatchCase:=False)
If Not found1 Is Nothing Then
lastRow = .Cells(.Rows.Count, found1.Column).End(xlUp).Row
.Range(.Cells(2, found1.Column), .Cells(lastRow, found1.Column)).NumberFormat = "0.00"
End If
Set found1 = srcRow.Find(What:="2018FundingNonlabor", LookAt:=xlWhole, MatchCase:=False)
If Not found1 Is Nothing Then
lastRow = .Cells(.Rows.Count, found1.Column).End(xlUp).Row
.Range(.Cells(2, found1.Column), .Cells(lastRow, found1.Column)).NumberFormat = "0.00"
End If
Set found1 = srcRow.Find(What:="2018 Total Funding", LookAt:=xlWhole, MatchCase:=False)
If Not found1 Is Nothing Then
lastRow = .Cells(.Rows.Count, found1.Column).End(xlUp).Row
.Range(.Cells(2, found1.Column), .Cells(lastRow, found1.Column)).NumberFormat = "0.00"
End If
End With
End Sub
Throw out unnecessary repeating With statements.
Last column number needs not to be determined you can use the last cell of row 1 direclty with .Cells(1, .Columns.Count).End(xlToLeft).
Throw out all .Select and .Activate.
Makes it much cleaner and more stable.
Or you even use an additional procedure to avoid repeating code at all, which is a good practice to not repeat code and better have procedures instead:
Option Explicit
Public Sub ProjectFundingFormat()
Dim Ws As Worksheet
Set Ws = Workbooks("Workbook1.xlsm").Worksheets("Sheet2") 'Needs to be open
With Ws
Dim srcRow As Range
Set srcRow = .Range("A1", .Cells(1, .Columns.Count).End(xlToLeft))
FindAndFormat srcRow, "2018FundingLabor"
FindAndFormat srcRow, "2018FundingNonlabor"
FindAndFormat srcRow, "2018 Total Funding"
End With
End Sub
Public Sub FindAndFormat(srcRow As Range, FindWhat As String)
With srcRow.Parent
Dim found1 As Range
Set found1 = srcRow.Find(What:=FindWhat, LookAt:=xlWhole, MatchCase:=False)
If Not found1 Is Nothing Then
Dim lastRow As Long
lastRow = .Cells(.Rows.Count, found1.Column).End(xlUp).Row
.Range(.Cells(2, found1.Column), .Cells(lastRow, found1.Column)).NumberFormat = "0.00"
End If
End With
End Sub
Related
I have a workbook with multiple sheets (Sheet 1, 2...etc) and a "Master" Sheet. I need to select a range from columns A:C until it meets a row with the value (tva) (including those rows). I want to compare that range from Master to the other sheets, and highlight the differences.
Sample image For example Master sheet has in A3 value "m".
This is what I have so far. I'm pretty new at this so any advice is appreciated :)
Sub comp()
Dim ws As Worksheet
Dim rngCell As Range
For Each ws In ThisWorkbook.Worksheets
ws.Activate
rngCell = Columns("A:C").Resize(Columns("A:C").Find(What:="tva", After:=Range("A1"), LookIn:=xlValues, SearchDirection:=xlPrevious).Row)
rngCell.Select
For Each rngCell In ws.Range
If Not rngCell = Worksheets("Master").Cells(rngCell.Row, rngCell.Column) Then
rngCell.Interior.Color = vbYellow
End If
Next ws
End Sub
You can try following code, although it is did not cover other column, but small adjustment only need to check until column C (col 3):
Sub comp()
Dim ws As Worksheet
Dim valuerow As Long, irow As Long
For Each ws In ThisWorkbook.Worksheets
ws.Activate
valuerow = Cells.Find(What:="tva", After:=Range("A1"), LookIn:=xlValues, SearchDirection:=xlPrevious).Row
For irow = 1 To valuerow
If ws.Cells(irow, 1).Value <> Worksheets("Master").Cells(irow, 1).Value Then
ws.Cells(irow, 1).Interior.Color = vbYellow
End If
If ws.Cells(irow, 2).Value <> Worksheets("Master").Cells(irow, 2).Value Then
ws.Cells(irow, 2).Interior.Color = vbYellow
End If
Next
Next
End Sub
How can I highlight a single row a color if text in column A = X
Using Row 4 as an example:
What i'm ultimately trying to get is if Cell in Column A is = X then change row color from Range("B4:N4") to Black And Text.Color to White from Range("F4:N4")
Ultimately I would want it to be something like Range(Cells(i, "B"), Cells(LastRow, LastCol)) but only color one row.
This is what i am working with so far.
Sub Header()
Application.ScreenUpdating = False
Dim sht2 As Worksheet
Set sht2 = ThisWorkbook.Worksheets("Email Form")
sht2.Activate
sht2.Unprotect
Dim LastRow As Long, LastCol As Long
Dim rng As Range, c As Range
Dim WholeRng As Range
Dim i As Integer
On Error GoTo 0
With sht2
Set rng = .Cells
LastRow = rng.Find(What:="*", After:=rng.Cells(1), Lookat:=xlPart, LookIn:=xlFormulas, SearchOrder:=xlByRows, SearchDirection:=xlPrevious, MatchCase:=False).Row
LastCol = rng.Find(What:="*", After:=rng.Cells(1), Lookat:=xlPart, LookIn:=xlFormulas, SearchOrder:=xlByColumns, SearchDirection:=xlPrevious, MatchCase:=False).Column
'MsgBox wholerng.Address
Set WholeRng = Range(Cells(i, "B"), Cells(LastRow, LastCol)).Rows
For i = 4 To LastRow
If sht2.Cells(i, 1).Value = "X" Then
With WholeRng
With .Interior
.PatternColorIndex = xlAutomatic
.Color = 1
.TintAndShade = 0
.Font.Color = 0
End With
End With
End If
Next i
Dim b As Boolean
For Each rng In WholeRng.Rows
If Not rng.Hidden Then
If b Then rng.Interior.Color = 1
b = Not b
End If
Next
End With
Set sht2 = Nothing
Set rng = Nothing
Set WholeRng = Nothing
Application.ScreenUpdating = False
End Sub
VBA Conditional Formatting.
Option Explicit
Sub Header()
Dim sht2 As Worksheet
Dim firstRow As Long, lastRow As Long, lastCol As Long
'Application.ScreenUpdating = false
On Error GoTo 0
Set sht2 = ThisWorkbook.Worksheets("Email Form")
firstRow = 4
With sht2
.Activate
.Unprotect
lastRow = .Cells.Find(What:="*", After:=.Cells(1), Lookat:=xlPart, LookIn:=xlFormulas, SearchOrder:=xlByRows, SearchDirection:=xlPrevious, MatchCase:=False).Row
lastCol = .Cells.Find(What:="*", After:=.Cells(1), Lookat:=xlPart, LookIn:=xlFormulas, SearchOrder:=xlByColumns, SearchDirection:=xlPrevious, MatchCase:=False).Column
'black row, white text B:N
With .Range(.Cells(firstRow, "B"), .Cells(lastRow, lastCol))
'optionally remove any pre-existing CFRs
.FormatConditions.Delete
With .FormatConditions.Add(Type:=xlExpression, Formula1:="=UPPER($A4)=CHAR(88)")
.Interior.ThemeColor = xlThemeColorLight1
.Font.ThemeColor = xlThemeColorDark1
.SetFirstPriority
.StopIfTrue = False
End With
End With
'don't display values from B:E
With .Range(.Cells(firstRow, "B"), .Cells(lastRow, "E"))
With .FormatConditions.Add(Type:=xlExpression, Formula1:="=UPPER($A4)=CHAR(88)")
.NumberFormat = ";;;"
End With
End With
'I tnhink you want to reProtect the worksheet here
.Protect
End With
Application.ScreenUpdating = True
End Sub
I think you can achieve your goal using Conditional Formatting:
You can create a condition for each format setting for the two different ranges.
Select one range at a time, then from the Home tab, create a New Conditional Formatting Rule, choose to Use a Formula and then enter a formula like:
=$A2="X"
Note that when using relative/mixed references in conditional formatting, it will be compared to the first cell in the range you are working with. I've selected range B2:N7 to apply formatting to, so the mixed reference needs to be created as it should apply to the B2 cell. You can't see it, but the reference automatically changes for all other cells in the same range, the same as if you were filling a formula across the rest of the range. For example, the formatting for the K5 cell will be dependent on the value in $A5 (because the column reference is fixed but the row reference is dynamic).
Then set the background colour or font colour you want for the range specified. This condition will check column A of the corresponding row.
I re-wrote some of your code and added comments to show you why. But by and large, I followed your original approach.
Sub Header()
Dim Sht2 As Worksheet
Dim LastRow As Long, LastCol As Long
Dim IsBlack As Boolean, FillPattern As Long
Dim Rng As Range
Dim R As Long
' Set sht2 = ThisWorkbook.Worksheets("Email Form")
Set Sht2 = ThisWorkbook.Worksheets("Taylor")
' On Error GoTo 0 ' this is the default: no need to set
Application.ScreenUpdating = False
With Sht2
.Activate ' no need to activate this sheet
.Unprotect
' this is the whole sheet: Easier to refer to it as .Cells
' Set rng = .Cells
LastRow = .Cells(.Rows.Count, "A").End(xlUp).Row
LastCol = .Cells(1, .Columns.Count).End(xlToLeft).Column
' LastRow = Rng.Find(What:="*", After:=Rng.Cells(1), Lookat:=xlPart, _
' LookIn:=xlFormulas, SearchOrder:=xlByRows, _
' SearchDirection:=xlPrevious, MatchCase:=False).Row
' LastCol = Rng.Find(What:="*", After:=Rng.Cells(1), Lookat:=xlPart, _
' LookIn:=xlFormulas, SearchOrder:=xlByColumns, _
' SearchDirection:=xlPrevious, MatchCase:=False).Column
' MsgBox "Last row = " & LastRow & vbCr & _
' "Last column = " & LastCol
For R = 4 To LastRow
IsBlack = Not CBool(StrComp(.Cells(R, 1).value, "X", vbTextCompare))
FillPattern = CLng(Array(xlNone, xlSolid)(Abs(IsBlack)))
Set Rng = .Range(.Cells(R, 1), .Cells(R, LastCol))
With Rng.Interior
If .Pattern <> FillPattern Then
.Pattern = FillPattern
If IsBlack Then
.PatternColorIndex = xlAutomatic
.ThemeColor = xlThemeColorLight1
End If
.TintAndShade = 0
.PatternTintAndShade = 0
Rng.Font.ColorIndex = Array(xlAutomatic, 2)(Abs(IsBlack))
End If
End With
Next R
End With
' VBA does this cleanup automatically at the end of the sub
' Set sht2 = Nothing
' Set Rng = Nothing
Application.ScreenUpdating = False
End Sub
I am trying to find values by comparing 2 sheets and then copy the row to another sheet. Any suggestions?
Sub SpecialCopy()
Dim i As Long
Dim cellval, rng As Range
Dim ws1, ws2 As Worksheet
Dim targetSh As Worksheet
Set targetSh = ThisWorkbook.Worksheets("Sheet3")
Set ws2 = Sheets("Sheet2")
Set ws1 = Sheets("sheet1")
ws2.Select
With ActiveSheet
Set rng = .Range("A1:A" & .Cells(.Rows.Count, 1).End(xlUp).Row)
End With
For i = 2 To rng.Rows.Count
Set cellval = ws1.Columns(1).Find(What:=ws2.Range("U" & i).Value, After:=ActiveCell, LookIn:=xlFormulas, _
LookAt:=xlWhole, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False)
If cellval Is Nothing Then
Else
Range(Cells(1, i), Cells(33, i)).Copy Destination:=targetSh.Range("A" & targetSh.Cells(Rows.Count, "A").End(xlUp).Row + 1)
End If
Next i
End Sub
Feel that this is piggy-backing on others' comments above, but nobody has submitted an answer so here is my stab. Makes sense to use your sheet variables as you have defined them rather than ActiveSheet, and make sure you follow this through everywhere.
Sub SpecialCopy()
Dim i As Long
Dim cellval As Range, rng As Range
Dim ws1 As Worksheet, ws2 As Worksheet
Dim targetSh As Worksheet
Set targetSh = ThisWorkbook.Worksheets("Sheet3")
Set ws2 = Sheets("Sheet2")
Set ws1 = Sheets("Sheet1")
With ws2
Set rng = .Range("A1:A" & .Cells(.Rows.Count, 1).End(xlUp).Row)
End With
For i = 2 To rng.Rows.Count
Set cellval = ws1.Columns(1).Find(What:=ws2.Range("U" & i).Value, LookIn:=xlFormulas, _
LookAt:=xlWhole, MatchCase:=False, SearchFormat:=False)
If Not cellval Is Nothing Then
ws2.Range(ws2.Cells(1, i), ws2.Cells(33, i)).Copy Destination:=targetSh.Range("A" & targetSh.Cells(targetSh.Rows.Count, "A").End(xlUp).Row + 1)
End If
Next i
End Sub
Requirement: I need to copy 1 Column - Col G (need to determine the number of rows dynamically) from 1 Workbook to another.
Problem: Getting VBA Error:
Runtime Error: 9 - Subscript out of range Please help.
Sub Set_Open_ExistingWorkbook()
Dim wkb As Workbook
Set wkb = Workbooks.Open("C:\Users\me364167\Documents\Practice_OB_Status_Detailed_Report_Mainframe.xls")
'Set wkb = Workbooks.Open("C:\Users\me364167\Documents\Practice level_Opportunity Pipeline_Mainframe.xls")
Dim LastRow As Long
Dim Sheet1Data As Long
With ActiveSheet
LastRow = .Cells(.Rows.Count, "G").End(xlUp).Row
End With
Workbooks("Practice_OB_Status_Detailed_Report_Mainframe.xls").Worksheets("OB_Status_Detailed_Report").Range(Cells(1, "G"), Cells(LastRow, "G")).Copy
Workbooks("OB Macro.xlsx").Worksheets("OB_Status_Detailed_Report").Range(Cells(1, "A"), Cells(LastRow, "A")).PasteSpecial
' Workbooks("Practice_OB_Status_Detailed_Report_Mainframe.xls").Worksheets("OB_Status_Detailed_Report").Range(Cells(1, "G"), Cells(LastRow, "G")).Copy
' Workbooks("OB Macro.xlsx").Worksheets("OB_Status_Detailed_Report").Range(Cells(1, "A"), Cells(LastRow, "A")).PasteSpecial Paste:=xlValues
wkb.Close
End Sub
This perhaps? Your ranges are not fully qualified and as Shai Rado says you are missing a PS paremeter.
Sub Set_Open_ExistingWorkbook()
Dim wkb As Workbook
Set wkb = Workbooks.Open("C:\Users\me364167\Documents\Practice_OB_Status_Detailed_Report_Mainframe.xls")
'Set wkb = Workbooks.Open("C:\Users\me364167\Documents\Practice level_Opportunity Pipeline_Mainframe.xls")
Dim LastRow As Long
Dim Sheet1Data As Long
With ActiveSheet
LastRow = .Cells(.Rows.Count, "G").End(xlUp).Row
End With
With wkb.Worksheets("OB_Status_Detailed_Report")
.Range(.Cells(1, "G"), .Cells(LastRow, "G")).Copy
End With
With Workbooks("OB Macro.xlsx").Worksheets("OB_Status_Detailed_Report")
.Range(.Cells(1, "A"), .Cells(LastRow, "A")).PasteSpecial xlValues
End With
' Workbooks("Practice_OB_Status_Detailed_Report_Mainframe.xls").Worksheets("OB_Status_Detailed_Report").Range(Cells(1, "G"), Cells(LastRow, "G")).Copy
' Workbooks("OB Macro.xlsx").Worksheets("OB_Status_Detailed_Report").Range(Cells(1, "A"), Cells(LastRow, "A")).PasteSpecial Paste:=xlValues
wkb.Close
End Sub
I am trying to figure out the cleanest way to create a dynamic range and this, I think, is close to what I want it to do but I am not sure how to make it correct. Any thoughts?
Sub Macro1()
Dim RNG As Range
With Sheets("Open Jobs Report") 'Change to your sheet
Set RNG = .Range("A1", .Cells(.Cells(.Rows.Count, "A").End(xlUp).Row, .Cells(1, .Columns.Count).End(xlToLeft).Column))
End With
Try this:
Dim RNG As Range
Set RNG = .Range("A1", .Cells(.Cells(.Rows.Count, "A").End(xlUp).Row, .Cells(1, .Columns.Count).End(xlToLeft).Column))
Because you were using . in front of some of the range objects I assume it is in a With Block like this:
Sub foooooii()
Dim RNG As Range
With Sheets("Sheet3") 'Change to your sheet
Set RNG = .Range("A1", .Cells(.Cells(.Rows.Count, "A").End(xlUp).Row, .Cells(1, .Columns.Count).End(xlToLeft).Column))
End With
Debug.Print RNG.Address
End Sub
building on Scott's solution and just to shorten it a little:
Set RNG = .Range(.Cells(.Rows.Count, "A").End(xlUp), .Cells(1, .Columns.Count).End(xlToLeft))