Is there a command equivalent to readLine of Java in VBA.
I want to use the text input in the immediate window and put it in a variable.
Is it possible?
You can't use the Immediate Window interactively. For one thing -- while a sub is running it won't accept any keyboard input. You can, however, use it to pass data to a sub or function when you invoke it, so in a sense you can "scrape" data that is there already. Something along these lines:
Sub AddNums(ParamArray nums())
Dim total As Double
Dim i As Long
For i = 0 To UBound(nums)
total = total + nums(i)
Next i
Debug.Print total
End Sub
For example:
Beyond that -- you could move the input-gathering phase to a VBScript script running in console mode, invoke it from VBA, and use either a file (which the script writes to) or perhaps the clipboard to get the data from the script after it is done running. This should be feasible, though it is probably better to find a more idiomatic (form-based) way to do it within VBA.
I am not quite sure why you need to write from Immediate Window to a variable at a runtime - is it some weird debugging practices?
Normally, if you need to take an input you end up with a form to interact with an user.
However, if you do need to write to a variable at a runtime consider the following:
Sub Main()
Dim immediateInput As String
Dim readImmediate As Boolean
Do While (readImmediate = False)
readImmediate = True
Loop
End Sub
now, set a breakpoint at the readImmediate = true line and add immediateInput to the Watch. Bring up both the Immediate Window and Watches and run the macro.
When the runtime hits the breakpoint enter the below in the Immediate Window:
immediateInput = "hello world"
Now have a look in the Watches; your immediateInput's value should be "hello world".
Related
I am attempting to reduce the amount of clutter on my code by creating "shortcuts" if you will
For instance, I always have to type
ThisWorkBook.ActiveSheet.Range
Is there a way for me to define the above to create a less wordy macro? I have tried convert to range and string and the former returns an error (but I could still get intellisense recognize and attempt to autofill) while the string version doesnt work.
Just like in any programming language, you can use variables to store data
For example:
Dim myrange As Range: Set myrange = Sheets("Sheet1").Range("B5")
Alternatively, if you will be working with the same object multiple times, you can use the With keyword
For example. instead of writing you want to work with table every time on every new line you can do
With Sheets("Sheet1").ListObjects("Table1")
.ListRows.Add
.ListColumns(2).Range(3) = "Hello World!"
' ... and so on
End With
Also, please on a sidenote: Avoid using Select/ActiveSheet/ActiveWorkbook and so on!
More info on how to here
You can create functions or customized properties, which are always evaluated when called
Property Get pARng As Range
Set pARng = ThisWorkBook.ActiveSheet.Range
End Property
Function fARng As Range
Set fARng = ThisWorkBook.ActiveSheet.Range
End Function
'Usage
Sub xxx
'...
pARng.Rows(1).Activate
'Same as ThisWorkBook.ActiveSheet.Range.Rows(1).Activate
fARng.Rows(1).Activate
'using function instead achieves same result
End Sub
I would like to know if there is an equivalent of Python's pass statement in VBA.
I am using Excel 2016.
The use of Stop (see this answer) seems to be the best thing to do if you are looking for some "non-statement" that you can use to insert a breakpoint, because the Stop command causes the code to break when it is reached, i.e. you don't even need to mark it as a breakpoint because it is one.
You might also like to consider using Debug.Assert some_logical_expression, which will break automatically whenever the logical expression evaluates to False. So Debug.Assert False would be equivalent to Stop, and Debug.Assert x = 3 would be equivalent to If x <> 3 Then Stop.
In Python you need the Pass, because otherwise the methods will not run.
In VBA, its perfectly ok if you leave an empty method like this:
Public Function Foo() As String()
End Function
Maby you are looking for the "Stop" statement.
The good thing about it is that it doesn't clear your variables.
It depends what are you trying to achieve.
You may declare a Label and then use GoTo Label e.g. declare a label (like Skip:)in your code where you want to jump if a condition is met and then use GoTo Skip
Below is the small demo code to give you an idea about this...
Dim i As Long
For i = 1 To 10
If i = 5 Then GoTo Skip
MsgBox i
Next i
Skip:
I need to automatize a process which execute various (a lot) user-defined function with different input parameters.
I am using the solution of timer API found in I don't want my Excel Add-In to return an array (instead I need a UDF to change other cells) .
My question is the following: "Does anybody can explain to me HOW IT IS WORKING?" If I debug this code in order to understand and change what I need, I simply go crazy.
1) Let say that I am passing to the public function AddTwoNumbers 14 and 45. While inside AddTwoNumber, the Application.Caller and the Application.Caller.Address are chached into a collection (ok, easier than vectors in order not to bother with type). Application.Caller is kind of a structured object where I can find the function called as a string (in this case "my_function"), for example in Application.Caller.Formula.
!!! Nowhere in the collection mCalculatedCells I can find the result 59 stored.
2)Ok, fair enough. Now I pass through the two UDF routines, set the timers, kill the timers.
As soon as I am inside the AfterUDFRoutine2 sub, the mCalculatedCell(1) (the first -- and sole -- item of my collection) has MAGICALLY (??!?!?!!!??) obtained in its Text field exactly the result "59" and apparently the command Set Cell = mCalculatedCells(1) (where on the left I have a Range and on the right I have ... I don't know) is able to put this result "59" into the variable Cell that afterward I can write with the .Offset(0,1) Range property on the cell to the right.
I would like to understand this point because I would like to give MORE task to to inside a single collection or able to wait for the current task to be finished before asking for a new one (otherwise I am over-writing the 59 with the other result). Indeed I read somewhere that all the tasks scheduled with the API setTimer will wait for all the callback to be execute before execute itself (or something like this).
As you can see I am at a loss. Any help would be really really welcomed.
In the following I try to be more specific on what (as a whole)
I am planning to achieved.
To be more specific, I have the function
public function my_function(input1 as string, Field2 as string) as double
/*some code */
end function
I have (let's say) 10 different strings to be given as Field2.
My strategy is as follow:
1)I defined (with a xlw wrapper from a C++ code) the grid of all my input values
2)define as string all the functions "my_function" with the various inputs
3)use the nested API timer as in the link to write my functions IN THE RIGHT CELLS as FORMULAS (not string anymore)
3)use a macro to build the entire worksheet and then retrieve the results.
4)use my xlw wrapper xll to process further my data.
You may wonder WHY should I pass through Excel instead of doing everything in C++. (Sometime I ask myself the same thing...) The prototype my_function that I gave above has inside some Excel Add-In that I need to use and they work only inside Excel.
It is working pretty well IN THE CASE I HAVE ONLY 1 "instance" of my_function to write for the give grid of input. I can even put inside the same worksheet more grids, then use the API trick to write various different my_functions for the different grids and then make a full calculation rebuild of the entire worksheet to obtain the result. It works.
However, as soon as I want to give more tasks inside the same API trick (because for the same grid of input I need more calls to my_function) I am not able to proceed any further.
After Axel Richter's comment I would like to ad some other information
#Axel Richter
Thank you very much for your reply.
Sorry for that, almost surely I wasn't clear with my purposes.
Here I try to sketch an example, I use integer for simplicity and let's say that my_function works pretty much as the SUM function of Excel (even if being an Excel native function I could call SUM directly into VBA but it is for the sake of an example).
If I have these inputs:
input1 = "14.5"
a vector of different values for Field2, for instance (11;0.52;45139)
and then I want to write somewhere my_function (which makes the sum of the two values given as input).
I have to write down in a cell =my_function(14.5;11), in the other =my_function(14.5;0.52) and in a third one =my_function(14.5;45139).
These input changes any time I need to refresh my data, then I cannot use directly a sub (I think) and, in any case, as far as I understand, in writing directly without the trick I linked, I will always obtain strings : something like '=my_function(14.5;0.52). Once evaluated (for example by a full rebuild or going over the written cell and make F2 + return) will give me only the string "=my_function(14.5;0.52)" and not its result.
I tried at the beginning to use an Evaluate method which works well as soon as I write something like 14.5+0.52, but it doesn't work as soon as a function (nor a user-defined function) is used instead.
This is "as far as I can understand". In the case you can enlighten me (and maybe show an easier track to follow), it would be simply GREAT.
So far the comments are correct in that they repeat the simple point that a User-Defined Function called a worksheet can only return a value, and all other actions that might inject values elsewhere into the worksheet calculation tree are forbidden.
That's not the end of the story. You'll notice that there are add-ins, like the Reuters Eikon market data service and Bloomberg for Excel, that provide functions which exist in a single cell but which write blocks of data onto the sheet outside the calling cell.
These functions use the RTD (Real Time Data) API, which is documented on MSDN:
How to create a RTD server for Excel
How to set up and use the RTD function in Excel
You may find this link useful, too:
Excel RTD Servers: Minimal C# Implementation
However, RTD is all about COM servers outside Excel.exe, you have to write them in another language (usually C# or C++), and that isn't the question you asked: you want to do this in VBA.
But I have, at least, made a token effort to give the 'right' answer.
Now for the 'wrong' answer, and actually doing something Microsoft would rather you didn't do. You can't just call a function, call a subroutine or method from the function, and write to the secondary target using the subroutine: Excel will follow the chain and detect that you're injecting values into the sheet calculation, and the write will fail.
You have to insert a break into that chain; and this means using events, or a timer call, or (as in RTD) an external process.
I can suggest two methods that will actually work:
1: Monitor the cell in the Worksheet_Change event:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim strFunc As String strFunc = "NukeThePrimaryTargets" If Left(Target.Formula, Len(strFunc) + 1) = strFunc Then Call NukeTheSecondaryTargets End If End Sub
Alternatively...
2: Use the Timer callback API:
However, I'm not posting code for that: it's complex, clunky, and it takes a lot of testing (so I'd end up posting untested code on StackOverflow). But it does actually work.
I can give you an example of a tested Timer Callback in VBA:
Using the VBA InputBox for passwords and hiding the user's keyboard input with asterisks.
But this is for an unrelated task. Feel free to adapt it if you wish.
Edited with following requirements: It is necessary to run a user defined worksheet function, because there are addins called in this function and those work only within a Excel sheet. The function has to run multiple times with different parameters and its results have to be gotten from the sheet.
So this is my solution now:
Public Function my_function(input1 As Double, input2 As Double) As Double
my_function = input1 + input2
End Function
Private Function getMy_Function_Results(input1 As Double, input2() As Double) As Variant
Dim results() As Double
'set the Formulas
With Worksheets(1)
For i = LBound(input2) To UBound(input2)
strFormula = "=my_function(" & Str(input1) & ", " & Str(input2(i)) & ")"
.Cells(1, i + 1).Formula = strFormula
Next
'get the Results
.Calculate
For i = LBound(input2) To UBound(input2)
ReDim Preserve results(i)
results(i) = .Cells(1, i + 1).Value
Next
End With
getMy_Function_Results = results
End Function
Sub test()
Dim dFieldInput2() As Double
Dim dInput1 As Double
dInput1 = Val(InputBox("Value for input1"))
dInput = 0
iIter = 0
Do
dInput = InputBox("Values for fieldInput2; 0=END")
If Val(dInput) <> 0 Then
ReDim Preserve dFieldInput2(iIter)
dFieldInput2(iIter) = Val(dInput)
iIter = iIter + 1
End If
Loop While dInput <> 0
On Error GoTo noFieldInput2
i = UBound(dFieldInput2)
On Error GoTo 0
vResults = getMy_Function_Results(dInput1, dFieldInput2)
For i = LBound(vResults) To UBound(vResults)
MsgBox vResults(i)
Next
noFieldInput2:
End Sub
The user can input first a value input1 and then input multiple fieldInput2 until he inputs the value 0. Then the results will be calculated and presented.
Greetings
Axel
The Problem
I am trying to debug some code, and somewhere in the middle I stopped at a breakpoint. Now I want to change some variables and run a certain loop several times.
How far did I get?
I know how to change the variables, but somehow I get stuck when trying to run the loop in the immediate window. Here is an example:
Dim i As Integer
Dim j As Integer
For i = 0 To 6
j=i ' Do something
Next i
I tried several variations of the code, but each time I get the following error:
Compile error: Next without for
Other relevant information
I tried searching but mostly found information about problems with loops, whilst I am quite sure the loop itself is fine. (Especially as I reached it before arriving at the breakpoint).
The only place I saw someone addres this situation, he reduced the loop to a single line, however to do this every time would be very impractical in my case.
I realize that I could call a function containing the loop, and then the function call would probably work, but again this feels quite impractical. So I guess it boils down to the following question.
The question
What is a practical way to run a loop whilst debugging VBA code in Excel?
There is actually a way for using loops or other multi-line statements in the Immediate Window - using a colon : to separate statements instead of a new line.
Full solution is described here.
Note that in the Immediate Window you also don't have to declare the variables using a Dim statement.
To summarize, your snippet would look something like this:
For i = 0 To 6: j=i: debug.Print i+j: Next i
I think I understand your question. You want to run a multi-line code block (i.e. the loop) in the Immediate Window. This throws errors because the Immediate Window is only intended for single lines of code.
I don't have any suggestions other than those you already mentioned. I'd recommend putting your test loop into a separate function and calling that from the Immediate Window:
Sub Test()
Dim i As Integer
Dim j As Integer
For i = 0 To 6
j=i ' Do something
Next i
End
Another option is to set several breakpoints. You can also run one line of code at a time with F8.
What is likely the preferred method (i.e., what most people actually do) is use the full power of the IDE, which includes the Immediate, Locals and Watch panes. You can change the value of most variables at runtime by direct assignment in the Immediate Pane (i=6 will do exactly what you think it should do). The IDE also allows you to set breakpoints, add watch conditions, step through code line-by-line using the F8, step through function or procedure calls using Shift+F8, stepping over (and back) through code using the mouse/cursor, and with a few exceptions, you can even add new variables during runtime.
I've encountered a very strange bug in VBA and wondered if anyone could shed some light?
I'm calling a worksheet function like this:
Dim lMyRow As Long
lMyRow = WorksheetFunction.Match(vItemID, rngMyRange.Columns(1), 0)
This is intended to get the row of the item I pass in. Under certain circumstances (although I can't pin down exactly when), odd things happen to the call to the Match function.
If I execute that line in the immediate window, I get the following:
lMyRow = WorksheetFunction.Match(vItemID, rngMyRange.Columns(1), 0)
?lMyRow
10
i.e. the lookup works, and lMyRow gets a value assigned to it. If I let that statement execute in the actual code, I lMyRow gets a value of 0.
This seems very odd! I don't understand how executing something in the immediate window can succeed in assigning a value, where the same call, at the same point in program execution can give a value of 0 when it runs normally in code!
The only thing I can think of is that it's some odd casting thing, but I get the same behaviour taking if the variable to which I'm assigning is an int, a double, or even a string.
I don't even know where to begin with this - help!!
The only difference between the immediate window and normal code run is the scope.
Code in the immediate window runs in the current application scope.
If nothing is currently running this means a global scope.
The code when put in a VBA function is restricted to the function scope.
So my guess is that one of your variables is out of scope.
I would put a breakpoint in your function on that line and add watches to find out which variable is not set.
And if you don't have Option Explicit at the top of your vba code module, you should add it.
You're not assigning the function name so that function will always return zero (if you're expecting a Long). It seems you should have
makeTheLookup = lMyRow
at the end of your function.
I don't know if you are still looking at this or not but I would have written it this way:
Function makeTheLookup(vItemID As Variant, rngMyRange as Range)as Long
makeTheLookUp = WorksheetFunction.Match(vItemID, rngMyRange.Columns(1), 0)
End Function
I cannot reproduce the problem with Excel 2007.
This was the code I used:
Sub test()
Dim vItemID As Variant
Dim lMyRow As Long
Dim rngMyRange As Range
Set rngMyRange = ActiveWorkbook.Sheets(1).Range("A1:Z256")
vItemID = 8
lMyRow = WorksheetFunction.Match(vItemID, rngMyRange.Columns(1), 0)
Debug.Print lMyRow
End Sub
It may sound stupid but are you sure that all parameters of the Match function are the same in your macro and in the immediate window? Maybe the range object has changed?
Thanks for the answers guys - I should have been slightly more specific in the way I'm making the call below:
Function makeTheLookup(vItemID As Variant, rngMyRange as Range)
Dim lMyRow As Long
lMyRow = WorksheetFunction.Match(vItemID, rngMyRange.Columns(1), 0)
End Function
The odd thing is, I'm passing the two parameters into the function so I can't see any way they could be different inside and outside of the function. That said, I'm still entirely clueless as to what's causing this, particularly since it's a really intermittent problem
Is there any easy way of comparing the range object in the function context to the range object in the Immediate window context and telling if they're different? Given that range is a reference type, it feels like I should just be able to compare two pointers, but I've got no idea how to do that in VBA!
I'm using Excel 2007 by the way, although I'm not sure if that makes any difference.
As will has mentioned above, It most definitely seems like a problem of scope. Or an Obscure Bug.
I would try to use Debug.print statements, as well as Watch, and see if they match up, and take it from there.