Can't copy a value from one worksheet over to an array in another worksheet - arrays

In the same workbook, I've got two worksheets: Model and Results.
My goal is to copy the value of a cell in Model (for e.g., F8) over to a cell in an array (c4 to I23) in Results called ResultsArray (see code below).
When I run my module, no error appears, but the code doesnt seem to work either (the value of F8 doesnt get copied over to the specified cell in ResultsArray).
Appreciate any help.
Tried running different variations of the code below
Sub CopyTest()
Dim ResultsArray As Variant
ResultsArray = Worksheets("Results").Range("C4:I23")
ResultsArray(1, 1) = Worksheets("Model").Range("F8").Value
End Sub
I'm using ResultsArray(1,1) because I am hoping to introduce a loop into the code to populate cells in the array based on the loop counter, e.g., ResultsArray(loopcounter,1)

So turns out I just needed to add "Set" in the 2nd line before "ResultsArray" when assigning the range from the worksheet "Model" to it:
Sub CopyTest()
Dim ResultsArray As Variant
Set ResultsArray = Worksheets("Results").Range("C4:I23")
ResultsArray(1, 1) = Worksheets("Model").Range("F8").Value
End Sub
I've tested this addition and it works

Related

application defined or object defined error whey copying data into array

I am used to assigning ranges to arrays. However, for some reason right now I am constantly getting an application or object defined error (the first code line below). The second line below works fine. It is identical to the first line except I just copy the range showing all the variables exist.
I have checked in the watch window, arrActuals is Variant/Variant(). Adding .Value at the end of the first line did not solve the error either. Any ideas on why this is happening?
arrActuals = wkbOVHFile.Sheets(szAOPPage).Range(Cells(iStartCopy, IntActOVHCol), Cells(iEndCopy, IntActOVHCol))
wkbOVHFile.Sheets(szAOPPage).Range(Cells(iStartCopy, IntActOVHCol), Cells(iEndCopy, IntActOVHCol)).Copy
Cells without a qualifying worksheet object defaults to the active sheet, so your code fails when wkbOVHFile.Sheets(szAOPPage) is not the active sheet.
More robust like this:
Dim rng As Range
With wkbOVHFile.Sheets(szAOPPage)
Set rng = .Range(.Cells(iStartCopy, IntActOVHCol), _
.Cells(iEndCopy, IntActOVHCol))
End With
arrActuals = rng.Value
rng.Copy

Visio VBA - How can I distribute shapes with a known, fixed distance

I'd like to place all currently selected shapes into an array. I'd then like to sort that array so I can find either the top most or left most shape in the array. I'd then like to use that shape as my starting point, and then from there align the other shapes a fixed, known distance apart. I've tried to place the shapes into an array like so:
Dim numShapes As Integer, i As Integer
Dim arrShapes As Visio.Selection
numShapes = Visio.ActiveWindow.Selection.Count
For i = 1 To numShapes
arrShapes(i) = Visio.ActiveWindow.Selection(i)
Next i
I have tried to create the array with no type specification, specifying as variant, and as in this example as selection. I don't know if I can put them into a list of some kind either? Obviously I can't get to the point of sorting the array and then distributing my shapes until I can get the array to populate. I'm placing a break point in the code and I have the "Locals" window open and I can see that the array is not being populated.
Update:
Why does this work,
Dim Sel As Visio.Selection
Dim Shp As Visio.Shape
Set Sel = Visio.ActiveWindow.Selection
For Each Shp in Sel
Debug.Print Shp.Name
Next
And this does not?
Dim i As Integer
Dim Shp As Visio.Shape
For i = 1 To Visio.ActiveWindow.Selection.Count
Set Shp = Visio.ActiveWindow.Selection(i)
Debug.Print Shp.Name
Next i
Regards,
Scott
There was a couple of problems in your code - fixing only one would not have got you any further in understanding if you had actually fixed anything.
Your arrShapes is declared as a general object - the Selection
Object is one of those objects that is the Jack of all trades, and
master of none.
You didn't "Set" when assigning to the array.
I don't have Visio on this machine, so cannot directly test the code below. I am also assuming that all items selected are shapes (usually a safe assumption in Visio).
Dim numShapes As Integer, i As Integer
Dim arrShapes() As Shape ' Set this up as an array of shape
If Visio.ActiveWindow.Selection.Count > 0 then ' don't want to cause a problem by setting the array to 0!
ReDim arrShapes(Visio.ActiveWindow.Selection.Count)
numShapes = Visio.ActiveWindow.Selection.Count ' while not really necessary it does help explain the code.
For i = 1 To numShapes
' must Set as we want the reference to the shape, not the default value of the shape.
Set arrShapes(i) = Visio.ActiveWindow.Selection(i)
Next i
Else
MsgBox "No shapes selected. Nothing done." ' soft fail
End If

