I drafted two tables to calculate some values. One value (attractiveness) appears in H16, the other (competivity) in H26.
Each time I calculate new values, I must be able to add these into columns K and L, when pressing a ADD-button. Both of the columns have the following range; K10:K26 and L10:L26.
So the first time I press "add", I want H16 to be transferred to K10 and H26 to L10. The second time I press "add", I want the new values in H16 and H26 to be inserted in K11 and L11.
I've already several ways, but my basic knowledge is just apparently less than basic.
You can get the last used row in a column like this:
Columns(col_number).Rows(Rows.Count).End(xlUp).Row
Assuming that K10 is the last used row you could do something like this:
Cells(Columns(11).Rows(Rows.Count).End(xlUp).Row + 1, 11).Value = Range("H16").Value
This would find the last used row + 1 and in column 11 (K) and set its value to the value of H16
Another way of doing this is to start at row 10 and just keep going down until you find a blank cell and set its value to whatever you want.
For eample:
'Create a variable to store the current row
Dim i As Long
'Start at row 10 and go down until you find a blank cell
For i = 10 To Rows.Count
'If the current cell is blank
If Cells(i, 11).Value = "" Then
'Set its value to H16
Cells(i, 11).Value = Range("H16").Value
'Stop looking for blank cells
Exit For
End If
Next
Related
I am trying to figure out how to autofill a specific range of cells based on already defined data in the same row. My task is more complex, but a simplification of the step can be seen in the code below. What I want to achieve is:
Define a range where I want to output my values
Multiply two values in the same row of the selected range cell (to its left), and output this number in the currently selected range cell. To do this, one of the numbers to be multiplied will be dependant on a string also in the row (which describes its type).
Loop through the defined range and repeat the calculation on each row.
My current code is as follows and outputs a "application defined or object defined error".
Any help would be much appreciated.
For a = Range("P12") To Range("P33") 'Range of cells I want to fill.
If Cells(a, -10).Value = "B" 'If the cell 10 to the left of our "a" value is = "B".
Then c = Cells(a, -10).Value * Worksheets("LCI").Range("D4").Value 'Then new variable "c" = (cell 9 to left of a) * (number from another sheet containing a database)
Cells(a).Value = c 'Update value of selected range cell to contain c which we calculated.
Next 'Repeat for all rows in range.
You are close.
You need to think of a as a cell or Range object. That variable is the cell itself which has properties like a.row and a.column that describe its location on the sheet in which it lives.
When you say Cells(a, -10) you are saying "On the Activesheet I want a Cell where the row is a, and where the column has the number -10". There is no row a (as a is a range/cell object and because you didn't specify which property of a you are wanting here it will default to a.value which is probably nothing) and there is no column -10 on the Activesheet.
Your loop is defined incorrectly. You can use a For Each loop to loop through cells in a range.
Instead:
For Each a In Range("P12:P33")
'clear `c` each loop
c=0
If a.Offset(,-10).Value = "B" Then 'start at cell `a` and move back 10 columns and grab the value
c = a.Offset(, -10).Value * Worksheets("LCI").Range("D4").Value
End If
a.Value = c
Next a
I’m trying to develop a small program using VBA and would like to add to it. As always I’m struggling to get it right any really could use some help on this project. I not sure how does the program move contents down from one cell to the next if the next cell is full without overwriting it and then move that one down.
I hope you can help.
I'm currently using the program below.
Sub do_it()
Dim n, sht As Worksheet, cell As Range, num, tmp, rngDest As Range
Set sht = ActiveSheet
n = sht.Range("A1")
For Each cell In sht.Range("D1:D12,A16:A31,D16:D31,G16:G31,J16:J31,M16:M31").Cells
tmp = cell.Offset(0, 1).Value
If cell.Value = n And tmp Like "*#-#*" Then
'get the first number
num = CLng(Trim(Split(tmp, "-")(0)))
Debug.Print "Found a positive result in " & cell.Address
'find the next empty cell in the appropriate row
Set rngDest = sht.Cells(num, sht.Columns.Count).End(xlToLeft).Offset(0, 1)
'make sure not to add before col L
If rngDest.Column < 12 Then Set rngDest = sht.Cells(num, 12)
cell.Offset(0, 1).Copy rngDest
Exit For
End If
Next
End Sub
I'm trying to have the program move all the number sets down in the column in the 6 column ranges E1:E12,B16:B30,E16:E30,H16:H30,K16:K30,N16:N30.
In only column E1:E12 I need the program to move the set of numbers (could be more than one set of numbers in the range) down to the following cell below it and increase the last number in the set (no limit to the count). So in the example of cell E1 (8-16) would move to E2 and become 8-17 (cell E1 would be blank when after the move).
When sets of number are located in cell E12 they would move to E1 but still increase the last number and would go round and round. Need help on the next one, how does the program move contents down from one cell to the next if the next cell is full without overwriting it and then move that one down, if this makes sense. An example is cell E12, how does it move up to E1 if E1 is full but has to be moved, which goes first?
For the remaining column ranges B16:B30,E16:E30,H16:H30,K16:K30,N16:N30 I need the program to move the set of numbers (could be more than one set of numbers in the range) down to the following cell below it and increase the last number in the set (no limit to the count). So in the example of cell N18 (5-3) it would move it to N19 and become 5-4 (delete the contents in N18 when finished). The second adjacent column to the right of the above, N18 in this case and located in only the following locations: C16:C30,F16:F30,I16:I30,L16:L30,O16:O30 have cells that contain values that must move but with no change in number. Cell O18 would move down to O19 and still have the number of 9.99. After the operation N18 and O18 would then be blank).
The two exceptions are if the last number is a 15, see cell B30 (8-15). Two things must happen:
1) I need the program to reference the number in the following 5 possible cells:
Cell B30 go to cell B32, reference number 1
Cell E30 go to cell E32, reference number 2
Cell H30 go to cell H32, reference number 3
Cell K30 go to cell K32, reference number 4
Cell N30 go to cell N32, reference number 5
Using example B30 the reference number is 1 (B32) so the program would search the range in column D1:D12 for the number 1 and move the set of numbers and increase the last digit, so it would become 8-16 in cell number E1.
2) The value in cell C31 must be moved via referencing the first number in cell B30 as a reference and search the following 10 possible cells: A35,D35,G35,J35,M35,Q35,A39,D39G39,J39,M39,O39 to find that number (in this example 8 would be cell D39 and the number 2.22 would be moved to cell D40.
After this operation there is no contents in either cell B30 and C30.
That’s it.
enter image description here
I not sure how does the program move contents down from one cell to the next if the next cell is full without overwriting it and then move that one down.
This should help with that:
Cells(irow + 1, icol).Insert Shift:=xlDown
Cells(irow, icol).Copy Cells(irow + 1, icol)
Cells(irow, icol).Clear
What I'm trying to achieve is there are 2 whole numbers in column A & B on the same row. I want to fill the row from Column C to show the whole numbers increments of one between the two numbers.
i.e.
A B C D E F G H I J K L
1 10 1 2 3 4 5 6 7 8 9 10
any help would be appreciated.
Assuming this is Excel and you can open the VBE Editor to use VBA
Here's a macro you can run or call via a button
See the comments in the code to understand what it's doing with the Dataseries fill function
Sub FillData()
Dim intStopAt As Integer
' Set to cell indicated low end of range
Cells(1, 1).Select
' Fill in "Start At" Number
ActiveCell.Offset(0, 2).Value = ActiveCell.Value
' Retrieve and use stop number to fill in series
intStopAt = ActiveCell.Offset(0, 1).Value
ActiveCell.Offset(0, 2).DataSeries Rowcol:=xlRows, Type:=xlLinear, Date:=xlDay, Step:=1, Stop:=intStopAt
End Sub
The below code assumes you have no header and that your value in A1 is always 1, and your value in B1 is the number you want to count to.
This can be modified to be more dynamic, but taking your question as is, this should work for you.
1) Check number to count to (CountTo)
2) Run loop for 1 to CountTo and auto-populate your column headers
To run: Open VBE and paste this code on the sheet where you wish to run it.
Sub Counter()
Dim CountTo As Integer
CountTo = Range("B1").Value
For i = 1 To CountTo
Cells(1, i + 2) = i
Next i
End Sub
This can be done without VBA, perhaps not as neat initially as #dbmitch's answer because the formula has to go across to the maximum possible number.
A1 is start number, > 0
B1 is end number (> A1)
In Cell C1 enter =A1
In Cell D1 enter =IF(AND(C1<$B1,C1>=$A1),C1+1,"") and then
drag/fill right as far as you need to.
I have formulated the code so that you can now select the filled rows (A through to wherever) and fill down.
A simple explanation:
C1 sets the start of the list
The AND formula in D1 onwards checks that the immediate left cell (for D1 this is C1, for E1 this is D1 etc.) is less than the end number and greater than the start number.
If the conditions are true, use the immediate left cell value + 1 as the result.
If the conditions are false, insert a blank.
Further checking can be done, I have assumed in the above solution that the numbers are positive and increasing.
You can use helper columns to indicate if you should increase or decrease (i.e. +1 or -1 as required.
Using a blank as the other answer falls down if the numbers go from -ve to +ve. In this case, you could use another symbol (e.g. x) and check for that in the AND function as well.
you could use this:
Sub main()
Dim cell As Range
With Range("A1", Cells(Rows.Count, 1).End(xlUp)).SpecialCells(xlCellTypeConstants, xlNumbers) ' reference column A cells from row 1 down to last not empty one with a "constant" (i.e. not a formula result) numeric content
For Each cell In .Cells 'loop through referenced range
cell.Offset(, 2).Resize(, cell.Offset(, 1).Value - cell.Value + 1).FormulaR1C1 = "=COLUMN()-COLUMN(C3)+RC1" 'write proper formula in current cell adjacent cells
Next
.CurrentRegion.Value = .CurrentRegion.Value ' get rid of formulas and leave values only
End With
End Sub
I am writing a Macro in Excel which is supposed to delete entire Rows, or add Rows, based on input.
Now the amount of rows to be deleted should be determined based on the amount of Rows which are already there, so say if I have 12 Rows and a cell nearby with a Sum amount of 3, I have used the Cell value so far to determine the amount of Rows to be removed.
|1(A1)| Title (B1)
|1(A2)| Title (B2)
|1(A3)| Title (B3)
|3(A4)| Sum (B4)
Here is the code I am using(the removing part, haven't gotten further yet):
If CInt(TextBox2.Value) = Cells(4, 1) Then
MsgBox ("Values are equal")
ElseIf CInt(TextBox2.Value) < Cells(34, 2) Then
a = Cells(4, 1) - CInt(TextBox2.Value)
For i = 1 To a
Rows(1).EntireRow.Delete
Next
End If
The Problem What I have realised with this is, that the Summation Cell which I use to determine the Amount of Rows to be deleted, will move if I delete a Row, so it will not be at position (4,1) (::A4::) anymore.
My Question: Is there a way to use the cell with an ID which would never
change, or dynamically change the addressed Value of the Cell ?
Thanks a lot in Advance!
If you Set a reference to a cell and delete cells above so that the cell move up, the cell reference will be updated accordingly. See following example:
Function testCellRef()
Dim c As Range, i As Long
Set c = [A18]
For i = 1 To 10
Range("A" & i).EntireRow.Delete
Debug.Print "Deleted row " & i & ", cell Address is now " & c.Address
Next i
End Function
will display in the immediate window:
Deleted row 1, cell Address is now $A$17
Deleted row 2, cell Address is now $A$16
Deleted row 3, cell Address is now $A$15
Deleted row 4, cell Address is now $A$14
Deleted row 5, cell Address is now $A$13
Deleted row 6, cell Address is now $A$12
Deleted row 7, cell Address is now $A$11
Deleted row 8, cell Address is now $A$10
Deleted row 9, cell Address is now $A$9
Deleted row 10, cell Address is now $A$9
Note that the last iteration, the row that is deleted (row 10) is below the cell tracked and so the address doesn't change.
Note also that if you replace [A18] by [A17], you will delete the row with the tracked cell and then the reference will become invalid at the 9th iteration and generate an error at the c.Address call.
You could find the row that contains the Sum formula each time by using something like this:
Columns("A").Find("=SUM", , xlFormulas, , xlRows, xlPrevious).Value
That will search column A, starting at the last row and working up and will return the value of the cell that contains "=SUM". If you have more than one cell with that you may need to change the direction or go another route.
Another option would be adding a variable like the example below:
x = 0
If CInt(TextBox2.Value) = Cells(4 + x, 1) Then
MsgBox ("Values are equal")
ElseIf CInt(TextBox2.Value) < Cells(34 + x, 2) Then
a = Cells(4 + x, 1) - CInt(TextBox2.Value)
For i = 1 To a
Rows(1).EntireRow.Delete
x = x - 1
Next
End If
I assume you also need to change the cell you compare to in column B. When adding a row, just use x = x + 1.
To delete the rows you have to loop backwards, that way the row numbers you assume at the beginning of the loop will remain intact.
I am repeatedly performing an action on multiple columns, and would like to eliminate my redundant code. I am posting the code for the first two columns as I believe that is enough to demonstrate what I am doing, but the code is repeated for a total of 16 columns (Column E - Column T).
OldplayerRosterLocation with the offset is basically a "vba vlookup" for the old player to find where they are on the sheet so the proper row stats are modified as needed. It works, but I would like to reduce the redundant code.
'Below determines what weeks old player has already played.
'First part replaces team win/loss for that week as a value instead of
'formula so second part does not ruin sheet.
If Range("E61") = "1" Then 'Wk#1
Range("E42").Value = Range("E62")
Range("E43").Value = Range("E63")
'Second part clears weekly results for new player each weeks that the
'old player has already played.
Range(OldPlayerRosterLocation).Offset(0, 3).ClearContents
Range(OldPlayerRosterLocation).Offset(1, 3).ClearContents
Range(OldPlayerRosterLocation).Offset(2, 3).ClearContents
End If
If Range("F61") = "1" Then 'WK#2
Range("F42").Value = Range("F62")
Range("F43").Value = Range("F63")
Range(OldPlayerRosterLocation).Offset(0, 4).ClearContents
Range(OldPlayerRosterLocation).Offset(1, 4).ClearContents
Range(OldPlayerRosterLocation).Offset(2, 4).ClearContents
End If
How can I simplify this code?
I'd be sure you could use this for your 16 columns:
Dim c As Range
For Each c In Range("E61:T61")
If c = "1" Then
c.Offset(-19, 0).Value = c.Offset(1, 0).Value
c.Offset(-18, 0).Value = c.Offset(2, 0).Value
For j = 0 To 2
Range(OldPlayerRosterLocation).Offset(j, c.Column - 2).ClearContents
Next
End If
Next
c is a range object (a cell in this case). So we use For Each ... In instead of For ... To. c.Column gives the column number of c. When we subtract 2, we get the number of columns to Offset, where you want to ClearContents.
Use the Resize() function
Range(OldPlayerRosterLocation).Offset(0,3).Resize(3,1).ClearContents
...
Range(OldPlayerRosterLocation).Offset(0,4).Resize(3,1).ClearContents
It takes a single cell and creates a range spanning 3 rows and 1 column. Also commonly used for fast value transfers. For example:
Range("B1").Resize(100,1).Value = Range("A1").Resize(100,1).Value
copies 100 rows from A1 into B1. For you, I proposed the following style changes:
' Old Code
'Range("E42").Value = Range("E62")
'Range("E43").Value = Range("E63")
' New Code
Range("E42").Resize(2,1).Value = Range("E62").Resize(2,1).Value