VBA Spliting Code and passing arguments - vba

I'm quite a beginner at coding and the problem that I'm having is that the procedure is too large. I read that this can be fixed by dividing the code into smaller modules. However I want to know if the values of the variables defined outside the modules can be taken into account when you call the variable inside the modules to modify it. Also, after being modified can you use the new value outside the module and in another module? Can someone explain me how the VBA works in these cases? Thank you so much.
I read the answer you gave me but while i understand the concept there is no example that fit my case. I would really appreciate an example so I can fully understand how to solve my issue. What i have is basically:
sub simulador()
Sheets(2).Activate
With ActiveSheet
a=1
b=1
c=1
for t=2 to 20
procedure using and modifying variables a and c
b=cells(t,15)
for a=2 to 20
code using variable b
next a
d=3
j=9
procedure using the variables a b and j
for ga=2 to 20
code using variable d
next ga
next t
end with
end sub
And what i need to do is create a sub1 whit:
procedure using and modifying variables a and c
b=cells(t,15)
A sub 2 whit:
for a=2 to 20
code using and modifying variable b
next a
An sub 3 whit:
procedures using the variables a b and j
for ga=2 to 20
code using variable d
next ga
So at the end would be like:
sub simulador()
Sheets(2).Activate
With ActiveSheet
a=1
b=1
c=1
for t=2 to 20
Call sub 1
Call sub 2
d=3
j=9
Call sub 3
next t
end with
end sub
In all the cases i want to call the subroutines passing the variables Byref so once they are modified stay modified so another sub can use them with the new value. Also the active sheet should remain active when the procedures in those subroutines are executed. I can't figure out how everything works exactly. Thanks for your help.

I don't have the will to spend time in explain how this works, because these are there very basics of programming, so.... search on google this:
vb function passing parameter difference byref and byval

Related

How to make my module move an object using value set in UserForm/

I'm trying to automatize some processes I often do at work. Unfortunately I have no clue about programming so I've been struggling a lot with this.
I have an userform that has a textbox where you're supposed to type in how much you want the object to be moved on X axis. There are multiple objects and I can't wait to experiment how to move them all in proper direction, but the issue is, I can't even move one.
I created a variable, but I can't seem to be able to use it with Object.Move.
Right now VBA tells me to assign the values to an array, so I did that, but I can't put variables into an array apparently.
I've tried simply declaring the variable as public, calling it let's say for example "Value", and using Object.Move (Value), 0
or
Object.Move Value(), 0
Tried both, because I was not sure which one is correct.
After many trials I finally skipped most of the previous errors I was getting, and now I'm stuck at trying to set up an Array using a variable from the UserForm.
Here's the code inside Userform
VBA
Public Sub TextBox1_Initialize()
M = TextBox1
Unload M
End Sub
And here's the code inside the module
VBA
Public M As Integer
Sub Move()
Dim XY(M, 0) As Integer
Object.Move XY
End Sub

How can I run several macros where the Macro name begins with a specific string of characters?

I've created several custom functions which I would like to Register. Currently, I have a different procedure for which I specify the registration for each function (there's no issue with that piece). However, the only way I know of to registering all these functions is by calling each Macro by name in another procedure like this:
Sub spRegisterFunctions()
Call spRegisterCUSTOMAfunction
Call spRegisterCUSTOMBfunction
Call spRegisterCUSTOMCfunction
Call spRegisterCUSTOMDfunction
End Sub
I'm actually looking for something more dynamic so that every time I create a new function, and it's corresponding "spRegister..." procedure, I don't have to remember to add the "Call" code to the "Sub spRegisterFunction()" procedure for that specific function.
Here's an example of what attempting to do:
Sub spRegisterFunctions()
Dim mc as Macro
For Each mc in VBProject("NameOfProject").Module("NameOfModule")
If Left(mc.Name,10)="spRegister" then
Call mc
End If
Next mc
End Sub
As you can see, I'm attempting to run any macro in a specific module who's name begins with "spRegister". Obviously the code above will not work, partly because some of those objects don't even exist.
Is there any way to do this?

How to pass formula to another procedure?

Sorry if this question looks quite random, as I am still learning VBA.
So thing is that my procedure requires input variable for the conditional formatting formula, and I am not quite sure if it requires me to pass on the formula from another procedure.
i.e.
Sub Procedure1 (FormulaX As ??)
With Worksheets("Sheet1").Range("Range1").FormatConditions. _
Add(Type:=xlExpression, Formula1=FormulaX)
...
End With
End Sub
Sub Procedure2
Call Procedure1 ("=$A1<5")
End Sub
I am very beginner into the VBA and I am quite confused with passing variables for conditional formatting formula. (Maybe I am finding it hard to understand the sentence clearly)
Or if there is any other way to approach this, what will that be?
Edit: Instruction given is "Your procedure definition should require input variables for the conditional formatting formula"
You can just do:
Sub Procedure1 (FormulaX As String)
....
The instructions simply asks for an input, which can be realized with a String.

How to read specific lines of codes in another sub?

