I'm working with some checkboxes on a userform, and am checking if they have been checked by the user in my code. The question I'm running into is in how to properly check for this condition. I've found several examples, and am wondering where I may run into trouble with each.
For example, I have seen several snippets use:
If checkBox1.Value = "True" Then
or
If checkBox1.Value Then
or
If checkBox1 Then
Is there any functional difference between these? It seems like the latter is the shortest, most succinct application, however the engineer's brain in me is saying there must be a reason for the other two cases (although the more I work with VBA, the less I believe in that concept).
Any assistance or guidance you could provide would be appreciated.
I would recommend the second one. It is always best to specify the property of an object explicitly rather than relying on defaults. There is no point in comparing a Boolean to True/False, since it already is True or False, and there is less point comparing it to a String value (which would be different in different regions).
In this case they are all the same and can be used interchangeably. Yet, I would only use the first or the second option.
checkBox1 is essentially incomplete and VBA automatically assumes (for you) that you are referring to its value and hence "completes" (during run-time) your code to checkBox1.Value. This takes time and may essentially slow down your code (even if this is barely noticeable).
To most programmers the second option is the preferred option because the if statement evaluates if something is True or False. Since the .Value of the checkbox is already True or False the first option is unnecessarily long. The value of checkbox1 is alredy True. So, why would you compare it to True?
At the same time I always prefer to use the first option as it makes the code easier to read for me (personal preference).
So, I'd say option 1 or 2: it's your choice.
Related
Concerned about code falling over in scenarios I haven't thought of during testing and so wanted to understand the difference between these two approaches, which appear to accomplish exactly the same thing:
ActiveWindow.Selection.ShapeRange(1)
ActiveWindow.Selection.ShapeRange.Item(1)
Context is: Identifying the shape in which the active cursor position is, or if whole shapes selected, the first shape in the selected items (i.e. if there's an active cursor inside a shape, it returns that shape; if the user has selected multiple shapes, it returns the first shape).
Looking at MSDN:
For first option, appears you can add the index in the brackets to access whatever shape number in selected shapes https://learn.microsoft.com/en-us/office/vba/api/powerpoint.shaperange
But looking at "Item", appears to do exactly the same thing by definition "Returns a single Shape object from the specified ShapeRange collection."
https://learn.microsoft.com/en-us/office/vba/api/powerpoint.shaperange.item
What is the difference and in what situations can it lead to erroring out?
TIA
That link posted by Tim Williams gives a good explanation of what's going on - well worth a read.
In answer to your specific questions:
There's no difference in the two lines of code. Since .Item is the default property of a collection object, ShapeRange(1) is doing the same as ShapeRange.Item(1). Coding style is a matter of personal preference, but most VBA developers avoid implicit references. Having said that, I'd say most of us do leave out .Item when referencing a collection, eg ThisWorkbook.Worksheets("Sheet1"). If you're interested, I do find .Item useful for code that is wrapped in a With ... End With block:
With ThisWorkbook.Worksheets
.Add After:=.Item(.Count)
End With
No, your code won't fail. The only reason it might fail would be if Microsoft changed its default property for the Collection object, and you're more likely to be eaten by a shark while being struck by lightening on the same day your lottery numbers came up.
Sometimes when developing you find that typical property names show up in lower case.
TempVars.Item("abc")
Might appear like this.
TempVars.item("abc")
Or
tbxMyTextbox.Value
Shows up as
tbxMyTextbox.value
The question is why does this happen and how do you fix it?
I've asked myself this question several times and seen others ask it in SO and elsewhere. In most cases the question comes up when searching for answers on other coding errors. Sometimes the developer (me too) wonders if there's something wrong that they're missing that causes this lower case issue.
A while back I ran across an answer (I'll add the original reference when I run across it again) that made the most sense and actually allowed me to correct this nagging issue.
Apparently it happens when you use a variable in lower case that has a name that's the same as a property.
So
Dim value as string
will result in
myObject.Value
appearing as
myObject.value
Solution?
Because VBE apparently considers this variable across the entire IDE -- apparently without regard to scope; the way to revert to the proper case is to temporarily create the variable in upper case and avoid naming variables with the same name as existing properties in your application.
So the solution for the .value / .Value issue above would be to temporarily include the line
Dim Value as string
in a module within your app. Run the code that includes this line.
Afterwards, remove this temporary line of code.
Then as hoped, .value properties will again appear as .Value and not .value.
Of course, we should avoid those reserved words in the first place, but if at some point that wasn't done the above should fix the issue.
Here are some reserved word links:
Microsoft - Access 2002 & later
Allen Browne's bad word list
Reserved Word search tool (various languages)
Thanks to #ScottCraner for the nudge about avoiding reserved words.
Try something like this:
CallByName(myObject, "value", VbGet)
I'm using the trick described here - !A1 - to get the the range of cells up to and including the current one (typically for a Rows() function). This works great for day to day usage, and eliminates a lot of errors that I get when moving ranges around when I previously had to use an adjacent set of rows.
Unfortunately, my formulas need to be evaluatable from VBA. With __THISCELL__ as my !A1 cell, and the cell housing the formula as $Z$100 the following evaluates to an error:
Application.Evaluate(rngCell.formula)
And the following evaluates to $A$1:$Z$50
rngCell.Worksheet.Evaluate(rngCell.formula)
Obviously an approach is to replace __THISCELL__ with rngCell.Address(External:=True) prior to evaluation, but here's the kicker: I'd like to be able to execute my formula parser in a workbook which uses, say THIS_CELL, THISCELL or __THISCELL safely, and I'd also like to be able to safely execute my code in a workbook with a name like __NOT__THIS_CELL__.
All I need for this is a mechanism to evaluate relative references relative to a specific cell address - which since people do use R1C1 references in VBA a fair bit, I imagine must be around. However, I don't know it. Can anyone help?
NB: I like to avoid fiddling with ActiveCell, Selection, etc. where possible, since those smell like the excel equivalent of SendKeys - who knows what the user is doing when you access them. Even then, though, I'm not certain I'll get the right answer, because for the Worksheet.Evaluate approach, I'm not positioned in cell $A$1!
If I understand your question, I believe you're looking for the Range().Offset method.
Range().Offset(rOffset, cOffset) refers to a range that is rOffset lower and cOffset to the right of the given range (negative values for up and left are allowed). Also, .Offset can access and set all of the properties of the range, just like you would do with .Range.
The approach I've taken for the time being is implicit in the question: when a named range is detected, store the current selection and worksheet, select the one which we use as the evaluation context, and then use Evaluate. This seems to work, provided the cell being evaluated is inside the activesheet.
I don't like jumping the selection all over the place - feels dirty - but short of a more elegant solution, it does work.
So I have a frustratingly simple issue that I cannot seem to solve.
If Me.Bank_Credit.Value = Null Then
Me.Bank_Credit.Value = 0
End If
Basically, I have an unbound box that the user enters data into and then hits a button. After a YES on confirmation box, the data on the unbound box is copied over to the bound box. However, if the user does not enter anything, that in turn creates an empty bound field which can seriously screw up queries down the road.
That being said, the above code simply will not work for me. If I set, for instance, If Me.Bank_Credit.Value = 1 and then run it, the 1s get turned into 2s, as should happen. But it simply refuses to work for Null or even "".
I'm so sure there is a simple solution to this issue, I just can't figure it out.
Thanks in advance
Nothing is ever equal to Null, not even another Null. And nothing is ever not equal to Null, not even another Null.
When Bank_Credit is Null, the following expression will return Null ... not True as you might expect, or even False.
Debug.Print (Me.Bank_Credit.Value = Null)
It's the same reason for this result in the Immediate window:
Debug.Print Null = Null
Null
Use the IsNull() function.
If IsNull(Me.Bank_Credit.Value) Then
Also, look at the Nz() help topic to see whether it can be useful. You could do this, although it's not really an improvement over IsNull(). But Nz() can be very convenient for other VBA code.
Me.Bank_Credit = Nz(Me.Bank_Credit, 0)
HansUp's answer is right, but I thought it relevant to add that there is a similar construct for "Nothing" which is basically a VBA keyword for a dereferenced object. You have to use statements like
If myRange is Nothing Then
You will see these sort of statements all over the VBA help files (and actually in other languages that have a keyword similar to this).
I've been working with Access for a while now, and although I understand the obvious benefit of a Function over a Sub, been that it can return values as a result, I'm not sure as to why I should use a Sub over a Function. After all unless I'm mistaken; Functions can do everything Subs can do?
Note: I'm fully aware of how to use both Sub's and Function's so not looking for an explanation of how they work.
In terms of performance, this would not be any significant issue here.
The main difference is that user defined function can be used in expression in your code, where as a sub cannot.
This is really a HUGE Mount Everest of a difference here.
This difference is not really limited to Access, but tends to applies to every programing language and system I can think of that supports the creating of user defined functions.
The key advantage of using defined function are MANY but the most basic issue is that such function can be used in EXPRESSIONS.
For example, in an on click setting for a button on a form, you can generally have a single VBA [Event Code] routine attached to that button.
However you can ALSO place an expression in the property sheet like this:
=MyUserFunction()
The above is a handy tip, since then you can highlight 10 controls on a form, and type in the above expression and you just assigned the above function to those 10 buttons. You cannot do the above with a sub.
Another significant difference is you can use a function as a data source (expression) for a text box on a form or report (again you cannot do this with a sub).
Another significant difference is you can utilize these functions in SQL. This is a truly fantastic ability as then you can have code "run" for each row of a query. And this means you can extend the ability and functionally of SQL.
And you can even use this idea to display a VBA variable in a sql query as you simply build a public function that returns the VBA variable and this can be used in a query – you cannot however use VBA variables in a query!
And this extending of SQL opens up endless ideas:
So I can build a public function called ToMorrow()
Public Function Tomorrow() as date
Tomorrow() = date() + 1
End Function.
Now in the query builder, I can go:
Select FirstName, lastName, Tomorrow() as NextDay from tblCustomers
And you can even make custom conversions such as:
Select FirstName, LastName, Celsius([DailyGreenHouseTemp]) from tblGreenHouse.
The above Daily temperature reading could in in Fahrenheit and you simply have to define a public function called Celsius like this:
Public Function Celsius(Temperature As Variant) As Variant
Celsius = (Temperature * 1.8) + 32
End Function
Now while the above function is simple, it could do complex record set processing a complex algorithm to determine the moisture above a flower pot based on temperature and humidity.
So once we define such a public function, then the key concept is such a function can be used not only in VBA code as an expression, but ALSO can be used amazing enough this ability includes SQL.
So even in code, you can go:
If MyCustomfucntion(SomeVar) = lngTestValue then
Again in the above, you cannot use a sub in VBA expressions.
And even more interesting is when using custom XML for ribbons in Access, then if you use a function() expression for the "on action" attribute then you can avoid the need for ribbon call backs. Even better is the ribbon will call those functions() in the current form, not a public code module like you MUST do with ribbon call backs.
I could probably type on for another 10+ pages as to the difference, but I think that would start to be redundant and I don't want to appear condensing in any way here.
So the basic difference between a sub and function in VBA or in fact in most programming languages is quite much the same.
And the benefits of using a function in Access or just about any programing language are also much the same. For example I can define a user defined function in t-sql (scalar) – and again you then are free to use that t-sql function in any of your t-sql code or even quires that you create and use for sql server.
So this is basic and simple difference between a sub and a function, and I dare say those who have written computer code will in just about any programing language will instantly realize the above significant and useful differences between a subroutine and a function.
The main difference is not only the return value, it seems that subs are faster than functions
(at least in .net) because the MSIL code of subs is much shorter when no value is returned. so overall subs are faster when no value is returned.
oh i've just found a great source for it (talks about .net), maybe you would like to read further about it- Functions vs. Subroutines
Yes, a Function is just a Sub that returns a value.
I'm not absolutely sure, however, I think subs are faster than functions because the variables of a subroutine are defined upon creation of the subroutine and are accessed by referencing the memory location. Functions must allocate memory space every time they are accessed.
Subroutines modify the variables in the calling code and functions leave them intact. So a subroutine can provide several modified pieces of information to the calling code (as many changes as there are variables, including arrays) but a function can only provide one answer at a time for the values that are passed to it. Because of this difference, if it is important that a variable in a subroutine does not change its value, one must assign the value to a temporary variable defined within the subroutine itself.
FWIW (my theory ;) -
Lets think of the real world to understand this.
Lets say you want to get something done. There are (at least) 2 ways of doing this.
First way, send out requests for information to helpers and they will return with the information for you. so you remain in control ie all info is flowing back to you and you are deciding what to do next if any. this is more of the centrally controlled environment. this is the essence of 'function' in vba
Second way, divide up work into separate tasks and assign responsibility to your helpers to finish the task for you ie actual work is performed here by helpers in contrast to just gathering info. This is the essence of 'sub' in vba.
So think of what to do if code breaks. with function calls, you concentrate on the central command to look for reason of failure. With sub calls, you have to run into each sub's work and find out what they did wrong.
Of course, you can screw up the purpose and have functions do work and subs just get info but that would just be really confusing when things break! Oh but you cant do that, read this link - http://www.cpearson.com/excel/differen.htm, which states that Excel forbids functions changing cell values and subs being called from cells.
You will note that events are always subs, never functions. However, in MS Access, it can be useful to create functions when you wish to use them as the property of an event:
On Close: = MyCloseFunction()
Subs can return a value ByRef.
I found one other difference, at least on Excel but likely other Office apps. If you want to customize the ribbon by adding a button to launch a VB program, when you choose Macros in the "Choose commands from" dropdown menu, it lists any Subs in your code but not Functions. Note that a Private Sub will also be hidden from the customize ribbon selection, as will a Public Function.
So to summarize, these will be available to add as buttons on the ribbon:
Sub, Public Sub
And these will not be available to add:
Function, Public Function, Private Function, Private Sub