Pasting inside a range, which is counting up the cells for its second parameter, the row - vba

I would like to paste data from a range, copy it in a new range.
This new range is supposed to count up its row by +1 (represented by variable i)
for each value (self) that is being pasted.
I use self, because i need to extract values from a range that includes empty cells.
I tested the first part, the debug print works, so the self values are obtained correctly.
I must be making a mistake with the Range(27, i) part, and also with the Set i = 15 part.
Help very appreciated.
sincerely
Private Sub EvaluateButton_Click()
Dim EvaRange As Range 'Evaluation range
Dim i As Integer 'Counter for free columns
Worksheets("testsheet").Activate
Set EvaRange = Range("C10:C999")
EvaRange.Copy Range("Z15")
Range("Z15:Z999").Select
Set i = 15
For Each self In Selection.SpecialCells(xlCellTypeConstants)
Debug.Print (self)
i = i + 1
self.Copy Range(27, i)
Next
End Sub
Edit: i tried a second version, i think that variables are defined like this:
Dim x As Integer
x = 6
So shouldn't this work?
Private Sub EvaluateButton_Click()
Dim EvaRange As Range
Dim i As Integer
Worksheets("testsheet").Activate
Set EvaRange = Range("C10:C999")
EvaRange.Copy Range("Z15")
Range("Z15:Z999").Select
i = 15
For Each self In Selection.SpecialCells(xlCellTypeConstants)
Debug.Print (self)
self.Copy Range(27, i)
i = i + 1
Next

This will remove my empty lines :)
Now, I have the problem, that my last value is duplicated down the line, a new challenge to handle :)
Private Sub EvaluateButton_Click()
Dim EvaRange As Range 'Evaluation range
Dim i As Integer 'Counter for free columns
Worksheets("testsheet").Activate
Set EvaRange = Range("C10:C999")
EvaRange.Copy Range("Z15")
Range("Z15:Z999").Select
i = 15
For Each self In Selection.SpecialCells(xlCellTypeConstants)
Debug.Print (self)
self.Copy Cells(i, 27)
i = i + 1
Next

Related

How to loop on range of rows in LibreOffice Calc spreadsheet, comparing cell values, setting cell values and deleting row, if condition is true

I have the following requirement in my LibreOffice Calc spreadsheet:
ForEach Row 'r' in selected range,
starting from the last row in the range,
and moving backwards (up) one row at a time,
do some cell value comparisons, and based on that, either skip the row,
or set some cell values, and delete the selected row,
then proceed with the same process, with the row just above that.
ie.,
Representing CellValue(Column[A], Row[r])
as A[r],
And Representing the row before (just above) that,
as A[r-1],
I need to do the following:
FOR (r = LastRowInSelectedRange; r>1; r=r-1) {
IF FollowingConditionsAreTrue (
(r > 1)
AND (A[r] IsEqualTo A[r-1])
AND (B[r] IsEqualTo C[r-1])
AND (E[r] IsEqualTo E[r-1])
) ThenDoTheFollowing {
SET C[r-1] = C[r]
DeleteRow(r)
} EndIF
} EndFOR
Question:
How can we implement this in LibreOffice Calc?
The following should do the trick. It assumes your data are in the range A1:E10 in a sheet called Sheet1. To use a different range change the appropriate lines. If you want to select the range by hand, comment out the line oCellRange = oSheet.getCellRangeByName("A1:E10") and uncomment the line oCellRange = oDoc.getCurrentSelection(). That will only work if you have a single selection, not multiple ones.
Sub iterateThroughRange()
Dim oDoc As Object
oDoc = ThisComponent
Dim oSheet As Object
oSheet = oDoc.getSheets().getByName("Sheet1")
Dim oCellRange As Object
oCellRange = oSheet.getCellRangeByName("A1:E10")
'The above line gets a named range. To get a slected area instead
'comment it out and uncomment the following line:
'oCellRange = oDoc.getCurrentSelection()
Dim oTableRows As Object
oTableRows = oCellRange.getRows()
Dim nRows As Integer
nRows = oTableRows.getCount()
Dim oTableColumns As Object
oTableColumns = oCellRange.getColumns()
Dim nColumns As Integer
nColumns = oTableColumns.getCount()
Dim oThisRow As Object, oPreviousRow As Object
Dim oThisRowData() As Variant, oPreviousRowData() As Variant
Dim oThisRowAddress As Variant
For r = nRows - 1 To 1 Step - 1
oThisRow = oCellRange.getCellRangeByPosition(0, r, nColumns - 1, r)
oThisRowData = oThisRow.getDataArray()
oPreviousRow = oCellRange.getCellRangeByPosition(0, r - 1, nColumns - 1, r - 1)
oPreviousRowData = oPreviousRow.getDataArray()
'Column A = index 0
'Column B = index 1
'Column C = index 2
'Column E = index 4
If oThisRowData(0)(0) = oPreviousRowData(0)(0) AND _
oThisRowData(0)(1) = oPreviousRowData(0)(2) AND _
oThisRowData(0)(4) = oPreviousRowData(0)(4) Then
oPreviousRowData(0)(2) = oThisRowData(0)(2)
oPreviousRow.setDataArray(oPreviousRowData)
'The following two lines delete the range and move the cells up
oThisRowAddress = oThisRow.getRangeAddress()
oSheet.removeRange(oThisRowAddress, com.sun.star.sheet.CellDeleteMode.UP)
'To delete the entire row instead of just the affected cells,
'comment out the above two lines and uncomment the following line:
'oTableRows.removeByIndex(r, 1)
End If
Next r
End Sub

