So I have built a formula that has Absolute Cell References, and wanted to repeat the same formula down 3000 cells with each one referencing increment cells. (1st formula referring to Cell $A$1, 2nd formula referring to $A$2) I know that I could easily do this without referencing exact cells and the Fill Handle and this is currently how it's set up, however there's a very large number of people who work in this spreadsheet that have bad Excel manners, and regularly delete rows and cells or copy and paste, which breaks the formulas.
Rather than manually editing the same formula in each cell to change the references from relative to absolute, I was wanting to run a Macro to automatically run the formula for 3000 cells.
I had at first built a Macro that fills 20 cells with the formula, but it didn't adjust the formula based on the active cell. (Always entered with range $A$1:$A$20, and not $A$21:$a$40 when started further down) I changed the Macro to loop, but it looks with all formulas referencing $A$1 rather than updating.
The Macro set up to loop is as follows:
Sub HDDatesRef()
ActiveCell.Select
ActiveCell.FormulaR1C1 = "=IF(AND(HD!R1C1>0,ISBLANK(HD!R1C4)),HD!R1C1,""n/a"")"
ActiveCell.Offset(1, 0).Range("A1").Select
Loop Until ActiveCell.Value = ""
End Sub
Any and all help with figuring this out would help immensely. Right now I also have access to Liknedin Learning, so if there's any suggestions for courses on there I should look into so I can understand what I need to do will help with this.
The Excel application object has a function called ConvertFormula which you can use to change a formula between reference styles (A1 or R1C1) and to specify whether the rows and columns should be relative references or absolute references.
If you start off by creating the formula in each row as a relative reference then you can use ConvertFormula to turn it into an absolute reference. The only restriction is that the formula cannot be longer than 255 characters.
Adapting your code and following the advice in How to avoid using Select in Excel VBA gives us:
Option Explicit
Sub HDDatesRef()
Dim r As Range
' If we know the cell address we want to start in then we could use that directly
' e.g. Set r = Worksheets("HD").Range("E1")
Set r = ActiveCell
Do
' The With block just saves us typing r.FormulaR1C1 multiple times
With r
' Don't know what your relative formula would be. I've assumed that we are
' working in column E but adjust as appropriate
.FormulaR1C1 = "=IF(AND(HD!RC[-4]>0,ISBLANK(HD!RC[-1])),HD!RC[-4],""n/a"")"
' Take the formula we already have which is in R1C1 format, keep it in R1C1 format,
' change it from a relative reference based on cell r to an absolute reference
' and make that the new formula for this cell
.FormulaR1C1 = Application.ConvertFormula(.FormulaR1C1, xlR1C1, xlR1C1, xlAbsolute, r)
End With
' Move down one row
Set r = r.Offset(1, 0)
Loop Until r.Value = ""
End Sub
In case you aren't familiar with them. here are the references for Option Explicit and With...End With
You can do this without looping, Excel is smart enough to know you want incremental.
As an example do run this on a fresh sheet:
Sub ShowIncremental()
Range("A1:A10").Formula = "=Row(A1)"
Range("B1:B10").Formula = "=A1*2"
Range("C1:C10").Formula = "=sum(B$1:B1)"
End Sub
Notice the formulas created in A1:C10. Notice Excel incremented them even though the code didn't say to except in the case where we absoluted B$1.
I recommend you do something similar with your code to avoid looping, this will be much much faster.
Related
I have a worksheet used for my office. Occasionally, a few extra lines are needed in one section, so I created a button that adds said line (for the non-excel users). At the bottom of the section is a simple <=SUM(D82:D92)>.
In this way, whenever data is added, the amount is summed.
However, when a new line is added, the sum formula stays the same. I'm trying to change the D92 to D93 (and etc.).
How can I add a line AND update the sum formula so that it stays dynamic.
Please give advice on the below code:
'botton cell in sum range
Dim BC As String
Dim rng As Range
BC = ActiveCell.Address
Set rng = Range(Range("d82"), Range(BC))
ActiveCell.Offset(1, 0).Select
ActiveCell = WorksheetFunction.Sum(rng)
EDIT:
Fixed it!
ActiveCell.Offset(1, 3).Select
ActiveCell.FormulaR1C1 = "=SUM(R82C4:R[-1]C)"
If you don't mind using a formula with OFFSET, you could just change =SUM(D82:D92) in cell D93 into =SUM(D82:OFFSET(D93,-1,0)). This formula will update as expected: it will just keep looking for a reference to 1 row above itself to find the end of the sum range. E.g. a sub with Range("D93").EntireRow.Insert will push the formula into D94, now as =SUM(D82:OFFSET(D94,-1,0)).
Edit: I suggested OFFSET, thinking that INDEX wasn't possible in this case, but of course it is. Same result can be gained by using =SUM(D82:INDEX(D82:D93,ROW(93:93)-82)) entered into D93. The benefit would be that OFFSET is a 'volatile function', which will recalculate with each worksheet change. With INDEX, you don't have this problem.
I'm trying to make a button which on click will print out the value of a cell as a string and not the appearance of the cell itself (if that makes sense) using the .PrintOut method in VBA. That cell is the active cell, whose value I set based on the cell next to it. Here is my code:
Sub Graphic2_Click()
Dim MyNumber as Integer
MyNumber = ActiveCell.Offset(-1, 0) + 1
ActiveCell.Value = MyNumber
ActiveCell.Printout
End Sub
I also tried MyNumber.PrintOut but I get an "Invalid Qualifier" error.
Am I missing out something too simple?
Please, try the next code. It use a temporary 'helper cell' where the format to be pasted (and recuperated after printing out):
Sub Graphic2_Click()
Dim helperCell As Range
With ActiveCell
.value = CLng(Offset(-1, 0)) + 1
Set helperCell = .Offset(1) 'it may be any cell to temporarilly be used
.Copy
helperCell.PasteSpecial xlPasteFormats
.ClearFormats
.PrintOut
helperCell.Copy
.PasteSpecial xlPasteFormats: helperCell.ClearFormats
End With
End Sub
To literally print just the contents of the cell:
Clear number formatting for the specified cell
Autofit column width for that column
Turn off gridlines
Turn off row and column headings
Set print area to the single cell, dismissing any warnings
Print out the active sheet
Each of these are straightforward to do in VBA, and probably straightforward to research on SO anyway.
You may also consider a mechanism to return the changed settings to their initial states afterwards. This would involve pushing (storing) the initial state to a variable or variables first, and popping (restoring) it back afterwards.
Explanation:
The VBA method .PrintOut is something you do to a worksheet, not a cell or its contents. Therefore, to get what you need, you need to set up the worksheet for printing so that the only thing that will appear is the contents of your chosen cell. This is what the above steps do.
For more information about the .PrintOut method, see:
https://learn.microsoft.com/en-us/office/vba/api/excel.sheets.printout
Or, to continue what the OP tried:
You could try something like:
ActiveCell.Formula = Range(ActiveCell.Offset(-1,0)).Value2 + 1
If this does not work, try:
ActiveCell.Formula = Range(ActiveCell.Offset(-1,0).Address).Value2 + 1
Or try these without the + 1 on the end, to verify that the rest of the formula is working the way you want it too. As mentioned, you may get a type mismatch issue causing an error if you don't trap first for whether the referenced cell contains a number.
.Formula in this example is how I am setting the content of the cell, and it can be used even when setting a value not necessarily literally a formula. You could use Value instead if you prefer.
.Value2 is a robust method of extracting the evaluated content of the source cell, as a value instead of as a formula.
The PrintOut method is to print a worksheet, not a range or single cell.
Note: This answer is not tested, as I am not near Excel right now.
Also... it's possible that there could be much simpler ways to do what you are trying to accomplish. Could you provide a bit more detail about the context of what you are trying to do.
Good day dear community,
I currently have a problem with VBA/Excel that I can't find a solution to. What I want to achieve is not complicated, but I can't find a way.
Let's assume we have two columns. In any row of one column A the User enter a value and then I start a macro. This macro executes certain instructions. Among other things, this macro ensures that if a cell in column A has a value, then the value "Yes" is entered in the same row in column B. Now my problem: As soon as the user deletes the cell value in column A, the value "Yes" in column B should also be deleted. At first glance you might think that i can use this confdition:
=IF(A1="";"";yes)
The problem is that as soon as the user has entered a value in the cell, "yes" is immediately written in the cell, but this is not desired. Because this task should be taken over by the macro.
As a small side note: I have simplified my problem. Due to the structure of my project, only the macro is allowed to write "yes".
Thanks.
Evaluate Excel Formula in VBA
In your code, you will define the occupied range in column A, and apply the second line appropriately.
Option Explicit
Sub checkColumnRange()
' Some code
' Define the column range...
' e.g.:
Dim rg As Range: Set rg = Range("A1:A10")
rg.Offset(, 1).Value = Evaluate("IF(" & rg.Address(0, 0) _
& "<>"""",""Yes"","""")")
' Some code
End Sub
I have a table that contains a column that has a risk score. I want to write a formula to examine each cell and determine if the cell is blank, then make the cell value 100, else leave the cells current value. The code I'm trying to use( For cell D2) is as follows:
=IF(ISBLANK(D2),100,D2)
I'm having trouble doing this due to a cell's inability to reference itself easily and I believe inserting this formula into the cell simply overwrites the cells current value, any thoughts?
Say the values you want to process are from D2 through D100. Try this small macro:
Sub OneHundred()
Dim r As Range
Set r = Range("D2:D100").Cells.SpecialCells(xlCellTypeBlanks)
r.Value = 100
End Sub
Adjust the range to meet your needs.
It can be done because I have a spreadsheet that allows this to happen. Part of my formula in cell T3 is as follows: IF(B3="","",IF(B3="Ready","",IF(T3="",TODAY(),T3))) First it checks some other things but at the end it checks itself to see if it is blank. If it is, it writes todays date. Otherwise it just writes itself.
I remember I had to change something in the settings to allow this to happen but I can't find it now.
I am tasked with creating A map of our warehouse.
In the data I have to have model, description and location.
What I am having trouble with is, I am using data from a second sheet to populate the "map"
i.e. ='1'!F2
when I try to drag and use it to fill an entire line it changes to ='1'!g2. I would like it to go to ='1'!F3
I see the logic in what it is doing...but I dont want it to use that logic..I want it to use the next cell below it to populate that cell.
The simplest thing might be to Copy and then Paste Special > Transpose the data on "1" to a new sheet. Then you could drag formulas that refer to the new sheet and they'd behave as expected.
EDIT: Based on your original question, this will fill in the results of columns to the right as you drag it down and vice-versa. This literally does what your original question asked:
=INDEX(Sheet1!$F$2:$Z$8000,COLUMN(),ROW())
Start in A1 and drag in either direction. To add a header line or rows to left just insert rows or columns to top or left (to keep the formula sound).
EDIT: Here's the Transpose function, per #brettdj's suggestion. I find it difficult to work with, but it certainly makes it clearer what's going on:
In cells F2:8000 of your target sheet enter:
=TRANSPOSE(Sheet1!$F2:$Z8000)
Then, with all those cells selected, go into edit mode in one of the cells and do Ctrl Shft Enter to array-enter it. If you have to resize the source range I believe you have to repeat these steps with the correct ranges. I'm an Index fan myself, so would stick with that. Offset is volatile, so I'd avoid it. If I've got any of this last edit wrong, #brettdj will help us.
Since what you want is non-native behaviour, it might be worth writing a small VBA macro to do the copy, and assign it to a keyboard shortcut.
Here's a simple example to copy a formula one cell to right, updating reference one cell down (preserves Absolute/Relative settings in formula).
It assumes A1 style address, work only if the active cell contains a formula referencing a single cell (ends silently if not). Will silently overwrite anything in the destination cell.
Sub CopyToRight()
Dim clFrom As Range
Dim clAddr As Range
Dim addr As String
On Error GoTo EH
Set clFrom = ActiveCell
If clFrom.Formula Like "=*!*" Then
Set clAddr = Range(Mid(clFrom.Formula, 2))
If clAddr.Count = 1 Then
If clFrom.Formula Like "=*!$*$*" Then
addr = clAddr.Offset(1, 0).Address(True, True)
ElseIf clFrom.Formula Like "=*!$**" Then
addr = clAddr.Offset(1, 0).Address(False, True)
ElseIf clFrom.Formula Like "=*!*$*" Then
addr = clAddr.Offset(1, 0).Address(True, False)
Else
addr = clAddr.Offset(1, 0).Address(False, False)
End If
clFrom.Offset(0, 1).Formula = "='" & clAddr.Worksheet.Name & "'!" & addr
End If
End If
clFrom.Offset(0, 1).Select
EH:
End Sub