Visual Basic Excel Macro - excel

I want to have a little Macro in excel. The Macro should take a double number from A1 and multiply this number by 5 and return it back into A1 but i always get error messages etc.
My code up to now:
Function multiply()
Dim a As Long
For a = 1 To 65563
cell(a,3) = cell(a,3).Value * 5
next a
End Function
I have not worked with VBA before.

That does what you ask, but it's a sub as you can't edit worksheet values using a function
Public Sub multiply()
On Error GoTo err
Dim val As Long
val = ActiveSheet.Cells(1, 1).Value
ActiveSheet.Cells(1, 1).Value = val * 5
Exit Sub
err:
End Sub

you dont need to use function just use these subs:
bellow you can multiplay all of *column A * values:
Sub example()
For a = 1 To 65563
Cells(a, 1).Value = Cells(a, 1).Value * 5
Next a
End Sub
considering 65563 CELLS isn't a good idea, i suggest you to use the sub bellow to count rows and reduce memory usage.
Sub example2()
Dim countrows As Long
countrows = Range("A" & Rows.Count).End(xlUp).Row
For a = 1 To countrows
Cells(a, 1).Value = Cells(a, 1).Value * 5
Next a
End Sub

You don't actually need a macro for this - although if you do want to use VBA you can avoid time consuming loops altogether
1 Manual Method using Paste Special - Multiply
from walkenbach
To increase a range of values by 5 times:
Enter 5 into any blank cell.
Select the cell and choose Edit, Copy.
Select the range of values (Column A in your example) and choose Edit, Paste Special.
Choose the Multiply option and click OK.
Delete the cell that contains the 5
2 Code using Paste Special - Multiply
Using Zack Barresse's code from vbax - with minor amendments
This code updates the selected range with a user-entered multiplier
Sub psMultiply()
' http://www.vbaexpress.com/kb/getarticle.php?kb_id=47
Dim y As Long 'The multiplier value, user-defined
Dim x As Range 'Just a blank cell for variable
Dim z As Range 'Selection to work with
Set z = Selection
y = Application.InputBox("Enter selection multiplier:", _
Title:="Selection multiplier", Default:=10, Type:=1)
Set x = Cells(Rows.Count, "A").End(xlUp).Offset(1)
If y = 0 Then Exit Sub 'Cancel button will = 0, hence cancel
If x <> "" Then
Exit Sub
Else: x.Value = y
x.Copy
z.PasteSpecial Paste:=xlPasteAll, Operation:=xlMultiply
Application.CutCopyMode = False 'Kill copy mode
End If
x.ClearContents 'Back to normal
End Sub

Why not make it a little more generic by only multiplying the numbers you select:
Sub MultiplyByFive()
Dim cl As Range
For Each cl In Selection
cl = cl * 5
Next cl
End Sub
This way you avoid the 65536 hard coding.

Related

I want to create an Excel macro file to help me with Speeding my basic calculations and practice with it

I want to create this macro sheet so that for any active cell, if I add the given row and column values(as in the image link attached) and enter correct summation it retains white color, or else turns green.
https://imgur.com/chJUmho
I am actually a NOOB at excel vba, so the code may have some wrong format. It's also giving 'error 5' in structure of variable 'r' input, so I'm stuck.
Sub Add_Nos()
Dim r As Integer
Dim c As Integer
Dim active As Integer
r = Worksheets("Sheet1").Cells("A" & (ActiveCell.Row)).Value
c = Worksheets("Sheet1").Cells((ActiveCell.Column) & 1).Value
active = Range(ActiveCell).Value
If active = r + c Then
Range(ActiveCell).Interior.ColorIndex = 0
Else
Range(ActiveCell).Interior.ColorIndex = 4
End If
End Sub
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
If Selection.Count = 1 Then
Call Add_Nos
End If
End Sub
Run-time Error 5:
You've mixed up Range and Cells notation.
Range is appropriate for an A1-style reference: .Range("A" & ActiveCell.Row).
Cells uses a row and column index: .Cells(ActiveCell.Row, 1). Or you can use the column letter: .Cells(ActiveCell.Row, "A").
Note that you have the same issue on the next line, which should be:
c = Worksheets("Sheet1").Cells(1, ActiveCell.Column).Value
Other Points:
ActiveCell is a Range object - don't enclose it inside Range. So:
active = ActiveCell.Value
ActiveCell.Interior.ColorIndex = 0
ActiveCell.Interior.ColorIndex = 4
Call can be omitted.