VBA Excel: Different colors in one line diagram depending on value

I'm looking for a way to have three different colors in the same line chart of a diagram in Excel, depending on the values themselves or where they are from (from which sheet f.e).
Till now, I have the following code:
Sub ChangeColor()
Dim i As Integer
Dim IntRow As Integer
Dim r As Range
ActiveSheet.ChartObjects("Cash").Activate
ActiveChart.SeriesCollection(1).Select
IntRow = ActiveChart.ChartObjects("Cash").Count
For i = 2 To IntRow
Set r = Cells(2, i)
If r.Value < 3000 Then
Selection.Border.ColorIndex = 5
Else
Selection.Border.ColorIndex = 9
End If
Next
End Sub
However, the if statement is not considered and the color of the whole line changes only whenever I change the first ColorIndex. I have no idea, how to color parts of the line depending on the values in the underlying table.
Moreover, by defining IntRow as ActiveChart.ChartObjects("Cash").Count I'm not able to get the length of my array. This problem can be solved by manual counting and declaring IntRow as an Integer, however, the version above seems nicer (if that is possible of course).
I appreciate any help! Thank you.
Alexandra
You can read the values directly from the chart series:
Sub ChangeColor()
Dim cht As Chart, p As Point, s As Series
Dim i As Integer
Dim numPts As Long
'access the chart directly - no select/activate required
Set cht = ActiveSheet.ChartObjects("Cash").Chart
'reference the first series
Set s = cht.SeriesCollection(1)
'how many points in the first series?
numPts = s.Points.Count
'loop over the series points
For i = 1 To numPts
Set p = cht.SeriesCollection(1).Points(i)
p.Border.ColorIndex = IIf(s.Values(i) < 3000, 5, 9)
Next
End Sub

VBA - check for duplicates while filling cells through a loop

