I am a beginning in visual basic. What I am trying to do is whenever a box is clicked, highlight a specific range. Then, if another box is clicked after that, the previous range will unhighlight, and another range will highlight. Here is my code but it doesn't work right now.
Dim FSelect As Boolean
Dim myRange As Range
Sub Rectangle18_Click()
If FSelect Then
UnhighlightBox (myRange) <---error - runtime error "424" object required
End If
Range("C9:D9").Select
HighlightBox
FSelect = True
Set myRange = Range("C9:D9")
End Sub
Sub Rectangle19_Click()
If FSelect Then
UnhighlightBox (myRange)
End If
Range("C11:D11").Select
HighlightBox
FSelect = True
Set myRange = Range("C11:D11")
End Sub
Sub HighlightBox()
Selection.Interior.ColorIndex = 36
End Sub
Sub UnhighlightBox(cellRng As Range)
cellRng.Interior.ColorIndex = 2
End Sub
When I throw this code into excel it complains about Select. I don't think you can use Select as a variable...
EDIT: Select is a reserved keyword in VB/A, It begins the Select Case block.
Putting the parentheses around the argument when calling the UnhighlightBox procedure is incorrect.
Two possible correct forms:
UnhighlightBox myRange
Call UnhighlightBox(myRange)
I find the first form (without the Call keyword) to be preferable
For the Excel 2003 help:
You are not required to use the Call
keyword when calling a procedure.
However, if you use the Call keyword
to call a procedure that requires
arguments, argumentlist must be
enclosed in parentheses. If you omit
the Call keyword, you also must omit
the parentheses around argumentlist.
Please note that this does not apply to a function which returns a value. A function needs to be called as part of an assignment (e.g. a = f(x)) and the arguments must be enclosed in parentheses
Your use of the FSelect boolean (which initialises to false) should be preventing the problem with calling UnhighlightBox before myRange is ever set.
When using the UnhighlightBox routine you either need to put the Call statement before hand or remove the parenthesis.
For example:
Call UnhighlightBox (myRange)
or
UnhighlightBox myRange
For more info on why to use Call, etc see the either of the following:
what-does-the-call-keyword-do-in-vb6
MSDN
Related
I have a macro that goes through column(s) and removed numbers from all cells in the range. I would like to add an optional parameter, so I can call the sub while telling it which columns to run on. Here's what I have:
Sub GEN_USE_Remove_Numbers_from_Columns(Optional myColumns as String)
The idea being I can call it from another sub, like this GEN_USE_...Columns("A B C")
But, I can't run that from the VB Editor, nor can I see that macro in the Macro Window (when clicking View --> Macros). Why not? Why do I have to call it with a parameter (even GEN_USE_...Columns("")) I can't just call GEN_USE_...Columns() anymore.
I've seen that you can add = Nothing to the end, to set a default value if none is given. I've tried that () but it didn't do anything.
I guess my question is A) How come I can't see my macros that have Optional parameters, in the macro window? and B) Why can't I call the macro with parameters directly from the VB Editor? I have to actually create a sub, then I can call the macro within that sub. No more just highlighting some text and hitting "Play".
I know the two issues are probably related, so any insight would be appreciated!
(PS: I know we're supposed to post code, but I don't think that's very relevant. Of course, if you'd like to see it, let me know and I'll update).
Use Optional myColumns as Variant to show it in the Run Macro ([alt]+[F8]) dialog. Alternately, leave it hidden; you can type the name and click Run. The variant type is also the only one that responds properly to the IsMissing function.
Sub GEN_USE_Remove_Numbers_from_Columns(Optional myColumns As Variant)
If IsMissing(myColumns) Then
myColumns = Intersect(Selection.Parent.UsedRange, Selection).Address '.address 'cause you were using a string
End If
Debug.Print Range(myColumns).Address(external:=True)
End Sub
You can call the sub with parameters from the VBE's Immediate window ([ctrl]+G).
A Sub with ANY parameters, optional or not, cannot be run directly and can only be called from another Sub or Function
Best option is to write a wrapper Sub that will appear in the Macros window
Sub USER_Remove_Numbers_from_Columns()
GEN_USE_Remove_Numbers_from_Columns
End Sub
I've seen many users asking questions trying to change the colors of cells using User-defined functions. I was always under the impression that it was not possible to do so. My understanding was that a user-defined function cannot change any properties of a cell except the value of the cell that contains the formula. Subs are what change cells themselves.
However, when playing around with some code to test this, I found that it's not always the case.
Using the simple code:
Function ColorCell(rng As Range)
If rng.Value = 1 Then
ColorCell = False
Else
ColorCell = True
rng.Interior.ColorIndex = 3
End If
End Function
If I enter the function into a cell, I achieve expected results, no cells change colors. However, if I use the Formulas > Insert Function button and navigate to my formula to insert it this way, it does color the targeted cells.
How is this possible, and why did the function behave differently when entered in different ways?
EDIT: this was tested using Excel 2007
use this code...just replace sheet name and try
Sheets("sheet_name").range(j:j).clear
for j=2 to 15
if Sheets("sheet_name").Cells(j, 1).value=1 then
else
Sheets("sheet_name").Cells(j, 1).Interior.ColorIndex = 3
next j
As we all find out sooner or later, in user functions you can't access subs that change things in your spreadsheet directly.
But try this:
Dim ColorMeTarget As Range, ColorMeVal As Long
Public Function ColorMe(ByVal TargetRange As Range, ByVal ColVal As Long)
Set ColorMeTarget = TargetRange
ColorMeVal = ColVal
ColorMe = ColVal
End Function
Public Sub ColorMeSub()
Application.OnTime Now + TimeValue("00:00:05"), "ColorMeSub"
If ColorMeTarget.Interior.Color <> ColorMeVal Then ColorMeTarget.Interior.Color = ColorMeVal
End Sub
If you run the sub first, it will constantly scan the static variables ColorMeTarget and ColorMeVal to see if there is a change. The function ColorMe will set these values. Some additional code is needed in case ColorMeTarget is not yet initialized.
If you get smarter, you could have the function first check to see if there is indeed a change and add the new coloring requests to a stack. Your reoccurring sub can then 'catch up', especially if you have many functions like this.
You can then even have all kinds of additional controls added to your function/macro--EVEN STUFF NOT COVERED BY THE LATEST VERSIONS OF 'CONDITIONAL FORMATING'!!! YAY!!!!
Something to try: In some of my automated macros, I am able to set OnTime through a function but cannot make it work here. It would be cleaner to have the function set the OnTime and not have a reoccuring sub that needs initializing.
I use Worksheet_Change event to detect value change in working range. Example.I want to do something when range A1:A5 has been change. I use below event.
Sub Worksheet_Change(ByVal Target As Range)
If Not Intersect(Target, Range(<Your working range>)) Is Nothing Then 'Define range that you want to do
'Statement here
...
End If
End Sub
When the range value has been change. It will execute your code.
And other way. Use Conditional Formatting.
could also try the non-script method of auto-coloring a cell based on the condition of the cell (aka Conditional Formatting):
I am trying to use the function: Cells(Rows.Count, 14).End(xlUp).Row to determine the last row with data. This and similar formulas appear in many spots in my VBA code. My spreadsheet is quite complex and I often need to add columns. So rather than referring to Column 14, I'd like to use a value I can easily change in only one place. I am using a named Column of sorts that I only need to update in one place. Items sold appears in column N. I realize that this code is very simple, but I simplified it down for the sake of asking a question. When I try to run the Test sub, I a compile errror: ByRef argument type mismatch and the variable Item_Sold. The reason I am using a letter is that Range() needs a letter, but Cells().End(xlUp).Row needs a number.
It works if I move: Items_Sold = "N" to the sub from the function, but this means this code would have to go in every sub rather than in just one function.
Function:
Function ColNum(ColumnNumber As String) As Integer
Dim Items_Sold As String
Items_Sold = "N"
ColNum = Range(Replace("#:#", "#", ColumnNumber)).Column
End Function
Macro:
Sub Test()
Dim Total_Items_Sold As Integer
Total_Items_Sold = Cells(Rows.Count, ColNum(Items_Sold)).End(xlUp).Row
End Sub
Use a Global constant.
At the top of your module, outside of any Sub/Function:
Const COL_NUM As Long = 14
Usage:
Sub Test()
Dim Total_Items_Sold As Long
Total_Items_Sold = ActiveSheet.Cells(Rows.Count, COL_NUM).End(xlUp).Row
End Sub
Add a global variable at the beginning of the code by writing
public Items_Sold as String
that will solve your ByRef problem. But still you will have problem with undeclared value of Items_Sold when invoking Test() unless you set the value of Items_Sold somewhere before.
I have a very basic question about VBA sub routines. What I'm trying to do is
Set activeCell to Range variable
Pass that variable to Sub routine
Do something with the activeCell
What I tried to do is
Sub myMacro()
Dim myCell As Range
Set myCell = ActiveCell
mySub(myCell)
End Sub
Sub mySub(cell As Range)
' Do something
End Sub
I keep getting an "Object required" error.
What is the problem here?
When you pass arguments to a function, you dont need to use parenthesis. Eg:
mySub myCell
You could also use Lance sugention and use use Call AND parenthesis. (Press F1 over Call in the VBA Editor to get more info about it)
Call mySub(myCell)
Either way is correct, but the first notation might prove more helpful while learning VBA as the great mojority of Answers in forums use the first one.
You need to use the Call statement on the subroutine.
Call mySub(myCell)
I know this sounds simple, but seemingly it is not.
If I write this in Word VBA, it always says "incompatible types" - why?
And how do I make it work?
Sub GetRange()
Dim r As Range
Set r = ActiveDocument.Paragraphs(5).Range
ProcessRange (r)
End Sub
Sub ProcessRange(r As Range)
Debug.Print "This generates an error (incompatible types)- why?"
End Sub
It is not allowed to call a Sub with parenthesis, except if you are using the Call statement.
Hence you have to use either:
Call ProcessRange(r)
Or:
ProcessRange r
The reason for that is that in VBA (and VBS, VB6, too) the parenthesis can have a whole lot of different meanings.
In your case the range object will be evaluated before passing the result to ProcessRange. In this case it leads to a string being passed to the sub, because the default property of Range is Text.
See this article for an overview: http://blogs.msdn.com/ericlippert/archive/2003/09/15/52996.aspx
Process Range is a sub so don't invoke it with parentheses. (The error occurs because (r) causes r to be evaluated which returns its default property value which isn't of type range so mismatches what ProcessRange expects.
Use either;
ProcessRange r
or
call ProcessRange(r)
Using parenthesis visual basic assumes you're calling a function.
ProcessRange r
does the trick