Excel macro - please xplain this code - excel

If data_version < 2.11 Then
Range("A10").Select
Selection.Copy
Range("A17").Select
ActiveSheet.Paste
ActiveCell.FormulaR1C1 = "Resume Path Information"
Range("A12:B12").Select
Selection.Copy
Range("A18").Select
ActiveSheet.Paste
ActiveCell.FormulaR1C1 = "Server Path:"
Range("B18") = ""
Dim formula As String
Dim cu_row As Integer
cu_row = 5
Do
'Fix cell to add resume server path
If Len(Trim(Worksheets("People").Cells(cu_row, ResumeFile).Value)) > 0 Then
formula = "=Process!B$18 & """ & Right(Worksheets("People").Cells(cu_row, ResumeFile).Value, Len(Worksheets("People").Cells(cu_row, ResumeFile).Value) - 2) & """"
Worksheets("People").Cells(cu_row, ResumeFile).formula = formula
'Else be sure it is blank
Else
Worksheets("People").Cells(cu_row, ResumeFile).ClearContents
End If
cu_row = cu_row + 1
Loop Until Worksheets("People").Cells(cu_row, 1) = ""
Range("A1").Select
End If

Well, strictly it doesn't do anything because you've got a trailing End If that doesn't match any earlier If. But ...
It looks at successive rows of the worksheet called "People", starting in row 5 and stopping when it finds a row with nothing in the first column. For each row, it looks in the column whose number is in variable ResumeFile. If there's nothing but whitespace there, it clears it completely. Otherwise, it throws away the first two characters, and interpolates the rest into the magic string Process!B$18 & "VALUE_GOES_HERE", which it stores (as a formula) into the same cell. Here, & performs string concatenation.
Finally, it selects cell A1 for some reason.
So, if that column of the worksheet contained "Fred", "Jim" and "Sheila" before, and if cell B18 of the "Process" worksheet contains "Boo!", then you'll get "Boo!ed", "Boo!m" and "Boo!eila".

Related

Calculate time difference between 2 dates and give outputs in total hours is generating output as #### which is wrong

I am very new to Excel, VBA, Macro. My macro was working fine because I gave a simple formula, for example, D2(column name)-C2(column name) = Total time in HH:MM format new column. But I notice for some output is just #### not sure what is wrong. 1).Column)).Formula = _
"=" & cl.Offset(1, 0).Address(0, 0) & "-" & .Cells(2, col1).Address(0, 0)
cl.Offset(, 1).EntireColumn.NumberFormat = "[hh]:mm"
The issue occurs because your date in J is earier than in I and therefore the result is negative. You can use the ABS() function to get the absolute difference as positive value.
Therefore adjust your formula as below:
.Formula = "=ABS(" & cl.Offset(1, 0).Address(0, 0) & "-" & .Cells(2, col1).Address(0, 0) & ")"
You have an incorrect formula in this line:
.Range(cl.Offset(1, 1), .Cells(lastR, cl.Offset(1, 1).Column)).Formula = _
"=" & cl.Offset(1, 0).Address(0, 0) & "-" & .Cells(**2**, col1).Address(0, 0)
Why .Cells(2, col1)? This is always giving you row2 of column 1.
Also, after this line:
If cl.Value = "Full Out Gate at Inland or Interim Point (Destination)_recvd"
Then
Add:
If cl.Offset(0,1).Value = "Response Time" Then Exit For
This will keep you from inserting a new column every time you run the macro.
Try using clear variable names and consistent method for referring to rows and columns.
actCol = col1
recvdCol = cl.Column
responseCol = cl.offset(0,1).Column
.Range(lastR, responseCol).Formula = _
"= Abs(" & .Cells(lastR, recvdCol) & "-" & .Cells(lastR, actCol).Address(0, 0) & ")"
I would use a simpler approach. Highlight the entire table, and click "Format as Table", and be sure to check off "My table has headers." This will give you a named range (default name is Table1, but you can change it). Then, in the Response Time column, simply enter your formula on the first row of the table, but use your mouse to select the cells instead of typing in a cell name like "I2". You will find that the resulting formula includes something like =[#actl]-[#recvd], except that the actl and recvd will be replaced by your actual column names. And, the formula will apply to every row of the table. If you add a new row, the formula will automatically appear in that row. No code needed.
If you have a reason to use code instead of a Table (named ranges), then I would recommend (1) this code be placed directly in the "Main" worksheet module and (2) use use the "Worksheet_Changed" procedure. Microsoft Excel VBA Reference. In this case, any time the
Private Sub Worksheet_Change(ByVal Target As Range)
'Note, Target is the Range of the cell(s) that just changed.
If Intersect(Target, Range("A1:A10")) Is Nothing Or Target.Cells.Count > 1 Then Exit Sub
If ActiveSheet.Cells(1, Target.Column) = "Full Out Gate at Inland or Interim Point (Destination)_actual" Then
' Cell in actual column was modified. Let's set the formula in the Response Time column:
On Error Goto EH
Application.EnableEvents = False
' Add your code here. You'll need to modify it somewhat to accommodate this methodology.
Application.EnableEvents = True
End If
EH:
Application.EnableEvents = True
Err.Raise ' expand this to whatever error you wish to raise
End Sub
Err.Raise help

How to apply Autofill function for a dynamic range in VBA?

I'm in the process of creating a macro that should return 3 results:
adds 3 columns to the right after column C
implements characters per line counting formula which returns number of characters per line from column C in newely created column D
implements total characters count formula in column E (counts sum of characters count returned from column D)
Future Result: As current code gives formula results in cells D2 and E2 I want it to run Autofill function so that no matter the number of rows in the spreadsheet it gives results for all of them (just like double-clicking in the bottom right corner of a cell with formula).
This is how code looks like now:
Sub AutoFillTest
Columns("D:F").Insert Shift:=xlToRight, _
CopyOrigin:=xlFormatFromLeftOrAbove '
Range("D2").Select
ActiveCell.Formula = "=Len(Left(C2, IfError(Find(Chr(10), C2, 1), 99))) & IfError("" ,"" &
Len(Mid(C2, Find(Chr(10), A2, 1) + 1, 99)), """")"
#Here goes Autofill part which I'm looking for#
Range("D2,E2").Select
Range("E2").Activate
ActiveCell.Formula = "Len("C2")"
#Here goes Autofill part which I'm looking for#
End Sub
You can use autofill like this:
Set SourceRange = Worksheets("Sheet1").Range("A1:A2")
Set fillRange = Worksheets("Sheet1").Range("A1:A20")
SourceRange.AutoFill Destination:=fillRange
Then what you would need to is find the last row for the columns you need.
UPDATE
With your need for dynamic last row, something simple like this might work:
Add a function:
Public Function GetLastRow(str_TabName As String, lng_Column As Long, lng_Row As Long) As Long
 