I am writing a VBA code that goes through a defined matrix size and filling cells randomly within its limits.
I got the code here from a user on stackoverflow, but after testing it I realized that it does not fit for avoiding duplicate filling, and for instance when filling 5 cells, I could only see 4 cells filled, meaning that the random filling worked on a previously filled cell.
This is the code I'm working with:
Dim lRandom As Long
Dim sCells As String
Dim sRandom As String
Dim rMolecules As Range
Dim i As Integer, j As Integer
Dim lArea As Long
lArea = 400 '20x20
'Populate string of cells that make up the container so they can be chosen at random
For i = 1 To 20
For j = 1 To 20
sCells = sCells & "|" & Cells(i, j).Address
Next j
Next i
sCells = sCells & "|"
'Color the molecules at random
For i = 1 To WorksheetFunction.Min(5, lArea)
Randomize
lRandom = Int(Rnd() * 400) + 1
sRandom = Split(sCells, "|")(lRandom)
Select Case (i = 1)
Case True: Set rMolecules = Range(sRandom)
Case Else: Set rMolecules = Union(rMolecules, Range(Split(sCells, "|")(lRandom)))
End Select
sCells = Replace(sCells, "|" & sRandom & "|", "|")
lArea = lArea - 1
Next i
rMolecules.Interior.ColorIndex = 5
Using this same exact code which works perfectly, WHAT can I insert and WHERE do I do that so that the code would check if a cell is previously already filled with a string or a color?
I feel as though this code I'm looking for should be right before
rMolecules.Interior.ColorIndex = 5
But I'm not sure what to type.
EDIT
From the comments I realized that I should be more specific.
I am trying to randomly fill cells with the blue color (.ColorIndex = 5), but what I need to check first is if the randomizing hadn't marked a cell twice, so that for instance in this case, if I want to mark 5 different cells, it marks only 4 of them because of a duplicate and thus fills only 4 cells with the blue color. I need to avoid that and make it choose another cell to mark/fill.
I'd appreciate your help.
Keep the cells you use in a Collection and remove them as you fill the random cells:
Sub FillRandomCells(targetRange As Range, numberOfCells As Long)
' populate collection of unique cells
Dim c As Range
Dim targetCells As New Collection
' make sure arguments make sense
If numberOfCells > targetRange.Cells.Count Then
Err.Raise vbObjectError, "FillRandomCells()", _
"Number of cells to be changed can not exceed number of cells in range"
End If
For Each c In targetRange.Cells
targetCells.Add c
Next
' now pick random 5
Dim i As Long, randomIndex As Long
Dim upperbound As Long
Dim lowerbound As Long
For i = 1 To numberOfCells
lowerbound = 1 ' collections start with 1
upperbound = targetCells.Count ' changes as we are removing cells we used
randomIndex = Int((upperbound - lowerbound + 1) * Rnd + lowerbound)
Set c = targetCells(randomIndex)
targetCells.Remove randomIndex ' remove so we don't use it again!
c.Interior.Color = 5 ' do what you need to do here
Next
End Sub
Sub testFillRandomCells()
FillRandomCells ActiveSheet.[a1:t20], 5
FillRandomCells ActiveSheet.[b25:f30], 3
End Sub
EDIT: Changed to make the target range and number of changed cells configurable as arguments to a function. Also added error checking (always do that!).
Why not build a list of random numbers and place in a Scripting.Dictionary, one can use the Dictionary's Exist method to detect duplicates, loop through until you have enough then you can enter your colouring code confident that you have a unique list.

Running a Vba function on button press not working in excell