I was wondering if there is a way to run specified lines of code in another sub , say execute only line 1 through line 10 of Sub_2 before executing the code in say, Sub_1.
I have done some background research and found up a code suggested by #Andrew below.
Private Sub Sub_1(sender As System.Object, e As System.EventArgs) Handles Button1.Click
'Call the Save Sub
Call Sub_2(sender, e)
'Proceed to execute the rest of the this Sub_1
What the above code does at the moment is execute the entire sub I have called, which is not what I want to achieve.
I have also read about the using a shared routine common to both Subs as suggested by #Henry , but the problem for me is that variables are declared in the shared routine which are required at various stages in Sub_2, but which cannot be used as the program says they are not declared (in Sub_1).
Again, what I want to achieve is execute only a few lines of code from Sub_2 in Sub_1.
I am using Visual Basic 2010 Express.
What you are trying to do is technically possible (in various really hackish ways), but would easily become a code structure nightmare. Instead, consider an alteration to the way you are building your routines.
Subs and Functions are intended to be independent 'islands' of code, which can execute (generally) without knowing anything about the rest of the program. You can pass variables into them, and get variables back, but they should operate the same time after time.
Consider this theoretical code from the scenario you are proposing:
Dim variable_1
Private Sub Sub_1()
Dim variable_2
Call Sub_2()
End Sub
Private Sub Sub_2()
'lines 1-10
'lines 11-20
End Sub
Here we have the setup for what you're looking at. Both Subs can 'see' variable_1, but Sub_2 can't see variable_2. This is called scope. Finally, there is the issue of only wanting to execute lines 1-10 inside Sub_2 when being called from Sub_1.
The first thing to do is to separate our code into logical groups. According to what you're describing, lines 1-10 of Sub_2 make sense when looked at on their own, so this automatically means that they should be grouped together. Lines 11-20 may be a different story, but since they are sometimes relevant and others not, we should separate them as well.
Private Sub Sub_2()
'lines 1-10
End Sub
Private Sub Sub_3()
Call Sub_2()
'lines 11-20
End Sub
The change looks simple, but is actually quite powerful. When we only want to execute lines 1-10, we call Sub_2. If we want to execute lines 1-20, we call Sub_3. Sub_3 will automatically call Sub_2 (lines 1-10) to execute first, and then execute lines 11-20. Easy.
Now we just have to figure out what to do about the variables. There are quite a few ways you can handle this situation, but the easiest thing to do is to expand their scope. If all the variables you need to access are declared outside of these Subs (one "level up"), then they can all access them. For example:
Dim variable_1
Dim variable_2
Private Sub Sub_1()
Dim variable_3
'can access 1, 2, 3 but NOT 4, 5
Call Sub_2()
End Sub
Private Sub Sub_2()
Dim variable_4
'can access 1, 2, 4 but NOT 3, 5
End Sub
Private Sub Sub_3()
Dim variable_5
'can access 1, 2, 5 but NOT 3, 4
End Sub
This should get you started. Once you've got this down, you can read about the various ways to pass variables into Subs and Functions (which also gives some hints about how to get them out, as well).
I very much doubt you will be able to do that. A function is a unit of code which can be called via Reflection if required, however statements within a function are not exposed via Reflection and when optimised often may not even execute in the order that they are written.
Such a process would break a lot of bad practises - what if the code changes in the future for example? An implementation can change, although one wouldn't expect the function's definition to.
I would question why you are wanting to do this and look for an alternative means of achieving your goals.
If you were hell bent on such a implementation, then you could potentially break open the CLR code and decompile and then select certain aspects to compile and run - however it would be a lot of hard work, unsustainable and very bad practise.

VBA duplicated declaration in "if...else"

Simple as below:
If 1 = 2 Then
Dim i As Integer
Else
Dim i As Integer
End If
This will give an error as "duplicated declaration in current scope". Why?
Variables are local to the sub/function (procedure). In your case, the "current scope". VB, VBA, and VBScript do not have the concept of code blocks within a procedure. If I remember correctly, the only code blocks are modules, classes, forms (which are classes), and procedures.
You can declare a variable anywhere within the procedure as a convenience. Yet, the "current scope" is the procedure.
It was a design decision to make the language easier to use for B-eginners.
Duplicate declaration in current scope
The specified name is already used at this level of scope. For
example, two variables can have the same name if they are defined in
different procedures, but not if they are defined within the same
procedure.
Inserted from http://msdn.microsoft.com/en-us/library/gg251613.aspx
In VBA, declarations of two variables with the same name cannot be made in the same procedure. See this article for more information: Duplicate declaration in current scope.
In your case, the "current scope" is the current procedure. The if and else blocks share the same scope.
For example, the following will give the same error even though the second declaration is unreachable:
Sub ErrorSub()
Dim i As Integer
If False Then
Dim i As Integer
End If
End Sub
But the following is perfectly valid and will work fine:
Sub MySub()
Dim i As Integer
i = 4
MsgBox i
End Sub
Sub MyOtherSub()
Dim i As Integer
i = 3
MsgBox i
End Sub
Sub CallSubs()
MySub
MyOtherSub
End Sub
As mentioned, you cannot have more than one Dim statement for a variable with the same scope. Aside from that, however, why would you want to? Take your code for example.
If 1 = 2 Then
Dim i As Integer
Else
Dim i As Integer
End If
The purpose of a conditional block is to execute two different pieces of code under two different circumstances. If you are declaring the same variable either way, there is no need for the conditional block at all. In all likelihood, it should probably be moved before the conditional.