Put timestamp when a checkbox is ticked or unticked

I have a worksheet with 3 rows and 7 columns (A1:G3).
A and B columns have 6 checkboxes (A1:B3). Boxes in columns A & B are linked to columns C & D respectively. Cells in columns E & F are just replicating columns C & D respectively (live E1 cell is =C1 and F3 cell is =D3).
I want to put a timestamp in cell G for each row when a checkbox is ticked or unticked by using Worksheet_Calculate event in VBA for that sheet.
My code works when used for just 1 row.
Private Sub Worksheet_calculate()
Dim cbX1 As Range
Set cbX1 = Range("A1:F1")
If Not Intersect(cbX1, Range("A1:F1")) Is Nothing Then
Range("G1").Value = Now()
End If
End Sub
I want to combine the code for 3 rows.
Here are 2 variations:
1st one:
Private Sub Worksheet_calculate()
Dim cbX1 As Range
Dim cbX2 As Range
Dim cbX3 As Range
Set cbX1 = Range("A1:F1")
Set cbX2 = Range("A2:F2")
Set cbX3 = Range("A3:F2")
If Not Intersect(cbX1, Range("A1:F1")) Is Nothing Then
Range("G1").Value = Now()
ElseIf Intersect(cbX2, Range("A2:F2")) Is Nothing Then
Range("G2").Value = Now()
ElseIf Intersect(cbX3, Range("A3:F3")) Is Nothing Then
Range("G3").Value = Now()
End If
End Sub
When I combine them with ElseIf like in the code above, a timestamp gets put in only G1, no matter if I tick B1 or C2.
2nd one:
Private Sub Worksheet_calculate()
Dim cbX1 As Range
Dim cbX2 As Range
Dim cbX3 As Range
Set cbX1 = Range("A1:F1")
If Not Intersect(cbX1, Range("A1:F1")) Is Nothing Then
Range("G1").Value = Now()
End If
Set cbX2 = Range("A2:F2")
If Not Intersect(cbX2, Range("A2:F2")) Is Nothing Then
Range("G2").Value = Now()
End If
Set cbX3 = Range("A3:F2")
If Not Intersect(cbX3, Range("A3:F3")) Is Nothing Then
Range("G3").Value = Now()
End If
End Sub
When I combine them by ending each one with End If and start a new If, timestamp gets put in all of the G1, G2 and G3 cells, even if I tick just one of the boxes.
You seem to be confusing Worksheet_Calculate with Worksheet_Change and using Intersect as if one of the arguments was Target (which Worksheet_Calculate does not have).
Intersect(cbX1, Range("A1:F1")) is always not nothing because you are comparing six apples to the same six apples. You might as well ask 'Is 1,2,3,4,5,6 the same as 1,2,3,4,5,6?'.
You need a method of recording the values of your range of formulas from one calculation cycle to the next. Some use a public variable declared outside the Worksheet_calculate sub procedure; personally I prefer a Static variant array declared within the Worksheet_calculate sub.
The problem with these is initial values but this can be accomplished since workbooks undergo a calculation cycle when opened. However, it is not going to register Now in column G the first time you run through a calculation cycle; you already have the workbook open when you paste in the code and it needs one calculation cycle to 'seed' the array containing the previous calculation cycle's values.
Option Explicit
Private Sub Worksheet_Calculate()
Static vals As Variant
If IsEmpty(vals) Then 'could also be IsArray(vals)
vals = Range(Cells(1, "A"), Cells(3, "F")).Value2
Else
Dim i As Long, j As Long
With Range(Cells(1, "A"), Cells(3, "F"))
For i = LBound(vals, 1) To UBound(vals, 1)
For j = LBound(vals, 2) To UBound(vals, 2)
If .Cells(i, j).Value2 <> vals(i, j) Then
Application.EnableEvents = False
.Cells(i, "G") = Now
Application.EnableEvents = True
vals(i, j) = .Cells(i, j).Value2
End If
Next j
Next i
End With
End If
End Sub