Sheets(str_TabName).Select
'Range(str_Column & lng_Row).Select
Cells(lng_Row, lng_Column).Select
Selection.End(xlUp).Select
 
GetLastRow = ActiveCell.Row
 
End Function
Then amend the code like this:
Sub AutoFillTest
'' Get last row
Dim lng_LastRow as Long
'' Pass argument as required sheet, the column as a number, and the last row to start from
lng_LastRow = GetLastRow("Sheet1", 4, 100000)
Columns("D:F").Insert Shift:=xlToRight, _
CopyOrigin:=xlFormatFromLeftOrAbove '
Range("D2").Select
ActiveCell.Formula = "=Len(Left(C2, IfError(Find(Chr(10), C2, 1), 99))) & IfError("" ,"" &
Len(Mid(C2, Find(Chr(10), A2, 1) + 1, 99)), """")"
#Here goes Autofill part which I'm looking for#
Set SourceRange = Worksheets("Sheet1").Range("D2:D2")
Set fillRange = Worksheets("Sheet1").Range("D3:D" & lng_LastRow )
SourceRange.AutoFill Destination:=fillRange
Range("D2,E2").Select
Range("E2").Activate
ActiveCell.Formula = "Len("C2")"
#Here goes Autofill part which I'm looking for#
'' apply from the example above and see if it works for you
End Sub
Note I haven't checked your formulae

Simplify With For Loop VBA

So I am not very good with VBA and how it exactly how everything works but I am sure what I am doing can be condensed I am just not exactly sure how.
Here is the code I am working with:
Sub This()
If ComboBox5.Value = "Test" Then
If Range("R20").Value > 1 Then
Range("D37").Select
ActiveCell.FormulaR1C1 = "=ABS(R[-17]C*(1-R[-17]C[14]))+R[-17]C"
Range("E37").Select
ActiveCell.FormulaR1C1 = "=ABS(R[-17]C*(1-R[-17]C[13]))+R[-17]C"
Range("F37").Select
ActiveCell.FormulaR1C1 = "=ABS(R[-17]C*(1-R[-17]C[12]))+R[-17]C"
Range("G37").Select
ActiveCell.FormulaR1C1 = "=ABS(R[-17]C*(1-R[-17]C[11]))+R[-17]C"
Range("H37").Select
ActiveCell.FormulaR1C1 = "=ABS(R[-17]C*(1-R[-17]C[10]))+R[-17]C"
Range("I37").Select
ActiveCell.FormulaR1C1 = "=ABS(R[-17]C*(1-R[-17]C[9]))+R[-17]C"
Range("J37").Select
ActiveCell.FormulaR1C1 = "=ABS(R[-17]C*(1-R[-17]C[8]))+R[-17]C"
Range("K37").Select
ActiveCell.FormulaR1C1 = "=ABS(R[-17]C*(1-R[-17]C[7]))+R[-17]C"
Range("L37").Select
ActiveCell.FormulaR1C1 = "=ABS(R[-17]C*(1-R[-17]C[6]))+R[-17]C"
Range("M37").Select
ActiveCell.FormulaR1C1 = "=ABS(R[-17]C*(1-R[-17]C[5]))+R[-17]C"
Range("N37").Select
ActiveCell.FormulaR1C1 = "=ABS(R[-17]C*(1-R[-17]C[4]))+R[-17]C"
Range("O37").Select
ActiveCell.FormulaR1C1 = "=ABS(R[-17]C*(1-R[-17]C[3]))+R[-17]C"
Range("P37").Select
ActiveCell.FormulaR1C1 = "=ABS(R[-17]C*(1-R[-17]C[2]))+R[-17]C"
End If
End If
I recorded this Macro, and it works fine, but if I want to do this as well for Range(R23) it is kind of pain. So how would I go about condensing this code. I am sure the formula is not very clear so I want the new updated value of D37 to be:
D37 = (|(R20 - 1)|*D20) + D20
Possibly something like this, though I try not to use R1C1 notation because it is so difficult to read, so I'm not sure this is exactly what you're looking for.
Sub This()
If ComboBox5.Value = "Test" Then
Dim rng as Range, cl as Range, i as Long
If Range("R20").Value > 1 Then
Set rng = Range("D37:P37")
rng.FormulaR1C1 = "=ABS(R[-17]C*(1-R[-17]C18))+R[-17]C"
End If
If Range("R23").Value > 1 Then
'## NOTE: You may need to modify if the Column changes
rng.FormulaR1C1 = "=ABS(R[-17]C*(1-R[-17]C18))+R[-17]C"
Next
End Sub
Explanation of why I use C18 in the formula:
You're original code is using R1C1 notation with relative reference. As you traverse your range of cells (moving from left-to-right) your formula is decrementing the column position, e.g.:
Range("D37").FormulaR1C1 = "=ABS(R[-17]C*(1-R[-17]C[14]))+R[-17]C" '## C[14]
Range("E37").FormulaR1C1 = "=ABS(R[-17]C*(1-R[-17]C[13]))+R[-17]C" '## C[13]
So this means that even though you're changing the offset value in the brackets, you're still refering to the same column, which can be identified in absolute terms using R1C1 notation C18
It appears as though you are placing nearly the same formula in every column in the same row. So, as your title suggests, a for-loop might be appropriate. For instance,
For j = 4 to 100 'or whatever the last column number you want to be
cells(37, j).FormulaR1C1 = "=ABS(R[-17]C*(1-R[-17]C[" & 18 - j & "]))+R[-17]C"
next j

Variable for Excel Columns. Column Assigned to Variable

I have a macro that inserts 2 columns on my current sheet and pastes information from another sheet.
I want to create 2 variables that are assigned to each column that would change the next time I run the macro to paste the information in the next two columns.
Columns("BO:BO").Select
Selection.Insert Shift:=xlToRight
Range("BO2").Select
ActiveCell.FormulaR1C1 = "Feb weekly-wk 2"
Range("BO19").Select
ActiveCell.FormulaR1C1 = _
"=VLOOKUP(Comparison!RC2,'Jan16 wk4'!R3C15:R34C24,9,FALSE)"
Range("BO19").Select
Selection.AutoFill Destination:=Range("BO19:BO47"), Type:=xlFillDefault
Range("BO19:BO47").Select
Columns("BP:BP").Select
Selection.Insert Shift:=xlToRight
Range("BP2").Select
Selection.Style = "20% - Accent6"
Range("BP2").Select
ActiveCell.FormulaR1C1 = "Diff"
Range("BP19").Select
ActiveCell.FormulaR1C1 = "=RC[-2]-RC[-1]"
My idea is to set up a variable that I would replace my current "BO" and "BP" code with.
Dim X as String, Y as String
X = "BO"
y = "BP"
When I run the macro it would change the variable for this example "BO" to "BQ" and "BP" to "BR". Next time I run the macro would change the "BQ" to "BS" and "BR" to "BT".
I just cleaned your code a little:
Dim ColBO As Integer
Dim ColBP As Integer
Dim StrBO As String
Dim StrBP As String
StrBO = "BO"
StrBP = "BP"
ColBO = ActiveWorkbook.Range(StrBO & 1).Column 'instead of StrBO you could directly write ("BO" & 1)
ColBP = ActiveWorkbook.Range(StrBP & 1).Column 'Then you wouldnt need these two variables
Columns(ColBO).Insert Shift:=xlToRight
'Columns(ColBO).Select ' Trying to avoid selection but not sure if this works here...
'Selection.Insert Shift:=xlToRight
Range(1, ColBO).FormulaR1C1 = "Feb weekly-wk 2"
Range(19, ColBO).FormulaR1C1 = "=VLOOKUP(Comparison!RC2,'Jan16 wk4'!R3C15:R34C24,9,FALSE)"
Range(19, ColBO).AutoFill Destination:=Range("BO19:BO47"), Type:=xlFillDefault
Columns(ColBP).Insert Shift:=xlToRight 'Same here as above
Range(2, ColBP).Style = "20% - Accent6"
Range(2, ColBP).FormulaR1C1 = "Diff"
Range(19, ColBP).FormulaR1C1 = "=RC[-2]-RC[-1]"
For the future: If you can, try to avoid .Select/Selection/.Activate if possible. The code can mostly run without such commands and without activating a cell. ;)
If you are not actually writing BO/BP to the range you are transforming I would go with two ints, stored in a hidden sheet. Read/write each time you run the macro.
This is, in my opinion, the easier solution, other places to go would be global variables or storing it to a file.
If you want to use numeric variables you can change approach and use Cells instead of Range:
'You can use the rows below to know the column number
Range("BO1").Activate
ActiveCell.Value = ActiveCell.Column 'This way you get the column number into the cell
ColNum = ActiveCell.Column 'This way you get the column number into the variable
'So now you know that BO column number is 67 and you can use
Cells(1, 67) = "OK"
'Or, using variables:
RowNum = 1
ColNum = 67
Cells(RowNum, ColNum) = "You Got It!"
This makes you able to loop columns simply using a for ... next
If you need to loop from BO to BR you can use
For ColNum = 67 To 70
Cells(1, ColNum) = "OK"
Next ColNum
Hope it helps.

Clear column and row

Need vba code to Clear column from A to J and row from 21 to 200. Below code is clearing the column till end, need to delete till column J
Function ClearSummary()
Const TestName_Col = "B"
Const FirstRow_Num = "21"
MaxRowNumber = Range(TestName_Col & "200").End(xlUp).Row
If (MaxRowNumber > FirstRow_Num) Then
'select all rows in range & clear
CellReference = FirstRow_Num & ":" & MaxRowNumber
Rows(CellReference).Select
Selection.ClearContents
Selection.Hyperlinks.Delete
Selection.Font.Underline = xlUnderlineStyleNone
Selection.Font.ColorIndex = 0
End If
End Function
This should do the trick!
Range("A21:J200").Clear
Thumbs up to Chris for teaching me a new method!
A spin off of t.thielemans answer for those who do not want to lose things such as formatting or data validation
Range("A21:J200").ClearContents
This will ensure that you keep everything except the current value of the cells selected.

Resources