this is a simple stock price change code
my code is function(with parameters)
Function VanillaCall(S0 As Single, Exercise As Single, Mean As Single, sigma As Single, _
Interest As Single, Time As Single, Divisions As Integer, Runs As Integer) As Single
deltat = Time / Divisions
interestdelta = Exp(Interest * deltat)
up = Exp(Mean * deltat + sigma * Sqr(deltat))
down = Exp(Mean * deltat - sigma * Sqr(deltat))
pathlength = Int(Time / deltat)
piup = (interestdelta - down) / (up - down)
pidown = 1 - piup
Temp = 0
For Index = 1 To Runs
upcounter = 0
For j = 1 To pathlength
If Rnd > pidown Then upcounter = upcounter + 1
Next j
callvalue = Application.Max(S0 * (up ^ upcounter) * (down ^ (pathlength - upcounter)) - Exercise, 0) / (interestdelta ^ pathlength)
Temp = Temp + callvalue
Next Index
VanillaCall = Temp / Runs
End Function
parameters are passed from cells in excel.
i want to execute this function from button click and display return value in a cell say b12.
i have tried putting the code inside a button sub but its not working ,a call vanillacall inside sub too isnt working.
like..
private sub button1_click()
call vanillacall
end sub
Private Sub button1_click()
Range("B12").Value = vanillacall(....)
End Sub
As per your request, Pass arguments in Range like below. Below code is just for example (due to the changes in excel data)
Sub testing33()
Range("B12") = sample(Range("A5"), Range("B5"))
End Sub
Function sample(a As Range, b As Range)
sample = a.Cells.Value & ", " & b.Cells.Value
End Function
I'd do something like the below which would allow me to pick the range containing the data I want to pass to the function (as long as the range is contiguous and contains 8 cells) and pick the cell I want to output the result to.
Private Sub button1_click()
Dim inRng As Range, outRng As Range
inSelect:
Set inRng = Application.InputBox("Select Range to Calculate", Type:=8)
If inRng.Cells.Count <> 8 Then
MsgBox "Select a range with 8 cells!", vbCritical
GoTo inSelect
End If
outSelect:
Set outRng = Application.InputBox("Select Cell to Output To", Type:=8)
If outRng.Cells.Count > 1 Then
MsgBox "Select only one cell!", vbCritical
GoTo outSelect
End If
outRng.Value = VanillaCall(inRng.Cells(1), inRng.Cells(2), inRng.Cells(3), inRng.Cells(4), inRng.Cells(5), inRng.Cells(6), inRng.Cells(7), inRng.Cells(8))
End Sub
You need to get the values from the sheet and save in variables. Then pass the variables to the function. Then output the result to the sheet somewhere. You will need to adjust the range addresses and worksheet name as appropriate.
Private sub button1_click()
dim ws as worksheet
Set ws = worksheets("Sheet1") ' < change the sheet name as appropriate
dim S0 As Single
dim Exercise As Single
dim Mean As Single
dim sigma As Single
dim Interest As Single
dim Time As Single
dim Divisions As Integer
dim Runs As Integer As Single
S0 = ws.Range("B1") '< specify the cell that has this data
Exercise = ws.Range("B2") '< specify the cell that has this data
Mean = ws.Range("B3") '< specify the cell that has this data
sigma = ws.Range("B4") '< specify the cell that has this data
Interest = ws.Range("B5") '< specify the cell that has this data
Time = ws.Range("B6") '< specify the cell that has this data
Divisions = ws.Range("B7") '< specify the cell that has this data
Runs = ws.Range("B8") '< specify the cell that has this data
dim Result as Single
Result = vanillacall(S0, Exercise , Mean, sigma, Interest, Time, Divisions, Runs)
ws.Range("B10") = Result '<specify the cell where you want the result
end sub

Get Cell Value in Excel from Range

How can I extract the value of a cell from a range object? It seems like it should be simple. This Stackoverflow question and answers did not really help. Here is what I want to do but it fails every time with an exception on row.columns(0,0).
Dim rdr = oFindings.Range
For Each row As Excel.Range In rdr.Rows
Dim Account = row.Columns(0,0).value2.tostring
' Do other stuff
Next
To make it work I had to implement this code:
For Each row As Excel.Range In rdr.Rows
ndx = 0
For Each cell As Excel.Range In row.Columns
If ndx = 0 Then Account = NS(cell.Value2)
' Do other stuff
ndx += 1
next
Next
That seems like such a kludge. What is the secret?
Most of the problems have already been alluded to, but here is the answer with code.
Dim rdr As Excel.Range = oFindings.Range
For Each row As Excel.Range In rdr.Rows
'explicitly get the first cell as a range
Dim aCell As Excel.Range = row.Cells(1, 1)
'explicity convert the value to String but don't use .String
Dim Account as string = CStr(aCell.Value2)
If Not String.IsNullOrEmpty(Account) Then
' Do other stuff
End If
Next
Using aCell.Value2.toString will fail if the cell is empty because Value2 will be Nothing. Instead use CStr(aCell.Value2) which won't fail. But then you need to test if the string is null or empty before using the value.