VBA Excel 2013: Assign Array Values from Another UserForm

I'm relatively new to VBA. I have a program I'm writing where the user is given the option to change their input from a 2 dimensional array in another user form.
The first user form, UserForm1, allows the user to input the information from text fields and saves it to the respective array row, i, when pressing a Save command button.
When the user presses an OK command button, the user is asked if they want to add another set of data. If they say no, they are asked if they want to change data. If they say yes, then another user form, UserForm2, is opened.
The code for UserForm1 is similar to the code below:
Public MyArray as Variant, i as Integer
Sub Userform_Initialize()
ReDim MyArray(100,4)
End Sub
Sub SaveButton_click()
MyArray(i, 1) = TextField1.Value
MyArray(i, 2) = TextField2.Value
MyArray(i, 3) = TextField3.Value
MyArray(i, 4) = TextField4.Value
End Sub
Sub OKButton_click()
If msgbox("Do you want to add more data?", vbYesNo) = vbNo Then
If msgbox("Do you have corrections to be made?",vbYesNo) = vbYes Then
Load UserForm2
UserForm2.Show
Else: Exit Sub
End If
Else: i = i + 1
Exit Sub
End If
End Sub
In UserForm2, the user chooses the row number, i, from a combo box. When the row number is selected, the array information is automatically populated in text fields from UserForm1.
When the user presses the Save command button, it should pass the information from the text fields and write it to the respective row.
The code for UserForm2 is similar to the code below:
Public j as integer
Sub Userform_Initialize()
For j = 1 to UserForm1.i
ComboBox1.AddItem (j)
Next
End Sub
Sub SaveButton_click()
UserForm1.MyArray(ComboBox1.Value, 1) = TextField1.Value
UserForm1.MyArray(ComboBox1.Value, 2) = TextField2.Value
UserForm1.MyArray(ComboBox1.Value, 3) = TextField3.Value
UserForm1.MyArray(ComboBox1.Value, 4) = TextField4.Value
End Sub
Stepping through the code, the values from MyArray should be properly referenced, and I can see the values initially saved from UserForm1. However, the values are not changing as I step to the next line.
Does anyone have a solution for my problem? Thank you in advance for your help!
I believe I found my solution. I had to declare the array in the module containing the code to start the program as a public variable. After I did that and modified the code, the values were written properly to the array.
If anyone has other solutions, though, I would like to know. I'm not that experienced with VBA, so I want to hear other solutions.

Re-Initializing "ThisWorkbook.Path"

First, thanks to those of you who gave me the suggestion on using "ThisWorkbook.Path". It worked like a charm.
However, my code walks through seven (7) workbooks and when using "ThisWorkbook.Path" I can not re-initialize the "This.Workbook". Let me elaborate.
This is the workbook where the Macro resides:
Workbooks("Financial_Aggregator_v3.xls").Activate
This is the first workbook where the code adds a tab and does sub-totals. Basically, ThisWorkbook.Path works here:
Workbooks("Chapter_7-10_Mechanical.xls").Activate
After doing what I need done with "Mechanical" I have the following code snippet, which never turns out TRUE:
Workbooks("Financial_Aggregator_v3.xls").Activate
If FileThere(ThisWorkbook.Path & Application.PathSeparator & "Chapter_7-90_ECS_1_LLC.xls") Then
The code for the function, which works for the "Mechanical" sheet is:
Function FileThere(FileName As String) As Boolean
FileThere = (Dir(FileName) > "")
End Function
FYI, I tried to break all of the different Workbooks into different Sub(), but that didn't work. I also triple-checked the name of the workbooks.
Thanks in advance.
"ThisWorkbook" in Excel.VBA is sort of like "Me", in that it only applies to the workbook (.XLS) that actually holds the VBA code that is executing the "ThisWorkbook". What you need to do is to use Workbook objects to abstract the particular workbook that you want to test or manipulate.
Try something like this:
Public Sub TestWB()
Dim CurrWB As Workbook
'To get a workbook into our object variable:'
Set CurrWB = Workbooks("Chapter_7-10_Mechanical.xls")
'To Change the .Path:'
CurrWB.SaveAs NewFileName, AddToMru:=True
End Sub