Getting a 'Range' of object '_Global' failed (Run-Time Error 1004) when running an Excel macro

These are the steps of the macro:
This macro is supposed to select A1 and enter it as a blank space to reiterate the random variables in the excel sheet.
Select the output from the random inputs and copy it.
Select a place to output the copied date, in this case "Row 200, Column(n)" and then paste each set of results in a new column as n iterates.
I'm getting a 1004 range error, and I'm not sure how to fix it. What am I missing?
Sub newloop()
'
' newloop Macro
'
Dim n As Integer
n = 1
Do Until n = 5
Range("A1").Select
ActiveCell.FormulaR1C1 = ""
Range("AA25,AA47,AA69,AA91,AA113,AA135,AA157,AA179,AA201,AA223,AA245,AA267,AA289").Select
Selection.Copy
Range("R200C" & n).Select
ActiveSheet.Paste
n = n + 1
Loop
End Sub
other than fixing the range syntax error, you can avoid changing A1 cell at every iteration since sheet calculation would be triggered at every copy/paste operation:
Sub newloop()
Dim n As Integer
Range("A1").Value = "" ' trigger first sheet calculation
With Range("AA25,AA47,AA69,AA91,AA113,AA135,AA157,AA179,AA201,AA223,AA245,AA267,AA289") ' reference input range
For n = 1 To 5
.Copy Cells(200, n) ' copy referenced range and paste it to current nth column from row 200 downwards
Next
End With
End Sub
even better, have sheet calculate directly by means of Calculate method:
Sub newloop()
Dim n As Integer
ActiveSheet.Calculate
With Range("AA25,AA47,AA69,AA91,AA113,AA135,AA157,AA179,AA201,AA223,AA245,AA267,AA289")
For n = 1 To 5
.Copy Cells(200, n)
Next
End With
End Sub
The R1C1 notation is not supported in Range() as a parameter. Thus, change:
Range("R200C" & n).Select
with:
Cells(200,n).Select
and the error would dissappear.
The Solution
It is a good habit to use constants at the beginning of the code, so you can
quickly change something and observe the behavior of the code e.g. you want to paste the data into the 500th row or you want 10 times the results instead of 5, or you want to add another cell range...
Sub NewLoop()
Const cStrRange As String = "AA25,AA47,AA69,AA91,AA113,AA135,AA157," & _
"AA179,AA201,AA223,AA245,AA267,AA289"
Const cLngRow As Long = 200
Const cN As Integer = 5
Dim oRng As Range
Dim n As Integer
Set oRng = Range(cStrRange)
For n = 1 To cN
Range("A1").FormulaR1C1 = ""
oRng.Copy Cells(cLngRow, n)
Next
End Sub
Missing the Point
When you don't read the OP's wishes carefully:
Exemplary, Short and Shorter
Option Explicit
Sub NewLoopExemplary()
Const cStrA As String = "A1"
Const cStrRange As String = "AA25,AA47,AA69,AA91,AA113,AA135,AA157," & _
"AA179,AA201,AA223,AA245,AA267,AA289"
Const cLngRow As Long = 200
Const cN As Integer = 5
Dim oRng As Range
Range(cStrA).FormulaR1C1 = ""
Set oRng = Range(cStrRange)
oRng.Copy Cells(cLngRow, 1).Resize(1, cN)
End Sub
Sub NewLoopShort()
Const n As Integer = 5
Range("A1").FormulaR1C1 = ""
Range("AA25,AA47,AA69,AA91,AA113,AA135,AA157,AA179,AA201,AA223,AA245,AA267," _
& "AA289").Copy Cells(200, 1).Resize(1, n)
End Sub
Sub NewLoopShorter()
Range("A1").FormulaR1C1 = ""
Range("AA25,AA47,AA69,AA91,AA113,AA135,AA157,AA179,AA201,AA223,AA245,AA267," _
& "AA289").Copy Cells(200, 1).Resize(1, 5)
End Sub

