I am setting up a new pricing schedule which reads selected information from a 'Register' tab, based on selected criteria, and copying this into a new tab. This data is formatted so it looks aesthetically pleasing.
I am finding formatting the code is slowing down the run speed significantly. If possible I would like to speed this up as I will be iterating this multiple times.
I hae sped the program up a reasonable amount. Initially it took 30s, whereas now it is about 10s.
I have followed information from this website as best as I can:
https://www.soa.org/News-and-Publications/Newsletters/Compact/2012/january/com-2012-iss42-roper.aspx
I feel there is still scope to improve more, though I am unsure how, and am reaching out to see if there is, or are, better ways to improve the code so it runs quicker.
Option Explicit
Sub create_pricing_schedule()
'define workbook variables
Dim Start_Time As Double, End_Time As Double
Dim file1 As Workbook
Dim ws1 As Worksheet
Dim ws2 As Worksheet
Dim ws3 As Worksheet
Dim ws4 As Worksheet
Dim namedRange1 As Range
Dim namedRange2 As Range
Set file1 = ThisWorkbook
Set ws2 = file1.Worksheets("Pricing Schedule")
Set ws3 = file1.Worksheets("Control")
Set ws4 = file1.Worksheets("Register")
Set namedRange1 = file1.Names("Client_Register").RefersToRange
Set namedRange2 = file1.Names("Pricing_Range").RefersToRange
'define general variables
Dim i As Integer
Dim collect(1 To 500, 1 To 10) As Variant
Dim rw As Range
Dim selectedClient As String
Dim lastrow As Integer, lastrow2 As Integer, lastrow3 As Integer
i = 1
'time how long it takes to improve efficiency
Start_Time = Timer
'speedup so less lagg
Call speedup
'delete everything from the pricing schedule/reset
With Sheets("Pricing Schedule")
.UsedRange.ClearContents
.Cells.Interior.ColorIndex = 0
.Cells.Borders.LineStyle = xlNone
.Cells.HorizontalAlignment = xlLeft
.Cells.MergeCells = False
.Range("A:Z").WrapText = False
.Rows.RowHeight = "15"
End With
'resize the client register
lastrow = ws4.Range("A100000").End(xlUp).Row
With ActiveWorkbook.Names("Client_Register")
.RefersTo = "=Register!$A$1:$AE$" & lastrow
End With
selectedClient = ws3.Range("B3").Value
'copy from database to the pricing schedule as a non formatted list of all the info - this runs quickly, but I am open to changing it
For Each rw In Range("Client_Register").Rows
If Range("Client_Register").Cells(rw.Row, 2) = selectedClient Then
collect(i, 1) = Range("Client_Register").Range("E" & rw.Row)
collect(i, 2) = Range("Client_Register").Range("D" & rw.Row)
collect(i, 3) = Range("Client_Register").Range("F" & rw.Row)
collect(i, 4) = Range("Client_Register").Range("J" & rw.Row)
collect(i, 5) = Range("Client_Register").Range("K" & rw.Row)
collect(i, 6) = Range("Client_Register").Range("L" & rw.Row)
collect(i, 7) = Range("Client_Register").Range("M" & rw.Row)
collect(i, 8) = Range("Client_Register").Range("P" & rw.Row)
collect(i, 9) = Range("Client_Register").Range("I" & rw.Row)
collect(i, 10) = Range("Client_Register").Range("H" & rw.Row) ' used to determine if pass through fee
ws2.Range("B" & i + 6) = collect(i, 1)
ws2.Range("C" & i + 6) = collect(i, 2)
ws2.Range("D" & i + 6) = collect(i, 3)
ws2.Range("E" & i + 6) = collect(i, 4)
ws2.Range("F" & i + 6) = collect(i, 5)
ws2.Range("G" & i + 6) = collect(i, 6)
ws2.Range("H" & i + 6) = collect(i, 7)
ws2.Range("I" & i + 6) = collect(i, 8)
ws2.Range("J" & i + 6) = collect(i, 9)
ws2.Range("K" & i + 6) = collect(i, 10)
i = i + 1
End If
Next
'add in the colour and count how many rows there are
lastrow2 = ws2.Range("C5000").End(xlUp).Row
With ActiveWorkbook.Names("Pricing_Range")
.RefersTo = "='Pricing Schedule'!$A$1:$K$" & lastrow2
End With
ws2.Range("B7" & ":" & "J" & lastrow2).Interior.Color = RGB(242, 242, 242)
'==========this bit is slow, can it be quicker?==========
'add spacing, titles, and colour to sub headers
i = 7
For Each rw In Range("Pricing_Range").Rows
If Range("Pricing_Range").Cells(i, 3) <> Range("Pricing_Range").Cells(i + 1, 3) Then
Range("Pricing_Range").Rows(i + 1).Insert Shift:=xlShiftDown
Range("Pricing_Range").Rows(i + 1).Insert Shift:=xlShiftDown
Range("Pricing_Range").Rows(i + 1).Interior.ColorIndex = 0
Range("Pricing_Range").Rows(i + 2).Interior.ColorIndex = 0
Range("Pricing_Range").Range("B" & i + 2 & ":" & "J" & i + 2).Interior.Color = RGB(255, 128, 1)
Range("Pricing_Range").Range("B" & i + 2 & ":" & "J" & i + 2).Borders(xlEdgeTop).Color = RGB(0, 0, 0)
Range("Pricing_Range").Range("B" & i + 2 & ":" & "J" & i + 2).Borders(xlEdgeBottom).Color = RGB(0, 0, 0)
Range("Pricing_Range").Range("B" & i + 2).Value = Range("Pricing_Range").Range("C" & i + 3).Value
'if it is a pass through fee then add it in to the sub headers
If Range("Pricing_Range").Range("K" & i + 3).Value = "Pass-Through" Then
Range("Pricing_Range").Range("J" & i + 2).Value = "Pass-Through Fees"
Range("Pricing_Range").Range("J" & i + 2).HorizontalAlignment = xlRight
End If
i = i + 3
Else
i = i + 1
End If
Next
'==================================================
'set up the main title rows
ws2.Select
Range("Pricing_Range").Range("B2").Value = ws3.Range("B3").Value
Range("Pricing_Range").Range("B2").Font.Size = 20
Range("Pricing_Range").Range("B2").Font.Bold = True
Range("Pricing_Range").Range("B2").Font.FontStyle = "Calibri Light"
Range("Pricing_Range").Range("B2:J3").Select
With Selection
.HorizontalAlignment = xlCenter
.VerticalAlignment = xlCenter
.WrapText = False
.MergeCells = True
.Cells.Interior.Color = RGB(255, 128, 1)
.Cells.Borders(xlEdgeTop).Color = RGB(0, 0, 0)
.Cells.Borders(xlEdgeBottom).Color = RGB(0, 0, 0)
End With
'tidy up things in the sheet
With Worksheets("Pricing Schedule")
'set up the headers and first title
.Range("B6") = .Range("C7")
.Range("B5:J6").Interior.Color = RGB(255, 128, 1)
.Range("B5:J5").Borders(xlEdgeTop).Color = RGB(0, 0, 0)
.Range("B5:J5").Borders(xlEdgeBottom).Color = RGB(0, 0, 0)
.Range("B6:J6").Borders(xlEdgeTop).Color = RGB(0, 0, 0)
.Range("B6:J6").Borders(xlEdgeBottom).Color = RGB(0, 0, 0)
.Range("B5").Value = "Fee Code"
.Range("C5").Value = "Product Line"
.Range("D5").Value = "Item"
.Range("E5").Value = "Volume From"
.Range("F5").Value = "Volume To"
.Range("G5").Value = "Frequency"
.Range("H5").Value = "Location"
.Range("I5").Value = "Price"
.Range("J5").Value = "Nature of Fee"
'tidy up column widths
.Range("A5").RowHeight = 30
.Range("A1").ColumnWidth = 2
.Range("B1").ColumnWidth = 15
.Range("C1").ColumnWidth = 40
.Range("D1").ColumnWidth = 45
.Range("E1").ColumnWidth = 11
.Range("F1").ColumnWidth = 11
.Range("G1").ColumnWidth = 35
.Range("H1").ColumnWidth = 15
.Range("I1").ColumnWidth = 12
.Range("J1").ColumnWidth = 50
.Range("J:J").WrapText = True
.Range("K:K").Delete
End With
'clear the extra orange line at the end
lastrow3 = ws2.Range("B1000").End(xlUp).Row
With ws2.Rows(lastrow3 + 2)
.Cells.Interior.ColorIndex = 0
.Cells.Borders.LineStyle = xlNone
.ClearContents
End With
'add print area
With Worksheets("Pricing Schedule")
.PageSetup.Zoom = False
.PageSetup.Orientation = xlPortrait
.PageSetup.PrintArea = "$B$2:$J$" & lastrow3
.PageSetup.FitToPagesWide = 1
.PageSetup.FitToPagesTall = False
.PageSetup.PrintTitleRows = "$2:$6"
End With
'return to normal
Call slowdown
'time how long it takes to improve efficiency
End_Time = Timer
Worksheets("Control").Cells(6, 2) = End_Time - Start_Time
End Sub
Sub speedup()
Application.Calculation = xlManual
Application.ScreenUpdating = False
Application.EnableEvents = False
Application.DisplayStatusBar = False
End Sub
Sub slowdown()
Application.Calculation = xlCalculationAutomatic
Application.ScreenUpdating = True
Application.EnableEvents = True
Application.DisplayStatusBar = True
End Sub
I found a few lines that could save you some execution time.
'****EDIT****Changed this to direct range reference rather than go through the Names collection.
'Set namedRange1 = file1.Names("Client_Register").RefersToRange
'Set namedRange2 = file1.Names("Pricing_Range").RefersToRange
Set namedRange1 = file1.Range("Client_Register")
Set namedRange2 = file1.Range("Pricing_Range")
Used range takes more time rather use .cells directly
'delete everything from the pricing schedule/reset
'****EDIT***
With ws2 'Sheets("Pricing Schedule")
'used range takes more time rather use .cells directly
.Cells.ClearContents
Rather than use arrays you can directly update values as shown below
'I am using i for the row count
ws2.Range("B" & i + 6).Value = namedRange1.Cells(i, 5).Value
ws2.Range("C" & i + 6).Value = namedRange1.Cells(i, 4).Value
ws2.Range("D" & i + 6).Value = namedRange1.Cells(i, 6).Value
ws2.Range("E" & i + 6).Value = namedRange1.Cells(i, 10).Value
ws2.Range("F" & i + 6).Value = namedRange1.Cells(i, 11).Value
ws2.Range("G" & i + 6).Value = namedRange1.Cells(i, 12).Value
ws2.Range("H" & i + 6).Value = namedRange1.Cells(i, 12).Value
ws2.Range("I" & i + 6).Value = namedRange1.Cells(i, 16).Value
ws2.Range("J" & i + 6).Value = namedRange1.Cells(i, 9).Value
ws2.Range("K" & i + 6).Value = namedRange1.Cells(i, 8).Value
i = i + 1
The main culprit for your slower performance is the insert operation. try to work the logic to not having insert. If not possible, try to insert rows outside the loop in a single operation rather than in the loop
Range("Pricing_Range").Rows(i + 1).Insert Shift:=xlShiftDown
Range("Pricing_Range").Rows(i + 1).Insert Shift:=xlShiftDown
Your handling of the collect array is inefficient. Consider reading the entire Client Register into an array with MyArray = Range.Value. Then prepare the output array in memory and write it to the worksheet after all looping is done, in one go, with TargetRange.Value = collect.
Avoid inserting rows. What's wrong with the existing? If you are preparing all data in an array to be pasted to the worksheet, empty array elements will produce empty worksheet cells. In this way all inserting can be avoided and all you need to do is to format.
There is time cost for every access to the worksheet, whether to read or write. Even for formatting, try to create ranges that are treated in the same manner. Avoid accessing the worksheet in loops.
Example of With and block assignment from an array:
'copy from database to the pricing schedule as a
' non formatted list of all the info - this runs quickly,
' but I am open to changing it
With Range("Client_Register")
For Each rw In .Rows
If .Cells(rw.Row, 2) = selectedClient Then
collect(i, 1) = .Range("E" & rw.Row)
collect(i, 2) = .Range("D" & rw.Row)
collect(i, 3) = .Range("F" & rw.Row)
collect(i, 4) = .Range("J" & rw.Row)
collect(i, 5) = .Range("K" & rw.Row)
collect(i, 6) = .Range("L" & rw.Row)
collect(i, 7) = .Range("M" & rw.Row)
collect(i, 8) = .Range("P" & rw.Row)
collect(i, 9) = .Range("I" & rw.Row)
collect(i, 10) = .Range("H" & rw.Row)
'you could even skip the row-by-row population of values
' and assign as a block after exiting the loop
ws2.Range("B" & i + 6).Resize(1, 10).Value = _
Array(collect(i, 1), collect(i, 2), collect(i, 3), _
collect(i, 4), collect(i, 5), collect(i, 6), _
collect(i, 7), collect(i, 8), collect(i, 9), _
collect(i, 10))
i = i + 1
End If
Next
End With
Note this will break if your Client_Register refers to a range which doesn't start on Row1, because of the relative range references.
Eg:
Range("A1:A10").Range("A1") 'refers to A1
Range("A2:A10").Range("A1") 'refers to A2
Related
Also how do I stop the loop from taking in empty cells? I've tried Do While and Do Until but it still takes in the empty cells. I want the code to take the values in the Input Values tab one row at a time and give results for each one until an empty cell. Then sum the results given by each row of inputs. This is the code I have so far. The calculation itself works, but the loop doesn't.
'''
Sub TEST()
Dim i As Long
For i = 1 To 1000000
i = i + 1
'Pasting Input Values into Inputs Taken
Sheets("Input Values").Range("A" & i).Copy
Sheets("Inputs Taken").Range("D5").PasteSpecial xlPasteValues
Sheets("Input Values").Range("B" & i).Copy
Sheets("Inputs Taken").Range("D6").PasteSpecial xlPasteValues
Sheets("Input Values").Range("C" & i).Copy
Sheets("Inputs Taken").Range("D7").PasteSpecial xlPasteValues
Sheets("Input Values").Range("D" & i).Copy
Sheets("Inputs Taken").Range("D8").PasteSpecial xlPasteValues
Sheets("Input Values").Range("E" & i).Copy
Sheets("Inputs Taken").Range("C11").PasteSpecial xlPasteValues
Sheets("Input Values").Range("F" & i).Copy
Sheets("Inputs Taken").Range("D11").PasteSpecial xlPasteValues
Sheets("Input Values").Range("G" & i).Copy
Sheets("Inputs Taken").Range("C16").PasteSpecial xlPasteValues
Sheets("Input Values").Range("H" & i).Copy
Sheets("Inputs Taken").Range("D16").PasteSpecial xlPasteValues
Sheets("Input Values").Range("I" & i).Copy
Sheets("Inputs Taken").Range("G9").PasteSpecial xlPasteValues
Sheets("Input Values").Range("J" & i).Copy
Sheets("Inputs Taken").Range("G10").PasteSpecial xlPasteValues
Sheets("Input Values").Range("K" & i).Copy
Sheets("Inputs Taken").Range("G11").PasteSpecial xlPasteValues
Sheets("Input Values").Range("L" & i).Copy
Sheets("Inputs Taken").Range("G12").PasteSpecial xlPasteValues
Sheets("Input Values").Range("M" & i).Copy
Sheets("Inputs Taken").Range("G13").PasteSpecial xlPasteValues
Sheets("Input Values").Range("N" & i).Copy
Sheets("Inputs Taken").Range("G14").PasteSpecial xlPasteValues
'Setting Opening PUP to 100% and refreshing
Sheets("Inputs Taken").Range("G5").Value = 1
Application.CalculateFull
'Calculating No RPs
Sheets("Output").Range("C7").Formula = _
"=SUMPRODUCT(Model!BJ6:BJ365,Model!AD6:AD365,Model!AG6:AG365)"
Sheets("Output").Range("C8").Formula = _
"=SUMPRODUCT(Model!AD6:AD365,Model!AG6:AG365,Model!BK6:BK365)"
Sheets("Output").Range("C10").Formula = _
"=SUMPRODUCT(Model!AD6:AD365,Model!AG6:AG365,Model!BM6:BM365)"
Sheets("Output").Range("C11").Formula = _
"=SUMPRODUCT(Model!AD6:AD365,Model!AG6:AG365,Model!BN6:BN365)"
Sheets("Output").Range("C12").Formula = _
"=SUMPRODUCT(Model!AD6:AD365,Model!AG6:AG365,Model!BO6:BO365)"
Sheets("Output").Range("C13").Formula = _
"=SUMPRODUCT(Model!AD6:AD365,Model!AG6:AG365,Model!BP6:BP365)"
Sheets("Output").Range("C14").Formula = "=SUM(Output!C11:C13)"
Sheets("Output").Range("C17").Formula = _
"=-SUMPRODUCT(Model!AD6:AD365,Model!AG6:AG365,Model!BS6:BS365)"
Sheets("Output").Range("C18").Formula = _
"=-SUMPRODUCT(Model!AD6:AD365,Model!AG6:AG365,Model!BT6:BT365)"
Sheets("Output").Range("C19").Formula = _
"=-SUMPRODUCT(Model!AD6:AD365,Model!AG6:AG365,Model!BU6:BU365)"
Sheets("Output").Range("C20").Formula = _
"=-SUMPRODUCT(Model!AD6:AD365,Model!AG6:AG365,Model!BV6:BV365)"
Sheets("Output").Range("C21").Formula = _
"=-SUMPRODUCT(Model!AD6:AD365,Model!AG6:AG365,Model!BW6:BW365)"
Sheets("Output").Range("C22").Formula = _
"=-SUMPRODUCT(Model!AD6:AD365,Model!AG6:AG365,Model!BX6:BX365)"
Sheets("Output").Range("C23").Formula = _
"=-SUMPRODUCT(Model!AD6:AD365,Model!AG6:AG365,Model!BY6:BY365)"
Sheets("Output").Range("C24").Formula = _
"=-SUMPRODUCT(Model!AD6:AD365,Model!AG6:AG365,Model!BZ6:BZ365)"
Sheets("Output").Range("C25").Formula = _
"=-SUMPRODUCT(Model!AD6:AD365,Model!AG6:AG365,Model!CA6:CA365)"
Sheets("Output").Range("C26").Formula = _
"=-SUMPRODUCT(Model!AD6:AD365,Model!AG6:AG365,Model!CB6:CB365)"
Sheets("Output").Range("C5").Formula = "=Model!BL6-Model!BS6-Model!BT6"
Sheets("Output").Range("C15").Formula = "=SUM(Output!C7:C10,Output!C14)"
Sheets("Output").Range("C27").Formula = "=SUM(Output!C17:C26)"
Sheets("Output").Range("C29").Formula = "=-SUM(Model!AN6:AN365)"
Sheets("Output").Range("C30").Formula = "=-SUM(Model!AP6:AP365)"
Sheets("Output").Range("C31").Formula = "=-Output!C2"
Sheets("Output").Range("C33").Formula = "=SUM(Output!C29:C31,Output!C27,Output!C15)"
'Removing Formulas from output
Sheets("Output").Range("C5:C33").Copy
Sheets("Output").Range("C5:C33").PasteSpecial xlPasteValues
'Changing PUP rate
Sheets("Inputs Taken").Range("G5").Value = 0
Application.CalculateFull
'Calculate with RP
Sheets("Output").Range("D7").Formula = _
"=SUMPRODUCT(Model!BJ6:BJ365,Model!AD6:AD365,Model!AG6:AG365)"
Sheets("Output").Range("D8").Formula = _
"=SUMPRODUCT(Model!AD6:AD365,Model!AG6:AG365,Model!BK6:BK365)"
Sheets("Output").Range("D10").Formula = _
"=SUMPRODUCT(Model!AD6:AD365,Model!AG6:AG365,Model!BM6:BM365)"
Sheets("Output").Range("D11").Formula = _
"=SUMPRODUCT(Model!AD6:AD365,Model!AG6:AG365,Model!BN6:BN365)"
Sheets("Output").Range("D12").Formula = _
"=SUMPRODUCT(Model!AD6:AD365,Model!AG6:AG365,Model!BO6:BO365)"
Sheets("Output").Range("D13").Formula = _
"=SUMPRODUCT(Model!AD6:AD365,Model!AG6:AG365,Model!BP6:BP365)"
Sheets("Output").Range("D14").Formula = "=SUM(Output!D11:D13)"
Sheets("Output").Range("D17").Formula = _
"=-SUMPRODUCT(Model!AD6:AD365,Model!AG6:AG365,Model!BS6:BS365)"
Sheets("Output").Range("D18").Formula = _
"=-SUMPRODUCT(Model!AD6:AD365,Model!AG6:AG365,Model!BT6:BT365)"
Sheets("Output").Range("D19").Formula = _
"=-SUMPRODUCT(Model!AD6:AD365,Model!AG6:AG365,Model!BU6:BU365)"
Sheets("Output").Range("D20").Formula = _
"=-SUMPRODUCT(Model!AD6:AD365,Model!AG6:AG365,Model!BV6:BV365)"
Sheets("Output").Range("D21").Formula = _
"=-SUMPRODUCT(Model!AD6:AD365,Model!AG6:AG365,Model!BW6:BW365)"
Sheets("Output").Range("D22").Formula = _
"=-SUMPRODUCT(Model!AD6:AD365,Model!AG6:AG365,Model!BX6:BX365)"
Sheets("Output").Range("D23").Formula = _
"=-SUMPRODUCT(Model!AD6:AD365,Model!AG6:AG365,Model!BY6:BY365)"
Sheets("Output").Range("D24").Formula = _
"=-SUMPRODUCT(Model!AD6:AD365,Model!AG6:AG365,Model!BZ6:BZ365)"
Sheets("Output").Range("D25").Formula = _
"=-SUMPRODUCT(Model!AD6:AD365,Model!AG6:AG365,Model!CA6:CA365)"
Sheets("Output").Range("D26").Formula = _
"=-SUMPRODUCT(Model!AD6:AD365,Model!AG6:AG365,Model!CB6:CB365)"
Sheets("Output").Range("D5").Formula = "=Model!BL6-Model!BS6-Model!BT6"
Sheets("Output").Range("D15").Formula = "=SUM(Output!D7:D10,Output!D14)"
Sheets("Output").Range("D27").Formula = "=SUM(Output!D17:D26)"
Sheets("Output").Range("D29").Formula = "=-SUM(Model!AN6:AN365)"
Sheets("Output").Range("D30").Formula = "=-SUM(Model!AP6:AP365)"
Sheets("Output").Range("D31").Formula = "=-Output!C2"
Sheets("Output").Range("D33").Formula = "=SUM(Output!D29:D31,Output!D27,Output!D15)"
'Removing Formulas from output
Sheets("Output").Range("D5:D33").Copy
Sheets("Output").Range("D5:D33").PasteSpecial xlPasteValues
If Sheets("Input Values").Cells(i, 2).Value = "" Then Exit For
Next i
End Sub
'''
As is the case with all heroic efforts undertaken against all odds, your attempt at coding is truly inspiring. I have reduced your code but not quite enough. As you perhaps see, the middle section is repeated twice, once for column C and then for column D, and that should have been achieved by calling the same procedure twice, with just one different argument. Perhaps you will make this your task over the Easter holidays :-) Here's your revised code.
Sub TEST()
Dim WsIn As Worksheet ' Input
Dim WsT As Worksheet ' Taken
Dim WsOut As Worksheet ' Output
Dim WsMod As Worksheet ' Model
Dim Arr As Variant
Dim Rl As Long
Dim R As Long
Dim Rout As Long ' WsOut row
Dim Cmod As Long ' WsMod column
Set WsT = Sheets("Inputs Taken")
Set WsIn = Sheets("Input Values")
Set WsOut = Sheets("Output")
Set WsMod = Sheets("Model")
Application.ScreenUpdating = False
Rl = WsIn.Cells(WsIn.Rows.Count, "B").End(xlUp).Row
For R = 1 To Rl
'Pasting Input Values into Inputs Taken
With WsIn
Arr = .Range(.Cells(R, 1), .Cells(R, 4)).Value
WsT.Cells(5, "D").Resize(UBound(Arr, 2), UBound(Arr)) _
.Value = Application.Transpose(Arr)
Arr = .Range(.Cells(R, 5), .Cells(R, 6)).Value
WsT.Cells(11, "C").Resize(UBound(Arr), UBound(Arr, 2)).Value = Arr
Arr = .Range(.Cells(R, 7), .Cells(R, 8)).Value
WsT.Cells(16, "C").Resize(UBound(Arr), UBound(Arr, 2)).Value = Arr
Arr = .Range(.Cells(R, 9), .Cells(R, 14)).Value
WsT.Cells(9, "G").Resize(UBound(Arr, 2), UBound(Arr)) _
.Value = Application.Transpose(Arr)
End With
'Setting Opening PUP to 100% and refreshing
WsT.Cells(5, "G").Value = 1
'Calculating No RPs
With WsOut
Cmod = 62 ' BJ:BP
For Rout = 7 To 13
If Rout <> 9 Then ' skip result in C9
.Cells(Rout, "C").Value = SumProduct(Cmod, WsMod)
Cmod = Cmod + 1
End If
Next Rout
.Cells(14, 3).Value = Application.Sum(.Range("C11:C13"))
Cmod = 71 ' BS:CB
For Rout = 17 To 26
.Cells(Rout, "C").Value = SumProduct(Cmod, WsMod, True)
Cmod = Cmod + 1
Next Rout
.Cells(5, 3).Value = WsMod.Cells(6, "BL").Value _
- WsMod.Cells(6, "BS").Value _
- WsMod.Cells(6, "BT").Value
.Cells(15, 3).Value = Application.Sum(.Range("C7:C10, C14"))
.Cells(27, 3).Value = Application.Sum(.Range("C17:C26"))
.Cells(29, 3).Value = Application.Sum(WsMod.Range("AN6:AN365")) * -1
.Cells(30, 3).Value = Application.Sum(WsMod.Range("AP6:AP365")) * -1
.Cells(31, 3).Value = WsOut.Cells(2, 3).Value * -1
.Cells(33, 3).Value = Application.Sum(.Range("C29:C31, C15, C27"))
End With
'Changing PUP rate
WsT.Cells(5, "G").Value = 0 ' Excel should recalculate automatically
' Application.CalculateFull
'Calculate with RP
With WsOut
Cmod = 62 ' BJ:BP
For Rout = 7 To 13
If Rout <> 9 Then ' skip result in D9
.Cells(Rout, "D").Value = SumProduct(Cmod, WsOut)
Cmod = Cmod + 1
End If
Next Rout
.Cells(14, 4).Value = Application.Sum(.Range("D11:D13"))
Cmod = 71 ' BS:CB
For Rout = 17 To 26
.Cells(Rout, "D").Value = SumProduct(Cmod, WsOut, True)
Cmod = Cmod + 1
Next Rout
.Cells(5, 4).Value = WsMod.Cells(6, "BL").Value _
- WsMod.Cells(6, "BS").Value _
- WsMod.Cells(6, "BT").Value
.Cells(15, 4).Value = Application.Sum(.Range("D7:D10, D14"))
.Cells(27, 4).Value = Application.Sum(.Range("D17:D26"))
.Cells(29, 4).Value = Application.Sum(WsMod.Range("AN6:AN365")) * -1
.Cells(30, 4).Value = Application.Sum(WsMod.Range("AP6:AP365")) * -1
.Cells(31, 4).Value = WsOut.Cells(2, 3).Value * -1
.Cells(33, 4).Value = Application.Sum(.Range("D29:D31, D15, D27"))
End With
Exit For
Next R
Application.ScreenUpdating = True
End Sub
Private Function SumProduct(ByVal Cmod As Long, _
WsMod As Worksheet, _
Optional ByVal Negative As Boolean) As Double
Dim AuxRng As Range
With WsMod
Set AuxRng = .Range(.Cells(6, Cmod), .Cells(365, Cmod))
SumProduct = Application.SumProduct( _
.Range("AD6:AD365"), _
.Range("AG6:AG365"), _
AuxRng) * IIf(Negative, -1, 1)
End With
End Function
I draw your attention to the end of the main procedure where it says Exit For. This curtails the run to a single loop. I thought, perhaps you never saw the result of your labors. In some instances you are converting columns to rows, and to save my life I wouldn't be able to tell where to put the next line of your data, not to mention the 999,998 you were hoping for. I have reduced that number to the actual number of rows in your worksheet but that isn't the problem. The immediate problem is where to put the next data set - or how that data set could be different from the one the code now generates.
I have a code which builds a table based on the data in another sheet. In this sheet there are three columns - Time, URN and Location. Time is shown as HH:MM:SS, URN is a 4 digit number and Location is a postcode displayed in the usual format.
I have normally used this code with a Date instead of time, but I have been trying to use it with time. I have made a slight adjustment after declaring the date as a variable, adding in the time value part.
I am now getting a
Run-time error '91': Object variable or With block variable not set,
with the following highlighted:
.Cells(FndDt.Row, FndNum.Column) = "P"
I have tried removing this piece of code and adding in a On Error Resume Next but I then get an error on the lines above or below it.
Option Explicit
Sub chrisellis250()
Dim Dt, Urn, i As Long, x As Long, lr As Long, lc As Long: x = 2
Dim colwidth As Long
Dim FndDt As Range, FndNum As Range, Dat As Date, Num As String, Loc As String
Dat = TimeValue("00:00:00")
Application.ScreenUpdating = False
With Sheet2
lr = .Cells(.Rows.Count, 2).End(xlUp).Row
.Range(.Cells(2, 1), .Cells(.Rows.Count, 1)).AdvancedFilter xlFilterCopy, , .Range("E1"), True
With .Range("E1").CurrentRegion: Dt = .Value: End With
Sheet1.Range("A3").Resize(UBound(Dt) - 1) = .Range("E2:E" & UBound(Dt)).Value: .Columns(5).Clear
Sheet1.Range("A3").Resize(UBound(Dt) - 1).Interior.ColorIndex = 15
.Range(.Cells(2, 2), .Cells(.Rows.Count, 2)).AdvancedFilter xlFilterCopy, , .Range("E1"), True
With .Range("E1").CurrentRegion: Urn = .Value: End With
For i = 1 To 2
Sheet1.Cells(2, x).Resize(, UBound(Urn) - 1) = Application.WorksheetFunction.Transpose(.Range("E2:E" & UBound(Urn)).Value)
If i = 1 Then colwidth = 8.3 Else colwidth = 55
Sheet1.Cells(2, x).Resize(, UBound(Urn) - 1).ColumnWidth = colwidth
If x = 2 Then Sheet1.Cells(1, x) = "URN" Else Sheet1.Cells(1, x) = "XXXXX"
Sheet1.Cells(1, x).Resize(, UBound(Urn) - 1).MergeCells = True
Sheet1.Cells(1, x).Resize(, UBound(Urn) - 1).Interior.ColorIndex = 15
x = x + UBound(Urn) - 1
Next i
.Columns(5).Clear
For i = 2 To .Cells(.Rows.Count, 1).End(xlUp).Row
If .Range("B" & i) <> "" Then
Dat = .Range("A" & i): Num = .Range("B" & i): Loc = .Range("C" & i)
With Sheet1
.Range("B3").Resize(lr, UBound(Urn) - 1).Font.Name = "Wingdings 2"
lc = .Cells(2, .Columns.Count).End(xlToLeft).Column
Set FndDt = .Range("A:A").Find(Dat, LookIn:=xlValues, lookat:=xlWhole)
Set FndNum = .Range(.Cells(2, 1), .Cells(2, lc)).Find(Num, LookIn:=xlValues, lookat:=xlWhole)
.Cells(FndDt.Row, FndNum.Column) = "P": .Cells(FndDt.Row, FndNum.Column).Font.Color = vbGreen
On Error Resume Next
If Not .Cells(FndDt.Row, FndNum.Column + UBound(Urn) - 1) Like "*" & Loc & "*" Then
.Cells(FndDt.Row, FndNum.Column + UBound(Urn) - 1) = IIf(.Cells(FndDt.Row, FndNum.Column + UBound(Urn) - 1) = "", Loc, .Cells(FndDt.Row, FndNum.Column + UBound(Urn) - 1) & "," & Loc)
End If
End With
End If
Next i
With Sheet1
With .Range("B3").Resize(UBound(Dt) - 1, UBound(Urn) - 1)
.SpecialCells(xlCellTypeBlanks).Font.Color = vbRed: .SpecialCells(xlCellTypeBlanks).Value = "O":
End With
With .Range("B3").Offset(, UBound(Urn) - 1).Resize(UBound(Urn) - 1, UBound(Urn) - 1)
.SpecialCells(xlCellTypeBlanks).Interior.ColorIndex = 15
End With
AddOutsideBorders .Range("A1").Resize(UBound(Dt) + 1, 1 + ((UBound(Urn) - 1) * 2))
With .Cells
.Columns.AutoFit
.HorizontalAlignment = xlCenter
.RowHeight = 25
End With
End With
End With
Application.ScreenUpdating = True
End Sub
Public Function AddOutsideBorders(rng As Range)
With rng.Borders
.LineStyle = xlContinuous
.Color = vbBlack
.Weight = xlThin
End With
End Function
I have some problems with excel and VBA, in that don't know have much knowledge. I copied text from pdf and it's awful.
I have cells which contain some text.
The problem is that the text from one paragraph is broken down over several cells. At the beginning of each paragraph is a word in bold (e.g. CLR.) which describes the rest of the text. As such, it defines where each paragraph should start. How I can merge these cells into one?
I see
I want
Sub MergeText()
Dim strMerged$, r&, j&, i&
r = 1
Do While True
If Cells(r, 1).Characters(1, 1).Font.Bold Then
strMerged = "": strMerged = Cells(r, 1)
r = r + 1
While (Not Cells(r, 1).Characters(1).Font.Bold) And Len(Cells(r, 1)) > 0
strMerged = strMerged & Cells(r, 1)
r = r + 1
Wend
i = i + 1: Cells(i, 2) = strMerged
Cells(i, 2).Characters(1, InStr(1, strMerged, ".", vbTextCompare)).Font.Bold = True
Else
Exit Do
End If
Loop
End Sub
Modify (if needed) and try:
Option Explicit
Sub test()
Dim LastRow As Long, i As Long, j As Long, Count As Long
Dim str As String
With ThisWorkbook.Worksheets("Sheet1") 'Change sheet name if needed
LastRow = .Cells(.Rows.Count, "A").End(xlUp).Row
For i = LastRow To 2 Step -1
If (UCase(Left(.Range("A" & i), 1)) <> Left(.Range("A" & i), 1)) And UCase(Left(.Range("A" & i - 1), 1)) = Left(.Range("A" & i - 1), 1) Then
Count = 0
For j = 1 To Len(.Range("A" & i - 1))
If .Range("A1").Characters(j, 1).Font.FontStyle = "Bold" Then
Count = Count + 1
Else
Exit For
End If
Next j
str = .Range("A" & i - 1).Value & " " & .Range("A" & i).Value
With .Range("A" & i - 1)
.Value = str
.Font.Bold = False
With .Characters(Start:=1, Length:=Count).Font
.FontStyle = "Bold"
End With
End With
.Rows(i).EntireRow.Delete
ElseIf (UCase(Left(.Range("A" & i), 1)) <> Left(.Range("A" & i), 1)) And UCase(Left(.Range("A" & i - 1), 1)) <> Left(.Range("A" & i - 1), 1) Then
str = .Range("A" & i - 1).Value & " " & .Range("A" & i).Value
With .Range("A" & i - 1)
.Value = str
.Font.Bold = False
End With
.Rows(i).EntireRow.Delete
End If
Next i
End With
End Sub
I have this code where the content is: filling formulas in cells that have no formula, then copy/paste values of entire row of those cells. I used 2 times "For Next", first for filling formula and the second to paste values
Sub CDPSKoCongThuc()
Application.ScreenUpdating = False
Application.EnableEvents = False
Application.Calculation = xlCalculationManual
Dim RowNKC As Integer
RowNKC = Range("CuoiNKC").Row - 1
Dim RowCDPS As Integer
RowCDPS = Range("CuoiCDPS").Row - 1
Dim i As Integer
Dim x As Integer
For i = 9 To RowCDPS
If Cells(i, 9).HasFormula = False Then
Cells(i, 7).FormulaR1C1 = "=SUMIF(NKC!R9C12:R" & RowNKC & "C12,CDPS!RC[-6],NKC!R9C15:R" & RowNKC & "C15)"
Cells(i, 8).FormulaR1C1 = "=SUMIF(NKC!R9C13:R" & RowNKC & "C13,CDPS!RC[-7],NKC!R9C15:R" & RowNKC & "C15)"
Cells(i, 9).FormulaR1C1 = "=ROUND(SUMIF(NKC!R9C12:R" & RowNKC & "C12,CDPS!RC[-8],NKC!R9C14:R" & RowNKC & "C14),0)"
Cells(i, 10).FormulaR1C1 = "=ROUND(SUMIF(NKC!R9C13:R" & RowNKC & "C13,CDPS!RC[-9],NKC!R9C14:R" & RowNKC & "C14),0)"
Cells(i, 11).FormulaR1C1 = "=MAX(RC[-8]+RC[-4]-RC[-3]-RC[-7],0)"
Cells(i, 12).FormulaR1C1 = "=MAX(RC[-4]+RC[-8]-RC[-5]-RC[-9],0)"
Cells(i, 13).FormulaR1C1 = "=ROUND(MAX(RC[-8]+RC[-4]-RC[-7]-RC[-3],0),0)"
Cells(i, 14).FormulaR1C1 = "=ROUND(MAX(RC[-4]+RC[-8]-RC[-5]-RC[-9],0),0)"
End If
Next i
'Paste Values Formula
For x = 9 To RowCDPS
If Cells(x, 9).Font.Bold = False And Len(Cells(x, 1).Value) > 3 Then
Rows(x).EntireRow.Copy
Rows(x).PasteSpecial xlPasteValues
End If
Next x
Application.Calculation = xlCalculationAutomatic
Application.EnableEvents = True
Application.ScreenUpdating = True
End Sub
I'm not going to write them all but you could use VBA to do the caculations and put the value in the cell so you don't have to paste the values or work with excel calculations at all.
For example...
Cells(i, 11).FormulaR1C1 = "=MAX(RC[-8]+RC[-4]-RC[-3]-RC[-7],0)"
would be
Cells(i, 11) = Application.Max(Cells(i, 3) + Cells(i, 7) - Cells(i,8) -Cells(i, 4), 0)
You should also make a variable for each sheet and use them to reference the cells so that its clearer to read
Dim shCDPS as Worksheet
Dim shNKC as worksheet
Set shCDPS = Sheets("CDPS")
Set shNKC = Sheets("NKC")
Then this formula
Cells(i, 7).FormulaR1C1 = "=SUMIF(NKC!R9C12:R" & RowNKC & "C12,CDPS!RC[-6],NKC!R9C15:R" & RowNKC & "C15)"
would become
shCDPS.Cells(i, 7) = Application.SumIf(shNKC.Range("L9:L" & RowNKC) , shCDPS.Range("A" & i), shNKC.Range("O15:O" & RowNKC))
i have several workbooks which get copy from one master workbook. what i want to do is when i enter data into the master workbook, i want to copy it into another workbook based on product type which i get fromn Combobox1.Value. to be more clear, which workbooks i want to copy the data depends on the ComboBox1.value. ie if the ComboBox1.value equals to "Penofix" then i want to copy the data into the workbook "Penofix.xlsm". i have finish coding on master input on how to enter data into particular row based on some condition but facing problem to copy the data into another workbooks.
Private Sub CmdEnter_Click()
Dim CountRow As Long
Dim i As Long
Dim prod as string
Dim j As Long
Dim Ws As Worksheet
Dim Count1 as Long
'CountRow is number of row in master workbook
CountRow = Worksheets("Input").Range("B" & Rows.Count).End(xlUp).Row
'assign variable prod with combobox1 value
prod = ComboBox1.Value
'i=32 because my row start at 32
For i = 32 To countRow + 31
While ComboBox1.Value = Worksheets("Input").Cells(i, 2).Value
Rows(i).Select
Selection.Insert shift = xlDown
With Worksheets("Input")
'insert data into master workbook
.Range("B" & i) = ComboBox1.Text
.Range("C" & i) = TextBox1.Text
.Range("D" & i) = TextBox2.Text
.Range("E" & i) = TextBox3.Text
.Range("F" & i) = TextBox4.Text
.Range("G" & i) = TextBox5.Text
.Range("H" & i) = ComboBox2.Text
.Range("I" & i) = TextBox6.Text
.Range("J" & i) = TextBox7.Text
.Range("K" & i) = TextBox8.Text
End With
'activate other workbook to copy data,if prod = Penofix,the workbook will be "Penofix.xlsm"
workbooks(prod & ".xlsm").Activate
'count the number of row in workbooks(prod & ".xlsm").
' i specified cell (31,3) to calculate the number of row used
Count1 = Workbooks(prod & ".xlsm").Worksheets("Sheet1").Cells(31,3).Value
Count1 = Count1 + 31
'copy data into workbooks(prod & ".xlsm")
'THIS IS THE LINE WHICH ERROR
Workbooks(prod & ".xlsm").Worksheets("Input").Range(Cells(Count1, 2), Cells(Count1 , 11)).Value = Workbooks("Master.xlsm").Worksheets("Input").Range(Cells(i, 2), Cells(i, 11)).Value
If MsgBox("One record written to Input. Do you want to continue entering data?", vbYesNo)= vbYes Then
ComboBox1.Text = ""
TextBox1.Text = ""
TextBox2.Text = ""
TextBox3.Text = ""
TextBox4.Text = ""
TextBox5.Text = ""
ComboBox2.Text = ""
TextBox6.Text = ""
TextBox7.Text = ""
TextBox8.Text = ""
Else
Unload Me
End If
Exit Sub
Wend
Next
End Sub
i've try to replace
Workbooks(prod & ".xlsm").Worksheets("Input").Range(Cells(Count1, 2), Cells(Count1 , 11)).Value = Workbooks("Master.xlsm").Worksheets("Input").Range(Cells(i, 2), Cells(i, 11)).Value
with this
Workbooks(prod & ".xlsm").Worksheets("Input").Cells(Count1, 2).Value = Workbooks("Master.xlsm").Worksheets("Input").Cells(i, 2).Value
and yeah its work but it just for one singe cell only. so i think the error is on the syntax :
Range(Cells(Count1,2), Cells(Count1,11))
but i dont know how to make it to copy the entire row
Workbooks("Master.xlsm").Worksheets("Input").Range(cells(i,B).cells(i,K)).Value = _
Workbooks(prod & ".xlsm").).Worksheets("Sheet1").Range(Cells(CountRow, B). Cells(CountRow, K)).Value
This code will update the master workbook, I doubt you want to this. Also there is a syntax error with .). and then some.
I think this is what you need:
Dim sht1 As Worksheet, sht2 As Worksheet
Set sht1 = Workbooks(prod & ".xlsm").Worksheets("Sheet1")
Set sht2 = Workbooks("Master.xlsm").Worksheets("Input")
sht1.Range(sht1.Cells(CountRow, 2), sht1.Cells(CountRow, 11)).Value = _
sht2.Range(sht2.Cells(i, 2), sht2.Cells(i, 11)).Value
Imroved code: Using resize(<row>, <column>)
Workbooks(prod & ".xlsm").Worksheets("Sheet1").Cells(CountRow, 2).resize(, 11).Value = _
Workbooks("Master.xlsm").Worksheets("Input").Cells(i, 2).resize(, 11).Value
For some added info, the Cells(<Row>, <Column>) will only take integers in for either <Row> and <Column>. Hence the column B is represented as 2.