How to fill-up cells within a Excel worksheet from a VBA function?

I simply want to fill-up cells in my spreadsheet from a VBA function. By example, I would like to type =FillHere() in a cell, and in result I will have a few cells filled-up with some data.
I tried with such a function:
Function FillHere()
Dim rngCaller As Range
Set rngCaller = Application.Caller
rngCaller.Cells(1, 1) = "HELLO"
rngCaller.Cells(1, 2) = "WORLD"
End Function
It breaks as soon as I try to modify the range. Then I tried this (even it's not really the behavior I'm looking for):
Function FillHere()
Dim rngCaller As Range
Cells(1, 1) = "HELLO"
Cells(1, 2) = "WORLD"
End Function
This is not working neither. But it works if I start this function from VBA using F5! It seems it's not possible to modify anything on the spreadsheet while calling a function... some libraries do that though...
I also tried (in fact it was my first idea) to return a array from the function. The problem is that I only get the first element in the array (there is a trick that implies to select a whole area with the formula at the top left corner + F2 + CTRL-SHIFT-ENTER, but that means the user needs to know by advance the size of the array).
I'm really stuck with this problem. I'm not the final end-user so I need something very easy to use, with, preferably, no argument at all.
PS: I'm sorry I asked this question already, but I wasn't registered at that time and it seems that I can't participate to the other thread anymore.
You will need to do this in two steps:
Change your module to be something like:
Dim lastCall As Variant
Dim lastOutput() As Variant
Function FillHere()
Dim outputArray() As Variant
ReDim outputArray(1 To 1, 1 To 2)
outputArray(1, 1) = "HELLO"
outputArray(1, 2) = "WORLD"
lastOutput = outputArray
Set lastCall = Application.Caller
FillHere = outputArray(1, 1)
End Function
Public Sub WriteBack()
If IsEmpty(lastCall) Then Exit Sub
If lastCall Is Nothing Then Exit Sub
For i = 1 To UBound(lastOutput, 1)
For j = 1 To UBound(lastOutput, 2)
If (i <> 1 Or j <> 1) Then
lastCall.Cells(i, j).Value = lastOutput(i, j)
End If
Next
Next
Set lastCall = Nothing
End Sub
Then in order to call the Sub go into the ThisWorkbook area in VBA and add something like:
Private Sub Workbook_SheetCalculate(ByVal Sh As Object)
Call WriteBack
End Sub
What this does is return the value of the topleft cell and then after calculation completes populates the rest. The way I wrote this it assumes only one FillHere function will be called at a time. If you want to have multiple ones which recalculate at the same time then you will need a more complicated set of global variables.
One word of warning is that this will not care what it overwrites when it populates the other cells.
Edit:
If you want to do this on a Application wide basis in an XLA. The code for the ThisWorkbook area should be something like:
Private WithEvents App As Application
Private Sub App_SheetCalculate(ByVal Sh As Object)
Call WriteBack
End Sub
Private Sub Workbook_Open()
Set App = Application
End Sub
This will wire up the Application Level calculation.
What you're trying to do won't work in Excel - this is by design.
You can do this, though:
Function FillHere()
Redim outputArray(1 To 1, 1 To 2)
outputArray(1, 1) = "HELLO"
outputArray(1, 2) = "WORLD"
FillHere = outputArray
End Function
If you then select two adjacent cells in your worksheet, enter =FillHere() and press Control+Shift+Enter (to apply as an array formula) then you should see your desired output.
Fundamentally, a function can only affect the cell it is called from. It sounds like you may need to look at using the Worksheet_Change or Worksheet_SelectionChange events to trigger the modification of cells in the intended range.
You can do this indirectly using a 2-stage process:
Write your UDF so that it stores data in a sufficiently persistent way (for example global arrrays).
then have an Addin that contains application events that fire after each calculation event, looks at any data stored by the UDFs and then rewrites the neccessary cells (with warning messages about overwrite if appropriate) and reset the stored data.
This way the user does not need to have any code in their workbook.
I think (but do not know for sure) that this is the technique used by Bloomberg etc.

Resources