Excel Loop Column A action column B

I'm currently looking for a code to improve my Dashboard. Actually, I need to know how to use a loop in a column X who will affect a column Y (cell on the same line).
To give you an example:
Column A: I have all Production Order (no empty cell)
Column B: Cost of goods Sold (Sometimes blank but doesn't matter)
I actually pull information from SAP so my Column B is not in "Currency".
The action should be:
If A+i is not empty, then value of B+i becomes "Currency".
It's also for me to get a "generic" code that I could use with other things.
This is my current code...
Sub LoopTest()
' Select cell A2, *first line of data*.
Range("A2").Select
' Set Do loop to stop when an empty cell is reached.
Do Until IsEmpty(ActiveCell)
ActiveCell.Offset(0, 1).Style = "Currency"
ActiveCell.Offset(1, 0).Select
Loop
End Sub
Another example, getting Last Row, in case your data contains any blank rows.
Sub UpdateColumns()
Dim wks As Worksheet
Dim lastRow As Long
Dim r As Long
Set wks = ActiveSheet
lastRow = ActiveSheet.Cells.SpecialCells(xlLastCell).Row
For r = 2 To lastRow
If wks.Cells(r, 1) <> "" Then
wks.Cells(r, 2).NumberFormat = "$#,##0.00"
End If
Next r
End Sub
I can see I was a little slower than the others, but if you want some more inspiration, heer is a super simple solution (as in easy to understand as well)
Sub FormatAsCurrency()
'Dim and set row counter
Dim r As Long
r = 1
'Loop all rows, until "A" is blank
Do While (Cells(r, "A").Value <> "")
'Format as currency, if not blank'
If (Cells(r, "B").Value <> "") Then
Cells(r, "B").Style = "Currency"
End If
'Increment row
r = r + 1
Loop
End Sub
Try the following:
Sub calcColumnB()
Dim strLength As Integer
Dim i As Long
For i = 1 To Rows.Count
columnAContents = Cells(i, 1).Value
strLength = Len(columnAContents)
If strLength > 0 Then
Cells(i, 2).NumberFormat = "$#,##0.00"
End If
Next i
End Sub
Explanation--
What the above code does is for each cell in Column B, so long as content in column A is not empty, it sets the format to a currency with 2 decimal places
EDIT:
Did not need to loop
Here's a really simply one, that I tried to comment - but the formatting got messed up. It simply reads column 1 (A) for content. If column 1 (A) is not empty it updates column 2 (B) as a currency. Changing active cells makes VBA more complicated than it needs to be (in my opinion)
Sub LoopTest()
Dim row As Integer
row = 1
While Not IsEmpty(Cells(row, 1))
Cells(row, 2).Style = "Currency"
row = row + 1
Wend
End Sub

How to automatically make copies of rows in Excel?

I have an excel file which looks like this:
row1_cell1 row1_cell2 row1_cell3
row2_cell1 row2_cell2 row2_cell3
row3_cell1 row3_cell2 row3_cell3
How can i make three (or any number of) copies of each row that i have in the sheet, which i would like to be added after the row being copied? So, in the end i would like to have this kind of a result:
row1_cell1 row1_cell2 row1_cell3
row1_cell1 row1_cell2 row1_cell3
row1_cell1 row1_cell2 row1_cell3
row2_cell1 row2_cell2 row2_cell3
row2_cell1 row2_cell2 row2_cell3
row2_cell1 row2_cell2 row2_cell3
row3_cell1 row3_cell2 row3_cell3
row3_cell1 row3_cell2 row3_cell3
row3_cell1 row3_cell2 row3_cell3
This is how I would do that for all rows on the sheet:
Option Explicit
Sub MultiplyRows()
Dim RwsCnt As Long, LR As Long, InsRw As Long
RwsCnt = Application.InputBox("How many copies of each row should be inserted?", "Insert Count", 2, Type:=1)
If RwsCnt = 0 Then Exit Sub
LR = Range("A" & Rows.Count).End(xlUp).Row
Application.ScreenUpdating = False
For InsRw = LR To 1 Step -1
Rows(InsRw).Copy
Rows(InsRw + 1).Resize(RwsCnt).Insert xlShiftDown
Next InsRw
Application.ScreenUpdating = True
End Sub
There isn't a direct way to paste them interleaved like what you wanted. However, you can create a temporary VBA to do what you want.
For example, you can:-
Create a VBA procedure (like the one below) in your Excel file.
Assign a keyboard shortcut (eg. Ctrl+Q) to it.
To do this, press Alt+F8, then select the macro, then click 'Options'.
Select the cells you want to copy, then press Ctrl+C.
Select the cell you want to paste in, then press Ctrl+Q (or whatever keyboard shortcut you chose).
Enter the number of times you want to copy. (In your example, it would be 3.)
WHAMMO! :D
Now you can delete the VBA procedure. :)
VBA Code:
Sub PasteAsInterleave()
Dim startCell As Range
Dim endCell As Range
Dim firstRow As Range
Dim pasteCount As Long
Dim rowCount As Long
Dim colCount As Long
Dim i As Long
Dim j As Long
Dim inputValue As String
If Application.CutCopyMode = False Then Exit Sub
'Get number of times to copy.
inputValue = InputBox("Enter number of times to paste interleaved:", _
"Paste Interleave", "")
If inputValue = "" Then Exit Sub 'Cancelled by user.
On Error GoTo Error
pasteCount = CInt(inputValue)
If pasteCount <= 0 Then Exit Sub
On Error GoTo 0
'Paste first set.
ActiveSheet.Paste
If pasteCount = 1 Then Exit Sub
'Get pasted data information.
Set startCell = Selection.Cells(1)
Set endCell = Selection.Cells(Selection.Cells.count)
rowCount = endCell.Row - startCell.Row + 1
colCount = endCell.Column - startCell.Column + 1
Set firstRow = Range(startCell, startCell.Offset(0, colCount - 1))
'Paste everything else while rearranging rows.
For i = rowCount To 1 Step -1
firstRow.Offset(i - 1, 0).Copy
For j = 1 To pasteCount
startCell.Offset(pasteCount * i - j, 0).PasteSpecial
Next j
Next i
'Select the pasted cells.
Application.CutCopyMode = False
Range(startCell, startCell.Offset(rowCount * pasteCount - 1, colCount - 1)).Select
Exit Sub
Error:
MsgBox "Invalid number."
End Sub
Old thread, however someone might find this useful:
The below information was copied from here
I needed to do almost the opposite. I needed the formula to increment by 1 every 22 rows, leaving the 21 rows between blank. I used a modification of the formula above and it worked great. Here is what I used:
=IFERROR(INDIRECT("J"&((ROW()-1)*1/22)+1),"")
The information was in column "J".
The "IFERROR" portion handles the error received when the resulting row calculation is not an integer and puts a blank in that cell.
Hope someone finds this useful. I have been looking for this solution for a while, but today I really needed it.
Thanks.

Resources